Friday, March 12, 2010

How to move to the first item in a WPF DataGrid after sorting

Although the WPF DataGrid exposed a Sorting event, this only tells you a sort is about occur. Unfortunately there is not a corresponding Sorted event. However with just a little help from the Dispatcher we can utilise the Sorting event to move to the first item in the grid.

I solved this using an attached behaviour, if your not familiar with this term think of it as an attached property that uses PropertyChanged event to add a feature to an existing control. Conceptually it's quite similar to an attached method in C#.

In the data grid we simply set the attached property to true. We also need to set the IsSynchronizedWithCurrentItem property to true as well, this is required to keep the current item in sync with the default CollectionView that the data grid will bind to.

<DataGrid
x:Name="dataGrid"
ItemsSource="{Binding Path=People}"
local:MoveFirstSortBehaviour.MoveFirstOnSort="True"
IsSynchronizedWithCurrentItem="True"
/>

The attached behaviour is really quite simple. All it does is subscribe to the Sorting event on the data grid. When the Sorting event occurs it uses the Dispatcher to move to the first item in the CollectionView the data grid is bound to. BeginInvoke is required because the sort hasn't occured yet, by the time our code is invoke the grid will be sorted.


public class MoveFirstSortBehaviour
{
public static bool GetMoveFirstOnSort(DependencyObject obj)
{
return (bool)obj.GetValue(MoveFirstOnSortProperty);
}

public static void SetMoveFirstOnSort(DependencyObject obj, bool value)
{
obj.SetValue(MoveFirstOnSortProperty, value);
}

public static readonly DependencyProperty MoveFirstOnSortProperty =
DependencyProperty.RegisterAttached("MoveFirstOnSort", typeof(bool), typeof(MoveFirstSortBehaviour),
new UIPropertyMetadata(false, OnMoveFirstOnSortChanged));

private static void OnMoveFirstOnSortChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (dataGrid == null !(bool)e.NewValue) return;

dataGrid.Sorting += (s, args) =>
{
dataGrid.Dispatcher.BeginInvoke((Action)delegate()
{
var view = CollectionViewSource.GetDefaultView(dataGrid.ItemsSource);
if (view == null) return;
view.MoveCurrentToFirst();
}, null);
};
}
}

1 comment:

Note: Only a member of this blog may post a comment.