C# 使用ctrl按钮在数据网格上滚动

C# 使用ctrl按钮在数据网格上滚动,c#,wpf,mvvm,datagrid,C#,Wpf,Mvvm,Datagrid,我希望我的datagrid仅在您同时按下ctrl键时使用鼠标滚轮滚动,否则我希望滚动页面。 我不熟悉wpf和mvvm,这是我在应用程序中使用的模式 这是包含datagrid的页面: <Page x:Class="Projectname.ChapterPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http

我希望我的datagrid仅在您同时按下ctrl键时使用鼠标滚轮滚动,否则我希望滚动页面。 我不熟悉wpf和mvvm,这是我在应用程序中使用的模式

这是包含datagrid的页面:

<Page x:Class="Projectname.ChapterPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup- 
      compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:Projectname" 
      xmlns:core="clr-namespace:Projectname.Core;assembly=Projectname.Core"
      mc:Ignorable="d" 
      d:DesignHeight="700" d:DesignWidth="900"
      Title="ChapterPage">

    <StackPanel>

        <TextBlock Grid.Column="0"
                           Grid.ColumnSpan="2"
                           Text="Kapitel"
                           Style="{StaticResource HeaderText}" 
                           Foreground="{StaticResource 
                           ForegroundVeryLightBrush}"
                           FontSize="{StaticResource FontSizeLarge}"
                           FontWeight="Bold"
                           Margin="50 -45 50 15"/>

        <Border Background="{StaticResource BlueBrush}"
                CornerRadius="10"
                Margin="10"
                MinHeight="45"
                Padding="2">

            <StackPanel HorizontalAlignment="Center"
                      Orientation="Horizontal">

                <Button Command="{Binding SaveCommand}"
                    Style="{StaticResource IconGrowButton}"
                    ToolTip="Speichern"
                    Margin="10 0"
                    MaxHeight="30"
                    MinWidth="30"
                    Cursor="Hand">
                    <Image Source="../Images/Icons/Save.png" />
                </Button>

                <Button Command="{Binding DeleteCommand}"
                    Style="{StaticResource IconGrowButton}"
                    ToolTip="Löschen"
                    MaxHeight="30"
                    MinWidth="30"
                    Margin="10 0 80 0"
                    Cursor="Hand">
                    <Image Source="../Images/Icons/Delete.png" />
                </Button>

                <Button Command="{Binding ResetCommand}"
                    Style="{StaticResource IconGrowButton}"
                    ToolTip="Zurücksetzen"
                    MaxHeight="30"
                    MinWidth="30"
                    Margin="10 0"
                    Cursor="Hand">
                    <Image Source="../Images/Icons/Reset.png" />
                </Button>

            </StackPanel>

        </Border>

        <DataGrid Margin="15 10"
                  HorizontalAlignment="Stretch"
                  ItemsSource="{Binding Chapters, 
                      UpdateSourceTrigger=PropertyChanged}"
                  Visibility="{Binding ChaptersVisibility, 
                      Converter={local:BooleanToVisibilityConverter}}"
                  SelectedItem="{Binding SelectedChapter}"/>

    </StackPanel>
</Page>

我的页面被加载到窗口中,滚动内容的scrollviewer位于窗口中

这是窗口:

        <Grid>

            <StackPanel>

                <Grid>

                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>

                    <Border Background="{StaticResource RedBrush}">
                        <Button Command="{Binding NavMenuCommand}"
                            Style="{StaticResource SystemIconButton}"
                            Cursor="Hand"
                            HorizontalAlignment="Left">
                            <Button.Content>
                                <Image Source="../Images/Icons/burger- 
                                    menue.png"
                                Height="25"/>
                            </Button.Content>
                        </Button>
                    </Border>

                </Grid>

                <local:ChapterPage
                       Padding="8 0"/>

            </StackPanel>

            <local:NavMenu Margin="0,41,628,0"/>

        </Grid>
    </ScrollViewer>


我完全不知道如何实现这一点,但如果可以避免的话,我不想使用xaml.cs


您需要由两个或所有参与的
ScrollViewer的公共父级处理
PreviewMouseWheel
事件:

main window.xaml
简化视图:

<Window PreviewMouseWheel="HandleScroll_OnPreviewMouseWheel">
  <ScrollViewer x:Name="RootScrollViewer">
    <DataGrid x:Name="DataGridToScrollOnKeyPress" />
  </ScrollViewer>
</Window>

MainWindow.xaml.cs

private ScrollViewer DataGridScrollViewer { get; set; }

private void OnLoaded(object sender, RoutedEventArgs e)
{
  // Find DataGrid by name (in case of multiple DataGrids)
  if (TryFindVisualChildElement(this.Root, "DataGridToScrollOnKeyPress", out DataGrid dataGrid))
  { 
    // And get its ScrollViewer (by type)
    if (TryFindVisualChildElement(dataGrid, string.Empty, out ScrollViewer scrollViewer))
    {
      this.DataGridScrollViewer = scrollViewer;
    }
  }
}

