epa*_*alm 6 c# wpf wcf backgroundworker
使用C#,WCF,WPF的客户端/服务器桌面应用程序.由于几乎所有操作都需要访问服务器(list/create/save/delete/etc),因此每个操作都有可能冻结整个UI.这是一个天真实现的例子,调用service.GetAll()可能需要"很长"的时间(超过几百毫秒):
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
vm.Users.Clear();
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}
Run Code Online (Sandbox Code Playgroud)
(题外话:我很想知道为什么名单有AddRange和的ObservableCollection没有.)
BackgroundWorker 救援:
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
e.Result = service.GetAllUsers();
};
worker.RunWorkerCompleted += (s, e) =>
{
vm.Users.Clear();
foreach (var user in (List<UserDto>)e.Result)
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
};
worker.RunWorkerAsync();
}
Run Code Online (Sandbox Code Playgroud)
(旁白:上面的代码已被简化,但这是它的要点.)
使用的代码BackgroundWorker完全符合我的要求.应用程序始终保持响应,并且在呼叫期间禁用该按钮.但是,这意味着为用户可能执行的每个操作添加15行.
说不是这样.
不,BackgroundWorker不是唯一的方法,但这是一种方式.任何其他方式都将包含某种形式的异步构造,需要Dispatch.BeginInvoke用于更新UI.例如,您可以使用ThreadPool:
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
});
Run Code Online (Sandbox Code Playgroud)
如果这是一个重复出现的模式(一个按钮将触发一些应该异步执行的操作,并且在此过程中按钮被禁用),您可以将其包装到一个方法中:
private void PerformAsync(Action action, Control triggeringControl)
{
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = false; });
action();
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = true; });
});
}
Run Code Online (Sandbox Code Playgroud)
......并称之为:
PerformAsync(() =>
{
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}, btnRefresh);
Run Code Online (Sandbox Code Playgroud)
作为使用它的一个选项ThreadPool,您也可以查看任务并行库.
执行此操作时,您应该注意如何处理UI状态.例如,您有多个触发相同操作的控件,请确保在操作期间禁用所有控件.
注意:这些只是简单的想法.代码尚未经过测试,因此可能包含错误.更多的是被视为讨论材料而不是成品解决方案.
WCF提供异步进行所有服务调用的功能.在项目中创建服务引用时,添加服务引用对话框具有"高级..."按钮.单击它,您将看到"生成异步操作"选项.如果单击该复选框,则将以同步和异步方式生成每个操作.
例如,如果我有一个操作"DoSomething()",那么在选中此框后,我将获得为调用DoSomething()和DoSomethingAsync()而生成的代码.
您还将获得Service.DoSomethingCompleted事件,您可以使用该事件在服务调用返回时定义回调处理程序.
这是我们用于在不锁定UI的情况下进行服务调用的方法.
以下是Microsoft提供的关于如何执行此操作的相当复杂的示例:http://msdn.microsoft.com/en-us/library/ms730059.aspx
| 归档时间: |
|
| 查看次数: |
7124 次 |
| 最近记录: |