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

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM