自定义 OSK:收听 TextBox 焦点

Custom OSK: Listen to TextBox Focus

我已经编写了一个自定义屏幕键盘作为用户控件,以便更好地控制用户可以输入的内容(Alphanumeric/Numpad/Navigation 键 - 类似的东西)并在设计时更好地控制屏幕布局时间.

OSK 通过操纵文本框控件的文本和 selection-properties/functions 来工作。

我的主要问题是如何找到正确的文本框来插入文本。

我的第一个天真的方法是手动注册我想使用 OSK 控件的每个文本框,并使用这些已注册文本框的 GotFocus/LostFocus 来确定活动控件:

public void RegisterInput(TextBox text) {
    if (!_listeners.ContainsKey(text)) {
        _listeners.Add(text, modes);
        text.GotFocus += Input_OnGotFocus;
        text.LostFocus += Input_OnLostFocus;
    }
}

private void Input_OnLostFocus(object sender, RoutedEventArgs routedEventArgs) {
    if (_focused == sender) {
        _focused = null;
        IsEnabled = false;            
        UpdateKeyboardMode(); // << Updates Keyboard layout (Alphanumerical vs Numpad) based on focused control
    }
}

private void Input_OnGotFocus(object sender, RoutedEventArgs routedEventArgs) {
    _focused = (TextBox) sender;
    IsEnabled = true;        
    UpdateKeyboardMode();
    Bindings.Update();
}

我在这里使用 Focus,因为我需要确定为每个 TextBox 显示哪种键盘(全尺寸字母数字键盘还是短小键盘)。然后使用 _focused TextBox 将按下的键直接注入其中。在我的页面的构造函数中,它也包含 OSK 控件,我将调用 RegisterInput() 并引用我在页面上定义的每个文本框。这很好用——如果我有这些参考资料的话。

但现在我正在使用 UserControls。这也删除了无法直接引用的文本框,但我可以在 InitializeComponent() 之后编写某种 VisualTree-Scan 以查找所有引用并在我找到的每个引用上调用 RegisterInput()。如果我只需要这样做一次,这不是问题(虽然它仍然很难看)。

更进一步 - 具有动态更改内容和数据模板的列表框。现在我需要在每次发生变化时明确地重新扫描整个 VisualTree。但是如何检测这些变化呢?

问题是: 我能否在我的 VisualTree gets/looses 中的 $any 元素获得焦点时立即获得事件,而无需事先知道所有这些元素(因此替换 RegisterInput()完全)?或者我可以听取对 VisualTree 的更改以重新扫描所有控件,然后为我找到的每个 TextBox 手动调用 RegisterInput() 吗?

目标是在每次引发 UI 中任何 TextBox/Control 上的 GetFocus/LostFocus 事件时调用一个处理程序,以便我可以更新键盘以显示完整的-大小的字母数字键盘(用于默认文本框)或缩短的数字键盘(例如,用于绑定到数字支持字段的文本框)。

或者:有没有其他方法可以插入文本调用UpdateKeyboardMode()尽快更新键盘布局选定的文本框发生变化?

我考虑的其他选项包括:

  1. 构建一个派生自 TextBox 的自定义控件,并让它自己注册到 OSK。如果找不到更好的方法,我可能会采用这种方法。但这将破坏对第 3 方库的支持,其中不存在我的控件,因此不使用 "special magical textbox with osk support".

  2. 根本不使用事件。用户在我的 OSK 上按下一个键后,立即使用 FocusManager 获取当前聚焦的 TextBox 并将文本注入聚焦实例。这种方法的问题是,它完全破坏了使 OSK 适应不同输入类型(字母数字与仅数字键盘)的能力,因为我无法在按下键之前确定我需要的键盘类型。

  3. 使用计时器重新扫描 VisualTree。不会那样做,那太过分了。

  4. 使用 Win10 IoT 提供的屏幕键盘。两个问题:它没有设计时支持并且显示在元素上方,即使焦点元素直接位于键盘下方(如果需要,可以接受),但我不知道如何在全尺寸字母数字键盘和一个缩短的数字键盘,它只包含数字和一些键。它也不允许使用自定义键(例如用于导航的箭头键,自定义 return 键处理)。

在聊天论坛讨论后,实际问题不是创建 Custom OSK 控件并使用它与 TextBoxs 交互,而是 "being bound to use custom control" 包装a textbox 需要显示 OSK 的所有地方。

解决方案是监听 OS-OSK 事件,当它们被触发时,弹出 Custom OSK 这样你就不必将 Textbox 包装在用户控制并在整个项目中使用它。

Link 到文档:- respond to the presence of the touch keyboard