2014-01-18 83 views
3

我有一個多線程應用程序,其中每個線程都有能力通過使用包含guiUpdateObjects的共享(和線程安全的)BlockingCollection來記錄未決的GUI更新。基於BlockingCollection更改的更新表

每個guiUpdateObject都包含有關要更新哪個控件和要顯示的內容的信息。我希望我的表單消耗該BlockingCollection上存在的任何項目並相應地更新各種控件。

這個設置對我以前在這個應用程序的Java版本中很有效,在這個版本中,在產生線程和執行初始化任務之後,主線程檢查定時循環上的項目。

我想我可以在C#中使用計時器事件做同樣的事情,但在Windows窗體中給出所有本機事件處理時,我想知道是否有更好的方法。也許,用自定義事件?希望對我目前的做法提出任何批評和/或建議如何最好地在C#中實現這一點。

更新基於漢斯建議:

上Control.BeginInvoke()讀取後,我明白,這將讓我PostMessage的到應用程序的消息隊列。這與我對BlockingCollection的使用類似,因爲它是線程安全的並立即返回而不等待消息被處理。

然而,利用BeginInvoke需要使用委託,並在讀完它們之後,我仍然對正確的實現感到困惑。我是否會在我的Form類或'worker'類中聲明委託,以便爲gui更新生成內容?如果我在Form類中聲明,除非我引用Form對象,否則該方法對我的工作者類將不可見。或者,如果我在工人類中聲明,Form類如何使委託方法和實際方法之間存在關聯?下面是一些代碼高亮我的問題:

public partial class GUI : Form 
{ 

    public GUI() 
    { 
     InitializeComponent(); 

     Thread workerThread = new Thread(new ThreadStart(new Worker().DoWork)); 
     workerThread.Start(); 
    } 

    private delegate void AppendSysLogDelegate(string logEntry); 
    private void AppendSysLog(string logEntry) 
    { 
     if (this.InvokeRequired) 
     { 
      this.BeginInvoke(new AppendSysLogDelegate(AppendSysLog), new object[] { logEntry }); 
      return; 
     } 
     systemLogger.AppendText(logEntry); 
    } 
} 

public class Worker 
{ 
    public void DoWork() 
    { 
    //what goes here to call AppendSysLog("Test log entry"); 
    } 
} 
+0

IMO,沒有這樣的事情作爲「C#窗體」。 –

+4

您重新發明了Control.BeginInvoke()維護的調用隊列。是的,它後面有一個事件確保這個隊列被清空,它在內部。只需使用BeginInvoke()。在任何關於Winforms編程的介紹性文章或書籍中閱讀更多關於它的內容。 –

+0

@HansPassant謝謝 - 在這裏有一個很好的BeginInvoke教程:http://www.codeproject.com/Articles/10311/What-s-up-with-BeginInvoke。我更新了一些關於BeginInvoke和delegates的後續問題的原始問題。 – cstack22

回答

0

檢查這個問題,並記出色的答案:

Is there anything like asynchronous BlockingCollection<T>?

現在你已經裝備了的blockingCollection.TakeAsync()等效的,你可以await其結果在UI線程上,例如:

async void btnTest_Click(object s, EventArgs e) 
{ 
    // don't forget to add exception handling 
    while(true) 
    { 
     var result = await blockingCollection.TakeAsync(); 
     this.textBox.AppendText(result.ToString()); 
    } 
}