[英]C# Multithread multiclass gui app, am I doing this right?
我创建了以下项目,向大家展示我打算如何做事。 但是我的主要项目将更大,并且将有多个班级。 我只是想让它正常工作,所以我知道我在编码时正在使用良好的做法。
好的,让我们开始:),所以我的表单有一个名为“ button1”的按钮和一个名为“ textBox1”的文本框,并且我有一个名为“ Class1”的类,其中有一个方法为“ testtest()”,我只是将Thread.Sleep在testtest方法中,这样我就可以发现它在另一个线程上运行。
这是我的表格代码
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类对我不可用。
最好的祝福
我不认为您实际上是在开始一个新线程。 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
}
首先,如果您愿意,可以使用ThreadPool类进行线程化。 我通常用它来触发新线程,例如,
ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
该链接进一步说明了它们。 对于GUI,您需要检查当前线程是否与UI线程相同(因为只有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函数。
阿里亚
使用您的方法(异步委托),您没有启动新线程,而是使用了.net线程池中的线程,该线程将在您完成工作时释放。 调用委托并在完成后被回调的正确方法如下:
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();
但是,通过回调发回调用线程的信号将变得冗长,因为您必须自己编写此代码。
关于Dispatcher,这是一个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;
}
根据您要完成的工作,可以采取几种不同的方法。 如果您要执行单个任务而又不阻塞UI线程,则可以使用BackgroundWorker 。 这将为您提供一种非常简单的方式来保持UI活泼,并使UI更新变得容易,而无需调用等。
如果要执行很多任务,则可能应该使用ThreadPool 。 如果您需要为线程分配优先级,否则它们将花费大量时间进行阻塞,那么您应该创建自己的实例线程。
您当然可以继续使用ThreadPool来做您自己的事情,但是还有其他一些方法可能会更好地满足您的特定需求。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.