The result of my BackgroundWorker throws an InvalidOperationException
in the RunWorkerCompletedEventHandler. It occurres on cancellation and complete.
The events of the GUI occurres fine, the worker.processChange(...)
works fine and the RunWorkerCompletedEventHandler (which is in the MainWindow.xaml.cs
) works also fine.
The cancelation of the Task.Delay(...).Wait()
works fine too.
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
private cProcessor m_Process = null;
public MainWindow()
{
m_Process = new(ProcressChanged, ProcessCompleted);
InitializeComponent();
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
m_Process.StartProgress();
}
private void btnStop1_Click(object sender, RoutedEventArgs e)
{
m_Process.StopProcess();
}
private void ProcressChanged(object sender, ProgressChangedEventArgs e)
{
pbProcessBar.Value = e.ProgressPercentage;
}
private void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
txtStatus.Content = (string)e.Result; //Here is a InvalidOperationException thrown
}
cProcessor.cs
class cProcessor
{
private BackgroundWorker m_worker = new()
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
private CancellationTokenSource m_CancellationToken = new();
public cProcessor(ProgressChangedEventHandler onProcessChanged, RunWorkerCompletedEventHandler onProcessFinished)
{
this.m_worker.DoWork += new DoWorkEventHandler(DoProcess);
this.m_worker.RunWorkerCompleted += onProcessFinished;
this.m_worker.ProgressChanged += onProcessChanged;
}
public void StartProgress()
{
if (this.m_worker.IsBusy != true)
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
throw new InvalidOperationException("Bug! Code called from a worker thread");
this.m_worker.RunWorkerAsync();
}
}
public void StopProcess()
{
if (this.m_worker.WorkerSupportsCancellation == true)
{
this.m_CancellationToken.Cancel();
this.m_worker.CancelAsync();
}
}
private void DoProcess(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (!worker.CancellationPending)
{
if (this.GoSleep(new TimeSpan(0, 0, 20)))
{
for (int i = 0; i <= 10; i++)
{
//Do some fancy stuff
Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
else
e.Cancel = true;
}
string msg = "";
if (e.Cancel == true)
msg = "Process stopped!";
else
msg = "Process completed!";
e.Result = msg;
}
private bool GoSleep( TimeSpan time)
{
var t = Task.Delay(time, this.m_CancellationToken.Token);
bool isWaitComplete = true;
try
{
t.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
if (e.GetType() != typeof(TaskCanceledException))
throw e;
else
isWaitComplete = false;
}
}
finally
{
t.Dispose();
}
return isWaitComplete;
}
}
EDIT: The Exception:
HResult=0x80131509
Message=Operation has been cancelled.
Source=System.ComponentModel.EventBasedAsync
StackTrace:
at System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary()
at System.ComponentModel.RunWorkerCompletedEventArgs.get_Result()
at WpfApp1.MainWindow.ProcessCompleted(Object sender, RunWorkerCompletedEventArgs e) in ...\WpfApp1\WpfApp1\MainWindow.xaml.cs:line 48
at System.ComponentModel.BackgroundWorker.OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
at System.ComponentModel.BackgroundWorker.AsyncOperationCompleted(Object arg)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at MS.Internal.CulturePreservingExecutionContext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
EDIT 2: As answerd in the Comments, the cancellation causes the Exception in the Result. So change:
private void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(!e.Cancelled)
txtStatus.Content = (string)e.Result;
}
User contributions licensed under CC BY-SA 3.0