Here is a simple example showing how to create background tasks in a WPF app with .NET 4.5 and above. This is so much easier than the old BackgroundWorker approach.
<Window x:Class="TestAsyncTasks.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestAsyncTasks"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid Margin="4">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button x:Name="ButtonStart" Content="Start" Click="Start_Click" Padding="4"/>
<Button x:Name="ButtonCancel" Content="Cancel" Click="Cancel_Click" Padding="4"/>
</StackPanel>
<TextBox Grid.Row="1" x:Name="Label1"></TextBox>
</Grid>
</Window>
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace TestAsyncTasks
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// To allow background task to be cancelled with cts.Cancel()
CancellationTokenSource cts;
private async void Start_Click(object sender, RoutedEventArgs e)
{
// Disable button so it can't be clicked again until finished
ButtonStart.IsEnabled = false;
Label1.Text = "Start\r\n";
// Setup the function to be called with updates
var progressUpdate = new Progress<int>(ReportProgressOnUIThread);
// Create a new CancellationTokenSource and optionally set a time
// when the task will automatically cancel if it has not already
// finished.
int AutoCancelAfterMS = 50000;
cts = new CancellationTokenSource(AutoCancelAfterMS);
// Must be in Try/Catch to trap the OperationCanceledException
try
{
int loopTo = 10;
int result = await MyBackgroundTaskAsync(loopTo, progressUpdate, cts.Token);
// This code does not run until MyBackgroundTaskAsync finishes
Label1.Text += $"Final result : {result}\r\n";
}
catch (OperationCanceledException ex)
{
// Do stuff to handle the cancellation exception
Label1.Text += "CANCELLED\r\n";
}
catch (Exception ex)
{
//Do stuff to handle other exceptions
Label1.Text += $"Exception : {ex.Message}\r\n";
}
// Reenable Start button
ButtonStart.IsEnabled = true;
Label1.Text += "Finished\r\n";
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
async Task<int> MyBackgroundTaskAsync(int DataFromParent, IProgress<int> progress, CancellationToken ct)
{
int result = await Task.Run<int>(async () =>
{
for (int n=0; n< DataFromParent; n++)
{
//You cannot do this because it's running on a non UI thread
// Label1.Text += $"{n} I don't work!\r\n";
// Throw OperationCanceledException if cts.Cancel() called
ct.ThrowIfCancellationRequested();
// Report progress back to UI thread
progress.Report(n);
// Do the slow things in the background
await SlowStuff();
}
// result gets this value which is returned as final result
return 42;
}, ct);
return result;
}
async Task SlowStuff()
{
// Simulate some slow code. This runs on a background thread.
await Task.Delay(1000);
}
void ReportProgressOnUIThread (int value)
{
// This runs on the UI thread so it can update the WPF controls
Label1.Text += value.ToString() + "\r\n";
}
}
}
No comments:
Post a Comment