it-swarm.com.de

Einberufen (delegieren)

Kann jemand bitte diese Erklärung erklären, die auf diesem Link steht - link

Invoke(Delegate):

Führt den angegebenen Delegaten in dem Thread aus, der das darunter liegende Fensterhandle des Controls besitzt.

Kann jemand erklären, was dies bedeutet (besonders das mutige), ich kann es nicht klar verstehen

78
user1903439

Die Antwort auf diese Frage liegt in der Funktionsweise von C # Controls

Steuerelemente in Windows Forms sind an einen bestimmten Thread gebunden und nicht fadensicher. Wenn Sie also die Methode eines Steuerelements aus einer .__ aufrufen. In einem anderen Thread müssen Sie eine der aufrufenden Methoden des Steuerelements für .__ verwenden. marshall den Aufruf an den richtigen Thread. Diese Eigenschaft kann für .__ verwendet werden. Stellen Sie fest, ob Sie eine invoke-Methode aufrufen müssen. Dies kann nützlich sein, wenn Sie wissen nicht, welcher Thread ein Steuerelement besitzt.

Von Control.InvokeRequired

Invoke bewirkt, dass der von Ihnen aufgerufene Code in dem Thread auftritt, in dem das Steuerelement "lebt" und Cross-Thread-Ausnahmen effektiv verhindert.

Aus historischer Sicht war dies in .NET 1.1 tatsächlich erlaubt. Das bedeutete, dass Sie versuchen könnten, Code im "GUI" -Thread von einem beliebigen Hintergrundthread aus auszuführen, und dies würde meistens funktionieren. Manchmal würde dies nur dazu führen, dass Ihre App beendet wird, weil Sie den GUI-Thread tatsächlich unterbrochen haben, während er etwas anderes ausführte. Dies ist die Cross Threaded Exception - Stellen Sie sich vor, Sie versuchen, eine TextBox zu aktualisieren, während die GUI etwas anderes malt. 

  • Welche Aktion hat Priorität? 
  • Ist es überhaupt möglich, dass beides gleichzeitig geschieht? 
  • Was passiert mit allen anderen Befehlen, die die GUI ausführen muss?

Sie unterbrechen effektiv eine Warteschlange, was unvorhergesehene Folgen haben kann. Invoke ist praktisch die "höfliche" Methode, um das, was Sie tun möchten, in diese Warteschlange zu bringen, und diese Regel wurde von .Net 2.0 durch eine ausgelöste InvalidOperationException durchgesetzt.

Um zu verstehen, was eigentlich hinter den Kulissen vor sich geht und was mit "GUI-Thread" gemeint ist, ist es hilfreich zu verstehen, was eine Message Pump oder Message Loop ist. 

Dies ist eigentlich schon in der Frage " Was ist eine Message Pump " beantwortet und wird zum Lesen des aktuellen Mechanismus empfohlen, mit dem Sie sich bei der Interaktion mit Steuerelementen beschäftigen.

Andere Lektüre, die Sie möglicherweise nützlich finden, umfasst:

Was ist los mit Begin Invoke

Eine der Hauptregeln der Windows-GUI-Programmierung ist, dass nur die Ein Thread, der ein Steuerelement erstellt hat, kann auf seinen Inhalt zugreifen und/oder ihn ändern (bis auf wenige dokumentierte Ausnahmen). Versuchen Sie es von einem beliebigen anderen Ort aus. Thread und Sie erhalten unvorhersehbares Verhalten von Deadlock bis Ausnahmen von einer halb aktualisierten Benutzeroberfläche. Der richtige Weg, um eine .__ zu aktualisieren. Die Steuerung eines anderen Threads besteht darin, eine entsprechende Nachricht an die .__ zu senden. Warteschlange für Anwendungsnachrichten. Wenn die Nachrichtenpumpe zu .__ wechselt. Beim Ausführen dieser Nachricht wird das Steuerelement auf derselben .__ aktualisiert. Thread, der es erstellt hat (Denken Sie daran, dass die Nachrichtenpumpe auf dem..... Thread ausgeführt wird).

und für einen mehr Code umfassenden Überblick mit einem repräsentativen Beispiel:

Ungültige cross-thread-Vorgänge

// the canonical form (C# consumer)

public delegate void ControlStringConsumer(Control control, string text);  // defines a delegate type

public void SetText(Control control, string text) {
    if (control.InvokeRequired) {
        control.Invoke(new ControlStringConsumer(SetText), new object[]{control, text});  // invoking itself
    } else {
        control.Text=text;      // the "functional part", executing only on the main thread
    }
}

Wenn Sie sich mit InvokeRequired auskennen, möchten Sie möglicherweise erwägen, eine Erweiterungsmethode zu verwenden, um diese Anrufe abzuschließen. Dies wird in der Stack Overflow-Frage Bereinigen von Code mit belastetem Aufruf erforderlich behandelt. 

Es gibt auch ein weiteres schreibe auf, was historisch geschehen ist , das von Interesse sein könnte.

115
dash

Ein Steuerelement oder Fensterobjekt in Windows Forms ist nur ein Wrapper um ein Win32-Fenster, das durch ein handle (manchmal als HWND bezeichnet) identifiziert wird. Die meisten Aktionen, die Sie mit dem Steuerelement ausführen, führen schließlich zu einem Win32-API-Aufruf, der diesen Handle verwendet. Das Handle gehört dem Thread, der es erstellt hat (normalerweise dem Haupt-Thread) und sollte nicht von einem anderen Thread bearbeitet werden. Wenn Sie aus irgendeinem Grund etwas mit dem Steuerelement aus einem anderen Thread tun müssen, können Sie Invoke verwenden, um den Haupt-Thread in Ihrem Namen dazu aufzufordern.

