DataGrids over ScrollViewer prevent it to scroll

妖精的绣舞 提交于 2019-12-10 18:53:27

问题


I have multiples DataGrids disposed over a ScrollViewer. These DataGrids have an "height: auto" property so that I can hide the scrollbar and view all the content. The only problem is that the DataGrids takes the focus and so I can't scroll the ScrollViewer. Is that a property to keep the focus on the ScrollViewer but also keeping the behaviour of the DataGrids (so I can select elements) ?

Thank you !


回答1:


I ran across this exact same issue except my scenario was a little bit more complicated. Instead of having DataGrid in a ScrollViewer, I had a bunch of UserControl (called ProductDataGrid and defined below) in my ScrollViewer:

ProductDataGrid.xaml:

<UserControl x:Class="My.Control.ProductDataGrid" ...>
    <Grid>
        <Grid.RowDefinitions>...</Grid.RowDefinitions>

        <TextBlock x:Name="Header" Grid.Row="0" ... />

        <DataGrid x:Name="ProductData" Grid.Row="1" ... />
    </Grid>
</UserControl>

ProductPortfolioListView.xaml:

<Page ...
      xmlns:my="clr-namespace:My.Control"
      ....>
    <Grid>
        <Grid.RowDefinitions>...</Grid.RowDefinitions>

        <ScrollViewer x:Name="ProductScrollViewer">
            <StackPanel>
                <my:ProductDataGrid ... />

                <my:ProductDataGrid ... />

                <my:ProductDataGrid ... />
            </StackPanel>
        </ScrollViewer>

The solution provided by Livsi is spot on correct but my UserControl did not have access to my ScrollViewer, so here is my solution:

ProductPortfolioListView.xaml:

<Page ...
      xmlns:my="clr-namespace:My.Control"
      ....>
    <Grid>
        <Grid.RowDefinitions>...</Grid.RowDefinitions>

        <ScrollViewer x:Name="ProductScrollViewer">
            <StackPanel>
                <my:ProductDataGrid ... 
                        PreviewMouseWheel="ProductDataGrid_PreviewMouseWheel" />

                <my:ProductDataGrid ... 
                        PreviewMouseWheel="ProductDataGrid_PreviewMouseWheel" />

                <my:ProductDataGrid ... 
                        PreviewMouseWheel="ProductDataGrid_PreviewMouseWheel" />
            </StackPanel>
        </ScrollViewer>

ProductPortfolioListView.xaml.cs:

void ProductDataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs args)
{
    ProductScrollViewer.ScrollToVerticalOffset(ProductScrollViewer.ContentVerticalOffset - args.Delta;
    args.Handled = true;
}

Note the beauty of this solution lies in the fact that I can separate my DataGrid from the Page that will hold them, so I achieve code isolation as well as less duplicated code. And even better, I absolutely utilize the fact that RoutedEvents keep propragating from the Source to all of its parents until someone handles it (which in my case is my ProductScrollViewer).




回答2:


It's to late, but I resolved this problem in this manner: I created the PreviewMouseWheel event for DataGrid and manually scrolled the wrapping ScrollViewer

private void dgInvoicesItems_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
this.scrInvoice.ScrollToVerticalOffset(this.scrInvoice.ContentVerticalOffset - e.Delta);
}



回答3:


TopMouseScrollPriorityBehavior.TopMouseScrollPriority

You can simply set the following Attached Property to your ScrollViewer

public class TopMouseScrollPriorityBehavior
{
    public static bool GetTopMouseScrollPriority(DependencyObject obj)
    {
        return (bool)obj.GetValue(TopMouseScrollPriorityProperty);
    }

    public static void SetTopMouseScrollPriority(DependencyObject obj, bool value)
    {
        obj.SetValue(TopMouseScrollPriorityProperty, value);
    }

    public static readonly DependencyProperty TopMouseScrollPriorityProperty =
        DependencyProperty.RegisterAttached("TopMouseScrollPriority", typeof(bool), typeof(TopMouseScrollPriorityBehavior), new PropertyMetadata(false, OnPropertyChanged));

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;
        if (scrollViewer == null)
            throw new InvalidOperationException($"{nameof(TopMouseScrollPriorityBehavior)}.{nameof(TopMouseScrollPriorityProperty)} can only be applied to controls of type {nameof(ScrollViewer)}");
        if (e.NewValue == e.OldValue)
            return;
        if ((bool)e.NewValue)
            scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
        else
            scrollViewer.PreviewMouseWheel -= ScrollViewer_PreviewMouseWheel;
    }

    private static void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
    {
        var scrollViewer = (ScrollViewer)sender;
        scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
        e.Handled = true;
    }
}

Usage

<ScrollViewer b:TopMouseScrollPriorityBehavior.TopMouseScrollPriority="True" VerticalScrollBarVisibility="Auto" Margin="5" PanningMode="VerticalFirst">
    <DataGrid ScrollViewer.PanningMode="None" ItemsSource="{Binding Items}" />
</ScrollViewer>

Where b: is the namespace that contains this behavior

Touch Support

To enable touch support you might also want to set ScrollViewer.PanningMode to None on your DataGrid and set the same property to VerticalFirst or other value on your top level ScrollViewer

Example

<ScrollViewer VerticalScrollBarVisibility="Auto" Margin="5" PanningMode="VerticalFirst">
    <DataGrid ScrollViewer.PanningMode="None" ItemsSource="{Binding Items}" />
</ScrollViewer>



回答4:


Try setting the CanContentScroll on the DataGrid to False like this:

<DataGrid ScrollViewer.CanContentScroll="False" ... />


来源:https://stackoverflow.com/questions/6186083/datagrids-over-scrollviewer-prevent-it-to-scroll

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!