How to autoscroll on WPF datagrid

You should use the datagrid method

datagrid.ScrollIntoView(itemInRow);

or

datagrid.ScrollIntoView(itemInRow, column);

this way provides no messing around finding the scroll viewer etc.


;)

if (mainDataGrid.Items.Count > 0)
{
    var border = VisualTreeHelper.GetChild(mainDataGrid, 0) as Decorator;
    if (border != null)
    {
        var scroll = border.Child as ScrollViewer;
        if (scroll != null) scroll.ScrollToEnd();
    }
}

I've written an attached property for grid autoscroll:

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;

public static class DataGridBehavior
{
    public static readonly DependencyProperty AutoscrollProperty = DependencyProperty.RegisterAttached(
        "Autoscroll", typeof(bool), typeof(DataGridBehavior), new PropertyMetadata(default(bool), AutoscrollChangedCallback));

    private static readonly Dictionary<DataGrid, NotifyCollectionChangedEventHandler> handlersDict = new Dictionary<DataGrid, NotifyCollectionChangedEventHandler>();

    private static void AutoscrollChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
    {
        var dataGrid = dependencyObject as DataGrid;
        if (dataGrid == null)
        {
            throw new InvalidOperationException("Dependency object is not DataGrid.");
        }

        if ((bool)args.NewValue)
        {
            Subscribe(dataGrid);
            dataGrid.Unloaded += DataGridOnUnloaded;
            dataGrid.Loaded += DataGridOnLoaded;
        }
        else
        {
            Unsubscribe(dataGrid);
            dataGrid.Unloaded -= DataGridOnUnloaded;
            dataGrid.Loaded -= DataGridOnLoaded;
        }
    }

    private static void Subscribe(DataGrid dataGrid)
    {
        var handler = new NotifyCollectionChangedEventHandler((sender, eventArgs) => ScrollToEnd(dataGrid));
        handlersDict.Add(dataGrid, handler);
        ((INotifyCollectionChanged)dataGrid.Items).CollectionChanged += handler;
        ScrollToEnd(dataGrid);
    }

    private static void Unsubscribe(DataGrid dataGrid)
    {
        NotifyCollectionChangedEventHandler handler;
        handlersDict.TryGetValue(dataGrid, out handler);
        if (handler == null)
        {
            return;
        }
        ((INotifyCollectionChanged)dataGrid.Items).CollectionChanged -= handler;
        handlersDict.Remove(dataGrid);
    }

    private static void DataGridOnLoaded(object sender, RoutedEventArgs routedEventArgs)
    {
        var dataGrid = (DataGrid)sender;
        if (GetAutoscroll(dataGrid))
        {
            Subscribe(dataGrid);
        }
    }

    private static void DataGridOnUnloaded(object sender, RoutedEventArgs routedEventArgs)
    {
        var dataGrid = (DataGrid)sender;
        if (GetAutoscroll(dataGrid))
        {
            Unsubscribe(dataGrid);
        }
    }

    private static void ScrollToEnd(DataGrid datagrid)
    {
        if (datagrid.Items.Count == 0)
        {
            return;
        }
        datagrid.ScrollIntoView(datagrid.Items[datagrid.Items.Count - 1]);
    }

    public static void SetAutoscroll(DependencyObject element, bool value)
    {
        element.SetValue(AutoscrollProperty, value);
    }

    public static bool GetAutoscroll(DependencyObject element)
    {
        return (bool)element.GetValue(AutoscrollProperty);
    }
}

Usage:

    <DataGrid c:DataGridBehavior.Autoscroll="{Binding AutoScroll}"/>

Tags:

C#

Wpf

Datagrid