I'm having trouble making my ComputeListener function work as expected.
I want the StatusBlock.Text
to be immediately updated on the UI even before Compute() begins, but I cannot get this to work.
I know this question has been asked elsewhere on StackOverflow, but none of the solutions that I saw worked for me.
I've dealt with several problems along the way, but the current issue is that no changes are made until ComputeListener() has fully completed its execution and all other features are locked until then.
I want to also be able to click the close button to stop the application if Compute() is taking too long, but this cannot happen either.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void ComputeListener(object sender, RoutedEventArgs args)
{
var t = Task.Run(() => Dispatcher.BeginInvoke(new Action(() => { StatusBlock.Text = "Status: Processing"; })));
t.Wait();
Task.Run(() => Dispatcher.BeginInvoke(new Action(() => { Compute(); })));
}
private void Compute()
{
//code here
}
Looks like you've correctly identified that executing Compute()
on the UI thread will stop the StatusBlock.Text
change from reflecting in the UI as desired, and that Task
should be used.
However you get cross-thread exceptions trying to update the UI from a worker thread, so you've used the Window.Dispatcher
to get back on the UI thread.
As Icepickle recommends - you want async
/ await
here. I think the following should work:
public async void ComputeListener(object sender, RoutedEventArgs args)
{
StatusBlock.Text = "Status: Processing";
await Task.Run(() => Compute());
}
private void Compute()
{
//code here
}
Or even better:
public async void ComputeListener(object sender, RoutedEventArgs args)
{
StatusBlock.Text = "Status: Processing";
await ComputeAsync();
}
private async Task ComputeAsync()
{
//async code here
}
Note if your implementation of Compute()
also needs access to the UI, you'll still run into issues with this - this is a code smell as your business logic (ie computation) should be independent of the WPF front-end.
I'd recommend moving towards an MVVM approach - this Xamarin.Forms documentation explains the general concepts well, which can be applied to WPF in much the same way
You should use the asynchronous dispatcher member Dispatcher.InvokeAsync
instead of wrapping it into a Task
.
Task.Run
is always awaitable to execute it asynchronously. Task.Wait()
contradicts the idea as it forces the Task
to execute synchronously, since it is blocking the thread until the Task
has completed, cancelled or faulted. Read the remarks of Microsoft Docs: Task.Wait
. When used in combination with Task.Run
chances are high for introducing a deadlock. So always avoid Task.Wait
and use the asynchronous and awaitable versions Task.WaitAny
and Task.WaitAll
if you need to join multiple Task
instances.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public async void ComputeListener(object sender, RoutedEventArgs args)
{
// Don't block while waiting for Dispatcher to execute the action
await Dispatcher.InvokeAsync(() => StatusBlock.Text = "Status: Processing");
// Executes asynchronously on a background thread (thread pool thread).
// Use for CPU bound operations
await ComputeOnNewBackgroundThreadAsync();
// Executes asynchronously on the current thread.
// Use for lightweight async operations
Task task = new Task(ComputeOnCurrentUiThread);
task.Start();
await task;
// Waiting for tasks example
var tasks = new List<Task>();
Task currentThreadTask = new Task(ComputeOnCurrentUiThread);
currentThreadTask.Start();
tasks.Add(currentThreadTask);
Task backgroundThreadTask = ComputeOnNewBackgroundThreadAsync();
tasks.Add(backgroundThreadTask);
// Wait asynchronously for both Task instances to complete
await Task.WhenAll(tasks);
}
private async Task ComputeOnNewBackgroundThreadAsync()
{
await Task.Run(
() =>
{
//code here
});
}
private void ComputeOnCurrentUiThread()
{
//code here
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.