C# - Ctrl ボタンを使用してデータグリッドをスクロールする

okwaves2024-01-25  9

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 を使いたくありません。

異なるスクロール動作が必要な理由は、データ グリッドとヘッダー領域の間に大きなユーザー コントロールがあるためです。これはページの分割図です。

質問を編集しました。もう私の言うことが分かりましたか?

– BuBBles2904

2020 年 9 月 3 日 9:25

ありがとうございます。次に、2 つの ScrollViewer が必要になります。1 つはコンテンツとしてページを持ち、もう 1 つはコンテンツとして DataGrid を持ちます。デフォルトでは、直接マウスオーバー入力を受信した ScrollViewer が優先されます。マウスオーバーの制約なしでスクロールできるようにすることが目的の場合は、マウス入力を処理する必要があります。d 両方のコントロールの共通の親でビューアをスクロールします。これを含む UserControl。完全なコンテキスト (スクロール ビューアとその親の両方) を示していただけますか?

– バイオニックコード

2020 年 9 月 3 日 9:29

ページのコードとウィンドウのコードを追加しました。

– BuBBles2904

2020 年 9 月 3 日 9:42

DataGrid をスクロールしてもよろしいですか?表示されていない場合、つまり以前にスクロールされて表示されなくなった場合。ユーザーの観点から見ると、望ましい動作は何の価値も追加しない可能性があります。なぜ彼はデフォルトのスクロール動作を次のように変更したいのでしょうか。スクロール バーを直接ドラッグしますか、それとも通常どおりマウス ホイールを使用しますか?あなたのアプリケーションを使用していて、DataGrid をスクロールしたいのに、代わりにページ全体をスクロールする場合、これは非常に煩わしく、邪魔になると思います。ユーザー エクスペリエンスに大幅な価値を追加しない限り、既知の受け入れられている/予期されるデフォルトの動作をそのままにしておく必要があります。

– バイオニックコード

2020 年 9 月 3 日 9:42

実際には、境界線とデータグリッドの間に、いくつかのテキスト ボックスを持つユーザー コントロールを含む別のグリッドがあります。このグリッドには多くのスペースが必要です。

– BuBBles2904

2020 年 9 月 3 日 9:46



------------------------

参加している ScrollViewer の両方またはすべての共通の親によって PreviewMouseWheel イベントを処理する必要があります。

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 
      && !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;
}

5

コンテンツのスクロール ビューアとデータグリッドは同じ xaml 内にありません。どうすれば入手できますか?

– BuBBles2904

2020 年 9 月 3 日 11:30

TryFindVisualChildElement メソッドを使用します。上記のコードを参照して、親 (この例では DataGridToScrollOnKeyPress) をメイン スクロール ビューアのインスタンスに置き換えます。これにより、DataGrid が見つかり、ScrollViewer にドリルダウンされるはずです。

– バイオニックコード

2020 年 9 月 3 日 11:49

例 (OnLoaded() と TryFindVisualChildElement()) を更新しました。 DataGrid の名前を調整するだけです。

– バイオニックコード

2020 年 9 月 3 日 15:12

取得しようとするとデータグリッドからのスクロールビューアは null を返します。いくつかのデバッグの後、VisualTreeHelper.GetChild(dataGrid, i) が 0 を返すことがわかりました。

– BuBBles2904

2020 年 9 月 4 日 5:53

ビジュアル ツリーにアクセスする前に、DatGrid がロードされていることが重要です。 DataGridScrollViewer プロパティを静的にすることができます。次に、Loaded イベント ハンドラーを DataGrid にアタッチし、上記の TryFindVisualChildElement を使用して ScrollViewer を取得し、それを静的 DataGridScrollViewer に割り当てます。DataGridScrollViewer にアクセスする前に、HandleScroll_OnPreviewMouseWheel に NULL チェックを追加することをお勧めします: 例: DataGridScrollViewer?...LineDown();

– バイオニックコード

2020 年 9 月 4 日 10:14

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。