WPF - 嵌套在Expander中的DataGrid没有滚动数据网格内容

时间:2017-09-10 09:48:58

标签: c# wpf datagrid expander

我在WPF应用程序上使用嵌套的 DataGrid Expander - 它创建了usercontrols。我在数据(来自数据库)列表中为每个元素的代码隐藏创建此控件。最后,我有一个列表,其中每个元素都是 Expadned ,带有嵌套的DataGrid。当我开发项目时,我看到DataDrid,但是当我开发许多组件时,我必须滚动内容。当光标位于扩展器上时,元素滚动有效但当我将鼠标悬停在DataGrid上时,滚动不起作用。

示例代码:

<ScrollViewer HorizontalAlignment="Left">
<DockPanel>
      <Expander x:Name="Expander1" Expanded="Expander1_Expanded">
        <Expander.Content>
            <DataGrid x:Name="DataGrid1" MouseLeftButtonUp="DataGrid1_MouseLeftButtonDown"  ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden" >        
                <DataGrid.CellStyle>
                    <Style TargetType="DataGridCell">
                        <Setter Property="BorderThickness" Value="0"/>
                    </Style>
                </DataGrid.CellStyle>
                <DataGrid.Columns>
                    <DataGridTextColumn Header="name1" Binding="{Binding Name}" IsReadOnly="True" />
                    <DataGridTextColumn Header="name2" Binding="{Binding Value}" IsReadOnly="True"/>
                    <DataGridTextColumn Header="name3" Binding="{Binding UnitName}" IsReadOnly="True"/>
                </DataGrid.Columns>
            </DataGrid>
        </Expander.Content>
        <Expander.Style>
            <Style TargetType="Expander">
                <Setter Property="IsExpanded" Value="False" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsExpanded, RelativeSource={RelativeSource Self}}" Value="True">
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Expander.Style>
    </Expander>

// and mor expander, added from codebehind 

</DockPanel>
</ScrollViewer>

最后网格:

enter image description here

当鼠标位于绿色环向右滚动的位置时

1 个答案:

答案 0 :(得分:2)

这是因为DataGrid本身可能包含ScrollViewer,当您拥有的项目多于给定高度内的项目时,会显示DataGrid。在这些情况下,您将希望允许DataGrid首先尝试处理滚动事件,如果它不知道如何处理它,例如当您尝试向下滚动时在底部,将滚动事件传递给其父级。

现在,看起来你的/// <summary> /// Helper for allowing scroll events to pass from a <see cref="DataGrid"/> to its parent. /// This ensures that a "scroll down" event occurring at an already scrolled-down /// <see cref="DataGrid"/> will be passed on to its parent, which might be able to handle /// it instead. /// </summary> public class DataGridScrollCorrector { public static bool GetFixScrolling(DependencyObject obj) => (bool)obj.GetValue(FixScrollingProperty); public static void SetFixScrolling(DependencyObject obj, bool value) => obj.SetValue(FixScrollingProperty, value); public static readonly DependencyProperty FixScrollingProperty = DependencyProperty.RegisterAttached("FixScrolling", typeof(bool), typeof(DataGridScrollCorrector), new FrameworkPropertyMetadata(false, OnFixScrollingPropertyChanged)); private static void OnFixScrollingPropertyChanged(object sender, DependencyPropertyChangedEventArgs e) { var grid = sender as DataGrid; if (grid == null) throw new ArgumentException("The dependency property can only be attached to a DataGrid", nameof(sender)); if ((bool)e.NewValue) grid.PreviewMouseWheel += HandlePreviewMouseWheel; else grid.PreviewMouseWheel -= HandlePreviewMouseWheel; } /// <summary> /// Finds the first child of a given type in a given <see cref="DependencyObject"/>. /// </summary> /// <typeparam name="T">The type of the child to search for.</typeparam> /// <param name="depObj">The object whose children we are interested in.</param> /// <returns>The child object.</returns> private static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject { if (depObj == null) return null; for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { DependencyObject child = VisualTreeHelper.GetChild(depObj, i); var visualChild = child as T; if (visualChild != null) return visualChild; var childItem = FindVisualChild<T>(child); if (childItem != null) return childItem; } return null; } /// <summary> /// Attempts to scroll the <see cref="ScrollViewer"/> in the <see cref="DataGrid"/>. /// If no scrolling occurs, pass the event to a parent. /// </summary> private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e) { var grid = sender as DataGrid; var viewer = FindVisualChild<ScrollViewer>(grid); if (viewer != null) { // We listen on changes to the ScrollViewer's scroll offset; if that changes // we can consider our event handled. In case the ScrollChanged event is never // raised, we take this to mean that we are at the top/bottom of our scroll viewer, // in which case we provide the event to our parent. ScrollChangedEventHandler handler = (senderScroll, eScroll) => e.Handled = true; viewer.ScrollChanged += handler; // Scroll +/- 3 rows depending on whether we are scrolling up or down. The // forced layout update is necessary to ensure that the event is called // immediately (as opposed to after some small delay). double oldOffset = viewer.VerticalOffset; double offsetDelta = e.Delta > 0 ? -3 : 3; viewer.ScrollToVerticalOffset(oldOffset + offsetDelta); viewer.UpdateLayout(); viewer.ScrollChanged -= handler; } if (e.Handled) return; e.Handled = true; var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) { RoutedEvent = UIElement.MouseWheelEvent, Source = sender }; var parent = ((Control)sender).Parent as UIElement; parent?.RaiseEvent(eventArg); } } 实际上不可滚动,这意味着以下可能有点矫枉过正,但是通过对鼠标滚轮处理程序引入以下修改来获得实现上述目标的一般解决方案:

3

此处,硬编码DataGrid是要在DataGrid中滚动的行数。然后,您可以将此校正器应用于所有相关的Application.Resources。例如,要在应用程序中的所有网格上使用它,您可以将其添加到App.xaml中的<Application x:Class="WpfApplication1.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" StartupUri="MainWindow.xaml"> <Application.Resources> <Style TargetType="DataGrid"> <Setter Property="local:DataGridScrollCorrector.FixScrolling" Value="True" /> </Style> </Application.Resources> </Application> ,如下所示:

DataGrid

信用:这个解决方案在某种程度上基于/ in this blog post的启发,但它将其功能限制为1(因为根据我的经验,它会破坏一堆其他控件#39;准​​备好挖掘他们的活动。)