为什么KeyUp和KeyDown事件变慢?

Lar*_*rry 7 wpf keyboard-events

我在WPF窗口上使用KeyUpKeyDown事件.

我在这个窗口的CompositionTarget_Rendering事件中也有很多调用,它创建UIElements并为它们设置动画.这是由下面的引擎类完成的:

int _Fps;
Stopwatch sw = new Stopwatch();

void CompositionTarget_Rendering_Stats(object sender, EventArgs e)
{
    _Fps++;
    var ms = sw.ElapsedMilliseconds;
    sw.Restart();
    engine.Update(ms / 1000f);
    timeFrames.Add(ms);
}
Run Code Online (Sandbox Code Playgroud)

我注意到我拥有的元素越多,get KeyUpKeyDown事件越慢.

当我在主窗口中有大约1000个UI元素时,在我按下或释放一个键后,control_KeyDown和control_KeyUp的代码将在大约半秒后执行.

如果窗口内的动画也是滞后的话,这不会让我感到惊讶,但实际情况并非如此.

  • 帧速率约为55 fps
  • 动画保持流畅
  • CompositionTarget_Rendering事件中的计算持续时间不超过20毫秒.

似乎只有键盘事件轮询遭遇了沉重的条件.

我的问题是:

  • WPF中键盘处理背后的魔力是什么:为什么它在重度条件下变得迟钝而不是渲染过程?
  • 如何处理更好的键盘输入并避免这种情况?

编辑:

我写了一个受安迪评论启发的样本.您可以将其粘贴到新WPF应用程序的主窗口中.它会在键向下或向上时更改窗口的颜色,并在CompositionTarget_Rendering事件中填充尽可能多的文本框.

public partial class MainWindow : Window
{
    WrapPanel root2;

    public MainWindow()
    {
        InitializeComponent();
        root2 = new WrapPanel();
        root2.Margin = new Thickness(10);
        this.Content = root2;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        for (var i = 0; i < 2000; i++)
            root2.Children.Add(new TextBlock() { Background = Brushes.Yellow });

        this.KeyDown += MainWindow_KeyDown;
        this.KeyUp += MainWindow_KeyUp;
        CompositionTarget.Rendering += CompositionTarget_Rendering;
    }

    void MainWindow_KeyUp(object sender, KeyEventArgs e)
    {
        this.Background = Brushes.Red;
    }

    void MainWindow_KeyDown(object sender, KeyEventArgs e)
    {
        this.Background = Brushes.Green;
    }

    void CompositionTarget_Rendering(object sender, EventArgs e)
    {
        foreach (var child in root2.Children)
            ((TextBlock)child).Text = DateTime.Now.Millisecond.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

根据您的机器性能,更改2000以增加文本框的数量.在某个数量上,有比KeyUp或KeyDown更多的CompositionTarget_Rendering触发器.当按下一个键以查看边框的颜色变化时,它是非常明显的:键已关闭,然后几次触发Composition_Rendering,然后触发keydown事件并且边框变为红色.

Lar*_*rry 0

为了回答我的第二个问题,我找到了另一种方法来执行全局键盘挂钩Using global Keyboard hook (WH_KEYBOARD_LL) in WPF / C#

KeyupKeydown事件响应没有延迟,事件在 CPU 和图形负载较重的情况下。