如何修复我的后台解决方案以进行线程安全调用
本文关键字:线程 安全 调用 何修复 我的 后台 解决方案 | 更新日期: 2023-09-27 18:19:31
我试图从另一个线程设置TextBox的Text属性。我在下面得到了这个例外;
"Cross-thread operation not valid: Control 'recTpcTxt' accessed from a thread other than the thread it was created on."
然后,我使用BackgroundWorker来解决这个问题。然而,我遇到了同样的异常信息。
编辑[1]:其实,这个环节我自己带导游;https://msdn.microsoft.com/en-us/library/ms171728(v=vs.110).aspx。我可以通过使用invokeproperty来解决我的问题。然而,我无法解决我与后台工作人员的问题
我的解决方案有问题吗?如何修复解决方案以设置UI变量的某些属性?
编辑[2]:澄清问题的更多代码
MqttManager.cs;
public partial class MqttManager : Form
{
MqttHandler mqttHandler = new MqttHandler();
public static MqttManager managerInst;
public MqttManager()
{
InitializeComponent();
managerInst = this;
...
}
...
private BackgroundWorker backgroundWorker;
public void NotifyUIForRecMsg(string topic, string message)
{
object[] objArr = { topic, message };
this.backgroundWorker.RunWorkerAsync(objArr);
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
e.Result = e.Argument;
}
private void backgroundWorker_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
object[] res = (object[])e.Result;
this.recTpcTxt.Text = (String)res[0];
}
}
MqttManager.Design.cs;
partial class MqttManager
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
...
this.backgroundWorker = new System.ComponentModel.BackgroundWorker();
this.backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker_DoWork);
this.backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker_RunWorkerCompleted);
}
#endregion
...
}
MqttHandler.cs;
class MqttHandler
{
MqttClient client;
...
/// <summary>
/// Publish received event handler.
/// </summary>
private void client_MqttMsgPublishReceived(Object sender, MqttMsgPublishEventArgs e)
{
MqttManager.managerInst.NotifyUIForRecMsg(e.Topic, Encoding.UTF8.GetString(e.Message));
}
}
检查以下内容:https://msdn.microsoft.com/en-us/library/ms171728(v=vs.110).aspx
基本上,要设置控件属性,您必须在同一个UI线程中。
这个简单的解决方案将调用转移到UI线程中的textbox1.Text = someText
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
此外,您可以使用textBox1.BeginInvoke
而不是Invoke
:它将在UI线程中运行,而无需锁定调用方线程等待SetText
委托完成
[编辑]在你的后台工作人员:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
object[] arg = (object[])e.Argument;
SetTextToTextBox(recTpcTxt, (string)arg[0]);
SetTextToTextBox(recMsgTxt, (string)arg[1]);
}
private void SetTextToTextBox(TextBox toSet, string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (toSet.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
toSet.Invoke(d, new object[] { text });
}
else
{
toSet.Text = text;
}
}
[编辑2]正确使用后台工作人员
注册事件DoWork
和RunWorkerCompleted
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
在退出backgroundWorker1_DoWork
之前,设置eventArgs的结果属性,并在backgroundWorker1_RunWorkerCompleted
中读取它们
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.Threading.Thread.Sleep(5000);
e.Result = new string[] { "one", "two" };
}
private void backgroundWorker1_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
string[] res = (string[])e.Result;
this.textBox1.Text = res[0];
}