从另一个类更新Progressbar

本文关键字:Progressbar 更新 另一个 | 更新日期: 2024-10-19 20:49:21

我正在C#/WPF(.Net framework 4.0)中编写一个应用程序。我遇到的一个问题是,如果可能的话,如何在应用程序非常繁忙的时候更新控件。我想我只是在尝试我在网上找到的东西来让它发挥作用(在极少数情况下确实如此)。该应用程序有四个类,一个主窗口类、一个Worker1类和一个Worker2类以及一个静态ExtensionMethods类。Worker2是从Worker1调用的,它完成了大部分工作。当它运行时,CPU是100%(核心是100%,系统有四个核心)。(所有名称空间都相同。)

public static class ExtensionMethods
{
    private static Action EmptyDelegate = delegate() { };
    public static void Refresh(this UIElement uiElement)
    {
        uiElement.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, EmptyDelegate);
    }
}

主窗口调用Worker1中的一个顶级函数,该函数经过一些设置,然后开始漫长的过程,过程如下:

MainWindow mainWindow = App.Current.MainWindow as MainWindow;
mainWindow.dispatcher_UpdateProgressBarMaximum(maxValue);
int count=0;
Worker2 worker2 = new Worker2();
while (bytesRead =(readData() !=0) {
    count++;
    worker2.doWork();
    mainWindow.dispatcher_UpdateProgressBar(count);
}

在主窗口类中是:

dispatcher_UpdateProgressBar(int Value)
{
Dispatcher.BeginInvoke(new Action(() => myProgressBar.Value = value), null);
        myProgressBar.Refresh();
}

(我也尝试过:myProgressBar.Dispatcher.Begin…etc.

但两者都不重要。对于有2到3次读取的小文件,我可以看到进度条正在更新。但是对于大文件,直到最后都不会更新。这种情况也发生在一些标签控件中,我在其中显示一些状态信息。在整个工作完成后,我可以选择显示一个消息框,显示所做的工作。对于标签,当我显示消息框时,标签会更新。该应用程序可能一个接一个地处理多个文件。

我曾考虑过使用后台线程,但不确定如何使用。也就是说,worker2.doWork()部分非常密集,但如果它在自己的线程上,那么线程开始后会立即调用mainWindow.dispatcher_Update…,没有什么可以阻止下一次读取的发生,对吧?

也许我编码的方式是不可能的。如果我使用Backgroundworker,这个类会在Main Window或Worker1中实例化吗?即使是一两个指针也很棒。

从另一个类更新Progressbar

In。NET 4.5中,他们添加了IProgress<T>接口和Progress<T>类,允许您从另一个线程报告进度,如果在那里创建了Progress对象,它将自动在UI线程上运行回调。

就是你现在的样子。NET 4.0你并不是完全运气不好,微软通过NuGet Package Microsoft发布了这些类作为框架的带外更新。BCL,它将这两个类反向端口连接到。NET 4.0。

一旦你有了Progress<T>,它就很容易使用了。

void StartWorker()
{
    var progress = new Progress<int>(UpdateProgressBar);
    worker1.Start(progress)
}

void UpdateProgressBar(int Value)
{
    //This code is invoked on the UI thread
    myProgressBar.Value = value;
}
//Elsewhere in Worker1
void Start(IProgress<int> progress)
{
    int count=0;
    Worker2 worker2 = new Worker2();
    while (bytesRead =(readData() !=0) 
    {
        count++;
        worker2.doWork();
        progress.Report(count);
    }
}

尽管如此,你还是应该试着重新思考你的数据模型。"拥抱WPF"并开始使用MVVM等概念来设置绑定,然后更新数据对象,然后更新UI(您可以将所有UI封送处理代码放在ViewModel中的OnPropertyChanged事件中)。

使用BackgroundWorker进行后台工作,通过ReportProgress调用更新GUI,并通过服务ProgressChanged事件来处理它,该事件包含"进度"-只需从那里更新进度条。

如果您需要在第一个后台任务完成时启动另一个后台任务,您可以通过RunWorkerCompleted事件来完成。