2011-01-21 52 views
1

我正在通過C#.NET爲另一個應用程序編寫插件。我的插件必須執行的某些流程相當耗時,所以我想利用多個線程,以便向用戶顯示進度條,說明當前任務的進度情況,而不是整個事件的懸掛情況。無法在第二個線程上創建表單

通常在主線程中會創建類似於此的UI,並且會創建輔助線程來完成工作,例如通過BackGroundWorker類。但是,在我的情況下,工作必須在主線程中完成,因爲我正在編寫插件的應用程序對於其他線程不滿意,因爲它爲創建的插件創建的線程無法訪問它。

因此,我正在創建第二個線程來創建我的UI(WinForms表單),然後與主線程進行通信以完成任何實際工作。

我可以在主線程中創建我的表單,但是當我嘗試在第二個線程中實例化表單時,我得到一個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線程STA的工作的ApartmentState。儘管我對這個多線程的東西一無所知,但不知道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; 
} 

就像我說的這似乎現在工作。我可以用我的插件啓動應用程序並重復顯示錶單。當我關閉程序時,表格也會被處理。

然而,現在我想弄清楚這個表單可以如何傳遞迴主線程。表單將需要能夠觸發主線程開始處理,然後主線程需要能夠定期向進程返回表單線程。在任何時候,表單線程應該能夠告訴主線程取消處理。最後,當處理完成時,主線程需要通知表單。

任何人都有關於如何做到這一點的提示?

+1

爲了完整起見,您可以分享創建表單並啓動它的代碼嗎? – VinayC 2011-01-21 04:07:11

+0

@VinayC我更新了我的帖子,代碼爲 – 2011-01-21 05:00:29

回答

0

要觸發主線程中的處理,可以使用任何WaitHandle派生類,如ManualResetEvent/AutoResetEvent - 本質上,主線程將等待等待句柄,並且表單線程可以發信號通知事件開始處理。

爲了將進度從主線程傳回到您的UI /表單線程,您可以使用事件或委託。最簡單的方法是聲明進程更新委託,用某種形式的方法實例化它。然後主線程可以調用它 - 這將基本上在窗體類(主線程)中運行該方法。在此方法中,您必須使用Invoke方法將表單調用到表單的線程。

1

這是行不通的。所有表單都需要在Windows中使用基礎消息泵,並且需要使用原始線程。

0

嘗試呼叫的方法,其通過使用方法Invoke使用

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