2012-05-14 41 views
63

如何在WinRT(Windows 8 Metro)的UI線程上運行代碼?在WinRT的UI線程上運行代碼

Invoke方法不存在。

+7

請注意未來的讀者:請記住,如果您的應用程序有多個窗口 - 有多個UI線程和調度程序。 –

回答

68

用途:

從你的UI線程,執行:

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

從你的背景(非UI線程)

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

,應該在兩個CP及更高版本的基礎之上。

+5

有沒有辦法在非UI線程上獲得調度程序?目前,我從CoreWindow.GetForCurrentThread() – Grigory

+3

中得到空號。調度程序綁定到一個UI線程,因此您需要在UI線程上檢索調度程序。一旦調度員被檢索到,你可以記住它。如果您在XAML應用程序中,那麼大多數UI對象都具有您可以使用的調度程序成員。 –

+0

那麼我的應用程序的哪些部分實際上在UI線程中運行? 我使用的是FrameWorkView(視窗:應用模型::核心:: IFrameworkView),並且不能使用我從運行()所獲得的調度員 - 方法。當我嘗試通過RunAsync創建MediaElement時,出現WrongThreadException。 – Habba

8

用途:

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

這對我的作品。

+3

這確實實際上並不保證在UI線程上運行它。它只會在「this」是UI上下文中的一個對象時纔會發生。 – Luke

5

在我看來,這是一種更簡單的方法。

獲取與UI關聯的TaskScheduler。

var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext(); 

然後啓動一個新的任務和上面的UISyncContext。

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

僅供參考:我得到一個InvalidOperationException「當前的SynchronizationContext不能用作TaskScheduler」。 – Akku

+0

我還得到一個InvalidOperation – LowDev1

+1

您的SynchronizationContext爲null。這就是你得到這個例外的原因。我的代碼沒有錯。 – Deeb

75

它更容易直接得到CoreWindow從非UI線程。以下代碼無處不在,即使當GetForCurrentThread()Window.Current返回null

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

例如:

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

你需要引用Windows.ApplicationModel.Core命名空間:

using Windows.ApplicationModel.Core; 
+0

使用this.I時,我得到System.NotImplementedException。我從UI線程訪問它。 – Naren

+0

這裏從來沒有這個例外。它可能來自其他地方,比如在你的塊說明中。 –

+0

當我試圖訪問分派器時,我得到這個異常。我沒有使用分派器執行任何代碼。 – Naren

0

DispatcherTimer也是一種選擇。

我用它必須在XAML的設計師來運行代碼(CoreWindow.Dispatcher,......不可在UWP-設計師)

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

免責聲明:
我要指出,這應該如果其他所有人都失敗了,那麼這是最後的選擇。

0

在UWP上,我試圖設置CaptureElement控件的Source屬性(在XAML中定義)時遇到問題,它正在抱怨準備在不同的線程中,即使我試圖從代碼中設置它通過Page_Loaded事件處理程序調用。我最終使用它來解決它:

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