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

WinUI 3中为CustomControl添加自定义事件及崩溃问题解决

WinUI 3 自定义控件添加状态变更事件及崩溃问题解决

一、需求与初始代码

需要在WinUI 3的自定义控件MyCustomTextBlock中添加状态变更事件,当CurrentStatus属性变化时触发,支持像Button的Click事件一样在XAML中绑定使用。

初始自定义控件代码

public sealed class MyCustomTextBlock : Control
{
    public enum Status
    { 
        Waiting,
        Busy,
    }
    
    private Status currentStatus;
    public Status CurrentStatus
    {
        get { return currentStatus; }
    }

    public MyCustomTextBlock()
    {
        this.DefaultStyleKey = typeof(MyCustomTextBlock);
        currentStatus = Status.Waiting;
    }

    // currentStatus变量会在控件内部的自定义方法中被设置
}

期望的XAML使用方式

<local:MyCustomTextBlock x:Name="MessageBlock"
                    Message="{TemplateBinding Message}"
                    DisplayMode="{TemplateBinding DisplayMode}"
                    StatusChanged="MessageBlock_StatusChanged">
</local:MyCustomTextBlock>

期望的事件处理代码

private void MessageBlock_StatusChanged(object sender, RoutedEventArgs e)
{
    // 检查CurrentStatus属性
    if (((MyCustomTextBlock)sender).CurrentStatus == MyCustomTextBlock.Status.Waiting)
        // 执行操作...
}

疑问:如何在控件代码中声明Event和EventHandler?WinUI 3的Microsoft.UI.Xaml库中找不到WPF里的EventManager.RegisterRoutedEvent()方法。

二、自定义事件的正确实现

WinUI 3中没有WPF的路由事件注册机制,推荐使用CLR自定义事件实现需求,步骤如下:

  1. 定义自定义事件参数类(可选,但能传递状态变更前后的值,提升实用性):
public class StatusChangedEventArgs : EventArgs
{
    public MyCustomTextBlock.Status OldValue { get; }
    public MyCustomTextBlock.Status NewValue { get; }

    public StatusChangedEventArgs(MyCustomTextBlock.Status oldValue, MyCustomTextBlock.Status newValue)
    {
        OldValue = oldValue;
        NewValue = newValue;
    }
}
  1. 修改自定义控件代码,添加事件声明并在状态变更时触发事件:
public sealed class MyCustomTextBlock : Control
{
    public enum Status
    { 
        Waiting,
        Busy,
    }
    
    private Status currentStatus;
    public Status CurrentStatus
    {
        get { return currentStatus; }
        private set 
        {
            if (currentStatus != value)
            {
                Status oldValue = currentStatus;
                currentStatus = value;
                // 触发状态变更事件
                OnStatusChanged(new StatusChangedEventArgs(oldValue, currentStatus));
            }
        }
    }

    // 声明自定义状态变更事件
    public event EventHandler<StatusChangedEventArgs> StatusChanged;

    public MyCustomTextBlock()
    {
        this.DefaultStyleKey = typeof(MyCustomTextBlock);
        currentStatus = Status.Waiting;
    }

    // 触发事件的内部方法
    private void OnStatusChanged(StatusChangedEventArgs e)
    {
        StatusChanged?.Invoke(this, e);
    }

    // 示例:控件内部修改状态的方法,调用此方法会自动触发事件
    public void UpdateStatus(Status newStatus)
    {
        CurrentStatus = newStatus;
    }
}

三、崩溃问题及解决办法

问题现象

按上述代码修改后,XAML中绑定StatusChanged事件后,运行时出现Win32非托管异常,应用崩溃,无具体异常信息,崩溃发生在MyCustomTextBlock构造函数执行完成后。

解决办法

移除XAML中的事件绑定声明:

<local:MyCustomTextBlock x:Name="MessageBlock"
                         Message="{TemplateBinding Message}"
                         DisplayMode="{TemplateBinding DisplayMode}">
</local:MyCustomTextBlock>

改为在控件Loaded事件中通过代码绑定事件:

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
        MessageBlock.Loaded += MessageBlock_Loaded;
    }
    
    private void MessageBlock_Loaded(object sender, RoutedEventArgs e)
    {
        MessageBlock.StatusChanged += MessageBlock_StatusChanged;
    }

    private void MessageBlock_StatusChanged(object sender, StatusChangedEventArgs e)
    {
        MyCustomTextBlock control = (MyCustomTextBlock)sender;
        if (e.NewValue == MyCustomTextBlock.Status.Waiting)
        {
            // 执行操作...
        }
        else if (e.NewValue == MyCustomTextBlock.Status.Busy)
        {
            // 执行其他操作...
        }
    }
}

该问题属于Microsoft.UI.Xaml的已知问题,通过代码后置绑定事件可规避崩溃。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 18:35:10