Hallo!
Ich habe da mal eine Frage zu einer Best-Practice.
Ich habe 2 BOs (A und B) und A hat ein Property mit einer Auflistung von mehreren Bs).
Im konstruktor von A wird ein Thread gestartet (aus dem ThreadPool) welcher das Property befüllt/initialisiert. In diesem Thread werden die einzelnen Bs geladen un der Auflistung hinzugefügt. Somit sind sie beim Zugrif auf die Auflistung bereits vorhanden (die Daten werden also bereits im Hintergrund geladen für bessere Performance).
Nun zu meinem Problem.
Wenn ich auf die Auflistung zugreife, obwohl der thread sie noch nicht gefüllt hat bekomme ich eine leere Auflistung zurück. Das ist ja ein unerwünschter Effekt des Ladens im Hintergrund.
Mein Ansatz wäre folgender:
In A gibt es eine Variable "bereits geladen" welche default auf "nein" steht. Der Thread zum Laden setzt diese Variable am Ende auf "ja".
Beim Zugriff auf die auflistung wird geprüft ob "bereits geladen" auf "ja" steht. Falls nicht dann warte ich mittels Thread.Sleep(100) bis es auf "ja" steht.
Ist das so gängige Best-Practice oder gibt es bessere Varianten? Mich stört konkret das Thread.Sleep, aber mir fällt eben keine bessere Möglichkeit ein.
Kannst du dir keinen Event bauen, der gefeuert wird, sobald der Thread fertig ist mit der Initialisierung?
Hallo,
also im Konstruktor Threads zu starten finde ich nicht grade gut, aber ist hier nicht das Thema.
Du kannst AutoResetEvent
verwenden:
public class A
{
private AutoResetEvent ev = new AutoResetEvent(false);
private List<object> bList;
public A()
{
// Threads
ThreadPool...(callback_methode);
}
void callback_methode()
{
bList = ...
ev.Set();
}
public List<object> Bs
{
get
{
ev.WaitOne();
return bList;
}
}
}
Beim Zugriff auf die auflistung wird geprüft ob "bereits geladen" auf "ja" steht. Falls nicht dann warte ich mittels Thread.Sleep(100) bis es auf "ja" steht.
Und wozu dann überhaupt ein Thread, wenn du im anderen warten willst?
Wenn du einen UI Thread entlasten willst, dann feuere ein Event nach Abschluss des Lesevorgangs.
Hallo Froggie,
In A gibt es eine Variable "bereits geladen" welche default auf "nein" steht.
Das ist gar nicht nötig, denn es kann auf != null geprüft werden und das liefert dasselbe Ergebnis.
Ich würde einfach bei A INotifyPropertyChanged implementieren und wenn die Bs geladen sind das PropertyChanged-Event feuern. In der UI ist die Auswahlmöglichkeit der Bs disabled solagen sie nicht geladen sind od. es wird eine leere Liste angezeigt. Erst wenn sie geladen sind, wird duch das PropertyChanged benachrichtigt, wird die Asuwahl enabled.
mfG Gü
Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.
"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"
Aufgrund der Rahmenbedingungen habe ich die Lösung von Sarc probiert.
Diese funktioniert bei mir ausgezeichnet.
Ich musste nur eine Kleinigkeit anpassen.
ev.WaitOne(10, true);
Vielen Dank nochmal!
Nur kurz am Rande, was spricht gegen eine BindingList oder eine ObservableCollection? Beide sagen dir Bescheid, wenn sich Items geändert haben; somit kann das GUI entsprechend drauf reagieren (über ListChanged bzw. CollectionChanged).
Der Background-Thread fügt einfach jedes Item ein, was er geladen hat, anstatt drauf zu warten bis alles fertig ist (Hinweis: eventuell bekommst du hier auch wieder Probleme beim Zugriff von verschiedenen Threads, dafür kannst du aber die Forensuche benutzen - gab schon genug Beiträge zu den Punkten).
Je nachdem, ob du auf der anderen Seite sogar WPF hast, sollte das ganze auch ohne größere Umbauten automagically funktionieren.
Hallo Froggie,
wenn ich es richtig verstehe, geht es letztlich darum, die Daten im GUI anzuzeigen. Dann ist aber WaitOne tabu, weil sonst das GUI blockiert.
Sicher kann man sagen, geht doch die Klasse nichts an, dass ihre Daten im GUI angezeigt werden sollen. Das ist nicht ganz falsch, aber man muss ja für den Benutzer der Klasse auch keine unnötigen Fallstricke einbauen.
Dazu kommt was FZelle andegeutet hat, dass es sowieso wenig Sinn macht, eine Aktion in einen anderen Thread zu verlagern und dann im ursprünglichen Thread darauf zu waren, bis die Aktion fertig ist.
Eine Lösung über Events (ob nun eigene oder die von passenden fertigen Klasse sei mal dahingestellt) ist wesentlich sinnvoller.
herbivore