Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF-嵌套在Expander中的DataGrid无滚动DataGrid内容_C#_Wpf_Datagrid_Expander - Fatal编程技术网

C# WPF-嵌套在Expander中的DataGrid无滚动DataGrid内容

C# WPF-嵌套在Expander中的DataGrid无滚动DataGrid内容,c#,wpf,datagrid,expander,C#,Wpf,Datagrid,Expander,我在WPF应用程序上安装了带有嵌套DataGrid的Expander,它创建用户控件。我在codebehind上为数据(来自数据库)列表中的每个元素创建此控件。最后,我有一个列表,其中每个元素都用嵌套的DataGrid进行了扩展。当我开发项目时,我会看到DataDrid,但是当我开发许多组件时,我必须滚动内容。当光标位于扩展器上时,元素滚动工作,但当我将鼠标悬停在DataGrid上时,滚动不工作 示例代码: <ScrollViewer HorizontalAlignment="Left"&

我在WPF应用程序上安装了带有嵌套DataGrid的Expander,它创建用户控件。我在codebehind上为数据(来自数据库)列表中的每个元素创建此控件。最后,我有一个列表,其中每个元素都用嵌套的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>

//和mor扩展器,从codebehind添加
最后,网格:


当鼠标位于绿色环向右滚动的位置时,会发生这种情况,因为
DataGrid
本身可能包含一个
ScrollViewer
,当您拥有的项目超过给定高度时,将出现该视图。在这些情况下,您需要允许
DataGrid
首先尝试处理滚动事件,如果它不知道如何处理,例如,当您尝试向下滚动时,同时已经在底部,请将滚动事件传递给其父级

现在,看起来您的
DataGrid
s实际上是不可滚动的,这意味着以下内容可能有点过火,但通过对鼠标滚轮处理程序进行以下修改,可以获得实现上述功能的通用解决方案:

/// <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);
    }
}

信用:该解决方案在某种程度上基于/受上述解决方案的启发,但它将其功能限制为
DataGrid
(因为根据我的经验,它将破坏一系列其他不准备隧道其事件的控件).

之所以会发生这种情况,是因为
数据网格本身可能包含一个
ScrollViewer
,当您拥有的项目超过给定高度时,就会显示该滚动查看器。在这些情况下,您需要允许
DataGrid
首先尝试处理滚动事件,如果它不知道如何处理,例如,当您尝试向下滚动时,同时已经在底部,请将滚动事件传递给其父级

现在,看起来您的
DataGrid
s实际上是不可滚动的,这意味着以下内容可能有点过火,但通过对鼠标滚轮处理程序进行以下修改,可以获得实现上述功能的通用解决方案:

/// <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);
    }
}

信用:这个解决方案在某种程度上是基于上面提到的一个,但它将其功能限制在
DataGrid
(因为根据我的经验,它将打破一堆其他控件,而这些控件不准备将它们的事件隧道化)。

这太棒了。你提供的代码和博客链接解决了我的问题,太棒了。你提供的代码和博客链接解决了我的问题