C# BackgroundWorker throws InvalidOperationException in RunWorkerCompletedEventHandler

-1

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;
    }
c#
multithreading
backgroundworker
asked on Stack Overflow May 20, 2021 by Chris • edited May 20, 2021 by Chris

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0