如何从其他类线程调用UI方法?UDP监听线程传参问题
问题解决:UDP监听线程传递数据到UI方法
我的UDP监听类线程运行正常,但不知道如何把recData字符串传递给UI方法UpdateCommand?我已经在UpdateCommand里用了Dispatcher,但不知道怎么在ListenForUDPPackages()里调用这个方法,试了好几种调用方式都不行,求帮忙。
namespace SoftEKA { public delegate void OnDataReceivedHandler(string newData); public class UDPListener { private int portToListen = 5001; private volatile bool listening; Thread UDPListeningThread; public string recData; public event OnDataReceivedHandler DataReceived; // constructor public UDPListener() { this.listening = false; } // starts the UDPListener-Thread public void StartListener(int exceptedMessageLength) { if (!this.listening) { UDPListeningThread = new Thread(ListenForUDPPackages); this.listening = true; UDPListeningThread.Start(); } } // stops the UDPListener-Thread public void StopListener() { this.listening = false; } // receives incoming UDP-Messages public void ListenForUDPPackages() { UdpClient listener = null; try { listener = new UdpClient(portToListen); } catch (SocketException) { //do nothing } if (listener != null) { { IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, portToListen); //MainWindow MW = new MainWindow(); try { while (true) { // received message as array of byte byte[] data = listener.Receive(ref groupEP); Console.WriteLine($"Received broadcast from {groupEP} :"); Console.WriteLine($"{Encoding.ASCII.GetString(data, 0, data.Length)}"); recData = Encoding.ASCII.GetString(data, 0, data.Length); MessageBox.Show(recData); ------> here!! Calling the UI-method UpdateCommand(recData) if (DataReceived != null) DataReceived(recData); else Console.WriteLine("Null ausgeloest"); } } catch (SocketException e) { Console.WriteLine(e); } catch (Exception e) { Console.WriteLine(e.ToString()); } finally { listener.Close(); Console.WriteLine("Done listening for UDP broadcast"); } } } } } public partial class MainWindow : Window { SoundPlayer soundPlayer = new SoundPlayer(@"c:\Users\Klaus\Music\beep.wav"); Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); IPEndPoint ep = new IPEndPoint(IPAddress.Parse("192.168.178.255"), 5000); UDPListener listener = new UDPListener(); public MainWindow() { InitializeComponent(); listener.StartListener(1024); } public void UpdateCommand(string data) { this.Dispatcher.Invoke(() => { Command.Text = data; }); } }
解决方法
你已经定义了DataReceived事件,这是解耦UDP监听逻辑和UI逻辑的正确方式,不需要在UDPListener类里直接调用UI方法,按以下步骤修改:
在MainWindow构造函数中订阅事件
修改MainWindow的构造函数,添加事件订阅:public MainWindow() { InitializeComponent(); // 订阅DataReceived事件,收到数据时触发处理方法 listener.DataReceived += Listener_DataReceived; listener.StartListener(1024); }实现事件处理方法
在MainWindow中添加事件处理方法,调用你的UpdateCommand:private void Listener_DataReceived(string newData) { UpdateCommand(newData); }修复UDPListener的循环控制
你当前的while(true)会导致StopListener方法失效,改成用listening变量控制循环:// 替换ListenForUDPPackages中的while循环 while (listening) { byte[] data = listener.Receive(ref groupEP); Console.WriteLine($"Received broadcast from {groupEP} :"); Console.WriteLine($"{Encoding.ASCII.GetString(data, 0, data.Length)}"); recData = Encoding.ASCII.GetString(data, 0, data.Length); // 注意:后台线程不能直接调用MessageBox,如需弹窗请用Dispatcher // Application.Current.Dispatcher.Invoke(() => MessageBox.Show(recData)); DataReceived?.Invoke(recData); // 简化事件触发写法 }优化事件触发写法
把原来的if (DataReceived != null) DataReceived(recData);改成空合并运算符的写法DataReceived?.Invoke(recData);,更简洁安全。
这样修改后,UDP监听线程收到数据时会触发DataReceived事件,MainWindow订阅该事件后调用UpdateCommand,通过Dispatcher更新UI元素,完全符合WPF的线程模型要求。
内容的提问来源于stack exchange,提问作者Klaus Dilper
相关产品推荐
相关产品推荐

