InputBindings 仅在聚焦时工作 [英] InputBindings work only when focused

查看:29
本文介绍了InputBindings 仅在聚焦时工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我设计了一个可重复使用的用户控件.它包含 UserControl.InputBindings.它非常简单,因为它只包含一个标签和一个按钮(以及新属性等)

I have designed a reuseable usercontrol. It contains UserControl.InputBindings. It is quite simple as it only contains a label and a button (and new properties etc.)

当我在窗口中使用控件时,它运行良好.但是键绑定仅在聚焦时有效.当一个控件绑定到 alt+f8 时,此快捷方式仅在聚焦时有效.当另一个有自己绑定的人被聚焦时,那个人可以工作,但 alt+f8 不再有效.当所有控件都没有焦点时,什么都不起作用.

When I use the control in my window it works well. But the key binding only works when focussed. When one control has a binding to alt+f8 this shortcut only works when it is focussed. When the other one with its own binding is focussed, that one works but alt+f8 no more. When none of the controls has the focus, nothing works.

如何实现我的用户控件定义窗口范围的键绑定?

How can I achieve that my usercontrol defines window-wide keybindings?

特别是遵循 MVVM 设计模式(使用 Caliburn.Micro),但感谢任何帮助.

Especially following MVVM design pattern (Caliburn.Micro used) but any help is appreciated.

用户控件的XAML:

<UserControl x:Class="MyApp.UI.Controls.FunctionButton"
             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" 
             xmlns:local="clr-namespace:MyApp.UI.Controls"
             xmlns:cm="http://www.caliburnproject.org"
             x:Name="Root"
             Focusable="True"
             mc:Ignorable="d" 
             d:DesignHeight="60" d:DesignWidth="120">
    <UserControl.Resources>
        ...
    </UserControl.Resources>
    <UserControl.InputBindings>
        <KeyBinding Key="{Binding ElementName=Root, Path=FunctionKey}" Modifiers="{Binding ElementName=Root, Path=KeyModifiers}" Command="{Binding ElementName=Root, Path=ExecuteCommand}" />
    </UserControl.InputBindings>
    <DockPanel LastChildFill="True">
        <TextBlock DockPanel.Dock="Top" Text="{Binding ElementName=Root, Path=HotkeyText}" />
        <Button DockPanel.Dock="Bottom" Content="{Binding ElementName=Root, Path=Caption}" cm:Message.Attach="[Event Click] = [Action ExecuteButtonCommand($executionContext)]" cm:Action.TargetWithoutContext="{Binding ElementName=Root}" />
    </DockPanel>
</UserControl>

示例用法:

    <Grid>
    <c:FunctionButton Width="75" Height="75" Margin="10,10,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" FunctionKey="F1" ShiftModifier="True" cm:Message.Attach="[Event Execute] = [Action Button1Execute]" />
    <c:FunctionButton Width="75" Height="75" Margin="10,90,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" FunctionKey="F2" ShiftModifier="True" cm:Message.Attach="[Event Execute] = [Action Button2Execute]" />
</Grid>

如前所述,每个按钮在鼠标点击时都有效(执行被触发),当我获得焦点时,我可以使用空间来激活按钮,焦点按钮的输入绑定有效,但非焦点按钮永远不会.

As said each button works (Execute gets fired) on mouse click and when focused I can use space to activate the button and the input binding of the focused button works but never of the un-focused.

推荐答案

InputBindings 将不会为未聚焦的控件执行,因为它们的工作方式 - 在可视化树中搜索输入绑定的处理程序从焦点元素到可视化树的根(窗口).当控件未获得焦点时,他将不会成为该搜索路径的一部分.

InputBindings won't be executed for a control that isn't focused because of the way they work - a handler for the input binding is searched in the visual tree from the focused element to the visual tree's root (the window). When a control is not focused, he won't be a part of that search path.

正如@Wayne 所提到的,最好的方法是简单地将输入绑定移动到父窗口.然而,有时这是不可能的(例如,当窗口的 xaml 文件中未定义 UserControl 时).

As @Wayne has mentioned, the best way to go would be simply move the input bindings to the parent window. Sometimes however this isn't possible (for example when the UserControl isn't defined in the window's xaml file).

我的建议是使用附加行为将这些输入绑定从 UserControl 移动到窗口.使用附加行为这样做还有一个好处,即能够处理任何 FrameworkElement 而不仅仅是您的 UserControl.所以基本上你会有这样的东西:

My suggestion would be to use an attached behavior to move these input bindings from the UserControl to the window. Doing so with an attached behavior also has the benefit of being able to work on any FrameworkElement and not just your UserControl. So basically you'll have something like this:

public class InputBindingBehavior
{
    public static bool GetPropagateInputBindingsToWindow(FrameworkElement obj)
    {
        return (bool)obj.GetValue(PropagateInputBindingsToWindowProperty);
    }

    public static void SetPropagateInputBindingsToWindow(FrameworkElement obj, bool value)
    {
        obj.SetValue(PropagateInputBindingsToWindowProperty, value);
    }

    public static readonly DependencyProperty PropagateInputBindingsToWindowProperty =
        DependencyProperty.RegisterAttached("PropagateInputBindingsToWindow", typeof(bool), typeof(InputBindingBehavior),
        new PropertyMetadata(false, OnPropagateInputBindingsToWindowChanged));

    private static void OnPropagateInputBindingsToWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((FrameworkElement)d).Loaded += frameworkElement_Loaded;
    }

    private static void frameworkElement_Loaded(object sender, RoutedEventArgs e)
    {
        var frameworkElement = (FrameworkElement)sender;
        frameworkElement.Loaded -= frameworkElement_Loaded;

        var window = Window.GetWindow(frameworkElement);
        if (window == null)
        {
            return;
        }

        // Move input bindings from the FrameworkElement to the window.
        for (int i = frameworkElement.InputBindings.Count - 1; i >= 0; i--)
        {
            var inputBinding = (InputBinding)frameworkElement.InputBindings[i];
            window.InputBindings.Add(inputBinding);
            frameworkElement.InputBindings.Remove(inputBinding);
        }
    }
}

用法:

<c:FunctionButton Content="Click Me" local:InputBindingBehavior.PropagateInputBindingsToWindow="True">
    <c:FunctionButton.InputBindings>
        <KeyBinding Key="F1" Modifiers="Shift" Command="{Binding FirstCommand}" />
        <KeyBinding Key="F2" Modifiers="Shift" Command="{Binding SecondCommand}" />
    </c:FunctionButton.InputBindings>
</c:FunctionButton>

这篇关于InputBindings 仅在聚焦时工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