Cannot Get Threading right on wpf UI
I am building a proof of concept application before it gets rollout to the real one.
Scenario I should be able to stop processing in the middle of it.
Toolbar 2 buttons "Start" & "Stop"
User press start and it process a long running task. User decides out of the blue to stop the task.
I cannot seem to get threading right!! I cannot press stop as it's waiting for the long running task as if the long running task is actually running on UI thread and not as intented on background thread.
What Am I doing wrong can you spot it? Thanks for your help
public partial class TestView : UserControl
{
private readonly BackgroundWorker _worker;
public TestView
{
InitializeComponent();
_worker = new BackgroundWorker();
_worker.RunWorkerCompleted += RunWorkerCompleted;
_worker.DoWork+=DoWork;
_worker.WorkerReportsProgress = true;
_worker.ProgressChanged+=_worker_ProgressChanged;
_worker.WorkerSupportsCancellation = true;
}
static void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("The task has been cancelled");
}
else if (e.Error != null)
{
MessageBox.Show("Error. Details: " + e.Error);
}
else
{
MessageBox.Show("The task has been completed. Results: " + e.Result);
}
}
private delegate void SimpleDelegate();
void DoWork(object sen开发者_运维技巧der, DoWorkEventArgs e)
{
for (var i = 0; i < 1000000; i++)
{
_worker.ReportProgress(i, DateTime.Now);
// SimpleDelegate simpleDelegate = () => txtResult.AppendText("Test" + System.Environment.NewLine);
//Dispatcher.BeginInvoke(DispatcherPriority.Normal, simpleDelegate);
}
MessageBox.Show("I have done it all");
}
private void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
DateTime time = Convert.ToDateTime(e.UserState);
txtResult.AppendText(time.ToLongTimeString());
txtResult.AppendText(Environment.NewLine);
}
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
_worker.RunWorkerAsync();
}
private void BtnStop_Click(object sender, RoutedEventArgs e)
{
_worker.CancelAsync();
MessageBox.Show("Process has been stopped!");
}
}
You run a very tight loop inside of DoWork and continuously push Invoked ProgressUpdates to the Main Thread. That will make it sluggish.
But the real problem is that DoWork has to cooperate in Cancellation:
void DoWork(object sender, DoWorkEventArgs e)
{
for (var i = 0; i < 1000000; i++)
{
if (_worker.CancelationPending)
{
e.Cancel = true;
break; // or: return to skip the messagebox
}
_worker.ReportProgress(i, DateTime.Now);
}
MessageBox.Show("I have done it all"); // remove or make depend on Cancelled
}
精彩评论