2010-10-31 45 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的方式进行操作,但还有其他方法可以更好地满足您的特定需求。