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);
};
}
}
Just the ticket - thanks
ReplyDelete