WPF - 分组 CollectionView 多次显示同一组
WPF - Grouped CollectionView showing multiple times same group
我在对绑定到 ItemsControl 的 CollectionView 进行分组时遇到问题。
在我的 ViewModel 中,我有多个组。 Group是Person的集合,每个Person都知道自己属于哪个组。
见最后的组和人类。
- 这是我想要做的:
我希望能够显示按组分组的人员集合。我强调我想在 Persons 集合的视图中创建这些组, 而不是 Groups.
集合
- 这是我的做法:
我有一个列表,其中包含所有组中的每个人(该列表称为 "Everyone"),并且我有一个 CollectionView,它是我从名为 "EveryoneGrouped" 的每个人创建的。然后,我将从 "Group" 创建的 PropertyGroupDescription 添加到我的 EveryoneGrouped 集合中。
- 这是我的问题:
组出现多次,实际上组出现的次数与它们包含的人的数量一样多。
如果我有以下组:
- 第一组 ["Alpha One"]
- 第二组 ["Alpha Two", "Beta Two"]
- 第三组 ["Alpha Three"、"Beta Three"、"Gamma Three"]
它将产生以下内容:
组 ONE 只出现一次,因为它只包含一个人。我希望第二组和第三组也只出现一次。
我只是不能指出我做错了什么,任何帮助将不胜感激。
编辑:多个组或个人可以具有相同的名称。
这是我生成上一个屏幕截图的代码:
视图模型
public class ViewModel
{
public CollectionView EveryoneGrouped { get; private set; }
private List<Person> Everyone { get; set; } = new List<Person>();
private List<Group> AllGroups { get; set; } = new List<Group>();
public ViewModel()
{
populateGroups();
populateEveryoneCollection();
createCollectionView();
}
private void populateGroups()
{
Group one = new Group
{
new Person { PersonName = "Alpha One" }
};
one.GroupName = "ONE";
Group two = new Group
{
new Person { PersonName = "Alpha Two" },
new Person { PersonName = "Beta Two" }
};
two.GroupName = "TWO";
Group three = new Group
{
new Person { PersonName = "Alpha Three" },
new Person { PersonName = "Beta Three" },
new Person { PersonName = "Gamma Three" }
};
three.GroupName = "THREE";
AllGroups.Add(one);
AllGroups.Add(two);
AllGroups.Add(three);
}
private void populateEveryoneCollection()
{
foreach(Group group in AllGroups)
{
foreach(Person person in group)
{
Everyone.Add(person);
}
}
}
private void createCollectionView()
{
EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group");
EveryoneGrouped.GroupDescriptions.Add(groupDescription);
}
}
XAML
<Window x:Class="FunWithCollectionViewGrouping.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:FunWithCollectionViewGrouping"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ItemsControl ItemsSource="{Binding EveryoneGrouped}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonName}" Margin="5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Name.Group.GroupName}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
</ItemsControl>
</Grid>
代码隐藏
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
人
public class Person
{
private static int PersonQuantity = 0;
private int _id = ++PersonQuantity;
public int Id { get { return _id; } }
public Group Group { get; set; }
public string PersonName { get; set; }
}
组
public class Group : ObservableCollection<Person>
{
private static int GroupQuantity = 0;
private int _id = ++GroupQuantity;
public int Id { get { return _id; } }
public string GroupName { get; set; }
public Group()
{
CollectionChanged += Group_CollectionChanged;
}
private void Group_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if( e.NewItems != null )
{
foreach(Person p in e.NewItems)
{
if ( p.Group != null ) { p.Group.Remove(p); }
p.Group = this;
}
}
if( e.OldItems != null )
{
foreach (Person p in e.OldItems)
{
if (p.Group != null && p.Group.Equals(this)) { p.Group = null; }
}
}
}
public override bool Equals(object obj)
{
Group other = obj as Group;
if (obj == null) return false;
return Id == other.Id;
}
public override int GetHashCode()
{
return Id;
}
}
谢谢。
按 GroupName
属性 的 Group
分组:
private void createCollectionView()
{
EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group.GroupName");
EveryoneGrouped.GroupDescriptions.Add(groupDescription);
}
并显示群组名称:
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
The problem I have with this solution is that multiple groups can have the same name (I updated my post to specify this), and they will be merged in the view if I do this. Groups are distinguished by their ID (which I can't sort by because then I would loose the group name in the view).
按 Id
属性 分组然后:
private void createCollectionView()
{
EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group.Id");
EveryoneGrouped.GroupDescriptions.Add(groupDescription);
}
并将TextBlock
绑定到组中第一项Group
的GroupName
属性:
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Items[0].Group.GroupName}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
What I don't understand is why it behaves this way, doesn't PropertyGroupDescription use Equals and GetHashCode?
显然不是。它使用反射能够按字符串指定的任何 属性 进行分组。
我在对绑定到 ItemsControl 的 CollectionView 进行分组时遇到问题。
在我的 ViewModel 中,我有多个组。 Group是Person的集合,每个Person都知道自己属于哪个组。
见最后的组和人类。
- 这是我想要做的:
我希望能够显示按组分组的人员集合。我强调我想在 Persons 集合的视图中创建这些组, 而不是 Groups.
集合
- 这是我的做法:
我有一个列表,其中包含所有组中的每个人(该列表称为 "Everyone"),并且我有一个 CollectionView,它是我从名为 "EveryoneGrouped" 的每个人创建的。然后,我将从 "Group" 创建的 PropertyGroupDescription 添加到我的 EveryoneGrouped 集合中。
- 这是我的问题:
组出现多次,实际上组出现的次数与它们包含的人的数量一样多。
如果我有以下组:
- 第一组 ["Alpha One"]
- 第二组 ["Alpha Two", "Beta Two"]
- 第三组 ["Alpha Three"、"Beta Three"、"Gamma Three"]
它将产生以下内容:
组 ONE 只出现一次,因为它只包含一个人。我希望第二组和第三组也只出现一次。
我只是不能指出我做错了什么,任何帮助将不胜感激。
编辑:多个组或个人可以具有相同的名称。
这是我生成上一个屏幕截图的代码:
视图模型
public class ViewModel
{
public CollectionView EveryoneGrouped { get; private set; }
private List<Person> Everyone { get; set; } = new List<Person>();
private List<Group> AllGroups { get; set; } = new List<Group>();
public ViewModel()
{
populateGroups();
populateEveryoneCollection();
createCollectionView();
}
private void populateGroups()
{
Group one = new Group
{
new Person { PersonName = "Alpha One" }
};
one.GroupName = "ONE";
Group two = new Group
{
new Person { PersonName = "Alpha Two" },
new Person { PersonName = "Beta Two" }
};
two.GroupName = "TWO";
Group three = new Group
{
new Person { PersonName = "Alpha Three" },
new Person { PersonName = "Beta Three" },
new Person { PersonName = "Gamma Three" }
};
three.GroupName = "THREE";
AllGroups.Add(one);
AllGroups.Add(two);
AllGroups.Add(three);
}
private void populateEveryoneCollection()
{
foreach(Group group in AllGroups)
{
foreach(Person person in group)
{
Everyone.Add(person);
}
}
}
private void createCollectionView()
{
EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group");
EveryoneGrouped.GroupDescriptions.Add(groupDescription);
}
}
XAML
<Window x:Class="FunWithCollectionViewGrouping.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:FunWithCollectionViewGrouping"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ItemsControl ItemsSource="{Binding EveryoneGrouped}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonName}" Margin="5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Name.Group.GroupName}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
</ItemsControl>
</Grid>
代码隐藏
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
人
public class Person
{
private static int PersonQuantity = 0;
private int _id = ++PersonQuantity;
public int Id { get { return _id; } }
public Group Group { get; set; }
public string PersonName { get; set; }
}
组
public class Group : ObservableCollection<Person>
{
private static int GroupQuantity = 0;
private int _id = ++GroupQuantity;
public int Id { get { return _id; } }
public string GroupName { get; set; }
public Group()
{
CollectionChanged += Group_CollectionChanged;
}
private void Group_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if( e.NewItems != null )
{
foreach(Person p in e.NewItems)
{
if ( p.Group != null ) { p.Group.Remove(p); }
p.Group = this;
}
}
if( e.OldItems != null )
{
foreach (Person p in e.OldItems)
{
if (p.Group != null && p.Group.Equals(this)) { p.Group = null; }
}
}
}
public override bool Equals(object obj)
{
Group other = obj as Group;
if (obj == null) return false;
return Id == other.Id;
}
public override int GetHashCode()
{
return Id;
}
}
谢谢。
按 GroupName
属性 的 Group
分组:
private void createCollectionView()
{
EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group.GroupName");
EveryoneGrouped.GroupDescriptions.Add(groupDescription);
}
并显示群组名称:
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
The problem I have with this solution is that multiple groups can have the same name (I updated my post to specify this), and they will be merged in the view if I do this. Groups are distinguished by their ID (which I can't sort by because then I would loose the group name in the view).
按 Id
属性 分组然后:
private void createCollectionView()
{
EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group.Id");
EveryoneGrouped.GroupDescriptions.Add(groupDescription);
}
并将TextBlock
绑定到组中第一项Group
的GroupName
属性:
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Items[0].Group.GroupName}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
What I don't understand is why it behaves this way, doesn't PropertyGroupDescription use Equals and GetHashCode?
显然不是。它使用反射能够按字符串指定的任何 属性 进行分组。