我正在编写 WinUI 3 桌面应用程序。主窗口包含一个TreeView
以汽车制造商的名称作为父项,汽车型号作为子项的名称。以下是相关代码:
MainWindow.xaml
:
<Window
x:Class="Cars.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="using:Cars.Model"
xmlns:view="using:Cars.View"
xmlns:utility="using:Cars.View.Utility">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="CarMakeTemplate" x:DataType="model:CarMake">
<TreeViewItem ItemsSource="{x:Bind Path=CarModels, Mode=OneWay}">
<StackPanel Orientation="Horizontal">
<view:CarMakeView CarMake="{x:Bind Mode=OneWay}"/>
<Button Content="Delete" Click="DeleteCarMake"/>
</StackPanel>
</TreeViewItem>
</DataTemplate>
<DataTemplate x:Key="CarModelTemplate" x:DataType="model:CarModel">
<TreeViewItem>
<view:CarModelView CarModel="{x:Bind Mode=OneWay}"/>
</TreeViewItem>
</DataTemplate>
<utility:CarItemSelector
x:Key="CarItemSelector"
CarMakeTemplate="{StaticResource CarMakeTemplate}"
CarModelTemplate="{StaticResource CarModelTemplate}" />
</Grid.Resources>
<TreeView ItemsSource="{x:Bind Cars, Mode=OneWay}"
ItemTemplateSelector="{StaticResource CarItemSelector}"
SelectionChanged="HandleSelectedCarMakeChanged">
</TreeView>
</Grid>
</Window>
MainWindow.cs
:
public sealed partial class MainWindow : Window, INotifyPropertyChanged
{
public ObservableCollection<CarMake> Cars { get; set; } =
new ()
{
new CarMake { Name = "Chevrolet", CarModels = { new CarModel { Name = "Camaro" }, new CarModel { Name = "Blazer" }, new CarModel { Name = "Beretta" } } },
new CarMake { Name = "Land Rover", CarModels = { new CarModel { Name = "Discovery" }, new CarModel { Name = "LR3" }, new CarModel { Name = "Range Rover" } } },
new CarMake { Name = "Quadra", CarModels = { new CarModel { Name = "Turbo-R 740" }, new CarModel { Name = "Type-66 Avenger" }} },
new CarMake { Name = "Powell Motors", CarModels = { new CarModel { Name = "The Homer" }}}
};
public MainWindow()
{
this.InitializeComponent();
}
private void DeleteCarMake(object sender, RoutedEventArgs eventInfo)
{
var carMakeToDelete = ((Button) eventInfo.OriginalSource).DataContext as CarMake;
var updatedCarMakes = new List<CarMake>(Cars);
updatedCarMakes.Remove(carMakeToDelete!);
Cars.Clear();
foreach (CarMake carMake in updatedCarMakes)
{
Cars.Add(carMake);
}
OnPropertyChanged(nameof(Cars));
}
private void HandleSelectedCarMakeChanged(TreeView sender, TreeViewSelectionChangedEventArgs info)
{
//do stuff
}
public event PropertyChangedEventHandler? PropertyChanged;
[NotifyPropertyChangedInvocator]
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
问题:这是导致神秘异常的事件顺序:
- 用户单击“删除”按钮。
DeleteCarMake()
通过回调调用。DeleteCarMake()
删除所选CarMake
内容并完全重置Cars
ObservableCollection
.- 下次用户单击时
TreeView
会引发异常。
该问题似乎与完全删除内容Cars
和随后将数据复制回Cars
(请注意,Cars
用作)ItemsSource
有关TreeView
。如果我只是删除carMakeToDelete
from Cars
,则下次用户单击TreeView
. 但是,由于我的简化代码无法表达的原因,我需要能够Clear()
Cars
在每次删除时完全 ' 内容,而不仅仅是删除单个项目。
完整的调用堆栈在这里,但尽我所能告诉相关部分似乎在中间:
Microsoft.UI.Xaml.Controls.dll!ViewModel::UpdateNodeSelection(struct winrt::Microsoft::UI::Xaml::Controls::TreeViewNode const &,enum TreeViewNode::TreeNodeSelectionState const &) Unknown
Microsoft.UI.Xaml.Controls.dll!ViewModel::UpdateSelection(struct winrt::Microsoft::UI::Xaml::Controls::TreeViewNode const &,enum TreeViewNode::TreeNodeSelectionState const &) Unknown
Microsoft.UI.Xaml.Controls.dll!SelectedTreeNodeVector::UpdateSelection(struct winrt::Microsoft::UI::Xaml::Controls::TreeViewNode const &,enum TreeViewNode::TreeNodeSelectionState) Unknown
Microsoft.UI.Xaml.Controls.dll!SelectedTreeNodeVector::RemoveAt(unsigned int) Unknown
Microsoft.UI.Xaml.Controls.dll!SelectedTreeNodeVector::Clear(void) Unknown
Microsoft.UI.Xaml.Controls.dll!winrt::impl::produce<class SelectedTreeNodeVector,struct winrt::Windows::Foundation::Collections::IVector<struct winrt::Microsoft::UI::Xaml::Controls::TreeViewNode> >::Clear(void) Unknown
Microsoft.UI.Xaml.Controls.dll!winrt::impl::consume_Windows_Foundation_Collections_IVector<struct winrt::Windows::Foundation::Collections::IVector<struct winrt::Microsoft::UI::Xaml::DependencyObject>,struct winrt::Microsoft::UI::Xaml::DependencyObject>::Clear(void) Unknown
Microsoft.UI.Xaml.Controls.dll!ViewModel::SelectNode(struct winrt::Microsoft::UI::Xaml::Controls::TreeViewNode const &,bool) Unknown
Microsoft.UI.Xaml.Controls.dll!TreeView::UpdateSelection(struct winrt::Microsoft::UI::Xaml::Controls::TreeViewNode const &,bool) Unknown
Microsoft.UI.Xaml.Controls.dll!TreeViewItem::UpdateSelection(bool) Unknown
Microsoft.UI.Xaml.Controls.dll!TreeViewItem::OnIsSelectedChanged(struct winrt::Microsoft::UI::Xaml::DependencyObject const &,struct winrt::Microsoft::UI::Xaml::DependencyProperty const &) Unknown
我想知道的是:如何安全地保存我Clear()
的内容,Cars
ObservableCollection
而不会在用户下次单击时引发异常TreeView
?
一个可能的线索:如果我没有在我TreeView
的事件中定义事件处理程序,那么异常永远不会发生。我不太确定这意味着什么,但希望其他人可以将拼图的各个部分拼凑起来。SelectionChanged
MainWindow.xaml