WPF多线程进程更新
本文关键字:更新 进程 多线程 WPF | 更新日期: 2023-09-27 17:49:18
我需要显示某种形式的反馈给用户,而一个小的过程(7-10秒)发生在后台。
我过去在Windows窗体中使用单独的线程和后台工作者没有任何问题,但在WPF中证明这很困难。
在这方面,我读了很多文章,以及我应该如何在WPF中使用分派器来启动一个新线程等。然而,当我尝试使用BackgroundWorker来显示等待图像反馈的形式时,它只是保持静态。我不认为这很重要,但它使用了FirstFloor (https://github.com/firstfloorsoftware/mui)的mui。
我正在尝试使用内置的ProgressRing功能(在同一线程内运行并且没有其他主要任务在后台运行时没有问题)
添加BackgroundWorker会带来一个异常,因为对象的跨线程访问,尽管许多博客声明WPF中的BackgroundWorks是跨线程的并且可以安全运行。
下面是最接近我所需要的代码:
private async void MyTaskProcess()
{
await Dispatcher.BeginInvoke(DispatcherPriority.Send, new ThreadStart(() =>
{
try
{
//Update the waiting ring image
ProgressRing.IsActive = true;
}
catch
{
ProgressRing.IsActive = false;
MessageBox.Show("Exception Thrown");
}
}));
await Dispatcher.BeginInvoke(DispatcherPriority.Background, new ThreadStart(() =>
{
try
{
//Run the main MS Excel export function
Export2Excel();
ProgressRing.IsActive = false;
}
catch
{
MessageBox.Show("Exception Thrown");
}
}));
}
在现代WPF应用程序中执行此操作的方法是启动一个新的Task
,在其中执行该工作;在后台,它将在线程池线程上执行工作:
Task.Factory.StartNew(this.DoWork)
现在在DoWork
报告进度,你InvokeAsync
回到主线程每当进度计数改变:
void DoWork()
{
foreach(var item in this.WorkItems)
{
// Do something
// Report Progress
++progress
Application.Current.Dispatcher.InvokeAsync(() => this.Progress = progress);
}
}
添加BackgroundWorker会带来一个异常,因为对象的跨线程访问,尽管许多博客声明WPF中的BackgroundWorks是跨线程的并且可以安全运行。
BackgroundWorker
工作与WPF, 只要你创建并启动UI线程上的BGW。(作为旁注,BGW对Windows窗体有相同的限制)。正如其他评论者所指出的,用BGW做进度更新的正确方法是使用ReportProgress
,而不是Dispatcher
。
但是,我建议使用较新的Task.Run
和IProgress<T>
进行进度更新。我有一篇博客文章对比了旧的BGW进度更新和新的基于IProgress<T>
的进度更新。
Export2Excel
必须在UI线程上运行,这就是你所做的全部工作,那么使用BGW或Task.Run
根本没有意义,因为无论如何都不能在后台线程上运行。
你去,到下面我写的链接并仔细阅读。我希望你一定会解决你的问题:
WPF中的线程