WPF ProgressBar Control Dispatch still blocking UI Thread
I am using WPF trying to run a Thread in the background that updates a progress bar. I don't wan to block the UI thread so I am running the following code. However the UI still blocked. It see开发者_如何学Cms so simple, what am I doing wrong?
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);
Why not leverage the BackgroundWorker
in this scenario...
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);
}
}
UPDATE:
If you are wanting to use the Dispatcher
; set the priority to Normal
and perform the processing on the background thread then calling a method on the UI thread to provide the update.
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;
}
The Dispatcher
is just a mechanism to run a bit of code on the UI thread at a later time. The priority you're passing in controls when it will get executed, not any type of thread priority. The contents of your delegate in this case are getting run on the UI thread. Using a BackgroundWorker
as mentioned by Aaron would certainly help here.
Also I might point out that usually a progress bar shows how close a task is to completing. If you don't know how long something is going to take or have no way of measuring progress, you can use an Indeterminate progress bar. Only update the value if you have some meaningful information. (though you may have just provided this for demonstration purposes)
Everything inside BeginInvoke is being run on the UI thread and so it will block.
What you need to do is run any time intensive code in your thread and then just update the UI inside the Invoke.
You want something more like this:
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;
});
}
精彩评论