探讨一种Silverlight的异步编程模式
2010-03-27 16:14 xiaosonl 阅读(1025) 评论(3) 编辑 收藏 举报在开发RIA程序时,处理异步操作是个挺麻烦的问题,尤其是串行的异步调用,经常代码会写的嵌套好几层。之前老赵也介绍过一种方法来简化异步操作。我这是另一种思路。
在之前的Silverlight程序开发过程中,我的编程模式是这样的:
- 用户执行一个UI操作,并引发UI事件,此时在UI线程开始执行后台代码。
- 在代码执行过程中,遇到需要异步的操作,如网络请求等,就在另一个线程执行该操作,执行完毕后利用事件或委托继续执行接下来的操作。如果这时异步操作比较多,就会有很多的事件或委托跳来跳去的,很不好看。
这时我们可以换一种思路,反过来做,每一次的操作,我们都发起一个新的线程来执行,不再从UI线程发起。执行过程中遇到的异步操作(网格请求,或者UI操作,因为这时UI有关的操作都必须使用BeginInvoke来调用),可以用ResetEvent来阻塞住发起操作的线程,异步操作执行结束后再继续 因为一开始是在非UI线程中发起操作,所以不会阻塞UI。
总结一下:
- 每个操作都是发起一个新的线程来执行。
- 每个异步方法都可以用ResetEvent来模拟成同步方法,就可以很方便像同步方法那样调用和组织, 但在简单的异步场景中优势不明显。
- 缺点是影响性能,用性能来换代码的可读性和可维护性。
最后附上一个简易示例代码(未经运行测试和优化),演示将[下载数据 => 处理数据并更新UI] 的过程模拟成同步操作:
代码
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void btnCommand_Click(object sender, RoutedEventArgs e)
{
Command();
}
//执行操作
public void Command()
{
ThreadPool.QueueUserWorkItem(t =>
{
UIInvoke(() =>
{
//弹出一个ProgressBar,提示操作正在进行中
});
//下载数据
string downloadData = DownLoad();
//更新UI
UIInvoke(() => txtMessage.Text = downloadData);
UIInvoke(() =>
{
//关闭ProgressBar,提示操作结束
});
});
}
//以同步的方式调用UI线程执行一个操作
private void UIInvoke(Action action)
{
Dispatcher dispatcher = Deployment.Current.Dispatcher;
if (dispatcher.CheckAccess())
{
action();
}
else
{
ManualResetEvent resetEvent = new ManualResetEvent(false);
resetEvent.Reset();
dispatcher.BeginInvoke(() =>
{
action();
resetEvent.Set();
});
resetEvent.WaitOne();
}
}
private string DownLoad()
{
ManualResetEvent reset = new ManualResetEvent(false);
reset.Reset();
//下载数据
WebClient client = new WebClient();
string result = "";
client.DownloadStringCompleted += (s, e) =>
{
result = e.Result;
reset.Set();
};
client.DownloadStringAsync(new Uri("http://下载地址"));
reset.WaitOne();
return result;
}
}
{
public MainPage()
{
InitializeComponent();
}
private void btnCommand_Click(object sender, RoutedEventArgs e)
{
Command();
}
//执行操作
public void Command()
{
ThreadPool.QueueUserWorkItem(t =>
{
UIInvoke(() =>
{
//弹出一个ProgressBar,提示操作正在进行中
});
//下载数据
string downloadData = DownLoad();
//更新UI
UIInvoke(() => txtMessage.Text = downloadData);
UIInvoke(() =>
{
//关闭ProgressBar,提示操作结束
});
});
}
//以同步的方式调用UI线程执行一个操作
private void UIInvoke(Action action)
{
Dispatcher dispatcher = Deployment.Current.Dispatcher;
if (dispatcher.CheckAccess())
{
action();
}
else
{
ManualResetEvent resetEvent = new ManualResetEvent(false);
resetEvent.Reset();
dispatcher.BeginInvoke(() =>
{
action();
resetEvent.Set();
});
resetEvent.WaitOne();
}
}
private string DownLoad()
{
ManualResetEvent reset = new ManualResetEvent(false);
reset.Reset();
//下载数据
WebClient client = new WebClient();
string result = "";
client.DownloadStringCompleted += (s, e) =>
{
result = e.Result;
reset.Set();
};
client.DownloadStringAsync(new Uri("http://下载地址"));
reset.WaitOne();
return result;
}
}
--------------------------个人签名的分割线--------------------------------------
我的个人综合博客:http://www.xiaosonl.com