WPF ListCollectionView按List <string>自定义分组/排序

时间:2017-06-27 09:55:15

标签: c# wpf

我的设置

我正在使用ListCollectionViewListBox中的数据进行排序和分组。

我的模特:

public class Game
{
    public string Name
    {
        get; set;
    }

    public List<string> Categories
    {
        get; set;
    }
}

我想做的是按Categories进行分组,其中视图中的组按字母顺序排序。并按Name按组对所有项目进行排序。

此外,我希望在视图底部有代表null或空类别的组。

例如:

Category1
    Name2
    Name3
Category2
    Name2
    Name3
    Name4
    Name5
Null/Empty
    Name1
    Name6

由于CategoriesList<string>,表示任何项目都可以在一个或多个组中,或者不包含任何项目。

问题

我不知道如何正确实现类别的排序。我知道我必须先设置多个SortDescriptions,然后按Categories排序,然后按Name秒排序,但我该如何做?

WPF默认情况下不知道如何对List<string>组进行排序,所以我尝试将其更改为自定义列表,该列表实现IComparable,但是无法处理空值(如果不能调用比较器,则无法调用其中一个对象是null)。

我也尝试在我的观点上实现CustomSort,但我认为以这种方式处理我的情况并非不可能(其中一个项目可以在多个组中)。

更新完整的代码

结果是:

Null
    Game1
Category2
    Game2
    Game3
Category1
    Game3
    Game4

我希望它是:

Category1
    Game3
    Game4
Category2
    Game2
    Game3
Null
    Game1

代码:

public partial class MainWindow : Window
{
    public class Game
    {
        public string Name
        {
            get; set;
        }

        public List<string> Categories
        {
            get; set;
        }
    }

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        var games = new List<Game>()
        {
            new Game()
            {
                Name = "Game1",
            },
            new Game()
            {
                Name = "Game2",
                Categories = new List<string>() { "Category2" }                    
            },
            new Game()
            {
                Name = "Game3",
                Categories = new List<string>() { "Category1", "Category2" }
            },
            new Game()
            {
                Name = "Game4",
                Categories = new List<string>() { "Category1" }
            }
        };

        var view = (ListCollectionView)CollectionViewSource.GetDefaultView(games);
        view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
        view.GroupDescriptions.Add(new PropertyGroupDescription("Categories"));
        MainList.ItemsSource = view;
    }
}

和XAML:

<Window x:Class="grouping.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:grouping"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <Grid>
        <ListBox Name="MainList">
            <ListBox.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <Expander Header="{Binding Name, TargetNullValue='Null'}" IsExpanded="True">
                                            <ItemsPresenter />
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </ListBox.GroupStyle>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

1 个答案:

答案 0 :(得分:2)

基本上,您的数据格式不适合在WPF中显示。您希望相同的条目出现在多个位置(每组一次),而典型的itemssource将显示每个项目一次,无论排序细节如何。

因此,您应该将数据转换为WPF更自然的表示形式。例如(使用自定义比较器进行排序):

public class GameListEntry : IComparable<GameListEntry>
{
    public string Name { get; set; }
    public string Category { get; set; }

    public int CompareTo(GameListEntry other)
    {
        if (Category == other.Category)
        {
            return 0;
        }
        if (Category == "Null / Empty")
        {
            return 1;
        }
        if (other.Category == "Null / Empty")
        {
            return -1;
        }
        return Category.CompareTo(other.Category);
    }
}


List<Game> games = ...;

var listedGameEntries = games.SelectMany(x => x.Categories.DefaultIfEmpty().Select(c => new GameListEntry { Name = x.Name, Category = string.IsNullOrEmpty(c) ? "Null / Empty" : c }));

var groupedGames = listedGameEntries.GroupBy(x => x.Category);

CompareTo可能需要增强或替换为不同的机制,以便按照应有的方式进行排序和分组。

编辑:添加了DefaultIfEmpty(),以确保即使有一个空的类别列表也可以输入一个条目。