2

Wir stellen eine Bibliothek zur Verfügung, die Code für ihre eigenen benutzerdefinierten Threads ausführen muss. Sobald dies erledigt ist, möchte ich, dass diese Threads Callbacks (Eventhandler) über eine Dispatcher (System.Windows.Threading.Dispatcher) aufrufen. Der Bibliotheksbenutzer muss den Dispatcher verwenden, um die Ereignisbehandlung an.Hat jeder WinRT/Windows Core-Thread einen Dispatcher?

Wir könnten einfach immer auf CoreApplication.MainView.CoreWindow.Dispatcher versenden, aber nicht alle Programme (z. B. Windows 10 IoT Core-Anwendungen) bieten eine Benutzeroberfläche und daher fehlt ihnen ein Hauptfenster.

Kann der Benutzer einfach auf System.Windows.Threading.Dispatcher.CurrentDispatcher verweisen, um die seines Threads zu erhalten? Oder können nicht alle Threads einen Dispatcher haben?

Bearbeiten: Hier ist mehr Kontext für diese Frage. Hoffentlich macht es die Frage leichter zu verstehen: https://github.com/getsenic/nuimo-windows/issues/2

+0

Warum möchten Sie Ereignishandler auf UI-Thread ausführen? Es ist ein häufiger Fall, wenn ein Objekt Ereignisse im Hintergrund (nicht UI) auslöst. Der Benutzer Ihrer Bibliothek muss Dispatcher verwenden, um mit diesen Ereignissen fertig zu werden, wenn er im Ereignishandler Zugriff auf UI-Elemente benötigt. – RavingDev

+0

Das WPF-Verhalten ist eher unintuitiv und hat viele Programmierer in Schwierigkeiten gebracht, viele Fragen dazu hier. WinRT hat diesen Fehler nicht wiederholt, Sie können nur einen Dispatcher aus einem Fenster holen. Was ist der logische Ansatz, ein Fenster kann nur funktionieren, wenn es von einem Thread erstellt wurde, der eine Dispatch-Schleife hat, ohne diese Schleife ist es tot als ein Türnagel. Wenn Sie kein Fenster haben, müssen Sie nicht mehr Code für einen bestimmten Thread ausführen. –

+0

Es gibt eine Methode, Ereignisse im UI-Thread auszulösen. Es ist jedoch erforderlich, dass Ihr Objekt über den UI-Thread erstellt/initialisiert wurde. Ist es dein Fall?Ich meine, dass es nur funktioniert, wenn das Objekt aus dem UI-Thread erstellt wurde. – RavingDev

Antwort

0

Oder können nicht alle Threads einen Dispatcher haben?

Dispatcher-Threads sind immer an UI-Threads gebunden. Die IoT-App für den kopflosen Modus verfügt über keine Benutzeroberfläche, sodass sie keinen Dispatcher-Thread enthält.

Kann der Benutzer einfach auf System.Windows.Threading.Dispatcher.CurrentDispatcher bezieht sich auf seinen Thread

Dispatcher zu bekommen

System.Windows.Threading.Dispatcher.CurrentDispatcher nur in Legacy-.NET-Plattform unterstützt wird. Die UWP-Alternative ist CoreApplication.MainView.CoreWindow.Dispatcher, wie Sie darauf hingewiesen haben.

Wenn Sie asynchrone Rückrufe im Headless (ohne GUI) -Modus durchführen möchten, können Sie wahrscheinlich auf Task Parallel Library (TPL), die ContinueWhenAll ContinueWhenAny usw. API ... zugreifen, die Ihren Anforderungen entsprechen. Siehe https://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.aspx.

+0

Lieber Jackie, danke für deine Antwort. Leider wird die Aufgabe nicht vom Bibliotheksbenutzer gestartet, sondern von der Bibliothek zu jedem Zeitpunkt gestartet (es handelt sich tatsächlich um einen Rückruf von einem Bluetooth-Gerät). Es spielt jedoch keine Rolle, dass eine Aufgabe involviert ist, da meine Frage darin besteht, eine "Ereignis-Aktion" auf einen Thread zu senden, auf den der Benutzer möchte, dass er an ihn gesendet wird. Genauer geht es hier um dieses Problem: https://github.com/getSenic/nuimo-windows/issues –

+0

@LarsBlumberg, erwägen Sie die Verwendung von SynchronizationContext.Post? Abhängig vom Headless-Modus können Sie den Synchronisierungskontext für die Benutzeroberfläche oder einen Nicht-UI-Thread festlegen. – Jackie

+0

Sieht gut aus! Woher bekommen Headless-Apps ihren 'SynchronizationContext'? –

1

Erstens bin ich nicht sicher, dass Sie Event-Handler auf UI-Thread ausführen sollten, weil nur Client weiß, ob er Zugriff UI-Elemente benötigt.

Zweitens, vor dem Aufruf CoreApplication.MainView Eigenschaft können Sie überprüfen, CoreApplication.Views.Count > 0 (ich bin nicht absolut sicher, dass es funktioniert, weil zur Zeit habe ich kein Gerät, um es zu testen).

Und Sie können dieses Problem auch auf andere Weise lösen: Speichern Sie im Konstruktor Ihres Objekts den SynchronizationContext des ausführenden Threads und verwenden Sie ihn dann zum Auslösen von Ereignissen. Es funktioniert, wenn Ihr Objekt vom UI-Thread instanziiert wird (in den meisten Fällen ist es wahr). Auf diese Weise können Sie den Dispatcher vollständig ablehnen.

public class NotifierExample 
{ 
    private readonly SynchronizationContext _synchronizationContext; 


    public event EventHandler SomethingHappened; 


    public NotifierExample() 
    { 
     _synchronizationContext = SynchronizationContext.Current; 
    } 


    public void Do() 
    { 
     Task.Factory.StartNew(() => 
     { 
      //do something 
      OnSomethingHappened(); 
     }); 
    } 


    private void OnSomethingHappened() 
    { 
     if (_synchronizationContext != null) 
     { 
      _synchronizationContext.Post(o => RaiseSomethingHappened(), null); 
     } 
     else 
     { 
      RaiseSomethingHappened(); 
     } 
    } 

    private void RaiseSomethingHappened() 
    { 
     var somethingHappened = SomethingHappened; 
     somethingHappened?.Invoke(this, EventArgs.Empty); 
    } 
} 
+0

Wir zwingen den Benutzer nicht, Handler auf UI-Thread auszuführen. Aber die Bibliothek muss von der Tatsache abstrahieren, dass die Ereignisse der Bibliothek in einem benutzerdefinierten Thread ablaufen - es ist nur unpraktisch, wenn Sie als Bibliotheksbenutzer alle Rückrufe in Ihren Hauptthread synchronisieren müssen, um die Benutzeroberfläche (falls vorhanden) zu aktualisieren. Die Verwendung von 'SynchronizationContext' sieht gut aus - wird es ausprobieren! –