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多线程进程更新

在现代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.RunIProgress<T>进行进度更新。我有一篇博客文章对比了旧的BGW进度更新和新的基于IProgress<T>的进度更新。

很难说你的代码应该是什么样子,因为你发布的代码实际上并没有在后台线程上运行任何东西。特别是,如果Export2Excel必须在UI线程上运行,这就是你所做的全部工作,那么使用BGW或Task.Run根本没有意义,因为无论如何都不能在后台线程上运行。

你去,到下面我写的链接并仔细阅读。我希望你一定会解决你的问题:

WPF中的线程