Прокрутка сетки данных с помощью кнопки ctrl

#c# #wpf #mvvm #datagrid

#c# #wpf #mvvm #сетка данных

Вопрос:

Я хочу, чтобы моя сетка данных прокручивалась только колесом мыши, когда вы одновременно нажимаете клавишу ctrl, иначе я хочу прокрутить страницу. Я новичок в wpf и mvvm, которые я использую в своем приложении.

Это страница, содержащая сетку данных:

 <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>
  

Моя страница загружена в окно, а средство просмотра прокрутки содержимого находится в окне.

Это окно:

         <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, если я могу этого избежать.

Причина, по которой я хочу другое поведение прокрутки, заключается в том, что существует большой пользовательский контроль между сеткой данных и областью заголовка. Вот изображение разделения страницы.

Комментарии:

1. Я отредактировал свой вопрос. Теперь ты меня понимаешь?

2. Спасибо. Затем у вас должно быть два ScrollViewer : один со страницей в качестве содержимого и, конечно, один с DataGrid содержимым. По умолчанию ScrollViewer при наведении курсора мыши на ввод имеет приоритет. Если цель состоит в том, чтобы разрешить прокрутку без ограничения наведения курсора мыши, тогда вы должны обрабатывать средства просмотра ввода с помощью мыши и прокрутки на общем родительском элементе обоих элементов управления, например, содержащем UserControl . Не могли бы вы, пожалуйста, показать полный контекст (как средства просмотра прокрутки, так и их родительский элемент)?

3. Я добавил код страницы и код окна.

4. Вы действительно хотите прокручивать DataGrid , даже если это не видно, т. Е. Ранее прокручивалось вне поля зрения. С точки зрения пользователя ваше желаемое поведение может не добавить никакого значения. Почему он хотел бы изменить свое поведение прокрутки по умолчанию, например, перетащить полосу прокрутки напрямую или использовать колесо мыши, как обычно? Если бы я использовал ваше приложение и глобальную сеть для прокрутки DataGrid , но вместо этого я прокручиваю всю страницу, я бы счел это довольно раздражающим и тревожным. Вы должны оставить известное и принятое / ожидаемое поведение по умолчанию, если вы значительно не добавите больше ценности для пользовательского интерфейса.

5. На самом деле между границей и сеткой данных есть другая сетка, которая содержит пользовательский элемент управления с несколькими текстовыми полями. Для этой сетки требуется много места.

Ответ №1:

Вам необходимо обработать PreviewMouseWheel событие общим родителем обоих или всех участвующих ScrollViewer :

MainWindow.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 
      amp;amp; !Keyboard.IsKeyDown(Key.LeftCtrl) 
      amp;amp; !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 
        amp;amp; (string.IsNullOrWhiteSpace(childElementName) || resultElement.Name.Equals(childElementName, StringComparison.Ordinal)))
    {
      childElement = resultElement;
      return true;
    }

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

  return false;
}
  

Комментарии:

1. Средство просмотра содержимого прокрутки и сетка данных не находятся в одном и том же xaml. Как я могу это получить?

2. Вы используете метод TryFindVisualChildElement. Посмотрите приведенный выше код и замените родительский элемент (в примере это DataGridToScrollOnKeyPress) на основной экземпляр scroll viewer. Это должно найти сетку данных и перейти к ScrollViewer.

3. Я обновил пример ( OnLoaded() и TryFindVisualChildElement() ). Вам нужно только настроить имя DataGrid .

4. Когда я пытаюсь получить scrollviewer из datagrid, он возвращает null. После некоторой отладки я обнаружил, что VisualTreeHelper. getChild(DataGrid, i) возвращает 0

5. Важно, чтобы DatGrid была загружена до того, как вы сможете получить доступ к ее визуальному дереву. Вы можете создать DataGridScrollViewer свойство static . Затем прикрепите Loaded обработчик событий к DataGrid и используйте TryFindVisualChildElement сверху, чтобы получить ScrollViewer и назначить его статическому DataGridScrollViewer . Лучше добавить нулевую проверку HandleScroll_OnPreviewMouseWheel перед доступом к DataGridScrollViewer : например, DataGridScrollViewer?..LineDown();