Question

I followed an example I saw online and create a progress dialog (code below), and in the main thread, I call

  ProgressDialog pd = new ProgressDialog("Loading File: ", VCDFileName);
  pd.Owner = Application.Current.MainWindow;
  pd.WindowStartupLocation = WindowStartupLocation.CenterOwner;
  ModuleHierarchyVM.TopLevelModules.Clear();


  VCDData TempVCDOutput = null;
  Action handler = delegate
  {
      VCDParser.ParseVCDFileForAllPorts(VCDFileName, this, pd.Worker, ModuleHierarchyVM.TopLevelModules, out TempVCDOutput);
  };

  pd.SetBGWorkerDelegate(handler);
  pd.ShowDialog();

I think that the error is happening in the function being passed to the delegate. I think I'm getting two exceptions ( one on each thread maybe?) the first one says,

TargetInvocationException was unhandled. Exception has been thrown by the target of an invocation.

I think this exception is being thrown by the UI thread because sometimes breakpoints are hit inside the function passed to the delegate before the exception is shown and sometimes they are not.

then after hitting f5 for a while, and going through the many break points in the function being done in the background,

I eventually come back to the UI thread and pd.ShowDialog() and get this exception:

InvalidOperationException was unhandled. ShowDailog can be called only on hidden windows.

I put a bunch of try catch blocks to try to catch the exception if it was happening inside the function being passed to the delegate but I didn't catch it. It doesn't seem to

Code from Progress Dialog

  public partial class ProgressDialog : Window
  {
    BackgroundWorker _worker;
    public BackgroundWorker Worker
    {
      get { return _worker; }
    }


    public string MainText
    {
      get { return MainTextLabel.Text; }
      set { MainTextLabel.Text = value; }
    }

    public string SubText
    {
      get { return SubTextLabel.Text; }
      set { SubTextLabel.Text = value; }
    }



    public bool IsCancellingEnabled
    {
      get { return CancelButton.IsVisible; }
      set { CancelButton.Visibility = value ? Visibility.Visible : Visibility.Collapsed; }
    }


    private bool _Cancelled = false;
    public bool Cancelled
    {
      get { return _Cancelled; }
    }

    private Exception error = null;
    public Exception Error
    {
      get { return error; }
    }


    private object result = null;
    public object Result
    {
      get { return result; }
    }


    /// <summary>
    /// Represents the method that will handle the DoWork event from the backgroundowkrker
    /// </summary>
    private Action workerCallback;

    private object BackgroundWorkerArgument;


    public ProgressDialog(string MainText, string SubText)
      : this()
    {
      this.MainText = MainText;
      this.SubText = SubText;
    }


    public ProgressDialog()
    {
      InitializeComponent();

      this.Loaded += new RoutedEventHandler(ProgressDialog_Loaded);

      _worker = new BackgroundWorker();
      _worker.WorkerReportsProgress = true;
      _worker.WorkerSupportsCancellation = true;


      _worker.DoWork += new DoWorkEventHandler(_worker_DoWork);
      _worker.ProgressChanged += new ProgressChangedEventHandler(_worker_ProgressChanged);
      _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
      Closing += new CancelEventHandler(ProgressDialog_Closing);
    }

    void ProgressDialog_Loaded(object sender, RoutedEventArgs e)
    {
      _worker.RunWorkerAsync(BackgroundWorkerArgument);
    }

    void ProgressDialog_Closing(object sender, CancelEventArgs e)
    {
      //if progress dialog is open
      if (DialogResult == null)
      {
        MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show("Are you sure you wish to cancel?",
           "Confirmation", System.Windows.MessageBoxButton.YesNo);
        if (messageBoxResult == MessageBoxResult.Yes)
        {
          if (_worker.IsBusy)
          {
            //notifies the async thread that a cancellation has been requested.
            _worker.CancelAsync();
          }
          DialogResult = false;
        }
        else
        {

          e.Cancel = true;
        }
      }
      else
      {

        if (_worker.IsBusy)
        {
          //notifies the async thread that a cancellation has been requested.
          _worker.CancelAsync();
        }
      }

    }




    void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      if (!Dispatcher.CheckAccess())
      {
        //run on UI thread
        RunWorkerCompletedEventHandler handler = _worker_RunWorkerCompleted;
        Dispatcher.Invoke(handler, null, DispatcherPriority.SystemIdle, new object[] { sender, e });
        return;
      }
      else
      {
        if (e.Error != null)
        {
          error = e.Error;
        }
        else if (!e.Cancelled)
        {
          //assign result if there was neither exception nor cancel
          result = e.Result;
        }
        ProgressBar.Value = ProgressBar.Maximum;
        CancelButton.IsEnabled = false;


        //set the dialog result, which closes the dialog
        if (DialogResult == null)
        {
          if (error == null && !e.Cancelled)
          {
            DialogResult = true;
          }
          else
          {
            DialogResult = false;
          }
        }
      }

    }

    void _worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
      if (!Dispatcher.CheckAccess())
      {
        //run on UI thread
        ProgressChangedEventHandler handler = _worker_ProgressChanged;
        Dispatcher.Invoke(handler, null, DispatcherPriority.SystemIdle, new object[] { sender, e });
        return;
      }
      else
      {
        if (e.ProgressPercentage != int.MinValue)
        {
          ProgressBar.Value = e.ProgressPercentage;
        }

      }

    }

    void _worker_DoWork(object sender, DoWorkEventArgs e)
    {
      try
      {
        if ((_worker.CancellationPending == true))
        {
          //cancel the do work event
          e.Cancel = true;
        }
        else
        {
          // Perform a time consuming operation and report progress.
          workerCallback();
        }

      }
      catch (Exception)
      {
        //disable cancelling and rethrow the exception
        Dispatcher.BeginInvoke(DispatcherPriority.Normal,
          new Action(delegate { CancelButton.SetValue(Button.IsEnabledProperty, false); }), null);
        throw;
      }
    }




    public void SetBGWorkerDelegate(Action workHandler)
    {
      SetBGWorkerDelegate(null, workHandler);
    }
    public void SetBGWorkerDelegate(object argument, Action workHandler)
    {
      //store reference to callback handler and launch worker thread
      workerCallback = workHandler;
      BackgroundWorkerArgument = argument;



    }


    private void CancelButton_Click(object sender, RoutedEventArgs e)
    {
      MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show("Are you sure you wish to cancel?", 
        "Confirmation", System.Windows.MessageBoxButton.YesNo);
      if (messageBoxResult == MessageBoxResult.Yes)
      {
        if (_worker.IsBusy)
        {
          //notifies the async thread that a cancellation has been requested.
          _worker.CancelAsync();
        }
        DialogResult = false;        
      }


    }
  }
}
Was it helpful?

Solution 2

Found my problem. earlier i think i somehow skipped the first exception. Anyway the first exception had an innerexception that gave the actual details. Somewhere I'm still modifying my observable collection from the wrong thread. I thought I had changed all of them, but there must be one still there

OTHER TIPS

I would suggest not starting the secondary thread externally but rather in the Loaded event handler of the dialogue itself. That way you simply call ShowDialog and the rest takes care of itself.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top