private void HandleScroll_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
  // Give the main scroll viewer chance to handle its own scroll,
  // if it is the scroll source (preserve default behavior)
  if (e.Source == this.Root 
      && !Keyboard.IsKeyDown(Key.LeftCtrl) 
      && !Keyboard.IsKeyDown(Key.RightCtrl))
  {
    return;
  }

  e.Handled = true;
  if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
  {
    if (e.Delta < 0)
    {
      this.DataGridScrollViewer?.LineDown();
    }
    else
    {
      this.DataGridScrollViewer?.LineUp();
    }
  }
  else // Some other control is scroll source => scroll main scroll viewer
  {
    if (e.Delta < 0)
    {
      this.RootScrollViewer.LineDown();
    }
    else
    {
      this.RootScrollViewer.LineUp();
    }
  }
}

// If the 'childElementName' parameter is NULL, an empty string or whitespace it will be ignored (only the type will be relevant)
public bool TryFindVisualChildElement<TChild>(DependencyObject parent, string childElementName, out TChild childElement)
  where TChild : FrameworkElement
{
  childElement = null;
  if (parent == null)
  {
    return false;
  }

  for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
  {
    DependencyObject child = VisualTreeHelper.GetChild(parent, i);
    if (child is TChild resultElement 
        && (string.IsNullOrWhiteSpace(childElementName) || resultElement.Name.Equals(childElementName, StringComparison.Ordinal)))
    {
      childElement = resultElement;
      return true;
    }

    if (TryFindVisualChildElement(child, childElementName, out childElement))
    {
      return true;
    }
  }

  return false;
}
private ScrollViewer DataGridScrollViewer{get;set;}
已加载专用void(对象发送方,RoutedEventArgs e)
{
//按名称查找数据网格(如果有多个数据网格)
if(TryFindVisualChildElement(this.Root,“DataGridtoCrollonkeyPress”,out DataGrid DataGrid))
{ 
//并获取其ScrollViewer(按类型)
if(TryFindVisualChildElement(dataGrid,string.Empty,out ScrollViewer))
{
this.DataGridScrollViewer=scrollViewer;
}
}
}
私有void HandleScroll_OnPreviewMouseWheel(对象发送器,MouseWheelEventArgs e)
{
//让主卷轴查看器有机会处理自己的卷轴,
//如果是滚动源(保留默认行为)
如果(e.Source==this.Root
&&!Keyboard.IsKeyDown(Key.LeftCtrl)
&&!Keyboard.IsKeyDown(Key.RightCtrl))
{
返回;
}
e、 已处理=正确;
if(Keyboard.IsKeyDown(Key.LeftCtrl)| | Keyboard.IsKeyDown(Key.RightCtrl))
{
如果(e.Delta<0)
{
这个.DataGridScrollViewer?.LineDown();
}
其他的
{
这个.DataGridScrollViewer?.LineUp();
}
}
else//其他控件是scroll source=>scroll主滚动查看器
{
如果(e.Delta<0)
{
this.RootScrollViewer.LineDown();
}
其他的
{
this.RootScrollViewer.LineUp();
}
}
}
//如果'childElementName'参数为NULL,则将忽略它的空字符串或空白(只有类型相关)
public bool TryFindVisualChildElement(DependencyObject父对象、字符串childElementName、out TChild childElement)
其中TChild:FrameworkElement
{
childElement=null;
如果(父项==null)
{
返回false;
}
for(int i=0;i
我编辑了我的问题。你现在明白我的意思了吗?谢谢。然后必须有两个
ScrollViewer
:一个以页面为内容,当然还有一个以
DataGrid
为内容。默认情况下,将鼠标直接放在输入接收上的
ScrollViewer
具有优先权。如果目标是允许在没有鼠标悬停约束的情况下滚动,则必须在两个控件的公共父控件(例如,包含
UserControl
)上处理鼠标输入和滚动查看器。能否显示完整的上下文(滚动查看器及其父级)?我添加了页面代码和窗口代码。是否确实要滚动
DataGrid
,即使它不在可见位置,即之前已从视图中滚动出去。从用户的角度来看,您想要的行为可能不会增加任何价值。他为什么要将默认滚动行为更改为直接拖动滚动条或像往常一样使用鼠标滚轮?如果我使用你的应用程序和广域网来滚动
DataGrid
,而不是滚动整个页面,我会发现这非常烦人和令人不安。除非显著增加用户体验的价值,否则应该保留已知和接受/预期的默认行为。实际上,在边界和datagrid之间,还有另一个网格包含一个带有多个文本框的usercontrol。该网格需要大量空间。内容的滚动查看器和数据网格不在同一xaml中。我如何获得它?您使用TryFindVisualChildElement方法。请参阅上面的代码,并用主滚动查看器实例替换父对象(在示例中为DataGridToScrollOnKeyPress)。这应该可以找到DataGrid并深入到ScrollViewer。我已经更新了示例(
onload()
TryFindVisualChildElement()
)。您只需调整
数据网格的名称即可。当我尝试从数据网格获取scrollviewer时,它返回null。经过一些调试后,我发现VisualTreeHelper.GetChild(dataGrid,I)返回0在访问其可视化树之前加载
DatGrid
非常重要。您可以使
DataGridScrollViewer
属性
static
。然后将加载的
事件处理程序附加到
DataGrid
并使用
tryFindVisualChillem