2010-12-01 37 views
4

我有一個使用包含線程的類的窗體的C#2.0應用程序。從線程調用Invoke/BeginInvoke

在線程函數中,不是直接調用事件處理函數,而是調用它。其效果是擁有窗體不需要調用InvokeRequired/BeginInvoke來更新其控件。

public class Foo 
{ 
    private Control owner_; 
    Thread thread_; 

    public event EventHandler<EventArgs> FooEvent; 

    public Foo(Control owner) 
    { 
     owner_ = owner; 
     thread_ = new Thread(FooThread); 
     thread_.Start(); 
    } 

    private void FooThread() 
    { 
     Thread.Sleep(1000); 
     for (;;) 
     { 
      // Invoke performed in the thread 
      owner_.Invoke((EventHandler<EventArgs>)InternalFooEvent, 
       new object[] { this, new EventArgs() }); 
      Thread.Sleep(10); 
     } 
    } 

    private void InternalFooEvent(object sender, EventArgs e) 
    { 
     EventHandler<EventArgs> evt = FooEvent; 
     if (evt != null) 
      evt(sender, e); 
    } 
} 

public partial class Form1 : Form 
{ 
    private Foo foo_; 

    public Form1() 
    { 
     InitializeComponent(); 

     foo_ = new Foo(this); 
     foo_.FooEvent += OnFooEvent; 
    } 

    private void OnFooEvent(object sender, EventArgs e) 
    { 
     // does not need to call InvokeRequired/BeginInvoke() 
     label_.Text = "hello"; 
    } 
} 

這顯然是違背了使用後臺線程像System.Timers.Timer和System.Io.Ports.SerialPort微軟的API使用的方法。這種方法有什麼內在的錯誤嗎?某種方式危險嗎?

感謝, PaulH


編輯:另外,如果表單沒有訂閱什麼事件,對嗎?它會阻塞表單的消息隊列中的表單不感興趣的事件嗎?

+0

請看我的編輯 – Falcon 2010-12-01 18:35:19

回答

3

這是一個線程安全調用,該方法將在窗體的線程中處理。

從概念的角度來看它沒什麼不妥。

儘管如此,定時器對於這樣的任務更加優雅。但是,間隔10ms的定時器可能會減慢GUI的速度,這可能是Invoke被使用的原因。

您不需要調用InvokeRequired,因爲很明顯控件位於另一個線程中。另外,當你想異步調用一個方法時,只需要調用BeginInvoke,這顯然不是這種情況。

關於您的編輯: 不,消息隊列不會被堵塞。如果沒有註冊處理程序,則不會觸發任何事件。再看看你的代碼;)