You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3中如何将XAML事件订阅至独立C#文件的事件处理器?

WinUI3 将ToggleButton事件分离到独立EventHandler类的优化建议

一、清理冗余的XAML事件绑定

你当前在XAML中给ToggleButton设置了Checked="PumpBTN_C"和Unchecked="PumpBTN_U",但已经在后台代码手动订阅了事件,这会导致双重绑定的潜在问题。直接移除XAML中的这两个属性:

<ToggleButton
    x:Name="PumpBTN"
    IsThreeState="False"
    Content="Pump" />

二、优化EventHandler类的设计

  1. 重命名类名:避免和.NET内置的Event类冲突,改成更具语义的名字,比如SerialDeviceEventHandler
  2. 管理串口资源:串口属于非托管资源,需要实现IDisposable接口确保资源被正确释放,防止内存泄漏
  3. 优化方法命名:把Main改成InitializeSerialPort,让代码可读性更强

修改后的EventHandler代码:

using System.IO.Ports;
using Microsoft.UI.Xaml;

namespace WinUI.XXXX.EventHandler;

public class SerialDeviceEventHandler : IDisposable
{
    private readonly SerialPort _serialPort;
    private bool _disposed = false;

    public SerialDeviceEventHandler()
    {
        _serialPort = new SerialPort();
        InitializeSerialPort();
    }

    private void InitializeSerialPort()
    {
        // 这里添加串口初始化逻辑,比如设置端口号、波特率
        // _serialPort.PortName = "COM3";
        // _serialPort.BaudRate = 9600;
        
        try
        {
            if (!_serialPort.IsOpen)
                _serialPort.Open();
        }
        catch (System.Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"串口初始化失败: {ex.Message}");
        }
    }

    public void PumpBTN_C(object sender, RoutedEventArgs e)
    {
        if (_serialPort.IsOpen)
        {
            // 写入泵启动指令
            _serialPort.WriteLine("PUMP_ON");
        }
    }

    public void PumpBTN_U(object sender, RoutedEventArgs e)
    {
        if (_serialPort.IsOpen)
        {
            // 写入泵停止指令
            _serialPort.WriteLine("PUMP_OFF");
        }
    }

    public void Dispose()
    {
        Dispose(true);
        System.GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;

        if (disposing)
        {
            if (_serialPort.IsOpen)
                _serialPort.Close();
            _serialPort.Dispose();
        }

        _disposed = true;
    }

    ~SerialDeviceEventHandler()
    {
        Dispose(false);
    }
}

三、优化页面的事件订阅与资源管理

  1. 提升EventHandler实例作用域:把SerialDeviceEventHandler的实例从构造函数局部变量改成页面私有字段,防止构造函数执行完后被GC回收,导致事件处理器失效
  2. 页面卸载时清理资源:在页面Unloaded事件中释放EventHandler资源,并取消事件订阅,避免内存泄漏

修改后的PrimaryPage代码:

using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
using WinUI.XXXX.EventHandler;

namespace WinUI.XXXX.Views;

public partial class PrimaryPage : Page
{
    public PrimaryViewModel ViewModel { get; }
    private SerialDeviceEventHandler _serialEventHandler;

    public PrimaryPage()
    {
        ViewModel = App.GetService<PrimaryViewModel>();
        InitializeComponent();

        _serialEventHandler = new SerialDeviceEventHandler();
        PumpBTN.Checked += _serialEventHandler.PumpBTN_C;
        PumpBTN.Unchecked += _serialEventHandler.PumpBTN_U;

        Unloaded += PrimaryPage_Unloaded;
    }

    private void PrimaryPage_Unloaded(object sender, RoutedEventArgs e)
    {
        _serialEventHandler.Dispose();
        PumpBTN.Checked -= _serialEventHandler.PumpBTN_C;
        PumpBTN.Unchecked -= _serialEventHandler.PumpBTN_U;
    }
}

四、后续测试与调试建议

  • 测试前确认串口设备连接正常,端口号、波特率等参数配置正确
  • 用System.Diagnostics.Debug.WriteLine输出调试信息,在Visual Studio的输出窗口查看串口操作状态
  • 给串口操作添加异常捕获,比如端口被占用、数据发送失败时,弹窗提示用户

内容的提问来源于stack exchange,提问作者BankTQMA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:19:55