WPF 防止UI阻塞 BackgroundWorker
案例:提交登录,后台(C#)长时间处理逻辑业务,导致前端界面阻塞(停止动画,页面不可以移动等)
解决方案,使用 BackgroundWorker:
说明:BackgroundWorker类允许您在单独的线程上执行某个可能导致用户界面(UI)停止响应的耗时操作(比如文件下载数据库事务等),并且想要一个响应式的UI来反应当前耗时操作的进度。
MVVM模式,登录示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 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示例:
1 2 3 4 5 6 7 8 9 10 | private void backgroundWorker_DoWork( object sender, DoWorkEventArgs e) { while (!bw.CancellationPending) { //Do SomeThing //在合适的时候使用 //backgroundWorker.ReportProgress(i); //报告一下进度 } } |
简单示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?