我正在使用C#.net 4.0 VS 2010。
我得到了一个表单中的代码,它基本上在表单加载时添加了一个Task,以便运行UDP侦听器(在无限循环上)。每当Listener从UDP套接字获取内容时,我都会在multiline-textbox(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());
}
}
....
答案 0 :(得分:1)
UI控件只能由创建它们的线程更改。您需要检查InvokeRequired
(WinForms)或Dispatcher.CheckAccess()
(WPF),然后调用Invoke
/ {{1 }}
答案 1 :(得分:0)
通常在使用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");
答案 2 :(得分:0)
您可以尝试更改异步功能以使用当前的同步上下文
return Task.Factory.StartNew<int>(() =>
{
if (WhatToDo == "OpenYourEars")
goListening();
return 1;
},
new CancellationToken(),
TaskCreationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext());