How to keep one or more DataGrid rows always at the top even after sorting

I have a DataGrid (in a View) bound to an ObservableCollection (in a ViewModel).

To this ObservableCollection I programmatically add a "magic string" since the selected item will be used to sort another collection elsewhere, and I add this dummy string to "clear" the filtering.

Currently, when the View loads, my magic string is always displayed on top (as I insert it into the index 0

), but as soon as I click on the title to change the sort order, the rows are rearranged alphabetically and my magic string is lost in the debris.

I want the magic row to always appear on top even when I click on the title to change the sort order.

ViewModel:

// (...)

public ObservableCollection<FilteringItem> ItemTypes
{
    get
    {
        var result = new ObservableCollection<FilteringItem>(_setups.Select(n => n.ItemType)
                                                             .Distinct()
                                                             .Select(s => new FilteringItem(s, s))
                                                             .OrderBy(v => v.Name));


        // Magic Happens Here: adding a "magic" row to remove filtering
        // (that is, "allow all") when used by some filtering method elsewhere;
        string allString = String.Format("All ({0})", result.Count);
        var filteringAll = new FilteringItem(allString, "");

        result.Insert(0, filteringAll);

        return result;
    }

}
// (...)

public class FilteringItem
{
    public string Name { get; private set; }
    public string Value { get; private set; }

    public FilteringItem(string name, string val)
    {
        Name = name;
        Value = val;
    }
}    

      

View:

<DataGrid ItemsSource="{Binding ItemTypes}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Tipo" Width="*" Binding="{Binding Name}"/>
    </DataGrid.Columns>
</DataGrid>

      

+3


source to share


1 answer


I have a job thanks to this blog post .

The "secret" was to intercept the event Sorting

(set e.Handled

to true

) and then pass the DataGrid.ItemsSource to ListCollectionView

and then assign the custom property IComparer

to ListCollectionView.CustomSort

.



Then, by sorting, you somehow identify your fixed string (by null, in my case), and always do it at the top (which in turn depends on ListSortDirection

).

public partial class ViewContainingDataGrid : UserControl
{
    public ViewContainingDataGrid()
    {
        this.InitializeComponent();
    }

    private void datagrid_Sorting(object sender, DataGridSortingEventArgs e)
    {
        e.Handled = true;
        SmartSort(sender, e.Column);
    }

    private void SmartSort(object sender, DataGridColumn column)
    {
        ListSortDirection direction = (column.SortDirection != ListSortDirection.Ascending) ?
                             ListSortDirection.Ascending : ListSortDirection.Descending;

        column.SortDirection = direction;
        var dg = sender as DataGrid;
        var lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(dg.ItemsSource);
        lcv.CustomSort = new SmartSorter(direction);
    }

}

public class SmartSorter : IComparer
{
    public ListSortDirection Direction { get; private set; }

    public SmartSorter(ListSortDirection direction)
    {
        Direction = direction;
    }


    public int Compare(object x, object y)
    {
        string valorx = x as string;
        string valory = y as string;

        int comparison = valorx.CompareTo(valory);
        if (Direction == ListSortDirection.Descending)
            comparison *= -1;

        // Override the sorting altogether when you find the special row value
        if (String.IsNullOrWhiteSpace(valorx))
            comparison = -1;
        else
        if (String.IsNullOrWhiteSpace(valory))
            comparison = 1;

        return comparison;
    }
}

      

+1


source







All Articles