0

我正在编写 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));
        }
    }

问题:这是导致神秘异常的事件顺序:

  1. 用户单击“删除”按钮。
  2. DeleteCarMake()通过回调调用。
  3. DeleteCarMake()删除所选CarMake内容并完全重置Cars ObservableCollection.
  4. 下次用户单击时TreeView会引发异常。

该问题似乎与完全删除内容Cars和随后将数据复制回Cars(请注意,Cars用作)ItemsSource有关TreeView。如果我只是删除carMakeToDeletefrom 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的事件中定义事件处理程序,那么异常永远不会发生。我不太确定这意味着什么,但希望其他人可以将拼图的各个部分拼凑起来。SelectionChangedMainWindow.xaml

4

1 回答 1

0

这似乎是一个计划在 WinUI 3 的下一个预览版本中修复的错误。来源在这里

于 2021-02-02T02:30:58.720 回答