BackgroundWorker是保持WCF/WPF应用程序响应能力的唯一方法吗? [英] Is BackgroundWorker the only way to keep a WCF/WPF application responsive?

查看:56
本文介绍了BackgroundWorker是保持WCF/WPF应用程序响应能力的唯一方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用C#,WCF,WPF的客户端/服务器桌面应用程序.由于几乎每个动作都需要访问服务器(列表/创建/保存/删除/等),因此每个动作都有可能冻结整个UI.这是一个简单的实现示例,其中调用service.GetAll()可能会花费很长的时间(超过几百毫秒):

Client/server desktop application using C#, WCF, WPF. Since pretty much every action is going to require a trip to the server (list/create/save/delete/etc), every action has the potential to freeze the entire UI. Here's an example of a naive implementation with a call to service.GetAll() which could take a "long" time (more than a few hundred milliseconds):

private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
    vm.Users.Clear();
    foreach (var user in service.GetAllUsers())
        vm.Users.Add(user);
}

(在旁边:我很想知道为什么列表具有AddRange ObservableCollection 不.)

(Aside: I'd love to know why List has AddRange and ObservableCollection doesn't.)

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();
}

(此外:上面的代码已经简化,但这就是要点.)

(Aside: code above has been simplified, but that's the gist of it.)

使用BackgroundWorker的代码完全按照我想要的方式工作.该应用程序始终保持响应状态,并且在通话过程中该按钮一直处于禁用状态.但是,这意味着在用户可能执行的每个操作中添加15行.

The code using BackgroundWorker works exactly how I want it to. The app remains responsive at all times, and the button is disabled for the duration of the call. However, this means adding 15 lines to every possible action the user might make.

说不是.

推荐答案

不,BackgroundWorker不是唯一的方法,而是一种方法.任何其他方式都将包括某种形式的异步构造,需要使用Dispatch.BeginInvoke来更新UI.例如,您可以使用ThreadPool:

No, BackgroundWorker is not the only way, but it's one way. Any other way will allso include some form of asynchronous construct with the need to use Dispatch.BeginInvoke to update the UI. You could for instance use the 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; });

});

如果这是重复发生的模式(按钮将触发一些应异步执行的操作,并且在此过程中禁用了该按钮),则可以将其包装为方法:

If this is a recurring pattern (a button will trigger some action that should be performed asynchronously, with the button being disabled during the process) you can wrap this into a method:

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; });     
    });
}

...并命名为:

PerformAsync(() => 
{
    foreach (var user in service.GetAllUsers())
        vm.Users.Add(user);
}, btnRefresh);

作为使用ThreadPool的一种选择,您也许还应该研究任务并行库.

As an option to using the ThreadPool, you should also perhaps look into the Task Parallel Library.

执行此操作时,应注意如何处理UI状态.例如,您有多个控件触发同一操作,请确保在操作期间所有控件均被禁用.

When doing this you should pay attention to how you handle UI state. For instance of you have more than one control which triggers the same action, make sure that all of them are disabled during the action.

注意:这些只是快速的想法.该代码尚未经过测试,因此可能包含错误.与其说是最终的解决方案,不如说是讨论材料.

Note: these are just quick ideas. The code has not been tested so it may contain errors. It's more to be regarded as discussion material than finished solutions.

这篇关于BackgroundWorker是保持WCF/WPF应用程序响应能力的唯一方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