加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – BackgroundWorker是保持WCF / WPF应用程序响应的唯一方法

发布时间:2020-12-15 18:35:44 所属栏目:百科 来源:网络整理
导读:使用C#,WCF,WPF的客户端/服务器桌面应用程序.由于几乎所有操作都需要访问服务器(list / create / save / delete / etc),因此每个操作都有可能冻结整个UI.这是一个通过调用service.GetAll()的天真实现的例子,它可能需要“很长”的时间(超过几百毫秒): privat
使用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);
}

(旁白:我很想知道为什么List有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();
}

(旁白:上面的代码已被简化,但这是它的要点.)

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

});

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

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的一个选项,您也应该查看Task Parallel Library.

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

注意:这些只是简单的想法.代码尚未经过测试,因此可能包含错误.更多的是被视为讨论材料而不是成品解决方案.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读