使用后台工作者并更新 UI
Using background worker and updating UI
当我需要执行一个需要很长时间的操作时,我会在 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();
这是'the way to go'更新UI还是'not done'?
同样的问题适用于 BackgroundWorker(也许只是启动一个新线程而不是 BackgroundWorker?)
不,不是。主要问题是您的进度条 - 它是在后台工作线程上创建的,而不是 UI 线程。它也从来没有真正挂在任何东西上 - 它显示在哪里?
正确的方法是拥有一个包含进度条的表单,并在启动后台工作程序之前在 UI 线程中打开它(或者只是开始拍摄),然后在完成时隐藏它。
Dispatcher 的更新逻辑是 "correct",尽管它目前遇到了一个未正确初始化的进度条。但是调用是你必须做的。
如果您需要从后台线程更新某些 UI 组件,您应该使用 Dispatcher 以编组对主线程的调用。话虽如此,您似乎正在尝试更新一些进度条。 BackgroundWorker class 已经为此提供了一种机制。所以你可以简单地在你的表单上有一个 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();
当我需要执行一个需要很长时间的操作时,我会在 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();
这是'the way to go'更新UI还是'not done'? 同样的问题适用于 BackgroundWorker(也许只是启动一个新线程而不是 BackgroundWorker?)
不,不是。主要问题是您的进度条 - 它是在后台工作线程上创建的,而不是 UI 线程。它也从来没有真正挂在任何东西上 - 它显示在哪里?
正确的方法是拥有一个包含进度条的表单,并在启动后台工作程序之前在 UI 线程中打开它(或者只是开始拍摄),然后在完成时隐藏它。
Dispatcher 的更新逻辑是 "correct",尽管它目前遇到了一个未正确初始化的进度条。但是调用是你必须做的。
如果您需要从后台线程更新某些 UI 组件,您应该使用 Dispatcher 以编组对主线程的调用。话虽如此,您似乎正在尝试更新一些进度条。 BackgroundWorker class 已经为此提供了一种机制。所以你可以简单地在你的表单上有一个 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();