案例:提交登錄,后台(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);