WPF:TreeViewItem Expanded/Collapsed 事件捕获异常

WPF: TreeViewItem Expanded/Collapsed Event Catches Exceptions

我正在使用 C# 开发 WPF 应用程序,我遇到了一个有趣的问题。为什么忽略从 TreeViewItem 中的 Expanded/Collapsed 事件抛出的异常?其他事件,包括 TreeViewItem 中的那些事件,如 MouseDoubleClick,表现出异常的正常行为。 Visual Studio 中的诊断工具显示正在抛出异常,然后在 PresentationFramework 代码中捕获异常。例如,

XAML

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TreeView>
            <TreeViewItem Header="Parent" Expanded="TreeViewItem_Expanded" MouseDoubleClick="TreeViewItem_MouseDoubleClick">
                <TreeViewItem Header="Child" />
            </TreeViewItem>
        </TreeView>
    </Grid>
</Window>

XAML.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
    {
        throw new Exception("Ignored"); //Same issue with Collapsed event
    }

    private void TreeViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        throw new Exception("Normal exception behavior");
    }
}

我正在努力实现一个延迟加载的 TreeView,我花了一天的大部分时间调试我的应用程序,结果发现它无声地失败了,原来的问题是一个简单的修复。我使用 Expanded 和 Collapsed 事件的方法是完全错误的吗?如果不是,是否有任何优雅的方法可以避免这些异常静默失败?

此行为并非特定于 Expanded 事件或任何其他事件。

原因是您的异常被 WPF 绑定引擎获取 "swallowed"。 TreeViewItem 的默认 ControlTemplate 包含一个 ToggleButton,它使用 [=] 将其 IsChecked 属性 绑定到 TreeViewItem.IsExpanded 属性 55=]模式:

<ToggleButton IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"/>

所以整个过程是这样的:

  1. 您单击项目的展开图标(实际上,这是 ToggleButton)。
  2. ToggleButton 将其 IsChecked 属性 设置为 true
  3. WPF 绑定引擎将新值 (true) 传输到 TreeViewItemIsExpanded 属性。
  4. 树项展开并引发 Expanded 事件。
  5. 您在事件处理程序中抛出异常。
  6. 由于我们仍在处理绑定传输(第 3 步),绑定引擎会捕获异常并将其记录到已配置的 TraceListener.
  7. 工作流继续,您在调用者的堆栈上看不到异常。

WPF 绑定引擎本机捕获异常,您无法更改它。 但是您可以实现自己的 TraceListener,它可以抛出所提供的异常或进行一些其他错误处理。

查看 this question 及其答案。