【问题标题】:Why doesn't keyboard input work for a ScrollViewer when the child control has input focus?当子控件具有输入焦点时,为什么键盘输入对 ScrollViewer 不起作用?
【发布时间】:2019-11-20 23:40:20
【问题描述】:

为什么当子控件具有输入焦点时,ScrollViewer 的键盘输入不起作用?

这就是场景。将打开一个 WPF 窗口。它将焦点设置到嵌入在 ScrollViewer 中的控件。

我按上下左右键。 ScrollViewer 似乎没有处理关键事件,有人知道为什么吗?

这是最简单的例子:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    FocusManager.FocusedElement="{Binding ElementName=control}"
    >
    <Grid>
        <ScrollViewer
            HorizontalScrollBarVisibility="Auto"
           >
            <ItemsControl
                x:Name="control"
                Width="1000"
                Height="1000"
                />
        </ScrollViewer>        
    </Grid>
</Window>

当您启动包含此窗口的应用程序时,“控制”似乎具有我想要的焦点。按下该键似乎会导致键事件冒泡到达ScrollViewer(我使用 WPF Snoop 进行了检查)。我不知道为什么它不响应输入。

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    问题

    ScrollViewer 会忽略 OriginalSource 不是 ScrollViewer 的所有 KeyDown 事件。 KeyDown 上的 OriginalSource 设置为获得焦点的控件,因此当子项获得焦点时,ScrollViewer 会忽略它。

    解决方案

    捕获 KeyDown 事件并直接在 ScrollViewer 上生成它的副本,以便它具有正确的 OriginalSource,如下所示:

    void ScrollViewer_KeyDown(object sender, KeyEventArgs e)
    {
      if(e.Handled) return;
      var temporaryEventArgs =
        new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key)
        {
          RoutedEvent = e.RoutedEvent
        };
      // This line avoids it from resulting in a stackoverflowexception
      if (sender is ScrollViewer) return;
      ((ScrollViewer)sender).RaiseEvent(temporaryEventArgs);
      e.Handled = temporaryEventArgs.Handled;
    }
    

    可以在 XAML 中添加事件处理程序:

    <ScrollViewer KeyDown="ScrollViewer_KeyDown" />
    

    或在代码中:

    scrollViewer.AddHandler(Keyboard.KeyDownEvent, ScrollViewer_KeyDown);
    

    如果 ScrollViewer 在某个模板内并且您有代码可以找到它,则后者更适用。

    【讨论】:

    • 谢谢,这听起来很有用,我会试试看。虽然我很想知道设计原因,但如果有的话,为什么这不能像我预期的那样工作。
    • 我不知道,但我知道他们做了很多可用性测试。我的猜测是,当 ScrollViewer 没有焦点滚动时,他们发现可用性受到影响。换句话说,我怀疑用户发现当按钮被聚焦时箭头导致滚动时,这种行为出乎意料和/或令人惊讶。
    【解决方案2】:

    为了让 ScrollViewer 对您的键盘键做出反应 - 它需要 IsFocused="True" - 现在它的子项具有焦点。

    为了证明这一点 - 尝试在 Loaded 事件中手动将焦点设置到 ScrollViewer(您可能必须设置 IsFocusable="True" 才能在 ScrollViewer 上工作) - 现在键应该可以工作了。如果您希望它以其他方式工作,则需要在 ScrollViewer 上设置适当的 EventHandlers(KeyDown/KeyPress 等)

    【讨论】:

    • 谢谢,但我认为您误解了这个问题。我希望孩子有重点。在我的应用程序中,孩子处理输入,然后事件然后冒泡到 ScrollViewer。问题是为什么 ScrollViewer 不处理它们?
    • 如果 ScrollViewer 没有焦点,箭头键的“自动映射”不起作用。正如我在回答中所写的,您需要将处理程序附加到 Keyevents。在您的代码中,您不处理事件。
    【解决方案3】:

    ItemsControl.Template 中使用ScrollViewer 时出现类似问题,没有键盘导航。添加FocusableIsTabStop 解决了我的问题。

    <ScrollViewer
        Focusable="True"
        IsTabStop="True">
        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
     </ScrollViewer>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多