Cosmin
Cosmin

Reputation: 166

WPF Datagrid scrolling

I am using WPF Datagrid and I would like to have it autoscrolled when a new row is added. For this, I added the CollectionChanged event for the ItemsSource and it works fine.

private void dataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        var items = (dataGrid.ItemsSource as ObservableCollection<MyViewModel>);

        if (items == null)
            return;

        items.CollectionChanged += MainWindow_CollectionChanged;
    }

private void MainWindow_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (dataGrid.Items !=null && dataGrid.Items.Count > 0)
            dataGrid.ScrollIntoView(dataGrid.Items[dataGrid.Items.Count - 1]);
    }

The problem is I want the autoscroll feature disabled while I click on any of the scroll bars of the Datagrid. Is there any way I can do this?

Thanks!

Upvotes: 0

Views: 2073

Answers (2)

Cosmin
Cosmin

Reputation: 166

After some more investigation, I found the following simple solution. For the Datagrid, I added the scroll event.

XAML:

<DataGrid Name="dataGrid" ScrollBar.Scroll ="dataGrid_Scroll">
</DataGrid>

CS:

private void dataGrid_Scroll(object sender, RoutedEventArgs e)
    {
        ScrollEventArgs scrollEvent = e as ScrollEventArgs;
        if (scrollEvent != null)
        {
            if (scrollEvent.ScrollEventType == ScrollEventType.EndScroll)
            {
                isScrolling = false;
            }
            else
            {
                isScrolling = true;
            }
        }
    }

Upvotes: 2

grek40
grek40

Reputation: 13458

You can use an attached property to observe the relevant ScrollBar events. Note, in the following example I am using two properties: EnableUserScrollingObserver in order to enable the event listeners and IsUserScrolling to report the current scrolling state.

public static class Attached
{
    public static bool GetEnableUserScrollingObserver(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnableUserScrollingObserverProperty);
    }

    public static void SetEnableUserScrollingObserver(DependencyObject obj, bool value)
    {
        obj.SetValue(EnableUserScrollingObserverProperty, value);
    }

    public static readonly DependencyProperty EnableUserScrollingObserverProperty =
        DependencyProperty.RegisterAttached("EnableUserScrollingObserver", typeof(bool), typeof(Attached),
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(EnableUserScrollingObserverChanged)));

    private static void EnableUserScrollingObserverChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var s = d as ScrollBar;
        if (s != null)
        {
            s.Scroll -= Scrollbar_Scroll;
            if ((bool)e.NewValue)
            {
                s.Scroll += Scrollbar_Scroll;
            }
        }
        else
        {
            // Using this on anything other than a ScrollBar sucks
            throw new InvalidOperationException("EnableUserScrollingObserver is designed for ScrollBar elements!");
        }
    }

    static void Scrollbar_Scroll(object sender, ScrollEventArgs e)
    {
        var s = sender as ScrollBar;
        switch (e.ScrollEventType)
        {
            case ScrollEventType.EndScroll:
                SetIsUserScrolling(s, false);
                break;
                /* All the things handled by default
            case ScrollEventType.First:
                break;
            case ScrollEventType.LargeDecrement:
                break;
            case ScrollEventType.LargeIncrement:
                break;
            case ScrollEventType.Last:
                break;
            case ScrollEventType.SmallDecrement:
                break;
            case ScrollEventType.SmallIncrement:
                break;
            case ScrollEventType.ThumbPosition:
                break;
            case ScrollEventType.ThumbTrack:
                break;
                 */
            default:
                SetIsUserScrolling(s, true);
                break;
        }
    }



    public static bool GetIsUserScrolling(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsUserScrollingProperty);
    }

    public static void SetIsUserScrolling(DependencyObject obj, bool value)
    {
        obj.SetValue(IsUserScrollingProperty, value);
    }

    public static readonly DependencyProperty IsUserScrollingProperty =
        DependencyProperty.RegisterAttached("IsUserScrolling", typeof(bool), typeof(Attached),
            new FrameworkPropertyMetadata(false));
}

Then connect the scroll information to your viewmodel IsScrolling property

<Style TargetType="ScrollBar">
    <Setter Property="local:Attached.EnableUserScrollingObserver" Value="True"/>
    <Setter Property="local:Attached.IsUserScrolling" Value="{Binding IsScrolling,Mode=OneWayToSource}"/>
</Style>

Finally, in your MainWindow_CollectionChanged method, add a check for the IsScrolling property.

Upvotes: 0

Related Questions