In my previous post I talked about using Attached Behaviors to scroll selected item into view. It turns out there is a bug in WPF DataGrid and ScrollIntoView could sometimes throw NullReferenceException when VirtualizingStackPanel.IsVirtualizing="True" .
To avoid this exception there was a solution suggested on this forum http://wpf.codeplex.com/Thread/View.aspx?ThreadId=39458 which basically executes ScrollIntoView on a thread with a very low priority.
Here is my previous solution with suggested work around.
public class DataGridBehavior
{
#region AutoScrollIntoView
public static bool GetAutoScrollIntoView(DataGrid dataGrid)
{
return (bool)dataGrid.GetValue(AutoScrollIntoViewProperty);
}
public static void SetAutoScrollIntoView(
DataGrid dataGrid, bool value)
{
dataGrid.SetValue(AutoScrollIntoViewProperty, value);
}
public static readonly DependencyProperty AutoScrollIntoViewProperty =
DependencyProperty.RegisterAttached(
"AutoScrollIntoView",
typeof(bool),
typeof(DataGridBehavior),
new UIPropertyMetadata(false, OnAutoScrollIntoViewWhenSelectionChanged));
static void OnAutoScrollIntoViewWhenSelectionChanged(
DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = depObj as DataGrid;
if (dataGrid == null)
return;
if (!(e.NewValue is bool))
return;
if ((bool)e.NewValue)
dataGrid.SelectionChanged += OnDataGridSelectionChanged;
else
dataGrid.SelectionChanged -= OnDataGridSelectionChanged;
}
static void OnDataGridSelectionChanged(object sender, RoutedEventArgs e)
{
// Only react to the SelectionChanged event raised by the DataGrid
// Ignore all ancestors.
if (!Object.ReferenceEquals(sender, e.OriginalSource))
return;
DataGrid dataGrid = e.OriginalSource as DataGrid;
if (dataGrid != null && dataGrid.SelectedItem != null)
{
// this is a workaround to fix the layout issue.
// otherwise ScrollIntoView should work directly.
dataGrid.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(ScrollItemIntoView),dataGrid);
}
}
static object ScrollItemIntoView(object sender)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid != null && dataGrid.SelectedItem != null)
{
dataGrid.ScrollIntoView(dataGrid.SelectedItem);
}
return null;
}
#endregion // AutoScrollIntoView
Happy Coding!
Thank you for this solution. Works great for me.
ReplyDeleteReally good tip, thanks!
ReplyDeleteThank you a lot, I really was crazy with that stuff.
ReplyDeleteHow to reproduce the bug ?
ReplyDelete