InputBindings仅在关注时起作用 [英] InputBindings work only when focused

查看:113
本文介绍了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设计模式(使用了Calibburn.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天全站免登陆