问题描述
我是 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);
}
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 实例返回一个新的视图源实例。