源项目地址:https://github.com/Microsoft/...
以下是把样例转换为简要说明,同时给出实际运行效果及关键代码:
1 MultiThreadingWebBrowser
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();
//});
}
2 SingleThreadedApplication
调用自身线程循环查找素数
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));
}
}
3 UsingDispatcher天气预报
在本示例中,模拟检索天气预报的远程过程调用。 使用一个单独的辅助线程来执行此调用,并在完成后在 UI 线程的 Dispatcher 中调度一个更新方法。
- 创建按钮处理程序
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 的调用。我们将一个描述天气的字符串传递给安排的此方法调用。
- 更新 UI
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”(获取预报)按钮。
以上。
技术细节和难点
- 使用线程编写组件
《Microsoft .NET Framework 开发人员指南》介绍了组件向其客户端公开异步行为的一种模式(请参见 基于事件的异步模式概述)。例如,假定我们希望将 FetchWeatherFromServer 方法打包到一个可重用的非图形组件中。如果采用标准的 Microsoft .NET Framework 模式,那么代码应与下面的内容类似。
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 将使用前面介绍的一种技术(如创建后台线程)来异步执行工作,同时不阻止调用线程。
此模式的最重要部分之一是最初在调用方法名称 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线程处理模型提及。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。