WPF ProgressBar控件调度仍然阻止UI线程

时间:2011-03-02 22:20:09

标签: c# .net wpf wpf-controls

我正在使用WPF尝试在后台运行一个更新进度条的线程。我不想阻止UI线程,所以我运行以下代码。但是UI仍然被阻止。看起来很简单,我做错了什么?

       Dispatcher.BeginInvoke(
        (ThreadStart) delegate(){                   
            for(double i = progressBar_ChangeProgress.Minimum;
                i < progressBar_ChangeProgress.Maximum;
                i++)
                {
                    for (int b = 0; b < 100000000; b++) { }
                    progressBar_ChangeProgress.Value = i;
                }
            EnableAllInputControls();
        }, DispatcherPriority.Background);

3 个答案:

答案 0 :(得分:5)

为什么不在这种情况下利用BackgroundWorker ......

        void Go()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerAsync();
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar_ChangeProgress.Value = e.ProgressPercentage;
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int b = 0; b < 100; b++) 
            {
                Thread.Sleep(100);
                worker.ReportProgress(b);
            }
        }

<强>更新

如果您想使用Dispatcher;将优先级设置为Normal并在后台线程上执行处理,然后在UI线程上调用方法以提供更新。

        void Go()
        {
            ThreadStart start = delegate()
            {
                //this is taking place on the background thread
                for (int i = 0; i < 100; i++)
                {
                    //this is slowing things down; no real relevance
                    Thread.Sleep(100);

                    //this will marshal us back to the UI thread
                    Dispatcher.Invoke(DispatcherPriority.Normal,
                                         new Action<int>(Update), i
                                         );
                }

            };

            new Thread(start).Start();
        }

        void Update(int value)
        {
            //this is taking place on the UI thread
            _progressBar.Value = value;
        }

答案 1 :(得分:2)

Dispatcher只是一种在以后的UI线程上运行一些代码的机制。您传入的优先级控制 它将被执行,而不是任何类型的线程优先级。在这种情况下,您的委托的内容将在UI线程上运行。使用Aaron提到的BackgroundWorker肯定会对此有所帮助。

另外我可能会指出,通常一个进度条显示任务完成的接近程度。如果您不知道要采取多长时间或无法测量进度,可以使用不确定进度条。如果您有一些有意义的信息,请仅更新该值。 (尽管你可能刚刚提供了这个用于演示目的)

答案 2 :(得分:0)

BeginInvoke 内的所有内容都在UI线程上运行,因此会阻止。

您需要做的是在线程中运行任何时间密集的代码,然后只更新Invoke中的UI。

你想要更像这样的东西:

for (double i = progressBar_ChangeProgress.Minimum;
    i < progressBar_ChangeProgress.Maximum;
    i++)
{
  for (int b = 0; b < 100000000; b++) { }
  Dispatcher.Invoke((ThreadStart) delegate(){                   
    progressBar_ChangeProgress.Value = i;
  });
}