从另一个类更新Progressbar

时间:2013-12-17 20:02:27

标签: c# wpf backgroundworker

我正在用C#/ WPF(.Net framework 4.0)编写一个应用程序。我遇到问题的一件事是如何在应用程序非常繁忙时更新控件。我想我只是试图尝试在网上找到的东西让它起作用(在极少数情况下它会这样)。 该应用程序有四个类,主窗口类,Worker1类和Worker2类以及静态ExtensionMethods类。从Worker1调用Worker2并完成大部分工作。当它运行时,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);

}

在mainWindow类中是:

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

(我也尝试过:myProgressBar.Dispatcher.Begin ......等。

但无论多么重要。对于有2或3个读取的小文件,我可以看到进度条得到更新。但是对于大文件,直到最后都没有更新。 这也发生在一些标签控件中,其中我显示一些状态信息。整个工作完成后,我可以选择显示已完成工作的消息框。对于标签,当我显示消息框时,标签会更新。该应用程序可能会依次处理许多文件。

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

也许我编码它的方式不可能。如果我使用了Backgroundworker,那么该类是否会在主窗口或Worker1中实例化?即使是一两个指针也会很棒。

2 个答案:

答案 0 :(得分:3)

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

由于你在.NET 4.0上运行并不是完全没有运气,微软通过NuGet包Out of band update将这些类作为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事件中)

答案 1 :(得分:2)

使用BackgroundWorker进行后台工作,并通过ReportProgress来电更新GUI,并通过提供包含“进度”的ProgressChanged event进行处理 - 只需更新进度条即可那里。

如果你需要在第一个任务完成时启动另一个后台任务,你可以从RunWorkerCompleted event完成。