Aufräumen von Code mit InvokeRequired
Ich weiß, dass, wenn die Manipulation von UI-Steuerelemente aus beliebigen nicht-UI-thread, müssen Sie marshal Ihre Aufrufe im UI-thread, um Probleme zu vermeiden. Der Allgemeine Konsens ist, dass Sie verwenden sollten InvokeRequired testen, und wenn es true ist, verwenden .Aufrufen, um führen Sie das Marshalling.
Dies führt zu einer Menge von code, der wie folgt aussieht:
private void UpdateSummary(string text)
{
if (this.InvokeRequired)
{
this.Invoke(new Action(() => UpdateSummary(text)));
}
else
{
summary.Text = text;
}
}
Meine Frage ist: kann ich weglassen, die InvokeRequired testen und einfach anrufen, Aufrufen, etwa so:
private void UpdateSummary(string text)
{
this.Invoke(new Action(() => summary.Text = text));
}
Gibt es ein problem dabei? Wenn ja, gibt es einen besseren Weg, um den InvokeRequired testen, zwar nicht mit kopieren und einfügen dieses Muster ganz über dem Platz?
InformationsquelleAutor der Frage Erik Forbes | 2010-10-06
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gut wie über dieses:
Verwenden Sie es wie diese:
InformationsquelleAutor der Antwort John Gietzen
Aufrufen
Invoke
von der UI-thread ist etwas ineffizient.Erstellen Sie stattdessen eine
InvokeIfNeeded
Erweiterung Methode, die eineAction
parameter. (dies würde auch ermöglichen es Ihnen, zu entfernennew Action(...)
von der callsite)InformationsquelleAutor der Antwort SLaks
, Die ich gelesen habe über die Argumente hin und her über das hinzufügen von ein Logik-check, um herauszufinden, ob die invoke-sollte verwendet werden, IFF, wenn Sie nicht auf dem UI-thread und nicht im UI-thread selbst. Ich schrieb eine Klasse, die untersucht, wie die Zeit zum ausführen (via Stoppuhr) von verschiedenen Methoden, um eine grobe Einschätzung der Effizienz einer Methode über eine andere stellen.
Werden die Ergebnisse möglicherweise überraschend für einige von Euch (diese tests wurden ausgeführt über die Form.Gezeigt event):
Ergebnisse sind wie folgt:
Mein Fazit ist, dass Sie können sicher aufrufen, zu jeder Zeit, unabhängig davon, ob Sie auf dem UI-thread oder ein worker-thread, ohne signifikanten overhead der Schleife zurück über das Nachrichtensystem. Allerdings, die meisten von der Arbeit AUF dem UI-thread statt, die viele Aufrufe im UI-thread (via Invoke()) ist von Vorteil und verbessern die Effizienz erheblich.
InformationsquelleAutor der Antwort Michael
Merke ich, dass es schon eine Antwort, die ist ziemlich viel Platz auf, aber ich wollte auch meine Meinung dazu (die ich auch gepostet hier).
Mir ist es ein wenig anders, denn es kann leicht mehr sicher zu handhaben, null Kontrollen und Ergebnisse zurückgeben kann, wenn nötig. Diese beiden haben in handliches kommen für mich, wenn Sie versuchen zu Berufen, zeigt eine MessageBox, die auf einem parent-Formular kann null sein, und die Rückkehr der DialogResult-zu zeigen, daß die MessageBox.
Verwendung:
InformationsquelleAutor der Antwort Mark Rushakoff
Ich bin nicht davon überzeugt, dass
Control.Invoke
ist die beste Wahl für die Aktualisierung der Benutzeroberfläche. Ich kann nicht sicher sagen, in Ihrem Fall, weil ich nicht wissen, die Umstände, in denenUpdateSummary
in genannt. Allerdings, wenn Sie anrufen, wird es regelmäßig als ein Mechanismus zum anzeigen von Informationen über den Fortschritt (das ist der Eindruck, den ich aus dem code-snippet), dann gibt es in der Regel eine bessere option. Dass option ist, um den UI-thread-Umfrage für den status anstatt die worker-thread schieben.Die Gründe, warum die polling-Ansatz sollte geprüft werden, in diesem Fall ist, weil:
Control.Invoke
auferlegt werden.So erstellen Sie eine
System.Windows.Forms.Timer
dass überprüft regelmäßig, ob der text angezeigt werden, auf dieControl
anstelle der Einleitung der push von den worker-thread. Wieder, ohne zu wissen, Ihre genauen Anforderungen, die ich nicht bereit bin zu sagen, dies ist definitiv die Richtung, die Sie gehen müssen, aber inden meistenvielen Fällen ist besser als dieControl.Invoke
option.Offensichtlich ist dieser Ansatz eliminiert die Notwendigkeit, die
InvokedRequired
prüfen Sie völlig. Nevermind die Tatsache, dass es vereinfachtalleanderen Aspekte des UI - /worker-thread-Interaktion.InformationsquelleAutor der Antwort Brian Gideon
Meine bevorzugte Methode für view-nur die Steuerung haben Sie alle die Kontrolle staatlichen gekapselt in eine Klasse, die aktualisiert werden können, ohne jemals durch irgendwelche inkonsistente Zustände (ein einfacher Weg, dies zu tun ist, um alle Dinge, die aktualisiert werden müssen, zusammen in eine unveränderliche Klasse, und erstellen Sie eine neue Instanz der Klasse, wenn ein update erforderlich ist). Dann haben Sie eine Methode ein, die gegeneinander Verriegelt sind.Austausch updateNeeded Flagge und, wenn es nicht ein update ausstehend, aber IsHandleCreated wahr ist, dann BeginInvoke kann die update-Prozedur. Der update-Vorgang sollte klar den updateNeeded fahne als das erste, was Sie tut, bevor Sie irgendwelche updates (wenn jemand versucht, zu aktualisieren, die Kontrolle zu diesem Zeitpunkt ein anderer Antrag wird BeginInvoked). Beachten Sie, dass Sie müssen bereit sein, zu fangen und zu schlucken eine Ausnahme (ich denke, IllegalOperation) wenn die Steuerung wird entsorgt, wenn du gerade vorbereiten, zu aktualisieren.
Übrigens, wenn eine Kontrolle noch nicht verbunden worden, um einen thread (indem Hinzugefügt wird, um eine sichtbare Fenster oder das Fenster, es ist auf sichtbar sind), es ist legal, Sie zu aktualisieren, direkt aber nicht legal oder BeginInvoke Aufrufen.
InformationsquelleAutor der Antwort supercat
Kann ich nicht kommentieren, aber hoffentlich jemand sieht, dass dieses und fügen Sie es auf die akzeptierte Antwort, die sonst vor Ort auf.
control.Invoke(new Action(() => action(control)));
Lesen solltencontrol.Invoke(new Action(() => action(control)), null);
Als schriftlich, die akzeptierte Antwort wird nicht kompilieren, da
ISynchronizeInvoke.Invoke()
keine überladung mit nur 1 argument wieControl.Invoke()
tut.Eine andere Sache ist, dass die Nutzung sein könnte klarer
summary.InvokeIfRequired(c => { summary.Text = text; });
anstatt wie geschriebensummary.InvokeIfRequired(c => { textBox.Text = text });
InformationsquelleAutor der Antwort Joseph A
Ist es einfacher zu benutzen BackgroudWorker, wenn möglich, für die Herstellung der UI-responsive und ReportProgress verwenden, um die Aktualisierung der Benutzeroberfläche, weil es läuft im selben thread wie die UI, also brauchen Sie nicht InvokeRequired.
InformationsquelleAutor der Antwort sh_kamalh