I'm working on a WPF application in C#, and I've come across an interesting problem. Why are exceptions which are thrown from an Expanded/Collapsed event in a TreeViewItem ignored? Other events, including those in a TreeViewItem like MouseDoubleClick, exhibit normal behavior for an exception. The Diagnostic Tools in Visual Studio shows that the exception is being thrown and then caught in the PresentationFramework code. As an example,
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");
}
}
I'm working on implementing a lazy-loaded TreeView, and I have spent the better part of a day debugging my application only to find out that it was silently failing and the original problem was a simple fix. Is my approach of using the Expanded and Collapsed events completely wrong? If not, is there any graceful way to not have these exceptions silently fail?
This behavior is not specific to the Expanded
event or any other events.
The reason is that your exceptions get "swallowed" by the WPF Binding Engine.
The default ControlTemplate
of the TreeViewItem
contains a ToggleButton
that binds its IsChecked
property to the TreeViewItem.IsExpanded
property using the two-way mode:
<ToggleButton IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"/>
So the whole process looks like:
ToggleButton
).ToggleButton
sets its IsChecked
property to true
.true
) to the TreeViewItem
's IsExpanded
property.Expanded
event.TraceListener
.The WPF Binding Engine catches the exceptions natively, you cannot change it.
But you could implement your own TraceListener
that can throw the provided exceptions or maybe do some other error handling.
Take a look on this question and its answers.