2010-10-31 44 views
2

我創建了以下項目,向您展示我打算如何做事。但是我的主要項目會更大,並且會有多個班級。我只是想讓這個工作正常,所以我知道我在編碼時使用了很好的做法。所以我的表單有一個名爲「button1」的按鈕和一個名爲「textBox1」的文本框,我有一個名爲「Class1」的類,它有一個方法「testtest()」,我只是將Thread.Sleep放在testtest方法中,以便我可以找到它在另一個線程上運行。C#多線程多類gui應用程序,我正在做對嗎?

這裏是我的表單代碼

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace Test 
{ 
    public partial class Form1 : Form 
    { 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    delegate void Class1Deligate(); 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Class1 c = new Class1(); 
     Class1Deligate testMethod = new Class1Deligate(c.testtest); 
     testMethod.BeginInvoke(endTestMethod, testMethod); 
    } 

    void endTestMethod(IAsyncResult ar) 
    { 

    } 
    } 
} 

,這裏是我的一個類代碼

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Windows.Forms; 

namespace Test 
{ 
    class Class1 
    { 
    public void testtest() 
    { 
     Thread.Sleep(8888); 
     MessageBox.Show("Done"); 
    } 
    } 
} 

我是否正確地創建一個新線程?有人可以告訴我如何從class1中的testtest方法在運行時更新textbox1嗎?我做了一個早期的文章,並被告知使用Dispatcher,但出於某種原因,似乎Dispatcher類不適用於我。

問候

回答

1

我不認爲你實際上是開始一個新的線程delegate.BeginInvoke可能使用內部ThreadPool來執行它的出價。作爲一個方面說明,我認爲你不應該在沒有合適的EndInvoke呼叫之後撥打BeginInvoke(否則從BeginInvoke呼叫返回的IAsyncResult的引用將不會被釋放)。

如果你想要一個新的線程,你可以使用Thread類創建一個新線程。

Thread t = new Thread(c.testtest); 
t.IsBackground = true; // end if main thread ends 
t.Start(); 

請注意,如果您使用上面的Thread類並使用GUI,則需要將方法附加到GUI線程以更新它。你可以這樣做,使用Control.Invoke呼叫

public void updateGUI(object state) { 
    if (control.InvokeRequired) { 
     control.Invoke(new Action<object>(updateGUI), state); 
     return; 
    } 
    // if we are here, we can safely update the GUI 
} 
+0

我不確定我是否需要一個新線程,因爲在某些示例中,我看到使用了Thread類,而在另一些示例中我看到使用了BeginInvoke,所以它真的讓我困惑。 – Arya 2010-10-31 03:50:23

+0

@Arya:那麼一些開始一個新的線程,一些使用backgroundworker,一些使用ThreadPool。您需要確定在您使用它時最適合的方式。所有的方法都有其優點和缺點。 – Patrick 2010-10-31 11:09:57

0

首先,有ThreadPool類可如果你喜歡穿。這是我通常用來消滅新線程,例如,

ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i); 

鏈接解釋了更多關於它們的信息。至於GUI,你需要檢查當前線程是否與UI線程相同(因爲只有UI線程才能更新UI),如果不是,則調用UI線程。這是可以做到像這樣,

delegate void ChangeFormUnsafeCallback(string text); 
private void ChangeFormUnsafe(string text) 
{ 
    // Do stuff to form/controls 
} 

private void SomeFunction() 
{  
    myForm.Invoke(new ChangeFormUnsafeCallback(ChangeFormUnsafe), "foo"); 
} 

你可以做一個檢查,看是否需要進行調用,但它通常是非常直截了當知道是否該函數將在UI線程中使用或不併適當調用。作爲一般的經驗法則,除非你的函數是由於表單發生的事情而運行的(例如,被點擊的按鈕),你將需要使用Invoke函數。

+0

您知道您是否需要通過檢查「InvokeRequired」來使用Invoke ...並且您不需要*聲明新的代理,您可以使用'Action '。 – Patrick 2010-10-31 11:06:33

+0

@Patrick是的我知道你可以用InvokeRequired進行檢查,我只是說99%的時間需要調用,因爲只有UI觸發的事件纔會在UI線程上運行。 – mike 2010-10-31 23:00:04

0

阿里亞

用你的方法(異步委託),你是不是開始一個新的線程,但使用的是從.NET線程池,當你的工作就完成了,這將釋放一個線程。正確的方法來調用委託,並如下完成時calledback是:

void button1_Click(object sender, EventArgs e) 
    { 
     Class1 c = new Class1(); 
     Action action = c.Test; 

     action.BeginInvoke(new AsyncCallback(EndTestMethod), null); 
    } 
    void EndTestMethod(IAsyncResult token) 
    {  
     Action callBack = (Action)((AsyncResult)token).AsyncDelegate; 
     callBack.EndInvoke(token); 
    } 

,如果你的方法相當短暫的異步委託的方法是有用的,你需要一個回調。否則,對於長時間運行的進程,您可能需要創建並啓動一個新線程。

Thread t = new Thread(c.Test); 
     t.IsBackground = true; 
     t.Start(); 

但是,通過回調信號回到調用線程將變得更加冗長,因爲您將不得不親自編寫此代碼。

關於分派器,這是一個WPF類,該類將隊列中的行爲由WPF應用程序中的UI線程處理(等等)。從你的代碼看起來你正在編寫一個Winforms應用程序,所以這種類型是不合適的。

最後,爲了更新文本框,您需要檢查您是否嘗試在創建控件(UI線程)的同一線程上訪問該控件。這是通過control.invokerequired和control.invoke完成的。如下:

 void AddText(string text) 
    { 
     if (textBox1.InvokeRequired) 
     { 
      textBox1.Invoke((Action<string>)AddText, text); 
     } 
     textBox1.Text = text; 
    } 
0

根據你想要完成的事情,有幾個different你可以去的方法。如果您希望執行單個任務而不阻塞UI線程,則可以使用BackgroundWorker。這將讓你有一個非常簡單的方法來保持你的用戶界面清晰,並且它使得更新用戶界面很容易,而不需要Invoke等。

如果你要解僱很多任務,你應該使用ThreadPool。如果您需要爲線程分配優先級,或者他們將花費大量時間阻塞,那麼您應該創建自己的實例線程。

您當然可以繼續按照您使用ThreadPool的方式進行操作,但還有其他方法可以更好地滿足您的特定需求。