WPF 防止UI阻塞 BackgroundWorker

案例:提交登录,后台(C#)长时间处理逻辑业务,导致前端界面阻塞(停止动画,页面不可以移动等)

 解决方案,使用 BackgroundWorker:

说明:BackgroundWorker类允许您在单独的线程上执行某个可能导致用户界面(UI)停止响应的耗时操作(比如文件下载数据库事务等),并且想要一个响应式的UI来反应当前耗时操作的进度。

MVVM模式,登录示例:

public class WindowLoginViewModel
{
    //定义BackgroundWorker
    BackgroundWorker backgroundWorker;
    //ViewModel构造函数
    public WindowLoginViewModel()
    {
        //BackgroundWorker实例化
        backgroundWorker = new BackgroundWorker();
        //指示BackgroundWorker是否可以报告进度更新
        //当该属性值为True是,将可以成功调用ReportProgress方法,否则将引发InvalidOperationException异常。
        backgroundWorker.WorkerReportsProgress = true;
        //指示BackgroundWorker是否支持异步取消操作
        //当该属性值为True是,将可以成功调用CancelAsync方法,否则将引发InvalidOperationException异常。
        backgroundWorker.WorkerSupportsCancellation = true;
        //用于承载异步操作
        backgroundWorker.DoWork += backgroundWorker_DoWork;
        //报告操作进度 
        backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
        //异步操作完成或取消时执行的操作,当调用DoWork事件执行完成时触发
     backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
    }

    //登录命令
    public DelegateCommand<Window> LoginCommand
    {
        get
        {
            return new DelegateCommand<Window>(Login);
        }
    }
    //登录业务
    public void Login(Window window)
    {
        //指示BackgroundWorker是否正在执行一个异步操作
        //此属性通常放在BackgroundWorker.RunWorkerAsync()方法之前,避免多次调用RunWorkerAsync()方法引发异常
        if (backgroundWorker.IsBusy)
        {
            return;
        }
        //开始执行一个后台操作。
        //调用该方法后,将触发BackgroundWorker.DoWork事件,并以异步的方式执行DoWork事件中的代码
        //RunWorkerAsync(Object)方法允许传递一个Object类型的参数到后台操作中,并且可以通过DoWork事件的DoWorkEventArgs.Argument属性将该参数提取出来
        backgroundWorker.RunWorkerAsync(window);
    }
    //取消命令
    public DelegateCommand<Window> CancelCommand
    {
        get
        {
            return new DelegateCommand<Window>(Cancel);
        }
    }
    //取消业务
    public void Cancel(Window window)
    {
        //请求取消当前正在执行的异步操作
        backgroundWorker.CancelAsync();
    }
    //BackgroundWorker报告操作进度
    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs args)
    {
        //状态说明
        //object userState = args.UserState;

        //状态参数
        //progressBar.Value = args.ProgressPercentage;

    }
    //BackgroundWorker执行业务
    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs args)
    {
        //指示应用程序是否已请求取消后台操作
        if (backgroundWorker.CancellationPending)
        {
            args.Cancel = true;
            return;
        }
        else
        {
            Window window = (Window)args.Argument;
            //ReportProgress(Int, Object)方法允许传递一个Object类型的状态对象到 ProgressChanged事件中,并且可以通过ProgressChanged事件的ProgressChangedEventArgs.UserState属性取得参数值。 
            backgroundWorker.ReportProgress(0, "参数说明");

            Models.Users user = new Models.Users();
            Application.Current.Dispatcher.Invoke((Action)(() =>{
                Globle.mainWindow = new MainWindow();
                window.Close();
            }));
        }
    }
    ///BackgroundWorker执行完成
    //此处UI会阻塞,所以不要放过多的处理程序
    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs args)
    {
        if (args.Error != null)
        {
            MessageBox.Show(args.Error.ToString());
            return;
        }
        //线程取消
        if (args.Cancelled)
        {
                
        }
        if (!args.Cancelled)
        {
            Application.Current.Dispatcher.Invoke((Action)(() =>{
                Globle.mainWindow.Show();
            }));
        }
    }
}    

 

DoWork示例:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    while (!bw.CancellationPending)
    {
        //Do SomeThing
        //在合适的时候使用
        //backgroundWorker.ReportProgress(i);
        //报告一下进度
    }
}

简单示例:

Action workAction = delegate {
    BackgroundWorker worker = new BackgroundWorker();
    worker.DoWork += (o, ea) =>
    {
        Login(Name, Password);
    };
    worker.RunWorkerCompleted += (s, e) =>
    {
        if (e.Error != null)
        {
            loginStatus.Text = "登录失败!";
        }
        else
        {
            loginStatus.Text = "登录成功!";
        }
    };
    worker.RunWorkerAsync();
};
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, workAction);

  

  

posted @ 2021-06-07 17:29  microsoft-zhcn  阅读(1497)  评论(0编辑  收藏  举报