WPF calls not working during long method processing
The following method does not apply the wpf changes (background = red) until the 2nd method (DoWork) exits:
private void change()
{
Background = Brushes.Red;
Dispatcher.BeginInvoke((Action) DoWork);
}
DoWork() takes several seconds to run and I don't really want to put it into a thread, as this code will be used in several places and will probably interact will the Dispatcher thread at various intervals. I've tried calling the Invalidate...() metho开发者_运维问答ds, but to no avail. The BeginInvoke() was added to see if the delay would allow the background change to be applied before the logic was called. Typically, the logic would be part of this method. Btw, most of the logic is performed on a different thread and shouldn't block the Dispatcher thread?!
Can someone please help? Thanks
The "Dispatcher" thread is the UI thread.
When you call Dispatcher.BeginInvoke((Action) DoWork);
, you're basically blocking the UI thread until DoWork
exits, since it's running on the UI thread.
This will prevent the UI from updating, hence you don't see the background change.
You really should consider moving DoWork
onto a background thread, either via the ThreadPool directly, a BackgroundWorker, or some other means. That would completely correct this problem, and prevent you from blocking the UI thread for a "few seconds" (which will happen if you run this using the Dispatcher's threading).
For communication between threads, we have the Dispatcher
class in WPF.
Dispatcher.Invoke(DispatcherPriority.Normal, (NoArgDelegate)delegate
{
------
});
BeginInvoke(..) method does not block the call but it simply put a new message to the queue to process by dispatcher thread. In the code you posted, you have no guarantee that background color change will processed before DoWorks starts.
You can put lower priority to the DoWork call to be sure that background is changed first:
private void Button_Click(object sender, RoutedEventArgs e)
{
grid.Background = new SolidColorBrush(Colors.Red);
Dispatcher.BeginInvoke((Action)DoWork, DispatcherPriority.ContextIdle);
}
private void DoWork()
{
Thread.Sleep(1000);
btn.Content = "Done";
}
But this is not the best solution known to the mankind.
Better would be to proceed with DoWork in separate thread. Above example using thread approach will look like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
grid.Background = new SolidColorBrush(Colors.Red);
Task t = new Task(DoWork);
t.Start();
}
private void DoWork()
{
Thread.Sleep(1000);
// Synchronize calls to the UI elements
Application.Current.Dispatcher.BeginInvoke((Action)(() => { btn.Content = "Done"; }));
}
Just remember to post all operations on UI elements to the UI thread.
精彩评论