【问题标题】:WPF - Grouped CollectionView showing multiple times same groupWPF - 分组的 CollectionView 显示多次相同的组
【发布时间】:2017-02-27 15:42:32
【问题描述】:


我在对绑定到 ItemsControl 的 CollectionView 进行分组时遇到问题。

在我的 ViewModel 中,我有多个组。 Group 是 Person 的集合,每个 Person 都知道它属于哪个组。
请参阅最后的 Group 和 Person 类。

- 这就是我想要做的:
我希望能够显示按他们的组分组的人的集合。我强调我想从人物集合而不是群组集合在视图中创建这些群组。

- 我是这样做的:
我有一个列表,其中包含所有组中的每个人(该列表称为“Everyone”),并且我有一个 CollectionView,它是从名为“EveryoneGrouped”的每个人创建的。然后,我将从“组”创建的 PropertyGroupDescription 添加到我的 EveryoneGrouped 集合中。

- 这是我的问题:
组出现多次,实际上组出现的次数与其包含的人员数量一样多。
如果我有以下组:
- 第一组 [“Alpha One”]
- 第二组 [“Alpha 2”、“Beta 2”]
- 第三组 [“Alpha 3”、“Beta 3”、“Gamma 3”]
它将产生以下内容:
组 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;
    }
}

谢谢。

【问题讨论】:

    标签: wpf xaml data-binding grouping collectionview


    【解决方案1】:

    GroupGroupName 属性分组:

    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>
    

    我对这个解决方案的问题是多个组可以具有相同的名称(我更新了我的帖子以指定这一点),如果我这样做,它们将被合并到视图中。组由它们的 ID 来区分(我无法排序,因为那样我会在视图中丢失组名)。

    然后按Id 属性分组:

    private void createCollectionView()
    {
        EveryoneGrouped = (CollectionView)CollectionViewSource.GetDefaultView(Everyone);
        PropertyGroupDescription groupDescription = new PropertyGroupDescription("Group.Id");
        EveryoneGrouped.GroupDescriptions.Add(groupDescription);
    }
    

    并将TextBlock 绑定到组中第一项的GroupGroupName 属性:

    <ItemsControl.GroupStyle>
        <GroupStyle>
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <TextBlock DockPanel.Dock="Left" FontWeight="Bold" Text="{Binding Items[0].Group.GroupName}" />
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </ItemsControl.GroupStyle>
    

    我不明白为什么它会这样,PropertyGroupDescription 不使用 Equals 和 GetHashCode 吗?

    显然不是。它使用反射能够按字符串指定的任何属性进行分组。

    【讨论】:

    • 这个解决方案的问题是多个组可以具有相同的名称(我更新了我的帖子以指定这一点),如果我这样做,它们将在视图中合并。组通过它们的 ID 来区分(我无法排序,因为那样我会在视图中丢失组名)。我想按组分组的另一个原因是因为我有一些命令我想将组作为参数传递给。
    • 我不明白的是为什么它会这样,PropertyGroupDescription 不使用 Equals 和 GetHashCode 吗?如果确实如此,那么它应该与按 ID 分组一样好......
    • 我编辑了我的答案。你想考虑投票,因为它解决了你原来的问题。如果您有其他问题,您应该提出一个新问题。
    • 啊,我不知道您可以在以 groupstyle 绑定时使用“项目”。我想我可以完成这项工作,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多