我目前正在制作一个家庭小程序(主要是因为每次我想告诉我爸爸的事情,我都懒得跑下楼梯。)
至于我的问题:
如果udpclient收到来自对等方的消息,我怎样才能让这段代码调用我的ReceiveText
方法? (注意:只有2个人才能运行这个,并且将两个ip硬编码到其中)
上述问题同时得到了艾哈迈德·伊利亚斯的回答,但是我遇到了他发布的链接中出现的障碍:
邮件正好像这样发送:
sendMe.Connect("192.168.0.121", 60500);
sendBytes = Encoding.ASCII.GetBytes(txtSend.Text);
sendMe.Send(sendBytes, sendBytes.Length);
sendMe.Close();
问题似乎在于接收端,从我从异常中读取的内容,当我尝试实际使用已发送的数据时,它似乎正在发生,因此我可以为我的Rich Text Box正确格式化等
这是接收&的代码。解析传入的数据:
UdpClient sendMe = new UdpClient(60500);
UdpClient illReceive = new UdpClient(60501);
Byte[] sendBytes;
string returnData;
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
...
try
{
illReceive.BeginReceive(new AsyncCallback(RecieveText), null);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
...
void ReceiveText(IAsyncResult res)
{
try
{
System.Reflection.Assembly a = _
System.Reflection.Assembly.GetExecutingAssembly();
System.IO.Stream s = a.GetManifestResourceStream("IPSend.ns.wav");
SoundPlayer player = new SoundPlayer(s);
player.Play();
byte[] received = illReceive.EndReceive(res, ref RemoteIpEndPoint);
returnData = Encoding.UTF8.GetString(received);
TextRange tr = new _
TextRange(rtbPast.Document.ContentEnd, rtbPast.Document.ContentEnd);
tr.Text = String.Format("{0} - Yorrick: {1} {2}", _
DateTime.Now.ToShortTimeString(), returnData, Environment.NewLine);
tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Black);
illReceive.BeginReceive(new AsyncCallback(RecieveText), null);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
PS:我现在正在使用MessageBox.Show,因此我可以清楚地看一下抛出的异常,从我对它的理解,它似乎是{{1方法。
抛出异常: (第1行的翻译:"调用线程无法打开此对象,因为它由另一个线程拥有。")
尝试C.Evenhuis后的新例外'代码(更改为WPF后): 这个例外背后的代码:
ReceiveText
PS:如果您需要查看我的整个代码,我已将其发布在Pastebin上,主要是因为它实际上在此处发布它有点太长了:Entire code on Pastebin < / p>
答案 0 :(得分:2)
导致此问题是因为像ReceiveText
这样的AsyncCallback方法通常运行在与&#34; main&#34;不同的线程中。线。控件只能从创建它们的线程中访问。
要解决此问题,您需要拆分&#34;接收&#34;部分:
void ReceiveText(IAsyncResult res)
{
try
{
byte[] received = illReceive.EndReceive(res, ref RemoteIpEndPoint);
returnData = Encoding.UTF8.GetString(received);
InformUser(returnData);
illReceive.BeginReceive(new AsyncCallback(RecieveText), null);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
来自&#34;显示&#34>部分:
void InformUser(string data)
{
// InvokeRequired tells you you're not on the correct thread to update the rtbPast
if (rtbPast.InvokeRequired)
{
// Call InformUser(data) again, but on the correct thread
rtbPast.Invoke(new Action<string>(InformUser), data);
// We're done for this thread
return;
}
System.Reflection.Assembly a = System.Reflection.Assembly.GetExecutingAssembly();
System.IO.Stream s = a.GetManifestResourceStream("IPSend.ns.wav");
SoundPlayer player = new SoundPlayer(s);
player.Play();
TextRange tr = new TextRange(rtbPast.Document.ContentEnd, rtbPast.Document.ContentEnd);
tr.Text = String.Format("{0} - Yorrick: {1} {2}", DateTime.Now.ToShortTimeString(), data, Environment.NewLine);
tr.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
tr.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Black);
}
答案 1 :(得分:1)
Yorrick,InformUser()中的“检查访问”逻辑被反转。如果当前线程与调度程序关联,CheckAccess()将返回true。只有在CheckAccess()返回false时才应调用Invoke()。当前正在发生的事情是你正在调用InformUser(),CheckAccess()返回false,并且执行会因为你仍在从错误的线程访问控件而导致之前遇到麻烦的相同代码。
你需要的是这个(否定支票):
if (!rtbPast.Dispatcher.CheckAccess()) // Invoke only when CheckAccess returns false
{
// Call InformUser(data) again, but on the correct thread
rtbPast.Dispatcher.Invoke(new Action<string>(InformUser), data);
// We're done for this thread
return;
}