2013-03-19 10 views
23

benutzte ich diese Funktion in einer Windows forms Anwendung:InvokeRequired in wpf

delegate void ParametrizedMethodInvoker5(int arg); 

private void log_left_accs(int arg) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new ParametrizedMethodInvoker5(log_left_accs), arg); 
     return; 
    } 

    label2.Text = arg.ToString(); 
} 

Aber in WPF es nicht funktioniert. Warum?

Antwort

0

WPF verwendet die , um den Zugriff auf die Nachrichtenpumpe zu steuern, anstatt jedes Steuerelement für den Zugriff auf den UI-Thread verantwortlich zu machen.

Sie sollten Dispatcher.Invoke verwenden, um dem UI-Thread in einer WPF-Anwendung einen Delegaten hinzuzufügen.

Es ist auch erwähnenswert, dass InvokeRequired nicht wirklich in einer Winform-App benötigt wird, noch ist es etwas, was Sie in einer WPF-Anwendung suchen sollten. Sie sollten wissen, dass Sie nicht im UIhread sind, wenn Sie Invoke aufrufen. Sie sollten niemals in einer Situation sein, in der eine bestimmte Methode manchmal vom UI-Thread aufgerufen wird und manchmal von einem Hintergrund-Thread aufgerufen wird. Wähle ein; Erzwingen Sie entweder immer, dass der Aufrufer vor dem Aufruf einer bestimmten Methode den UI-Thread aufruft (Sie müssen also nicht aufrufen), oder Sie nehmen an, dass der Aufrufer beim Aufruf der Methode nicht im UI-Thread enthalten ist. Es ist auch erwähnenswert, dass das Aufrufen von Invoke, wenn Sie bereits im UI-Thread sind, in Ordnung ist. Es gibt keine Fehler oder Probleme, die aus einer gelegentlichen Instanz des erneuten Aufrufs des UI-Threads resultieren (es fallen nur geringe Performance-Kosten an, also fügen Sie einfach keinen unnötigen Code dafür überall hinzu).

+4

Natürlich gibt es viele Situationen, wenn du nicht weißt, ob du auf dem Erstellungs-Thread stehst oder nicht und es überprüfen musst! – Christoph

+1

Haben Sie jemals eine Benutzerkontrolle gemacht, die es ermöglicht, Daten zu binden? Daten werden normalerweise von einem anderen Thread abgerufen, aber z. das Setzen des Wertes eines Textfelds kann auch durch ein anderes Steuerelement erfolgen (z. B. Ändern der Dropdown-Ergebnisse in einen anderen Standardwert => Sie befinden sich im UI-Thread. Zuweisen eines Wertes aus der Datenbank => Sie befinden sich in einem Worker-Thread) – Christoph

+0

Von Weise, verwenden Sie nicht Invoke(), verwenden Sie stattdessen BeginInvoke() (sowohl in WinForms und WPF). Der Grund ist, dass Invoke() zu hässlichen Deadlocks führen kann. – Christoph

9

In WPF verwenden, um die CheckAccess Methode anstelle von InvokeRequired

if (!CheckAccess()) { 
    // On a different thread 
    Dispatcher.Invoke(() => log_left_accs(arg)); 
    return; 
} 
+0

Und was ist mit Invoke? – oehgr

+0

CheckAccess ist eine Methode des Dispatcher, keine Methode des Window oder Control –

+0

@oehgr Verwendung 'Dispatcher.Invoke'.Ich werde update myanswer – JaredPar

38

In WPF, die Invoke Methode auf dem Dispatcher ist, so dass Sie Dispatcher.Invoke statt Invoke anrufen müssen. Außerdem gibt es keine InvokeRequired Eigenschaft, aber der Dispatcher hat eine CheckAccess Methode (aus irgendeinem Grund ist es in Intellisense versteckt). Also sollte dein Code sein:

delegate void ParametrizedMethodInvoker5(int arg); 
void log_left_accs(int arg) 
{ 
    if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread 
    { 
     Dispatcher.Invoke(new ParametrizedMethodInvoker5(log_left_accs), arg); 
     return; 
    } 
    label2.Text= arg.ToString(); 
} 
+1

Es ist möglich, dass der Dispatcher-Wert "null" ist. Aus diesem Grund hat 'DispatcherObject' die Methode' CheckAccess', die diese Möglichkeit berücksichtigt. – JaredPar

+0

@JaredPar, wissen Sie, in welchem ​​Fall der Dispatcher null sein kann? Ich habe es noch nie zuvor gesehen ... –

+0

Ich glaube, wenn ein Objekt eingefroren ist, wird sein 'Dispatcher'' null'. Suchen Sie nach Verweisen auf 'DispatherObject.DetachFromDispatcher' – JaredPar