从在C#中运行循环UDP侦听的独立线程更新多文本框
本文关键字:线程 独立 更新 文本 运行 循环 UDP 从在 | 更新日期: 2023-09-27 18:22:23
我使用的是C#.net 4.0 VS 2010。
我得到了一个表单中的代码,它基本上在表单加载时添加了一个Task,以便运行UDP侦听器(在无限循环中)。每当监听器从UDP套接字中得到一些东西时,我都会在多行文本框(this.textBox4.Text)中添加一行和消息
然而,我得到了一个异常,说"跨线程操作无效:"Contol‘textBox4’是从创建它的线程以外的线程访问的
我不想仅仅为了传递值而结束循环。有办法做到这一点吗?这是我的代码:
//main form load menu
private void frm_Menu_Load(object sender, EventArgs e)
{
Task<int> Listening = DoWorkAsync(1, "OpenYourEars");
.... // more code here
}
//async function
public Task<int> DoWorkAsync(int milliseconds, string WhatToDo)
{
return Task.Factory.StartNew<int>(() =>
{
if (WhatToDo == "OpenYourEars")
goListening();
... // more codes here
return 1;
});
}
//Listening on UDP socket
public void goListening()
{
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
string received_data;
byte[] receive_byte_array;
try
{
while (!done)
{
receive_byte_array = listener.Receive(ref groupEP);
received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
// display on TextBox4
this.textBox4.Text = "a'r'nb";
this.textBox4.Text = received_data.ToString().Trim();
}
}
catch (Exception e)
{
//gives "Contol 'textBox4' accessed from a thread other than
//the thread it was created on." when receiving a message.
MessageBox.Show(e.ToString());
}
listener.Close();
}
版本2-在@cremor和@George87的回答之后
private void frm_Menu_Load(object sender, EventArgs e)
{
MyValue = "Menu,7";
Task<int> Listening = DoWorkAsync(1, "OpenYourEars");
.... // more code here
}
private Task<int> DoWorkAsync(int milliseconds, string WhatToDo)
{
return Task.Factory.StartNew<int>(() =>
{
if (WhatToDo == "OpenYourEars")
goListening();
.... // more codes here
return 1;
});
}
//Listening
private void goListening()
{
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
string received_data;
byte[] receive_byte_array;
try
{
while (!done)
{
receive_byte_array = listener.Receive(ref groupEP);
received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
string aa = received_data.ToString().Trim();
if ( aa != "")
{
SetText("a'r'nb");
SetText(received_data.ToString().Trim());
aa = "";
}
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
listener.Close();
}
private delegate void SetTextCallback(string text);
private void SetText(string text)
{
try
{
if (this.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.BeginInvoke(d, new object[] { text });
}
else
{
SetText(text);
}
this.textBox4.Text = text;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
....
UI控件只能由创建它们的线程更改。您需要检查InvokeRequired
(WinForms)或Dispatcher.CheckAccess()
(WPF),然后调用Invoke
/BeginInvoke
。
通常在使用c#和使用多线程时,应该使用委托来使事情正常工作,而不违反跨线程政治。换句话说,不允许从其他线程使用在一个线程中定义的对象。要实现这一点,您应该使用委托来强制拥有线程为调用线程执行任务。
代替:
// display on TextBox4
this.textBox4.Text = "a'r'nb";
你可以使用这个:定义以下方法:
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (this.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
SetText(text);
}
this.textBox1.Text = text;
}
并像这个一样从头开始呼叫他们
SetText("a'r'nb");
您可以尝试更改异步函数以使用当前同步上下文
return Task.Factory.StartNew<int>(() =>
{
if (WhatToDo == "OpenYourEars")
goListening();
return 1;
},
new CancellationToken(),
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());