此问题在此处已有答案:
How do I update the GUI from another thread?(47个答案)
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on(22个答案)
去年关闭了。
我不知道如何让C# Windows Form应用程序从执行绪写入文字方块。例如,在Program.cs中,我们有绘制表单的标准main():
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
然后在Form1.cs中有:
public Form1()
{
InitializeComponent();
new Thread(SampleFunction).Start();
}
public static void SampleFunction()
{
while(true)
WindowsFormsApplication1.Form1.ActiveForm.Text += "hi. ";
}
我是不是完全错了?
更新
下面是bendewey提供的工作代码示例:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(SampleFunction).Start();
}
public void AppendTextBox(string value)
{
if (InvokeRequired)
{
this.Invoke(new Action<string>(AppendTextBox), new object[] {value});
return;
}
textBox1.Text += value;
}
void SampleFunction()
{
// Gets executed on a seperate thread and
// doesn't block the UI while sleeping
for(int i = 0; i<5; i++)
{
AppendTextBox("hi. ");
Thread.Sleep(1000);
}
}
}
8条答案
按热度按时间2cmtqfgy1#
在MainForm上创建一个函数来设置文本框,该文本框将检查InvokeRequired
虽然在静态方法中不能只调用。
您必须在某处具有对Form1的静态引用,但实际上并不建议或没有必要这样做,您是否可以将SampleFunction设置为非静态的?如果是这样,则可以直接调用
它将追加到不同的线程上,并在需要时使用Invoke调用将其封送到UI。
完整样品
7vhp5slm2#
我会尽可能经常地使用
BeginInvoke
而不是Invoke
,除非您确实需要等到控件更新后再使用BeginInvoke
将委托发布到WinForms消息队列上,并让调用代码立即继续执行Invoke
不仅发送委托,而且等待委托完成。因此,在示例中的
AppendTextBox
方法中,您可以将Invoke
替换为BeginInvoke
,如下所示:如果您想获得更丰富的内容,还可以使用
SynchronizationContext
类,它可以让您执行与Control.Invoke/Control.BeginInvoke
基本相同的操作,但其优点是不需要知道WinForms控件引用。Here是SynchronizationContext
的一个小教程。ukqbszuj3#
或者你可以这样做
pvcm50d14#
非常简单,无需担心委派和操作:
InvokeRequired检查代码是在UI线程上运行还是在其他线程上运行。只允许UI线程执行UI操作(如更改控件的内容)。如果代码不在UI线程上运行,则Invoke会将操作临时传递给UI线程。
这可能会降低性能并减少多线程的好处。在这种情况下,可以使用带有事件的队列。后台线程将更改放在队列中并继续。UI更改在事件中异步执行。
3zwtqj6y5#
您需要从拥有控件的执行绪执行动作。
这就是我如何在不增加过多代码噪音的情况下实现的:
其中Invoke重载是Lokad Shared Libraries的简单扩展:
xxhby3vn6#
看一下Control.BeginInvoke方法。要点是永远不要从另一个线程更新UI控件。BeginInvoke会将调用调度到控件的UI线程(在您的示例中是Form)。
要获取表单,请从示例函数中删除static修饰符,并使用this.BeginInvoke(),如MSDN中的示例所示。
myzjeezk7#
更简单的方法是使用BackgroundWorker控件...
vql8enpb8#
下面是我为避免
CrossThreadException
和从另一个线程写入文本框所做的工作。下面是我的
Button.Click
函数-我想生成一个随机数的线程,然后通过在该工作线程中调用getID()
方法和TextBox值来获取它们的IDs
。下面是
getId
(工作线程)代码: