0
votes

In a WPF DataGrid, scrolling by row is built in by default. That is, you click the down-arrow on the vertical scrollbar in a DataGrid, and you scroll down by precisely one row. However, if you click the right-arrow on the horizontal scroll-bar, you do not move to the right by one column- you just move to the right some fixed amount of pixels. I would like to click the right-arrow and scroll to the right by one column. Similarly, if the user clicks and drags the horizontal scrollbar, I would like the scrolling to only scroll by column increments, not by pixel increments.

Is it possible to set the WPF Datagrid so that horizontal scrolling is done by column, not by pixel?

EDIT: I would also like for the user to be able to scroll horizontally by clicking and dragging the thumb, similarly to the way that vertical scrolling would work by row.

1

1 Answers

1
votes

One solution would be to handle the ScrollViewer.ScrollChanged event...

<DataGrid x:Name="myGrid" ScrollViewer.ScrollChanged="dg_ScrollChanged"/>

and programmatically scroll to the next column offset, like this:

    private void dg_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (e.HorizontalChange != 0) // horizontal scroll
        {
            if (e.OriginalSource is ScrollViewer)
            {
                // scoll to column offset
                ScrollViewer sv = e.OriginalSource as ScrollViewer;
                sv.ScrollToHorizontalOffset(GetColumnOffset(e.HorizontalChange > 0, sv.HorizontalOffset - e.HorizontalChange, sv.ScrollableWidth));
                e.Handled = true;
            }
        }
    }

You'll have to write the 'GetColumnOffset' method. Here's a quick and dirty implementation I threw together. You could probably make it cleaner, and I didn't run a thorough test so it could contain errors:

    private double GetColumnOffset(bool forward, double currentPos, double maxOffset)
    {
        ObservableCollection<DataGridColumn> Columns = myGrid.Columns;
        double columnPosition = 0;
        double maxColumnPosition = 0;
        double maxColumnIndex = 0;
        foreach (var column in Columns)
        {
            columnPosition += column.ActualWidth;
            if (columnPosition < maxOffset)
            {
                maxColumnPosition = columnPosition;
                maxColumnIndex = Columns.IndexOf(column);
            }
            if (forward && columnPosition > currentPos)
            {
                return columnPosition;
            }
        }

        if (!forward)
        {
            columnPosition = maxColumnPosition;
            if (maxColumnPosition < currentPos)
            {
                return maxColumnPosition;
            }
            foreach (var column in Columns.Reverse())
            {
                if (Columns.IndexOf(column) <= maxColumnIndex)
                {
                    columnPosition -= column.ActualWidth;
                    if (columnPosition < currentPos)
                    {
                        return columnPosition;
                    }
                }
            }
        }

        return 0;
    }