wpf DataGrid RowDetailsTemplate Scroll

时间:2014-05-07 17:17:53

标签: wpf xaml wpfdatagrid

<DataGrid>
  <DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding Path=test}"></DataGridTextColumn>
  </DataGrid.Columns>
  <DataGrid.RowDetailsTemplate>
    <DataTemplate>
     <DataGrid Template="{DynamicResource TemplateDataGridPrintAndExport}"/>
    </DataTemplate>
  </DataGrid.RowDetailsTemplate>
 <DataGrid/>

我有一个像上面这样的数据网格。 Datgrid的行详细信息模板还包含数据网格。单击父级列时,将填充内部数据网格。我的问题是:如果行详细信息模板datagrid已完成并且用户鼠标悬停在其上,同时滚动父数据网格则滚动不起作用。用户应将鼠标悬停在主数据栏上以进行滚动。但是,它不是用户友好的。如何防止内部数据网格以这种方式运行?

5 个答案:

答案 0 :(得分:5)

我通过尝试替代方案找到了灵魂:

<DataGrid  ScrollViewer.CanContentScroll="False">
  <DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding Path=test}"></DataGridTextColumn>
  </DataGrid.Columns>
  <DataGrid.RowDetailsTemplate>
    <DataTemplate>
     <DataGrid Template="{DynamicResource TemplateDataGridPrintAndExport}"  IsReadOnly="True" ScrollViewer.CanContentScroll="False"  IsEnabled="False"/>
    </DataTemplate>
  </DataGrid.RowDetailsTemplate>
 <DataGrid/>

解决方案是将ScrollViewer.CanContentScroll="False"属性赋予外部数据网格,将IsReadOnly="True" ScrollViewer.CanContentScroll="False" IsEnabled="False"属性赋予内部数据网格。现在它顺利滚动并符合父数据网格。

答案 1 :(得分:3)

如果您使用的是.NET 4.5及更高版本,则可以在外部网格上使用VirtualizingPanel.ScrollUnit="Pixel",这将使您可以按像素而不是单位(项)滚动,因为在滚动时,这会导致相当奇怪的行为内部DataGrid,因为它开始跳来跳去。

然后,您可以使用内部DataGrid上的PreviewMouseWheel事件将滚动事件传递给父级,因为它是由内部控件捕获的。

Xaml:

<DataGrid VirtualizingPanel.ScrollUnit="Pixel">
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <DataGrid PreviewMouseWheel="DataGrid_PreviewMouseWheel"/>
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
</DataGrid>

cs:

private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    e.Handled = true;
    var parent = ((Control)sender).Parent as UIElement;
    parent?.RaiseEvent(new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
    {
        RoutedEvent = MouseWheelEvent,
        Source = sender
    });
}

答案 2 :(得分:1)

我想提出两种替代解决方案,因为选择的一种具有严重的副作用。 Kaizen提到的其中之一-您失去了与嵌套DataGrid及其子控件进行交互的能力。第二个是控件在禁用状态下的外观变化。

  1. 在osmanraifgunes的解决方案中将IsReadOnly="True"更改为IsHitTestVisible="False"。这样可以解决外观方面的副作用,但是您仍然无法与内部控件进行交互(使用鼠标)。代码:

    <DataGrid ScrollViewer.CanContentScroll="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=test}" />
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid
                    IsHitTestVisible="False"
                    ScrollViewer.CanContentScroll="False"
                    Template="{DynamicResource TemplateDataGridPrintAndExport}" />
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
    
  2. PreviewMouseWheel中的控件中捕获隧道RowDetailsTemplate事件,并将其作为冒泡事件传递回父级。这将有效地使RowDetailsTemplate中的控件仅对鼠标滚动不可见,并允许可视树中上方的控件按其意愿对其进行处理。 xaml:

    <DataGrid ScrollViewer.CanContentScroll="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Path=test}" />
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid
                    PreviewMouseWheel="DataGrid_PreviewMouseWheel"
                    Template="{DynamicResource TemplateDataGridPrintAndExport}" />
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
    

    后面的代码:

    private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        if (e.Handled)
        {
            return;
        }
        Control control = sender as Control;
        if(control == null)
        {
            return;
        }
        e.Handled = true;
        var wheelArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
        {
            RoutedEvent = MouseWheelEvent,
            Source = control
        };
        var parent = control.Parent as UIElement;
        parent?.RaiseEvent(wheelArgs);
    }
    

