2012-05-14 4 views
63

Come posso eseguire il codice sul thread dell'interfaccia utente in WinRT (Windows 8 Metro)?Esegui codice su thread UI in WinRT

Il metodo Invoke non esiste.

+7

Nota per i futuri lettori: Ricorda che se la tua app ha più finestre, ci sono più thread dell'interfaccia utente e dispatcher. –

risposta

68

Usa:

Dal tuo thread dell'interfaccia utente, eseguire:

var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher; 

Dal tuo background (filo non UI)

dispatcher.RunAsync(DispatcherPriority.Normal, 
    <lambda for your code which should run on the UI thread>); 

che dovrebbe funzionare su entrambi i CP e poi costruisce.

+5

C'è un modo per ottenere il dispatcher sul thread non UI? Attualmente ottengo null da CoreWindow.GetForCurrentThread() – Grigory

+3

No. I Dispatcher sono legati a un thread dell'interfaccia utente, quindi è necessario recuperare il dispatcher sul thread dell'interfaccia utente.Una volta che il dispatcher è stato recuperato, puoi ricordarlo. Se si utilizza un'applicazione XAML, la maggior parte degli oggetti dell'interfaccia utente disporranno di un membro del dispatcher che è possibile utilizzare. –

+0

Quindi quali parti della mia app sono effettivamente in esecuzione in UI Thread? Sto usando un FrameWorkView (Windows :: ApplicationModel :: Core :: IFrameworkView), e non posso usare il dispatcher che ho acquisito da Run() - metodo. Ricevo WrongThreadException quando sto cercando di creare MediaElement tramite RunAsync. – Habba

8

Usa:

this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() => Frame.Navigate(typeof(Welcome), this)); 

Funziona per me.

+3

Questo fa in realtà non garantisce di eseguirlo sul thread dell'interfaccia utente. Lo farà solo se "questo" è un oggetto nel contesto dell'interfaccia utente. – Luke

5

Questo è un modo molto più semplice a mio parere.

Ottieni TaskScheduler associato all'interfaccia utente.

var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext(); 

Quindi avviare una nuova attività e su UISyncContext precedente.

Task.Factory.StartNew(() => { /* Do your UI stuff here; */}, new System.Threading.CancellationToken(), TaskCreationOptions.PreferFairness, UISyncContext); 
+0

Nota: Ricevo un InvalidOperationException "L'attuale SynchronizationContext non può essere utilizzato come TaskScheduler". – Akku

+0

Ho anche un Invalidoperation – LowDev1

+1

Your SynchronizationContext è null. Ecco perché stai ricevendo quell'eccezione. Niente di sbagliato con il mio codice. – Deeb

75

E 'più facile per ottenere direttamente il CoreWindow dal thread non-UI. Il seguente codice funzionerà ovunque, anche quando GetForCurrentThread() o Window.Current restituisce null.

CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, 
    <lambda for your code which should run on the UI thread>); 

ad esempio:

CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, 
    () => 
    { 
     // Your UI update code goes here! 
    }); 

Avrai bisogno di fare riferimento Windows.ApplicationModel.Core namespace:

using Windows.ApplicationModel.Core; 
+0

Ricevo System.NotImplementedException durante l'utilizzo. Accedo al thread dell'interfaccia utente. – Naren

+0

Non ha mai avuto questa eccezione qui. Potrebbe provenire da qualche altra parte, come dentro le istruzioni del blocco. –

+0

Ricevo questa eccezione quando ho provato ad accedere al Dispatcher. Non ho eseguito alcun codice utilizzando il dispatcher. – Naren

0

DispatcherTimer è anche un'opzione.

L'ho usato per il codice che deve essere eseguito in XAML-designer (CoreWindow.Dispatcher, ... non sono disponibili in UWP-designer)

var localTimer = new DispatcherTimer 
{ 
    Interval = TimeSpan.FromMilliseconds(0) 
}; 
localTimer.Tick += (timer, e) => 
{ 
    (timer as DispatcherTimer).Stop(); 
    action(); 
}; 
localTimer.Start(); 

Disclaimer:
Vorrei sottolineare che questo dovrebbe essere un'opzione di ultima istanza se tutti gli altri falliscono.

0

Su UWP, stavo avendo problemi nel tentativo di impostare la proprietà Source del controllo CaptureElement (che è definito in XAML), si lamentava di essere preparato su thread diversi, anche se stavo provando a impostarlo dal codice che era invocato tramite un gestore di eventi Page_Loaded. Ho finito per usarlo per aggirare il problema:

previewControl.Dispatcher.TryRunAsync(CoreDispatcherPriority.Normal,() => { 
    previewControl.Source = _mediaCapture; 
}).GetAwaiter().GetResult();