源項目地址:https://github.com/Microsoft/...
如下是把樣例轉換爲簡要說明,同時給出實際運行效果及關鍵代碼:git
private void Browse(object sender, RoutedEventArgs e) { placeHolder.Source = new Uri(newLocation.Text); } private void NewWindowHandler(object sender, RoutedEventArgs e) { var newWindowThread = new Thread(ThreadStartingPoint); newWindowThread.SetApartmentState(ApartmentState.STA); newWindowThread.IsBackground = true; newWindowThread.Start(); } private void ThreadStartingPoint() { var tempWindow = new MainWindow(); tempWindow.Show(); Dispatcher.Run(); //Dispatcher.BeginInvoke(DispatcherPriority.Normal, //(ThreadStart)delegate () //{ // var temWindow = new MainWindow(); // temWindow.Show(); //}); }
調用自身線程循環查找素數 private void StartOrStop(object sender, EventArgs e) { if (_continueCalculating) { _continueCalculating = false; startStopButton.Content = "Resume"; } else { _continueCalculating = true; startStopButton.Content = "Stop"; startStopButton.Dispatcher.BeginInvoke( DispatcherPriority.Normal, new NextPrimeDelegate(CheckNextNumber)); } } public void CheckNextNumber() { Stopwatch x = new Stopwatch(); x.Start(); // Reset flag. _notAPrime = false; for (long i = 3; i <= Math.Sqrt(_num); i++) { if (_num%i == 0) { // Set not a prime flag to ture. _notAPrime = true; break; } } // If a prime number. if (!_notAPrime) { x.Stop(); elapsed.Text = x.ElapsedTicks.ToString(); bigPrime.Text = _num.ToString(); } _num += 2; if (_continueCalculating) { startStopButton.Dispatcher.BeginInvoke( DispatcherPriority.SystemIdle, new NextPrimeDelegate(CheckNextNumber)); } }
在本示例中,模擬檢索天氣預報的遠程過程調用。 使用一個單獨的輔助線程來執行此調用,並在完成後在 UI 線程的 Dispatcher 中調度一個更新方法。github
private void ForecastButtonHandler(object sender, RoutedEventArgs e) { // Change the status image and start the rotation animation. fetchButton.IsEnabled = false; fetchButton.Content = "Contacting Server"; weatherText.Text = ""; _hideWeatherImageStoryboard.Begin(this); // Start fetching the weather forecast asynchronously. var fetcher = new NoArgDelegate( FetchWeatherFromServer); fetcher.BeginInvoke(null, null); }
當單擊按鈕時,顯示時鐘圖並開始顯示它的動畫效果。 禁用該按鈕, 在一個新線程中調用 FetchWeatherFromServer 方法,而後返回,這樣 Dispatcher 就能夠在咱們等待收集天氣預報時處理事件。網絡
private void FetchWeatherFromServer() { // Simulate the delay from network access. Thread.Sleep(4000); // Tried and true method for weather forecasting - random numbers. var rand = new Random(); string weather; weather = rand.Next(2) == 0 ? "rainy" : "sunny"; // Schedule the update function in the UI thread. tomorrowsWeather.Dispatcher.BeginInvoke( DispatcherPriority.Normal, new OneArgDelegate(UpdateUserInterface), weather); }
爲簡單起見,此示例中實際沒有任何網絡代碼。 經過使新線程休眠四秒鐘來模擬網絡訪問的延遲。 此時,原始的 UI 線程仍然正在運行並響應事件。爲了對此進行說明,咱們使一個動畫保持運行,並使最小化和最大化按鈕也繼續工做。框架
當延遲結束,而且咱們已隨機選擇了天氣預報時,是時候向 UI 線程返回報告了。爲此,咱們在 UI 線程中使用該線程的 Dispatcher 安排一個對 UpdateUserInterface 的調用。咱們將一個描述天氣的字符串傳遞給安排的此方法調用。dom
private void UpdateUserInterface(string weather) { //Set the weather image if (weather == "sunny") { weatherIndicatorImage.Source = (ImageSource) Resources[ "SunnyImageSource"]; } else if (weather == "rainy") { weatherIndicatorImage.Source = (ImageSource) Resources[ "RainingImageSource"]; } //Stop clock animation _showClockFaceStoryboard.Stop(this); _hideClockFaceStoryboard.Begin(this); //Update UI text fetchButton.IsEnabled = true; fetchButton.Content = "Fetch Forecast"; weatherText.Text = weather; }
當 UI 線程中的 Dispatcher 有時間時,會對 UpdateUserInterface 執行預約調用。此方法中止時鐘動畫並選擇一個圖像來描述天氣。它顯示此圖像並還原「fetch forecast」(獲取預報)按鈕。異步
以上。async
《Microsoft .NET Framework 開發人員指南》介紹了組件向其客戶端公開異步行爲的一種模式(請參見 基於事件的異步模式概述)。例如,假定咱們但願將 FetchWeatherFromServer 方法打包到一個可重用的非圖形組件中。若是採用標準的 Microsoft .NET Framework 模式,那麼代碼應與下面的內容相似。ide
public class WeatherComponent : Component { //gets weather: Asynchronous public string GetWeather() { string weather = ""; //predict the weather return weather; } //get weather: Asynchronous public void GetWeatherAsync() { //get the weather } public event GetWeatherCompletedEventHandler GetWeatherCompleted; } public class GetWeatherCompletedEventArgs : AsyncCompletedEventArgs { public GetWeatherCompletedEventArgs(Exception error, bool canceled, object userState, string weather) : base(error, canceled, userState) { _weather = weather; } public string Weather { get { return _weather; } } private string _weather; } public delegate void GetWeatherCompletedEventHandler(object sender, GetWeatherCompletedEventArgs e);
GetWeatherAsync 將使用前面介紹的一種技術(如建立後臺線程)來異步執行工做,同時不阻止調用線程。fetch
此模式的最重要部分之一是最初在調用方法名稱 Async 方法的線程上調用方法名稱 Completed 方法。 經過存儲 CurrentDispatcher,您可使用 WPF 輕鬆地實現這一點。可是,以後只能在 WPF應用程序中使用該非圖形組件,而不能在 Windows Forms或 ASP.NET 程序中使用該組件。動畫
DispatcherSynchronizationContext 類可知足這一需求。能夠將該類視爲還使用其餘 UI 框架的 Dispatcher 的簡化版本。
public class WeatherComponent2 : Component { public string GetWeather() { return fetchWeatherFromServer(); } private DispatcherSynchronizationContext requestingContext = null; public void GetWeatherAsync() { if (requestingContext != null) throw new InvalidOperationException("This component can only handle 1 async request at a time"); requestingContext = (DispatcherSynchronizationContext)DispatcherSynchronizationContext.Current; NoArgDelegate fetcher = new NoArgDelegate(this.fetchWeatherFromServer); // Launch thread fetcher.BeginInvoke(null, null); } private void RaiseEvent(GetWeatherCompletedEventArgs e) { if (GetWeatherCompleted != null) GetWeatherCompleted(this, e); } private string fetchWeatherFromServer() { // do stuff string weather = ""; GetWeatherCompletedEventArgs e = new GetWeatherCompletedEventArgs(null, false, null, weather); SendOrPostCallback callback = new SendOrPostCallback(DoEvent); requestingContext.Post(callback, e); requestingContext = null; return e.Weather; } private void DoEvent(object e) { //do stuff } public event GetWeatherCompletedEventHandler GetWeatherCompleted; public delegate string NoArgDelegate(); }
此處在MSDN或Microsoft Help查看器中WPF線程處理模型說起。