【问题标题】:Having trouble creating a form on a second thread在第二个线程上创建表单时遇到问题
【发布时间】:2011-01-21 04:01:05
【问题描述】:

我正在通过 C#.NET 为另一个应用程序编写插件。我的插件必须执行的一些过程相当耗时,所以我想利用多个线程,这样我就可以向用户显示当前任务的进度条,而不是整个事情只是挂起。

通常情况下,这样的 UI 会在主线程中创建,并且会创建辅助线程来完成工作,例如通过 BackGroundWorker 类。但是,在我的情况下,工作必须在主线程中完成,因为我正在为其编写插件的应用程序对线程不满意,而不是它为插件创建的线程-在访问它。

因此,我创建了第二个线程以在(WinForms 表单)中创建我的 UI,然后与主线程通信以执行任何实际工作。

我可以在主线程中创建我的表单,但是当我尝试在第二个线程中实例化我的表单时,我得到了一个 InvalidOperationException。这发生在表单的设计器文件中,其中设置了列表视图中列的名称属性。

这里是异常的详细信息。

System.InvalidOperationException was caught
  Message=ColumnInfo cannot be set.
  Source=System.Windows.Forms
  StackTrace:
       at System.Windows.Forms.ListView.SetColumnInfo(Int32 mask, ColumnHeader ch)
       at System.Windows.Forms.ColumnHeader.set_Text(String value)
       at QA.Revit.RevitQAForm.InitializeComponent() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitQAForm.Designer.cs:line 758
       at QA.Revit.RevitQAForm..ctor() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitQAForm.cs:line 34
       at QA.Revit.RevitQAToolApp.FormMethod() in C:\Documents and Settings\eric.anastas\My Documents\_SVN WC\QA Tool\RevitModelCheckerPlugIn\RevitModelCheckerCmd.cs:line 99
  InnerException: 

更新

我现在似乎已经通过将辅助 UI 线程的 ApartmentState 更改为 STA 来完成这项工作。虽然我对这种多线程的东西完全陌生,不知道 ApartmentState 或 STA 是什么意思。

这是我的代码。

//property used to store a reference to the form
internal RevitQAForm RevitQAForm { get; set; }

//monitor object that when pulsed shows the form
public static readonly Object showFormLock = new object(); 


//this method is called by the parent app when it starts
public Autodesk.Revit.UI.Result OnStartup(Autodesk.Revit.UI.UIControlledApplication application)
{
    //this creates the form UI Thread
    _formThread = new System.Threading.Thread(new System.Threading.ThreadStart(FormMethod));
    _formThread.Name = "Form Thread";
    _formThread.SetApartmentState(System.Threading.ApartmentState.STA);
    _formThread.Start();

    //returns that the plug-in startup succeeded
    return Autodesk.Revit.UI.Result.Succeeded;
}

//the method is started on the second thread
private void FormMethod()
{
    try
    {
        //creates the form
        RevitQAForm = new RevitQAForm();

        lock (showFormLock)
        {
            while (true)
            { 
                //waits for a pulse
                System.Threading.Monitor.Wait(showFormLock);
                RevitQAForm.ShowDialog();
            }
        }
    }
    catch (System.Threading.ThreadAbortException)
    {
        //disposes the form if the thread is aborted
        RevitQAForm.Dispose();
    }
}

//this is called when the user request the form be shown
public void ShowForm()
{
    lock (showFormLock)
    {
        System.Threading.Monitor.Pulse(showFormLock);
    }
}

//this is called when the program closes
public Autodesk.Revit.UI.Result OnShutdown(Autodesk.Revit.UI.UIControlledApplication application)
{
    //aborts the form thread
    formThread.Abort();
    return Autodesk.Revit.UI.Result.Succeeded;
}

就像我说的,这似乎现在有效。我可以使用我的插件启动应用程序并重复显示表单。当我关闭程序时,表单也会被释放。

但现在我正试图弄清楚这个表单如何与主线程进行通信。表单需要能够触发主线程开始处理,然后主线程需要能够定期向表单线程报告其进度。在任何时候,表单线程都应该能够告诉主线程取消处理。最后,主线程需要在处理完成时通知表单。

有人对我如何做到这一点有任何提示吗?

【问题讨论】:

  • 为了完整起见,你能分享创建表单并启动它的代码吗?
  • @VinayC 我用代码更新了我的帖子

标签: c# .net winforms multithreading


【解决方案1】:

这行不通。所有表单都需要使用 Windows 中的底层消息泵,并且它们需要位于原始线程上。

【讨论】:

  • 一般来说是的。但是当然可以在辅助线程上创建一个消息泵并显示一个表单。然后,该线程可以独立于第一个线程处理事件。与原始线程中的表单进行通信是问题所在。
【解决方案2】:

要触发主线程中的处理,您可以使用任何 WaitHandle 派生类,例如 ManualResetEvent/AutoResetEvent - 本质上,主线程将等待等待句柄,并且表单线程可以发出事件开始处理的信号.

为了将进度从主线程传递回您的 UI/Form 线程,您可以使用事件或委托。最简单的方法是声明流程更新委托,用某种形式的方法实例化它。然后主线程可以调用它 - 这实际上将在您的表单类中运行该方法(在主线程上)。在此方法中,您必须使用表单的Invoke 方法编组对表单线程的调用。

【讨论】:

    【解决方案3】:

    尝试调用方法,该方法使用

    System.Windows.Forms.ListView.SetColumnInfo(Int32 mask, ColumnHeader ch)
    

    通过使用方法Invoke

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 2013-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多