C # UWP L’applicazione ha chiamato un’interfaccia che è stata sottoposta a marshalling per un thread diverso

Ho un’applicazione C # UWP che contiene una funzione che desidero chiamare ogni 5 secondi. La funzione funziona alla perfezione se chiamata da un pulsante, e il Timer scrive sulla multa della console di debug ogni 5 secondi … Quando chiamo la funzione dal Timer, tutto si spezza. Ho capito:

System.Exception non gestito dal codice utente HResult = -2147417842 Message = L’applicazione ha chiamato un’interfaccia che è stata sottoposta a marshalling per un thread diverso. (Eccezione da HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

Presumo che la tua funzione tocchi l’interfaccia utente dell’app. Tutto ciò che tocca l’interfaccia utente deve essere eseguito sul thread del dispatcher dell’interfaccia utente (la maggior parte delle app ne avrà solo una finché non si accede a più app per le windows).

È ansible utilizzare Windows.UI.Xaml. DispatcherTimer per eseguire il timer sul thread del dispatcher.

Se è necessario eseguire il codice su un thread di lavoro e quindi toccare l’interfaccia utente sul thread del dispatcher, è ansible chiamare Dispatcher. RunAsync per eseguire il marshalling di una chiamata sul thread del dispatcher.

Generalmente puoi trovare il tuo supervisore dalla tua finestra tramite Window.Dispatcher .

var ignored = Window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // Do something on the dispatcher thread }); 

Molto probabilmente stai utilizzando un Timer da System.Threading . Gli eventi del timer non vengono trattati come un normale evento della GUI e se si accede a un elemento della GUI il metodo richiamato da quel timer, causerà problemi poiché quel thread non è il proprietario della voce della GUI.

Utilizzare un Timer da System.Windows.Forms . Quel timer ha accesso agli elementi della GUI.

È ansible utilizzare Observable.Interval da Reactive Extensions e specificare esplicitamente su quale dispatcher si desidera osservare gli eventi del timer:

 Observable.Interval(TimeSpan.FromSeconds(1), Scheduler.Default) .ObserveOn(coreWindow.Dispatcher) .Subscribe(_ => Log.Warning("Dispatcher.HasThreadAccess: " + coreWindow.Dispatcher.HasThreadAccess)); 

Quello che mi piace di questo approccio è che dichiari esplicitamente cosa succede su quale thread (vedi SubscribeOn e ObserveOn ).