使用后台工作者和更新UI

时间:2016-03-27 15:08:57

标签: c# backgroundworker dispatcher ui-thread

当我需要执行需要很长时间的操作时,我会在这样的BackgroundWorker中调用它,因此它不会冻结UI;

BackgroundWorker bgWorker = new BackgroundWorker();

bgWorker.DoWork += (s, e) => { 
    //Do something long lasting
    for(int i = 0; i < x; i++){

        //Performing action i of x

        //While doing so update the progressbar
        prgBar.Dispatcher.Invoke(() =>{
            prgBar.Value += ((i / x) * 100.0);
        });

    }
};  

bgWorker.RunWorkerCompleted += (s, e) => { 
    //Finish up things
}; 
bgWorker.RunWorkerAsync();

这是“走的路吗?”更新用户界面还是“未完成”? 同样的问题适用于BackgroundWorker(可能只是启动一个新线程而不是BackgroundWorker?)

2 个答案:

答案 0 :(得分:3)

如果您需要从后台线程更新某些UI组件,则应使用Dispatcher来编组对主线程的调用。话虽如此,您似乎正在尝试更新一些进度条。 BackgroundWorker类已经为此提供了一种机制。因此,您只需在表单上使用ProgressBar控件,然后:

var bgWorker = new BackgroundWorker();

// Specify that this worker supports progress
bgWorker.WorkerReportsProgress = true;

bgWorker.OnProgressChanged += e => 
{
   // This is called on the main thread. It safe to update your UI components here
   myProgressBar.Value = e.ProgressPercentage;
};

bgWorker.DoWork += (s, e) => 
{ 
    // Do something long lasting
    for(int i = 0; i < x; i++) {
        //Performing action i of x

        // While doing so notify the subscribers of the progress event
        var progress = (int)((i / x) * 100.0);
        bgWorker.ReportProgress(progress);
    }
};  

bgWorker.RunWorkerCompleted += (s, e) => 
{ 
    //Finish up things
}; 

bgWorker.RunWorkerAsync();

答案 1 :(得分:1)

不,不是。主要问题是你的进度条 - 它在后台工作线程而不是UI线程上受到欢迎。它也永远不会挂在任何东西上 - 它在哪里显示?

正确的方法是拥有一个包含进度条的表单,并在UI线程中打开它(或者只是开始拍摄它)在启动后台工作程序之前,然后在完成后隐藏它。

Dispatcher的更新逻辑是&#34;正确&#34;虽然它目前触及一个未正确初始化的进度条。但是调用是你必须要做的。