Radu Olteanu
Radu Olteanu

Reputation: 443

Sort WPF ListView based on the other WPF Listview property order

I have the following two List Views defined like this :

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ListView Grid.Row="0" ItemsSource="{Binding Categories}"/>
    <ListView Grid.Row="1" ItemsSource="{Binding Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding CategoryName}" Foreground="Red"/>
                    <TextBlock Text="{Binding ItemName}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

and the ViewModel code :

 public class MainWindowViewModel
{
    static Random random = new Random();
    private static string RandomString(int length)
    {
        const string pool = "abcdefghijklmnopqrstuvwxyz0123456789";
        var chars = Enumerable.Range(0, length)
            .Select(x => pool[random.Next(0, pool.Length)]);
        return new string(chars.ToArray());
    }

    public ObservableCollection<string> Categories => new ObservableCollection<string> {"yy","asdf","test1"};
    public ObservableCollection<Item> Items
    {
        get {
            var list = new List<Item>();
            Enumerable.Range(0, 10).ToList().ForEach(_ => list.Add(
                                                    new Item { CategoryName = Categories[random.Next(0, Categories.Count)],
                                                               ItemName = RandomString(10) }));
            return new ObservableCollection<Item>(list);
        }
    }
}


public class Item
{
    public string CategoryName { get; set; }
    public string ItemName { get; set; }
}

I would like to sort my "Items" list view by CategoryName, but following the order that is present in the "Categories" ListView. So, if the order will suffer changes in the "Categories" ListView, I would like to re-sort the "Items" list view,to follow the new order. Also, if there's a WPF built-in mechanism that can handle this kind of situations I would like the use it.

Upvotes: 0

Views: 555

Answers (1)

Alex
Alex

Reputation: 1461

You can implement a custom sort logic by creating a new comparer class which implements IComparer interface and use it in ListCollectionView which will be bound to ListView instead of binding it directly ObservableCollection.

For example this is your custom comparer which implements sorting logic based on Categories collection:

public class CategoryComparer : IComparer
{
    private readonly List<string> _categories;

    public int Compare(object x, object y)
    {
        Item item1 = x as Item;
        Item item2 = y as Item;

        int index1 = _categories.IndexOf(item1.CategoryName);
        int index2 = _categories.IndexOf(item2.CategoryName);

        return index1 - index2;
    }

    public CategoryComparer(List<string> categories)
    {
        _categories = categories;
    }
}

Then in your ViewModel you will create a new property which will expose Items collection view and use custom comparer:

private ListCollectionView _itemsCollectionView = null;
public ListCollectionView ItemsCollectionView
{
    get
    {
        _itemsCollectionView = (ListCollectionView)CollectionViewSource.GetDefaultView(Items);
        _itemsCollectionView.CustomSort = new CategoryComparer(Categories.ToList());
        return _itemsCollectionView;
    }
}

Finally you will bind items ListView to the new collection view:

<ListView Grid.Row="1" ItemsSource="{Binding ItemsCollectionView}">
    ...
</ListView>

Also if your Categories collection is dynamic and elements can be added or removed from it you should remember to update ItemsCollectionView by giving it a new instance of CategoryComparer and call OnPropertyChanged in the ViewModel to notify the View about the change.

Upvotes: 1

Related Questions