WPF下C#串口监视器DataReceived事件处理及交互问题求助
已解决:WPF串口监视器UI更新异常与命令发送无返回问题
我最近在开发一个集成到基于winPcap的以太网通信工具里的WPF串口监视器(用来替代HyperTerminal或TeraTerm),需求很明确:读取单片机输出的菜单和命令列表并显示到TextBox,等加载完成后发送flash-命令烧写板载FPGA。开发过程中踩了两个大坑——更新TextBox时触发异常,发送命令后收不到返回结果,现在已经全部搞定,把修复后的完整代码分享给有需要的朋友:
namespace WpfApplication1 { /// <summary> /// Interaction logic for SerialMonitor.xaml /// </summary> public partial class SerialMonitor : Window { // VARIABLES public SerialPort comPort = new SerialPort(); public SerialMonitor() { // initialization InitializeComponent(); scanPorts(); } private void scanPorts() { textBoxIndata.Clear(); string[] ports = SerialPort.GetPortNames(); foreach (string port in ports) { comboBoxPorts.Items.Add(port); } } private void openComBtn_Click(object sender, RoutedEventArgs e) { comPort.Parity = Parity.None; comPort.DataBits = 8; comPort.ReadTimeout = 500; comPort.StopBits = StopBits.One; // 修复重复的空值判断 if (comboBoxPorts.SelectedItem != null && !string.IsNullOrEmpty(comboBoxBaud.Text)) { comPort.PortName = comboBoxPorts.SelectedItem.ToString(); if (int.TryParse(comboBoxBaud.Text, out int baudRate)) { comPort.BaudRate = baudRate; try { // Open port and add the event handler on datareceived comPort.Open(); comPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); label1.Content = "COM PORT OPEN"; } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } else { MessageBox.Show("请输入有效的波特率"); } } } private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; // 读取串口接收的数据 string indata = sp.ReadExisting(); // 调用UI更新方法,切换到UI线程 updateUI(indata); } // 修复UI更新的跨线程问题 private void updateUI(string s) { // WPF中必须通过Dispatcher在UI线程更新控件 if (textBoxIndata.Dispatcher.CheckAccess()) { textBoxIndata.AppendText(s); // 自动滚动到最新内容 textBoxIndata.ScrollToEnd(); } else { textBoxIndata.Dispatcher.Invoke(() => updateUI(s)); } } // 添加发送命令的按钮事件(假设XAML中有名为sendFlashBtn的按钮) private void sendFlashBtn_Click(object sender, RoutedEventArgs e) { if (comPort.IsOpen) { // 发送烧写命令,注意加换行(根据单片机协议调整) comPort.WriteLine("flash-"); } else { MessageBox.Show("请先打开串口"); } } // CLOSE AND EXIT BUTTONS private void closeComBtn_Click(object sender, RoutedEventArgs e) { if (comPort.IsOpen) { comPort.Close(); label1.Content = "COM PORT CLOSED"; } } private void exitBtn_Click(object sender, RoutedEventArgs e) { if (comPort.IsOpen) { comPort.Close(); } this.Close(); } } }
核心修复点说明
- 跨线程UI更新:SerialPort的
DataReceived事件在后台线程触发,直接操作TextBox会抛出线程异常,用Dispatcher.Invoke切换到UI线程执行更新是关键 - 完善数据接收逻辑:实现了
DataReceivedHandler读取串口数据,并用AppendText替代直接赋值Text,避免覆盖原有内容 - 命令发送优化:添加了专门的命令发送按钮事件,用
WriteLine发送命令(如果单片机需要特定结束符,比如回车换行,可根据协议调整),确保发送后能被单片机正确识别并返回结果 - 输入验证增强:增加了波特率的数值验证,避免无效输入导致的异常
内容的提问来源于stack exchange,提问作者Francesco Steinwender
相关产品推荐
相关产品推荐

