2011-01-21 5 views
1

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: 

업데이트 나는이 STA에 보조 UI 스레드의 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

+0

@VinayC 코드 –

답변

0

메인 스레드에서 처리를 트리거하려면, 예를 들어 ManualResetEvent/AutoResetEvent과 같은 WaitHandle 파생 클래스를 사용할 수 있습니다. 기본적으로 주 스레드는 대기 핸들을 기다리고 양식 스레드는 이벤트가 처리를 시작하도록 신호를 보낼 수 있습니다.

주 스레드에서 UI/양식 스레드로 진행 상황을 전달하기 위해 이벤트 나 대리자를 사용할 수 있습니다. 가장 간단한 방법은 프로세스 업데이트 대리자를 선언하고 일부 폼의 메서드로 인스턴스화하는 것입니다. 그런 다음 주 스레드가 호출 할 수 있습니다.이 스레드는 본질적으로 양식 클래스 내에서 (주 스레드에서) 메소드를 실행합니다. 이 메소드 내에서 양식의 스레드에 대한 호출을 마샬링해야합니다. Invoke 메소드를 사용하십시오.

1

이것은 작동하지 않습니다. 모든 양식은 Windows에서 기본 메시지 펌프를 사용해야하며 원래의 스레드에 있어야합니다.

+1

으로 내 게시물을 업데이트했습니다. 일반적으로 그렇습니다. 그러나 2 차 스레드에서 메시지 펌프를 작성하고 양식을 표시하는 것은 가능합니다. 그런 다음 해당 스레드는 첫 번째 스레드와 독립적으로 이벤트를 처리 할 수 ​​있습니다. 원래 스레드의 양식으로 다시 통신하는 것이 문제입니다. –

0

Invoke 메소드를 사용하여

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

사용 방법을 호출 할.

관련 문제