【发布时间】: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