微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

WPF 意外的 ICollectionView 行为

如何解决WPF 意外的 ICollectionView 行为

我是 WPF 的新手,只是在学习它是如何工作的。我的最终目标是为每个标题创建一个数据网格,显示与每个类别关联的项目集合的总数。

但我看到了一些意想不到的行为。我希望看到这个输出

标题1
类别1
类别 2

标题2
类别3

我实际看到的是这个:

标题1
类别3

标题2
类别3

我很困惑为什么。希望有人能透露一点。感谢您的帮助!

这是我的代码

主窗口.xaml

<Window x:Class="TestApp.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:TestApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <ItemsControl ItemsSource="{Binding headings}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Description}" />
                        <DataGrid ItemsSource="{Binding Categories}" AutoGenerateColumns="False">
                            <DataGrid.Columns>
                                <DataGridTextColumn Header="" Binding="{Binding Description}" Width="*" />
                            </DataGrid.Columns>
                        </DataGrid>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Window>

MainWindow.xaml.cs

    public partial class MainWindow : Window
    {
        public ObservableCollection<headingviewmodel> headings { get; }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            var category1 = new Categoryviewmodel()
            {
                Id = 1,Description = "Category 1",headingId = 1,};

            var category2 = new Categoryviewmodel()
            {
                Id = 2,Description = "Category 2",};

            var category3 = new Categoryviewmodel()
            {
                Id = 3,Description = "Category 3",headingId = 2,};

            var categories = new ObservableCollection<Categoryviewmodel>();
            categories.Add(category1);
            categories.Add(category2);
            categories.Add(category3);

            var heading1 = new headingviewmodel(categories)
            {
                Id = 1,Description = "heading 1",};

            var heading2 = new headingviewmodel(categories)
            {
                Id = 2,Description = "heading 2",};

            this.headings = new ObservableCollection<headingviewmodel>();
            this.headings.Add(heading1);
            this.headings.Add(heading2);
        }

headingviewmodel.cs

public class headingviewmodel : INotifyPropertyChanged
    {
        public ICollectionView Categories { get; }

        public headingviewmodel(ObservableCollection<Categoryviewmodel> categories)
        {
            this.Categories = CollectionViewSource.Getdefaultview(categories);
            this.Categories.Filter = CategoriesFilter;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private bool CategoriesFilter(object item)
        {
            var category = item as Categoryviewmodel;
            return category.headingId == this.Id;
        }

        private int id;
        public int Id
        {
            get
            {
                return id;
            }
            set
            {
                this.id = value;
                OnPropertyChanged();
                Categories.Refresh();
            }
        }

        public string Description { get; set; }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(name));
        }
    }

Categoryviewmodel.cs

public class Categoryviewmodel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public Categoryviewmodel() {}

        public int Id { get; set; }

        public string Description { get; set; }

        private int? headingId;
        public int? headingId
        {
            get
            {
                return headingId;
            }
            set
            {
                this.headingId = value;
                OnPropertyChanged();
            }
        }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(name));
        }
    }

解决方法

问题是,CollectionViewSource.GetDefaultView(categories) 将为相同的输入返回相同的 ICollectionView 实例,无论您调用它的频率如何。

由于您将相同的 categories 传递给两个 HeadingViewModel 构造函数,因此第二个构造函数 this.Categories.Filter = CategoriesFilter 将覆盖两个标题的过滤器。

,

grek40 因告诉我问题所在而获得金星奖 - 但对于其他遇到此问题的人来说,这里有一个解决方案:

在 HeadingViewModel.cs 中更改这一行:

this.Categories = CollectionViewSource.GetDefaultView(categories);

为此:

this.Categories = new CollectionViewSource { Source = categories }.View;

这会为解决问题的每个 Heading 实例返回一个新的视图源实例。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。