gpt4 book ai didi

WPF 入队和重放关键事件

转载 作者:行者123 更新时间:2023-12-04 02:05:22 26 4
gpt4 key购买 nike

我正在尝试提高 WPF 业务应用程序的响应能力,以便当用户在等待服务器响应后出现新屏幕的“之间”屏幕时,他们仍然可以输入数据。我可以对事件进行排队(在后台面板上使用 PreviewKeyDown 事件处理程序),但是我很难在加载后将我出列的事件扔回新面板。特别是新面板上的 TextBoxes 没有拾取文本。我尝试过引发相同的事件(在捕获它们时将 Handled 设置为 true,再次引发它们时将 Handled 设置为 false)创建新的 KeyDown 事件、新的 PreviewKeyDown 事件、执行 ProcessInput、在面板上执行 RaiseEvent、将焦点设置在右侧TextBox 和在 TextBox 上做 RaiseEvent,很多东西。

看起来应该很简单,但我无法弄清楚。

以下是我尝试过的一些方法。考虑一个名为 EventQ 的 KeyEventArgs 队列:

这是行不通的一件事:

        while (EventQ.Count > 0)
{
KeyEventArgs kea = EventQ.Dequeue();
tbOne.Focus(); // tbOne is a text box
kea.Handled = false;
this.RaiseEvent(kea);
}

这是另一个:
        while (EventQ.Count > 0)
{
KeyEventArgs kea = EventQ.Dequeue();
tbOne.Focus(); // tbOne is a text box
var key = kea.Key; // Key to send
var routedEvent = Keyboard.PreviewKeyDownEvent; // Event to send
KeyEventArgs keanew = new KeyEventArgs(
Keyboard.PrimaryDevice,
PresentationSource.FromVisual(this),
0,
key) { RoutedEvent = routedEvent, Handled = false };

InputManager.Current.ProcessInput(keanew);
}

还有一个:
        while (EventQ.Count > 0)
{
KeyEventArgs kea = EventQ.Dequeue();
tbOne.Focus(); // tbOne is a text box
var key = kea.Key; // Key to send
var routedEvent = Keyboard.PreviewKeyDownEvent; // Event to send
this.RaiseEvent(
new KeyEventArgs(
Keyboard.PrimaryDevice,
PresentationSource.FromVisual(this),
0,
key) { RoutedEvent = routedEvent, Handled = false }
);
}

我注意到的一件奇怪的事情是,在使用 InputManager 方法 (#2) 时确实会出现空格。但是普通的文本键没有。

最佳答案

当我进行一些研究时,我发现了相同的资源,因此我认为您在答案中所做的工作非常有效。

我查看并找到了另一种方法,使用 Win32 API。我不得不引入一些线程和小延迟,因为出于某种原因,关键事件没有以正确的顺序重播。总的来说,我认为这个解决方案更容易,而且我还想出了如何包含修饰键(通过使用 Get/SetKeyboardState 函数)。大写字母有效,键盘快捷键也应如此。

启动演示应用程序,按下键 1 space 2 space 3 tab 4 space 5 space 6 ,然后单击该按钮会产生以下结果:

enter image description here

Xml:

<UserControl x:Class="WpfApplication1.KeyEventQueueDemo"
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"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" >

<StackPanel>
<TextBox x:Name="tbOne" Margin="5,2" />
<TextBox x:Name="tbTwo" Margin="5,2" />
<Button x:Name="btn" Content="Replay key events" Margin="5,2" />
</StackPanel>
</UserControl>

后面的代码:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;

namespace WpfApplication1
{
/// <summary>
/// Structure that defines key input with modifier keys
/// </summary>
public struct KeyAndState
{
public int Key;
public byte[] KeyboardState;

public KeyAndState(int key, byte[] state)
{
Key = key;
KeyboardState = state;
}
}

/// <summary>
/// Demo to illustrate storing keyboard input and playing it back at a later stage
/// </summary>
public partial class KeyEventQueueDemo : UserControl
{
private const int WM_KEYDOWN = 0x0100;

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

[DllImport("user32.dll")]
static extern bool GetKeyboardState(byte[] lpKeyState);

[DllImport("user32.dll")]
static extern bool SetKeyboardState(byte[] lpKeyState);

private IntPtr _handle;
private bool _isMonitoring = true;

private Queue<KeyAndState> _eventQ = new Queue<KeyAndState>();

public KeyEventQueueDemo()
{
InitializeComponent();

this.Focusable = true;
this.Loaded += KeyEventQueueDemo_Loaded;
this.PreviewKeyDown += KeyEventQueueDemo_PreviewKeyDown;
this.btn.Click += (s, e) => ReplayKeyEvents();
}

void KeyEventQueueDemo_Loaded(object sender, RoutedEventArgs e)
{
this.Focus(); // necessary to detect previewkeydown event
SetFocusable(false); // for demo purpose only, so controls do not get focus at tab key

// getting window handle
HwndSource source = (HwndSource)HwndSource.FromVisual(this);
_handle = source.Handle;
}

/// <summary>
/// Get key and keyboard state (modifier keys), store them in a queue
/// </summary>
void KeyEventQueueDemo_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (_isMonitoring)
{
int key = KeyInterop.VirtualKeyFromKey(e.Key);
byte[] state = new byte[256];
GetKeyboardState(state);
_eventQ.Enqueue(new KeyAndState(key, state));
}
}

/// <summary>
/// Replay key events from queue
/// </summary>
private void ReplayKeyEvents()
{
_isMonitoring = false; // no longer add to queue
SetFocusable(true); // allow controls to take focus now (demo purpose only)

MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); // set focus to first control

// thread the dequeueing, because the sequence of inputs is not preserved
// unless a small delay between them is introduced. Normally the effect this
// produces should be very acceptable for an UI.
Task.Run(() =>
{
while (_eventQ.Count > 0)
{
KeyAndState keyAndState = _eventQ.Dequeue();

Application.Current.Dispatcher.BeginInvoke((Action)(() =>
{
SetKeyboardState(keyAndState.KeyboardState); // set stored keyboard state
PostMessage(_handle, WM_KEYDOWN, keyAndState.Key, 0);
}));

System.Threading.Thread.Sleep(5); // might need adjustment
}
});
}

/// <summary>
/// Prevent controls from getting focus and taking the input until requested
/// </summary>
private void SetFocusable(bool isFocusable)
{
tbOne.Focusable = isFocusable;
tbTwo.Focusable = isFocusable;
btn.Focusable = isFocusable;
}
}
}

关于WPF 入队和重放关键事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16076681/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com