I want to execute a long running task after clicking a wpf button. Here what I did.
private void Start(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(2000); // simulate task
}
}
Problem is, this will make wpf gui unresponsive. I also would like to allow cancellation and report progress every 1 second. I expand the code as below.
DispatcherTimer dispatcherTimer = new DispatcherTimer(); // get progress every second
private int progress = 0; // for progress reporting
private bool isCancelled = false; // cancellation
private void Start(object sender, RoutedEventArgs e)
{
InitializeTimer(); // initiallize interval timer
Start(10); // execute task
}
private void InitializeTimer()
{
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0,0,1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
Logger.Info("Current loop progress " + progress); // report progress
}
private void Cancel(object sender, RoutedEventArgs e) // cancel button
{
isCancelled = true;
}
private int Start(int limit)
{
isCancelled = true;
progress = 0;
for (int i = 0; i < limit; i++)
{
Thread.Sleep(2000); // simulate task
progress = i; // for progress report
if (isCancelled) // cancellation
{
break;
}
}
return limit;
}
My target platform is .NET 4.5. What is the recommended way to do this?
Thanks.
Here we show an example of the BackgroundWorker class in WPF. Step 2: In order to run the BackgroundWorker process we use the RunWorkerAsync method of the BackgroundWorker class. This mehod is used to start the execution of the background process by the raising of the DoWork event.
The BackgroundWorker class is used to run time-consuming tasks in the background; it leaves the user interface responsive. Sometimes we need to perform some time consuming tasks such as downloads etc. Execution of these tasks consumes a large amount of time.
The following code example shows how to run a time-consuming operation in the background. The form has Start and Cancel buttons. Click the Start button to run an asynchronous operation. Click the Cancel button to stop a running asynchronous operation. The outcome of each operation is displayed in a MessageBox.
Since the service class methods are running on a background thread, they can’t call a View Model method (which runs on the main thread) directly. We saw this above, in the last ContinueWith () call. In this case, we use the Dispatcher.Invoke () approach to call the View Model from our background task:
I thought I answered your question here. If you need more sample code on how to do this using Task Parallel Library, with CancellationTokenSource
and IProgress<T>
, here it is:
Action _cancelWork;
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
this.StartButton.IsEnabled = false;
this.StopButton.IsEnabled = true;
try
{
var cancellationTokenSource = new CancellationTokenSource();
this._cancelWork = () =>
{
this.StopButton.IsEnabled = false;
cancellationTokenSource.Cancel();
};
var limit = 10;
var progressReport = new Progress<int>((i) =>
this.TextBox.Text = (100 * i / (limit-1)).ToString() + "%");
var token = cancellationTokenSource.Token;
await Task.Run(() =>
DoWork(limit, token, progressReport),
token);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
this.StartButton.IsEnabled = true;
this.StopButton.IsEnabled = false;
this._cancelWork = null;
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
this._cancelWork?.Invoke();
}
private int DoWork(
int limit,
CancellationToken token,
IProgress<int> progressReport)
{
var progress = 0;
for (int i = 0; i < limit; i++)
{
progressReport.Report(progress++);
Thread.Sleep(2000); // simulate a work item
token.ThrowIfCancellationRequested();
}
return limit;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With