如何禁用 FlipView 键盘按键而不在子控件上禁用它

How to disable FlipView keyboard keypress without disabling it on child control

故事,我在我的 window 中使用 MahApps.Metro FlipView,FlipView 包含一个 GridView,这工作得很好,但我有一个问题,我不能使用键盘箭头来在 GridView 单元格中导航,UpDown 箭头有效,但 LeftRight 箭头无效,当我按下它时,翻转视图会更改页面。

我尝试这样处理 OnPreviewKeyPress,

private void FlipView_PreviewKeyDown(object sender, KeyEventArgs e)
{
    e.Handled = true;
}

但是 GridView 也没有收到按键。

您尝试处理 PreviewKeyDown 的方向是正确的。诀窍是,您需要手动触发 DataGrid.

KeyDown 事件

这是适用于我的测试用例的实现:

private void UIElement_PreviewKeyDown(object sender, KeyEventArgs e)
{
    var dataGrid = FlipView.SelectedItem as DataGrid;
    if (dataGrid == null) return; // the selected item is not a DataGrid
    if (!dataGrid.SelectedCells.Any()) return; // no selected cells to move between
    // create a new event args to send to the DataGrid
    var args = new KeyEventArgs(
        Keyboard.PrimaryDevice,
        Keyboard.PrimaryDevice.ActiveSource,
        0,
        e.Key);
    args.RoutedEvent = Keyboard.KeyDownEvent; // get the event
    dataGrid.RaiseEvent(args); // raise the event
    e.Handled = true; // prevent the FlipView from going forward/backward
}

假设: 您只想抑制移动 FlipView forward/backward 的能力,当 (1) 所选项目是 DataGrid 和 (2) DataGrid 有一个或多个选定的单元格。 (否则,您希望箭头键像往常一样工作。)


这是我的测试用例的完整代码:

MainWindow.xaml.cs:

using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Input;

namespace Sandbox
{
    public partial class MainWindow
    {
        public List<Item> Items { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            Items = new List<Item>
            {
                new Item { Id = 1, Name = "First" },
                new Item { Id = 2, Name = "Second" },
                new Item { Id = 3, Name = "Third" },
                new Item { Id = 4, Name = "Fourth" },
            };
        }

        private void UIElement_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            var dataGrid = FlipView.SelectedItem as DataGrid;
            if (dataGrid == null) return;
            if (!dataGrid.SelectedCells.Any()) return;
            var args = new KeyEventArgs(
                Keyboard.PrimaryDevice,
                Keyboard.PrimaryDevice.ActiveSource,
                0,
                e.Key);
            args.RoutedEvent = Keyboard.KeyDownEvent;
            dataGrid.RaiseEvent(args);
            e.Handled = true;
        }

        public class Item
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }
}

MainWindow.xaml:

<Window x:Class="Sandbox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Sandbox"
        xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
        mc:Ignorable="d"
        Title="MainWindow"
        Width="525"
        Height="350">
    <controls:FlipView x:Name="FlipView"
                       Margin="0, 0, 10, 0"
                       Height="200"
                       IsBannerEnabled="True"
                       PreviewKeyDown="UIElement_PreviewKeyDown">
        <controls:FlipView.Items>
            <DataGrid ItemsSource="{Binding Items}"
                      AutoGenerateColumns="True" />
            <Rectangle Margin="0, 0, 10, 0"
                       Width="50"
                       Height="50"
                       Fill="Red" />
            <Rectangle Margin="0, 0, 10, 0"
                       Width="50"
                       Height="50"
                       Fill="Blue" />
        </controls:FlipView.Items>
    </controls:FlipView>
</Window>

如果您希望箭头在选择了最左边或最右边的单元格时起作用,请将 PreviewKeyDown 事件处理程序替换为:

private void UIElement_PreviewKeyDown(object sender, KeyEventArgs e)
{
    var dataGrid = FlipView.SelectedItem as DataGrid;
    if (dataGrid == null) return;
    if (!dataGrid.SelectedCells.Any()) return;

    // get the column index of the selected cell
    var columnIndex = dataGrid.SelectedCells.First().Column.DisplayIndex;

    // exit if the selected cell is left/right and the arrow is left/right
    if (columnIndex == 0 && e.Key == Key.Left ||
        columnIndex == dataGrid.Columns.Count - 1 && e.Key == Key.Right) return;

    var args = new KeyEventArgs(
        Keyboard.PrimaryDevice,
        Keyboard.PrimaryDevice.ActiveSource,
        0,
        e.Key);
    args.RoutedEvent = Keyboard.KeyDownEvent;
    dataGrid.RaiseEvent(args);
    e.Handled = true;
}

此外,DataGrid 的 XAML 应设置以下属性以确保一次只能选择一个单元格:

<DataGrid ItemsSource="{Binding Items}"
          AutoGenerateColumns="True"
          SelectionMode="Single"
          SelectionUnit="Cell"
          IsReadOnly="True" />