Laden...

Einfrieren des GUIs verhindern: Thread oder Backgroundworker für asynchrone Vorgänge?

Erstellt von reloop vor 13 Jahren Letzter Beitrag vor 13 Jahren 2.982 Views
reloop Themenstarter:in
139 Beiträge seit 2010
vor 13 Jahren
Einfrieren des GUIs verhindern: Thread oder Backgroundworker für asynchrone Vorgänge?

Hallo liebe Community,

ich habe eine Frage zum Umgang der beiden o.g. Objekte. Ich möchte in einer Combobox suchen, welche an eine List<> gebunden ist. Da die Anwendung immer kurz hängt, wenn sich das DropDown mit den neuen Daten öffnet, möchte ich dieesen Vorgang gerne auslagern.

Nun meine Frage:

Nutze ich dafür einen Thread im ComboBox-DropdownOpen Event?

Und wie löse ich das Problem, wenn ich NACH beenden des Threads noch Code ausführen will? Quasi einen "ExitCode" oder "DoAfterWorkCode".

Oder ist mein Ansatz komplett Falsch und ich sollte auf einen Backgroundworker zurückgreifen?

Gruss,
reloop

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

grundsätzlich startest du im Ereignis-Handler einen asynchronen Vorgang - damit die UI nicht einfriert - und wenn in diesem Vorgang das Ergebnis vorliegt aktualisiert du die UI wie in [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke) beschrieben.

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!"

reloop Themenstarter:in
139 Beiträge seit 2010
vor 13 Jahren

Danke gfoidl.

Also kurzgefasst ist mein Vorgang dieser:

ComboboxOpen
---Thread der die Funktion "ManageMySearch" Aufruft
-----"ManageMySearch" beinhaltet die Filterung der Liste + einen AsyncCallBack mit der aktualisierung der Gui?

Gruss und vielen Dank,
reloop

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

das AsyncCallBack brauchst du nicht.

Cica so:


private void ComboboxOpen(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorktItem(_ =>
    {
        IEnumerable<string> results = MyFilterMethod(...);

        Action<IEnumerable<string>> cheapUIAccess = r => myListBox.DataSource = r;

        this.BeginInvoke(cheapUIAccess, results);
    });
}

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!"

reloop Themenstarter:in
139 Beiträge seit 2010
vor 13 Jahren

Umgebaut auf meine Anwendung sieht es jetzt so aus:

             ThreadPool.QueueUserWorkItem(_ =>
            {
                var searchResult = ReturnSearchResult(_search);

                Action<List<myData>> cheapUIAccess = r => ItemsSource = r;

                Dispatcher.BeginInvoke(cheapUIAccess, searchResult);
            });  

Verstehe ich den Ablauf richtig? der QueueUserWorkItem hängt die ihm über Lambda zugewiesene Methode dem Pool an abzuarbeitenden Methoden an?

Und wird mit Action<List<myData>> cheapUIAcess eine Methode erstellt, mit dem Parameter "r", der in der Methode selbst den ItemsSource mit seinem wert belegt?

Und zum Schluss wird mithilfe des BeginInvoke diese Funktion aufgerufen (cheapUiAcess) und der Parameter "searchResult" stellt indem Fall mein "r" da?

Verzeih mir diese Laienhaften Fragen, aber das hilft es mir besser zu verstehen.

Und eine Frage zum Schluss: Wo ist der Vorteil des QueueUserWorkItem gegenüber einem eigenen Thread? Oder wird er dadurch erzeugt?

Danke für deine Hilfe,
deine Beiträge sind mir jedes eine riesen Hilfe.

Gruss,
reloop

PS: Funktionieren tut es spitze!

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

zu den Frage: 3x Ja

Der ThreadPool hat den Vorteil dass dort Threads auf Lager sind -> einer wird genommen für die Arbeit und dann wieder auf das Lager gelegt. Das ist vorteilhaft im Vergleich zu jedesmal einen Thread erstellen, diesen arbeiten lassen und dann zerstören - da die Threaderstellung aufwändig ist.

Wenn du .net 4.0 verwendest wäre der zu bevorzugende Weg der über Tasks. Diese stellen eine weitere Abstraktion der Arbeit mit Threads dar (und intern wird standardmäßig mit dem ThreadPool - aus oben genannten Gründen - gearbeitet). Hier gibt es zusätzlich die Möglichkeit oder den Vorteil eines speziellen TaskSchedulers zu verwenden die es erlaubt ohne expliziten Invoke/BeginInvoke auf die UI zuzugreifen. Der Code wäre dann wie folgt (reduziert):


Task.Factory.StartNew(
	delegateForWork,
	CancellationToken.None,		// oder wenn du es abbrechen willst halt anderer Wert
	TaskCreationOptions.None,
	TaskScheduler.FromCurrentSynchronizationContext());

Somit "fangt" der TaskScheduler den aktuellen SynchronizationContext und dieser eledigt das delegieren in den UI-Thread.

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!"

795 Beiträge seit 2006
vor 13 Jahren

Wo ist der Vorteil des QueueUserWorkItem gegenüber einem eigenen Thread? Oder wird er dadurch erzeugt?

Es benutzt einen Thread aus dem Threadpool. Diese sind schon vorhanden und müssen nicht neu erzeut werden.

//Edit: zu spät 😁

`There are 10 types of people in the world: Those, who think they understand the binary system Those who don't even have heard about it And those who understand "Every base is base 10"`
reloop Themenstarter:in
139 Beiträge seit 2010
vor 13 Jahren

Danke, habe es jetzt so umgesetzt wie o.g. und es ist genau das wonach ich gesucht habe.

Letzte Frage:

" ThreadPool.QueueUserWorkItem(_ =>" wofür steht in dem Fall das "_" ?

Bei MouseOver zeigt er mir an: "parameter (object) _" .. kann ich in dem Zusammenhang aber leider nicht wirklich in Verbindung bringen.

458 Beiträge seit 2007
vor 13 Jahren

Das ist eine Lambda Expression.. man sollte normalerweise schon wissen was man tut und nicht einfach abtippen 😉

be the hammer, not the nail!

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

es ist ein das Argument des Delegaten für eine anonyme Methode, könnte auch jedes andere Zeichen sein oder sonst ein Argumentname. _ wird halt gewählt wenn dir sonst nix einfällt 😉
Siehe auch [Artikel] Delegaten, anonyme Methoden, Lambda-Ausdrücke & Co.

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!"