首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BackgroundWorker: InvalidOperationException in RunWorkerCompleted

BackgroundWorker: InvalidOperationException in RunWorkerCompleted
EN

Stack Overflow用户
提问于 2014-12-07 15:12:37
回答 6查看 2.1K关注 0票数 6

我有一个WinForm和一个backgroundWorker:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SeoTools.Utils;

namespace SeoTools.UI
{
    public partial class UIProgress : Form
    {
        public UIProgress(DoWorkEventHandler doWorkEventHandler, RunWorkerCompletedEventHandler runWorkerCompletedEventHandler)
        {
            InitializeComponent();
            this.backgroundWorker.WorkerReportsProgress = true;
            this.backgroundWorker.WorkerSupportsCancellation = true;
            this.backgroundWorker.DoWork += doWorkEventHandler;
            this.backgroundWorker.RunWorkerCompleted += runWorkerCompletedEventHandler;
        }

        public void Start()
        {
            var foo = SynchronizationContext.Current;
            backgroundWorker.RunWorkerAsync();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            btnStop.Enabled = false;
            btnStop.Text = "Stopping...";
            backgroundWorker.CancelAsync(); 
        }

       private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        try
        {
            wdgProgressBar.Value = e.ProgressPercentage;
            if (this.Visible == false)
            {
                this.ShowDialog();
                this.Update();
            }
        }
        catch (InvalidOperationException) {} 
    }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Hide(); //Here I get a InvalidOperationException
            this.Dispose();
        }    
    }
}

我第一次运行这个很好。但是当我第二次打电话给InvalidOperationException时,我得到了this.Hide()

“附加信息:跨线程操作无效:从创建线程的线程以外的线程访问控件'UIProgress‘。”

奇怪的是,在第一次运行foo时,Start()是一个WindowsFormsSyncronizationContext,但是在第二次尝试中,它是一个System.Threading.SyncronizationContext.

我正在编写的应用程序是一个ExcelDna插件。

编辑

Start()的调用如下:

代码语言:javascript
复制
 UIProgress uiProgress = new UIProgress(
                delegate(object sender, DoWorkEventArgs args)
                {
                   ....
                },
                delegate(object sender, RunWorkerCompletedEventArgs args)
                    {
                       ...
                    }
            );
            uiProgress.Start();
EN

回答 6

Stack Overflow用户

发布于 2014-12-07 15:39:08

必须从运行在UI线程上的代码中调用Start()方法,以允许BackgroundWorker正确操作。不是当你得到这个例外的时候。将保护代码添加到您的方法中,以便您可以诊断此事故:

代码语言:javascript
复制
    public void Start()
    {
        if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
            throw new InvalidOperationException("Bug! Code called from a worker thread");
        }
        backgroundWorker.RunWorkerAsync();
    }

现在,您可以在抛出语句上设置一个断点,并使用调试器的Call Stack窗口来找出发生这种情况的原因。

票数 7
EN

Stack Overflow用户

发布于 2014-12-15 10:58:17

您正在调用后台线程上的UI操作。这就是这种例外的原因。我会使用完全不同的方法来完成进度,最好的方法是在IProgress中使用任务。另一种使用方式是:

代码语言:javascript
复制
private void backgroundWorker_ProgressChanged( object sender , ProgressChangedEventArgs e )
    {

      this.UpdateOnMainThread(
        ( ) =>
        {
          wdgProgressBar.Value = e.ProgressPercentage;
          if ( this.Visible == false )
          {
            this.ShowDialog( );
            this.Update( );
          }
        } );
    }

    private void UpdateOnMainThread( Action action )
    {
      if ( this.InvokeRequired )
      {
        this.BeginInvoke( ( MethodInvoker ) action.Invoke);
      }
      else
      {
        action.Invoke( );
      }
    }

    private void backgroundWorker_RunWorkerCompleted( object sender , RunWorkerCompletedEventArgs e )
    {
      this.UpdateOnMainThread(
        ( ) =>
        {
          this.Hide( ); //Here I get a InvalidOperationException
          this.Dispose( );
        } );

    }
票数 3
EN

Stack Overflow用户

发布于 2014-12-11 03:00:46

在表单上使用BeginInvoke()方法:

//http://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx

代码语言:javascript
复制
    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.BeginInvoke(new InvokeDelegate(InvokeMethod));               
    }

    public delegate void InvokeDelegate();

    public void InvokeMethod()
    {
        this.Hide(); 
        this.Dispose();
    }
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27344054

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档