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>
source to share
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;
}
}
source to share