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

WinUI 3应用点击自定义控件按钮后偶发崩溃问题排查

可能的崩溃原因及修复方案

1. 依赖属性注册的目标类型错误

你的MyDialog类中,注册依赖属性时错误地使用typeof(AddinAutoAttachDialog)作为目标类型,实际类名应为MyDialog。WinUI依赖属性系统对类型匹配要求严格,这种不匹配会触发内部XAML解析异常,导致崩溃。

错误代码:

public static readonly DependencyProperty YesSelectedCommandProperty = 
    DependencyProperty.Register("YesSlectedCommand", typeof(ICommand), typeof(AddinAutoAttachDialog), new PropertyMetadata(null, OnYesCommandChanged));

修复后:

public static readonly DependencyProperty YesSelectedCommandProperty = 
    DependencyProperty.Register("YesSelectedCommand", typeof(ICommand), typeof(MyDialog), new PropertyMetadata(null, OnYesCommandChanged));

2. 属性名拼写不一致(Selected拼写错误)

代码中多处存在拼写错误:

  • 依赖属性注册名写成YesSlectedCommand(少字母e,正确应为YesSelectedCommand)
  • UserControl的CLR属性、XAML绑定均使用错误拼写,而ViewModel中[RelayCommand]自动生成的命令属性是YesSelectedCommand(正确拼写)

这种不匹配会导致绑定失效,触发WinUI内部命令执行异常。

修复步骤:
统一所有属性名为YesSelectedCommand和NoSelectedCommand:

// 依赖属性注册
public static readonly DependencyProperty YesSelectedCommandProperty = 
    DependencyProperty.Register("YesSelectedCommand", typeof(ICommand), typeof(MyDialog), new PropertyMetadata(null, OnYesCommandChanged));

public static readonly DependencyProperty NoSelectedCommandProperty =
    DependencyProperty.Register("NoSelectedCommand", typeof(ICommand), typeof(MyDialog), new PropertyMetadata(null, OnNoCommandChanged));

// CLR属性
public ICommand YesSelectedCommand
{
    get { return (ICommand)GetValue(YesSelectedCommandProperty); }
    set { SetValue(YesSelectedCommandProperty, value); }
}

public ICommand NoSelectedCommand
{
    get { return (ICommand)GetValue(NoSelectedCommandProperty); }
    set { SetValue(NoSelectedCommandProperty, value); }
}

修正UserControl的XAML绑定:

<Button Content="Yes"
        Command="{x:Bind YesSelectedCommand, Mode=OneTime}"/>

<Button Content="No"
        Command="{x:Bind NoSelectedCommand, Mode=OneTime}" />

修正View中的绑定:

<components:MyDialog Visibility="{x:Bind MainViewModel.ShowMyDialog, Mode=OneWay}"
     YesSelectedCommand="{x:Bind MainViewModel.YesSelectedCommand, Mode=OneWay}"
     NoSelectedCommand="{x:Bind MainViewModel.NoSelectedCommand, Mode=OneWay}" />

3. InfoBar同时使用IsOpen和Visibility导致冲突

你给InfoBar同时设置IsOpen="True"和绑定Visibility,两个属性都会控制显示状态,WinUI内部处理这种矛盾状态时可能引发布局异常。

修复方案:
只保留一种控制逻辑,推荐使用IsOpen(符合InfoBar设计意图):

<InfoBar Severity="Success"
         Title="..." 
         IsOpen="{x:Bind MainViewModel.ShowSuccessInfoBar, Mode=OneWay}"/>

<InfoBar Severity="Error"
         Title="..."
         IsOpen="{x:Bind MainViewModel.ShowErrorInfoBar, Mode=OneWay}" />

4. 未实现依赖属性的回调方法

你在依赖属性注册时指定了OnYesCommandChanged和OnNoCommandChanged回调,但未实现这些方法。虽然编译不会报错,但WinUI触发回调时会找不到方法,引发内部异常。

修复方案:
如果不需要回调,直接将PropertyMetadata的回调参数设为null;如果需要回调,实现对应方法:

// 不需要回调的情况
public static readonly DependencyProperty YesSelectedCommandProperty = 
    DependencyProperty.Register("YesSelectedCommand", typeof(ICommand), typeof(MyDialog), new PropertyMetadata(null));

// 实现回调方法的情况
private static void OnYesCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    // 添加自定义逻辑
}

5. UI线程访问问题(潜在风险)

如果ExecuteSomeOperations是异步或耗时操作,直接在命令中修改UI属性可能导致线程访问错误,引发偶发崩溃。

修复方案:
确保在UI线程修改属性:

[RelayCommand]
private async void YesSelected()
{
    bool succeeded = await Task.Run(() => ExecuteSomeOperations());
    await DispatcherQueue.EnqueueAsync(() =>
    {
        ShowMyDialog = false;
        ShowSuccessInfoBar = succeeded;
        ShowErrorInfoBar = !succeeded;
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 18:30:18