Wenn Sie beispielsweise den Text eines Labels aus einem Arbeitsthread ändern möchten, können Sie Folgendes tun:

theLabel.Invoke(new Action(() => theLabel.Text = "hello world from worker thread!"));
61
Thomas Levesque

Wenn Sie ein Steuerelement ändern möchten, muss dies in dem Thread erfolgen, in dem das Steuerelement erstellt wurde. Diese Invoke-Methode ermöglicht das Ausführen von Methoden im zugehörigen Thread (dem Thread, dem das darunterliegende Fensterhandle des Steuerelements gehört).

Im folgenden Beispiel löst thread1 eine Ausnahme aus, da SetText1 versucht, textBox1.Text von einem anderen Thread zu ändern. In Thread2 wird Action in SetText2 jedoch in dem Thread ausgeführt, in dem die TextBox erstellt wurde

private void btn_Click(object sender, EvenetArgs e)
{
    var thread1 = new Thread(SetText1);
    var thread2 = new Thread(SetText2);
    thread1.Start();
    thread2.Start();
}

private void SetText1() 
{
    textBox1.Text = "Test";
}

private void SetText2() 
{
    textBox1.Invoke(new Action(() => textBox1.Text = "Test"));
}
20
Mehmet Ataş
Invoke((MethodInvoker)delegate{ textBox1.Text = "Test"; });
5
BestDeveloper

this.Invoke(delegate) Stellen Sie sicher, dass Sie den Delegaten das Argument an this.Invoke() im Haupt-Thread/erstellten Thread aufrufen. 

Ich kann sagen, dass eine Thumb-Regel nur vom Haupt-Thread aus auf Ihre Formularsteuerelemente zugreifen kann.

Möglicherweise sind die folgenden Zeilen für die Verwendung von Invoke () sinnvoll.

    private void SetText(string text)
    {
        // InvokeRequired required compares the thread ID of the
        // calling thread to the thread ID of the creating thread.
        // If these threads are different, it returns true.
        if (this.textBox1.InvokeRequired)
        {   
            SetTextCallback d = new SetTextCallback(SetText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.textBox1.Text = text;
        }
    }

Es gibt Situationen, in denen Sie einen Threadpool-Thread (d. H. Worker-Thread) erstellen, der auf dem Haupt-Thread ausgeführt wird. Es wird kein neuer Thread erstellt, da für die Verarbeitung weiterer Anweisungen ein Thread verfügbar ist. Untersuchen Sie also zuerst, ob der aktuell ausgeführte Thread der Haupt-Thread ist, und verwenden Sie this.InvokeRequired. Wenn true zurückgegeben wird, wird der aktuelle Code im Worker-Thread ausgeführt. this.Invoke (d, neues Objekt [] {Text});

ansonsten aktualisieren Sie das UI-Steuerelement direkt (hier wird garantiert, dass Sie den Code im Haupt-Thread ausführen.)

2
Srikanth

In der Praxis bedeutet dies, dass der Delegat garantiert im Hauptthread aufgerufen wird. Dies ist wichtig, da im Falle von Windows-Steuerelementen, wenn Sie ihre Eigenschaften im Haupt-Thread nicht aktualisieren, die Änderung entweder nicht angezeigt wird oder das Steuerelement eine Ausnahme auslöst.

Das Muster ist:

void OnEvent(object sender, EventArgs e)
{
   if (this.InvokeRequired)
   {
       this.Invoke(() => this.OnEvent(sender, e);
       return;
   }

   // do stuff (now you know you are on the main thread)
}
2
briantyler

Dies bedeutet, dass der Delegat im UI-Thread ausgeführt wird, auch wenn Sie diese Methode von einem Hintergrund-Worker- oder Thread-Pool-Thread aus aufrufen. UI-Elemente haben thread affinity - sie sprechen nur direkt mit einem Thread: dem UI-Thread. Der UI-Thread ist definiert als der Thread, der die Steuerinstanz erstellt hat, und ist daher dem Fenster-Handle zugeordnet. Aber all das ist ein Implementierungsdetail.

Der Schlüsselpunkt ist: Sie würden diese Methode von einem Worker-Thread aus aufrufen, um auf die Benutzeroberfläche zuzugreifen (um den Wert in einem Label usw. zu ändern), da Sienicht dazuberechtigt sind ein anderer Thread als der UI-Thread.

1
Marc Gravell

Delegierte sind im Wesentlichen inline Action oder Func<T>. Sie können einen Delegaten außerhalb des Gültigkeitsbereichs einer Methode deklarieren, die Sie ausführen, oder einen lambda-Ausdruck verwenden (=>); Da Sie den Delegaten innerhalb einer Methode ausführen, führen Sie ihn in dem Thread aus, der für das aktuelle Fenster/die aktuelle Anwendung ausgeführt wird, bei dem es sich um das fett dargestellte Bit handelt.

Lambda-Beispiel

int AddFiveToNumber(int number)
{
  var d = (int i => i + 5);
  d.Invoke(number);
}
0
LukeHennerley

Dies bedeutet, dass der übergebene Delegat für den Thread ausgeführt wird, der das Control-Objekt (das ist der UI-Thread) erstellt hat.

Sie müssen diese Methode aufrufen, wenn Ihre Anwendung Multithreading ist und einige UI-Vorgänge von einem anderen Thread als dem UI-Thread ausgeführt werden sollen. Wenn Sie nur versuchen, eine Methode in einem Control aus einem anderen Thread aufzurufen, erhalten Sie eine System.InvalidOperationException.

0
user1610015