我有一个控制台应用程序,它在不同的线程中启动表单应用程序(来自另一个类)。
但是,我不想在主线程中从我的主类访问
richTextBox1
组件,这会引发一个错误,表明我正在尝试从另一个线程访问该组件。
我的代码: (表格申请)
public partial class ChatGui : Form
{
public static RichTextBox textBox;
public ChatGui()
{
InitializeComponent();
richTextBox1.ReadOnly = true;
richTextBox1.BackColor = SystemColors.Window;
}
public void WriteLine(string line)
{
richTextBox1.Text += line+"\r\n";
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
WriteLine("[You]: "+textBox1.Text);
NetworkManager.SendPacket("rchat_msg " + textBox1.Text.Replace(" ", "%20"));
textBox1.Text = "";
e.Handled = true;
}
}
public void Exit()
{
Application.Exit();
}
private void ChatGui_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
}
主控制台应用程序
public static void StartRemoteChat()
{
RemoteChat = true;
Program.ChatGui = new ChatGui();
new Thread(new ThreadStart(() =>
{
Application.Run(Program.ChatGui);
while (RemoteChat)
{
// ...
}
})).Start();
}
那么,如何从主线程访问
richTextBox1
组件(我想更改组件的一些变量)而不发生此错误?
控件由创建它的线程拥有。
在您的情况下,您启动的线程拥有该表单,因为它会绘制它,因此它将成为您的表单 ui 线程。
但是,当您尝试使用另一个线程对控件进行更改时,它会像您所说的那样抛出异常。
解决这个问题的方法是调用创建它的线程并进行您想要的更改,如下所示:
richTextBox1.BeginInvoke(new Action(()=>
{
// make changes to control here.
}));
我还建议您阅读一下this,因为我看到人们建议在控件上的 Winforms 应用程序中使用 Invoke 与 BeginInvoke
简短总结:
对于 Windows 窗体应用程序,我建议您通常应该使用 开始调用。这样你就不用担心死锁了
可以帮助您的是“CheckForIllegalCrossThreadCalls = false;”但在这里使用(在开始时):
public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
}
建议是每次调用“RichTextBox1”时都使用invoke 方法。 此方法允许与其他线程创建的元素进行交互。 示例:
richTextBox1.Invoke(new Action(() => richTextBox1.Text = "hello word"));
“CheckForIllegalCrossThreadCalls = false”是一个如果用在复杂的程序中就有足够危险的解决方案。 我希望我有帮助。
简单的调用invoke以从新线程调用该方法:
if (InvokeRequired)
{
Invoke(new Action(**METHODHERE**));
return;
}
并传递参数:
if (InvokeRequired)
{
Invoke(new Action<string>(**METHODHERE**) **parameter**);
return;
}
好读:https://msdn.microsoft.com/en-us/library/ms171728(v=vs.110).aspx
尝试设置以下属性。
RichTextBox.CheckForIllegalCrossThreadCalls=false;
这可能对你有帮助。