Search code examples
c#wpflistviewdata-bindingicomparable

Binding ListView to the set of IComparable


I am looking for a smart way of binding a ListView DataSource property to the set (any collection) of IComparable custom objects. I would like to have a control real time responding to changes of my collection and have results (in ListView) sorted using provided by the Interface method.

I suppose that it can be done by creating custom collection inheriting from ObservableCollection<T> or SortedSet<T> and binding to such class (which combines the advantages of both). I am new to WPF binding and searching for any hints.


Solution

  • You can do this by using CollectionViewSource, descendants of which wrap all collections used by WPF controls. You'll need to implement IComparer though. Here I use a helper class ComparableComparer<T> which uses IComparable<T> implementation, but you can put your logic into the Foo class if you want.

    MainWindow.xaml

    <Window x:Class="So16368719.MainWindow" x:Name="root"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <ListView ItemsSource="{Binding FooItemsSource, ElementName=root}">
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding Name}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Window>
    

    MainWindow.xaml.cs

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows.Data;
    
    namespace So16368719
    {
        public partial class MainWindow
        {
            public ObservableCollection<Foo> FooItems { get; set; }
            public ListCollectionView FooItemsSource { get; set; }
    
            public MainWindow ()
            {
                FooItems = new ObservableCollection<Foo> {
                    new Foo("a"), new Foo("bb"), new Foo("ccc"), new Foo("d"), new Foo("ee"), new Foo("ffff")
                };
                FooItemsSource = (ListCollectionView)CollectionViewSource.GetDefaultView(FooItems);
                FooItemsSource.CustomSort = new ComparableComparer<Foo>();
                InitializeComponent();
            }
        }
    
        public class Foo : IComparable<Foo>
        {
            public string Name { get; set; }
    
            public Foo (string name)
            {
                Name = name;
            }
    
            public int CompareTo (Foo other)
            {
                return Name.Length - other.Name.Length;
            }
        }
    
        public class ComparableComparer<T> : IComparer<T>, IComparer
            where T : IComparable<T>
        {
            public int Compare (T x, T y)
            {
                return x.CompareTo(y);
            }
    
            public int Compare (object x, object y)
            {
                return Compare((T)x, (T)y);
            }
        }
    }
    

    Note:

    • Implementation of ComparableComparer<T> is quick and dirty. It should also check for nulls.
    • You should use MVVM pattern and not code-behind.

    External links: