Search code examples
c#wpfdatagridscrollviewer

WPF DataGrid inside a ScrollViewer


I have a StackPanel with a header control and a DataGrid Inside a Scrollviewer; like so:

<ScrollViewer>
    <StackPanel Orientation="Vertical">
        <Canvas x:Name="header" 
                Height="300" />
        <DataGrid x:Name="dataGrid">
        </DataGrid>
    </StackPanel>
</ScrollViewer>

The scoll behavior should fulfill these requirements:

  • Scrolling while MouseOver the DataGrid should scroll the outer ScrollViewer
  • The header control (symbolized by Canvas) is scrolled by the ScollViewer.

  • The horizontal scrollbar at the bottom of the DataGrid should be preserved on screen at any time.

  • The horizontal scrollbar should not scroll the header control, only the DataGrid.

I tried various settings for the DataGrid.ScrollViewer but none have the desired effect, nor does changing the StackPanel to a WrapPanel or even Grid help any.

Is this possible? Any help and resources to read are appreciated.


Solution

  • I've been struggling with your first problem for some time as well - having an inner ScrollViewer (or DataGrid in this case) scroll the outer ScrollViewer. But I think I have a pretty elegant solution. You have to add an event handler to the PreviewMouseWheel event of the DataGrid (and a name to the ScrollViewer):

    <ScrollViewer x:Name="scroll_viewer">
        <StackPanel Orientation="Vertical">
            <Canvas x:Name="header" 
                    Height="300" />
            <DataGrid x:Name="dataGrid" PreviewMouseWheel="mousewheel">
            </DataGrid>
        </StackPanel>
    </ScrollViewer>
    

    Then the event handling method:

    private void mousewheel(object sender, MouseWheelEventArgs e)
    {
        //what we're doing here, is that we're invoking the "MouseWheel" event of the parent ScrollViewer.
    
        //first, we make the object with the event arguments (using the values from the current event)
        var args = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
    
        //then we need to set the event that we're invoking.
        //the ScrollViewer control internally does the scrolling on MouseWheelEvent, so that's what we're going to use:
        args.RoutedEvent = ScrollViewer.MouseWheelEvent;
    
        //and finally, we raise the event on the parent ScrollViewer.
        scroll_viewer.RaiseEvent(args);
    }
    

    Hope this helps!