C# 如何防止BackgroundWorker阻塞UI线程?
在我的XML编辑器中,我希望能够使用索引文件一次打开多个文件。显然,根据文件的数量,这可能需要一些时间,我想使用进度条通知用户程序仍在加载和执行某些操作。 根据我的研究,保持UI进度条更新的方法是使用BackgroundWorkerC# 如何防止BackgroundWorker阻塞UI线程?,c#,wpf,multithreading,C#,Wpf,Multithreading,在我的XML编辑器中,我希望能够使用索引文件一次打开多个文件。显然,根据文件的数量,这可能需要一些时间,我想使用进度条通知用户程序仍在加载和执行某些操作。 根据我的研究,保持UI进度条更新的方法是使用BackgroundWorker public MainWindow() { InitializeComponent(); tabList = new ObservableCollection<FileTab>();
public MainWindow()
{
InitializeComponent();
tabList = new ObservableCollection<FileTab>();
tabControl.ItemsSource = tabList;
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
backgroundWorker.WorkerReportsProgress = true;
}
(...)
private void OpenProjectButtonClick(object sender, RoutedEventArgs e)
{
openingProgressBar.Value = 0;
openingProgressBar.Visibility = System.Windows.Visibility.Visible;
backgroundWorker.RunWorkerAsync();
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int i = 0;
foreach (IndexFile file in indexManager.fileList)
{
this.Dispatcher.Invoke((Action)(() =>
{
tabList.Add(new FileTab(file.filePath));
}));
i++;
Console.WriteLine("-(DoWork)->" + i);
double percentage = (Convert.ToDouble(i) / Convert.ToDouble(indexManager.fileList.Count)) * 100;
Console.WriteLine("-(DoWork.percentage)-> "+ percentage);
backgroundWorker.ReportProgress((int)percentage);
}
}
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
openingProgressBar.Value = e.ProgressPercentage;
Console.WriteLine("-(ProgressChanged)->" + openingProgressBar.Value);
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
openingProgressBar.Visibility = System.Windows.Visibility.Collapsed;
backgroundWorker.Dispose();
Console.WriteLine("-(RunWorkerComplete)-> Done");
}
public主窗口()
{
初始化组件();
tabList=新的可观察集合();
tabControl.ItemsSource=表格列表;
backgroundWorker=新的backgroundWorker();
backgroundWorker.DoWork+=backgroundWorker\u DoWork;
backgroundWorker.ProgressChanged+=backgroundWorker\u ProgressChanged;
backgroundWorker.RunWorkerCompleted+=backgroundWorker\u RunWorkerCompleted;
backgroundWorker.WorkerReportsProgress=true;
}
(...)
private void OpenProjectButtonClick(对象发送方,路由目标)
{
openingProgressBar.Value=0;
openingProgressBar.Visibility=System.Windows.Visibility.Visible;
backgroundWorker.RunWorkerAsync();
}
无效backgroundWorker_DoWork(对象发送方,DoWorkEventArgs e)
{
int i=0;
foreach(indexManager.fileList中的IndexFile文件)
{
this.Dispatcher.Invoke((操作)(()=>
{
添加(新文件选项卡(file.filePath));
}));
i++;
控制台写入线(“-(DoWork)->”+i);
双百分比=(Convert.ToDouble(i)/Convert.ToDouble(indexManager.fileList.Count))*100;
Console.WriteLine(“-(DoWork.percentage)->”+百分比);
backgroundWorker.ReportProgress((int)百分比);
}
}
void backgroundWorker\u ProgressChanged(对象发送方,ProgressChangedEventArgs e)
{
openingProgressBar.Value=e.ProgressPercentage;
Console.WriteLine(“-(ProgressChanged)->”+openingProgressBar.Value);
}
void backgroundWorker\u RunWorkerCompleted(对象发送方,runworkercompletedeventarge)
{
openingProgressBar.Visibility=System.Windows.Visibility.Collapsed;
backgroundWorker.Dispose();
Console.WriteLine(“-(RunWorkerComplete)->完成”);
}
因为我在DoWork方法中访问tablist,所以我将该调用包装在Dispathcer.Invoke中。在这种形式下,代码实现了我想要的功能。它使折叠的progressBar可见,并每隔一段时间更新一次。遗憾的是,它没有在每次加载文件后更新百分比。从控制台中可以看到,ProgressChanged执行滞后于DoWork。根据我的理解,它在循环的每次迭代中都被调用。即使它触发了,用户界面也不会总是对此做出响应
所以我的问题是:我是否仍然以某种方式阻塞UI线程,如何修复它 尝试将报告进度操作移动到调度程序的操作中:
foreach (IndexFile file in indexManager.fileList)
{
this.Dispatcher.Invoke((Action)(() =>
{
tabList.Add(new FileTab(file.filePath));
Console.WriteLine("-(DoWork)->" + i);
double percentage = (Convert.ToDouble(i) / Convert.ToDouble(indexManager.fileList.Count)) * 100;
Console.WriteLine("-(DoWork.percentage)-> "+ percentage);
backgroundWorker.ReportProgress((int)percentage);
}));
i++;
}
dispatcher可能在另一个线程中运行…问题在于
您正在UI和BackgroundWorker之间进行耦合
解决方案
返回您的FileTab对象的ReportProgress
然后将
backgroundWorker\u ProgressChanged
中的FileTab对象添加到表格列表中
遗憾的是,这似乎并没有改变行为。这起作用了,现在速度如此之快,我几乎不再需要进度条了。。。谢谢不幸的是,我没有工作。我正在报告当前循环I
,在报告事件中,我将此int设置为一个名为ProgressValue
的属性。此ProgressValue
作为值绑定到progressbar。我的用户界面仍在阻塞。@C4u那么改变它怎么样?(我看不出你的问题)。在DoWork
(所有值都必须是用户界面上的自主值)中完成工作,每次完成一个部件时,通过ReportProgress
将其报告给用户界面威胁(这里您可以使用用户界面值(如ProgressValue
)最后,当您的所有工作都完成时,如果您需要在UI中再次执行某些操作,请调用RunWorkerCompleted
。我希望这将对您有所帮助:-)
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
int i = 0;
foreach (IndexFile file in indexManager.fileList)
{
i++;
Console.WriteLine("-(DoWork)->" + i);
double percentage = (Convert.ToDouble(i) / Convert.ToDouble(indexManager.fileList.Count)) * 100;
Console.WriteLine("-(DoWork.percentage)-> "+ percentage);
backgroundWorker.ReportProgress((int)percentage,new FileTab(file.filePath));
}
}