问题描述
我正在编写 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
中删除 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
事件定义事件处理程序,那么异常永远不会发生.我不太确定这意味着什么,但希望其他人可以将拼图的各个部分拼凑起来。
解决方法
这似乎是 WinUI 3 下一个预览版中将修复的错误。来源 here。