答案 3 :(得分:1)

我使用了@Bartłomiej Popielarz的第二种方法来使其工作。

就我而言,control.Parent总是返回null。这就是为什么我将相应行更改为

的原因
    var parent = VisualTreeHelper.GetParent(control) as UIElement;

我还创建了一个附加的属性来进行转发(更适合MVVM方法)。

    public class FixScrollingBehaviorOn
    {
        public static readonly DependencyProperty ParentDataGridProperty = DependencyProperty.RegisterAttached("ParentDataGrid", typeof(DataGrid), typeof(FixScrollingBehaviorOn),
            new FrameworkPropertyMetadata(default(DataGrid), OnParentDataGridPropertyChanged));

        public static bool GetParentDataGrid(DependencyObject obj)

        {
            return (bool)obj.GetValue(ParentDataGridProperty);
        }

        public static void SetParentDataGrid(DependencyObject obj, bool value)

        {
            obj.SetValue(ParentDataGridProperty, value);
        }

        public static void OnParentDataGridPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)

        {
            var dataGrid = sender as DataGrid;

            if (dataGrid == null)

            {
                throw new ArgumentException("The dependency property can only be attached to a DataGrid", "sender");
            }

            if (e.NewValue is DataGrid parentGrid)
            {
                dataGrid.PreviewMouseWheel += HandlePreviewMouseWheel;
                parentGrid.SetValue(ScrollViewer.CanContentScrollProperty, false);
            }
            else
            {
                dataGrid.PreviewMouseWheel -= HandlePreviewMouseWheel;

                if (e.OldValue is DataGrid oldParentGrid)
                {
                    oldParentGrid.SetValue(ScrollViewer.CanContentScrollProperty, ScrollViewer.CanContentScrollProperty.DefaultMetadata.DefaultValue);
                }
            }
        }

        private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e)

        {
            if (e.Handled)
            {
                return;
            }
            var control = sender as DataGrid;
            if (control == null)
            {
                return;
            }
            e.Handled = true;
            var wheelArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
            {
                RoutedEvent = UIElement.MouseWheelEvent,
                Source = control
            };
            var parent = VisualTreeHelper.GetParent(control) as UIElement;
            parent?.RaiseEvent(wheelArgs);
        }

请按照以下说明在内部DataGrid上随意使用它。请注意,ScrollViewer.CanContentScrollProperty是在AttachedProperty中设置的,可能不是每个人都喜欢的方法。

<DataGrid>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=test}" />
    </DataGrid.Columns>
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <DataGrid
                attachedProperties:FixScrollingBehaviorOn.ParentDataGrid="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
                Template="{DynamicResource TemplateDataGridPrintAndExport}" />
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
</DataGrid>

答案 4 :(得分:0)

Xaml:

<DataGrid ScrollViewer.CanContentScroll="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Path=test}" />
    </DataGrid.Columns>
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <DataGrid
                PreviewMouseWheel="DataGrid_PreviewMouseWheel"
                Template="{DynamicResource TemplateDataGridPrintAndExport}" />
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
</DataGrid>

后面的代码:

private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
  DataGrid dg = new DataGrid();
            if (sender is DataGrid)
            {
                dg = (DataGrid)sender;
            }
            dg.IsEnabled = false;
            await Task.Delay(200);
            dg.IsEnabled = true;
}