简体   繁体   English

子视图集中在MVVM应用程序中以查看命令

[英]Child view focus in MVVM application to see Command

I am developing an MVVM application. 我正在开发MVVM应用程序。 I have a main Window, which looks more or less like this: 我有一个主窗口,看起来或多或少像这样:

<Window>
   <ContentControl Content={Binding ContentViewModel} />
</Window>

Then I have this ViewModel, which exposes a certain number of Commands, and I want these commands to be available to the user both from the UI (with buttons, etc), AND from the keyboard, using KeyBindings. 然后,我有了这个ViewModel,它公开了一定数量的Command,并且我希望这些命令既可以从UI(带有按钮等)也可以从用户使用KeyBindings从键盘(对用户)可用。

The commands work properly from the UI buttons. 这些命令可以从UI按钮正常工作。 But the Keybindings don't always work, it'd seem to me that the problem is that the loaded view is not always in focus. 但是键绑定并不总是有效,在我看来,问题在于加载的视图并非始终处于焦点位置。 This is the code for the view. 这是该视图的代码。

<UserControl>
    <UserControl.InputBindings>
        <KeyBinding Key="Delete" Command="{Binding RemoveEntityCommand,  ElementName=Designer}" />
    </UserControl.InputBindings>
    <Grid>
        <namespace:Designer x:Name="Designer" />
    </Grid>
</UserControl>

How to solve this permanently for an MVVM application? 如何为MVVM应用永久解决此问题? I've encountered this problem multiple times. 我已经多次遇到此问题。

Note: all namespace declarations removed for simplicity. 注意:为简单起见,删除了所有名称空间声明。

Thanks. 谢谢。

I would probably attach a Command to the KeyDown or KeyUp event of the Window instead of the UserControl , and route it from there. 我可能会将Command附加到Window的KeyDown或KeyUp事件而不是UserControl ,然后从那里路由它。

It can either be routed to the ShellViewModel , which will in turn pass it to the current ContentViewModel if needed, or perhaps use some kind of Messaging system that broadcasts special key combinations, and ViewModel's can subscribe to them. 可以将其路由到ShellViewModel ,然后在需要时将其传递给当前的ContentViewModel ,或者使用某种广播特殊键组合的消息系统,而ViewModel可以订阅它们。

What I would do is implement a PreviewKeyUp event and use that to call a method on my view model, something like this: 我要做的是实现一个PreviewKeyUp事件,并使用该事件在我的视图模型上调用方法,如下所示:

protected void PreviewKeyUp(object sender, KeyEventArgs args) 
{
    args.Handled = myViewModel.HandleKeyUp(args.Key);
}

public bool HandleKeyUp(Key key) 
{
   // Determine if you should execute a command
   if(myCommands.ShouldExecuteOnKey(key))
   {
       // Execute the commad
       return true;
   }

   return false;
}

A lot of people seem to think that MVVM means no code-behind , but that's not always true, or even possible. 许多人似乎认为MVVM 并不意味着没有任何代码后置 ,但这并不总是正确的,甚至不可能。

Yeah, key bindings are a pain. 是的,键绑定很痛苦。 And I agree with Rachel that you likely want something available at the window level in this specific case. 我同意Rachel的观点,在这种特定情况下,您可能希望在窗口级别提供一些可用的功能。

You can avoid code behind and get the goodness of mvvm by doing the following: 可以通过执行以下操作避免出现代码隐藏并获得mvvm的好处:

  1. make your commands aware of key gestures 使您的命令了解按键手势
  2. give a KeyBinding an additional property that takes advantage of (1) 给KeyBinding一个利用(1)的附加属性

This is obviously a bit of infrastructure work tho it is testable and reusable once you have it in place. 很明显,这是基础架构的一部分工作,一旦安装就可以测试和重用。 In this case, since you want the bindings available at the window level, your ShellVm holds the commands and delegates to child view models as needed. 在这种情况下,由于您希望绑定在窗口级别可用,因此ShellVm保留命令并根据需要委托给子视图模型。 I've left just enough code below to give you a feel for the idea 我在下面只剩下了足够的代码,可以使您对该想法有所了解

HTH, HTH,
Berryl Berryl

sample bindings 样本绑定

<Window.InputBindings>
    <cmdRef:KeyBindingEx  CommandReference="{Binding AddCommand}"/>
</Window.InputBindings>

extended KeyBinding 扩展键绑定

public class KeyBindingEx : KeyBinding
{
    public static readonly DependencyProperty CommandReferenceProperty = DependencyProperty
        .Register("CommandReference", typeof(CommandReference), typeof(KeyBindingEx),          
                  new PropertyMetadata(OnCommandReferenceChanged));

    private static void OnCommandReferenceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        var kb = (KeyBinding) d;
        var cmdRef = e.NewValue as VmCommand;
        if(cmdRef==null) return;

        kb.Key = cmdRef.GestureKey;
        kb.Modifiers = cmdRef.GestureModifier;
        kb.Command = cmdRef;
    }

    public CommandReference CommandReference
    {
        get { return (CommandReference)GetValue(CommandReferenceProperty); }
        set { SetValue(CommandReferenceProperty, value); }
    }
}

Command Reference base class extract 命令参考基类摘录

public class CommandReference : PropertyChangedBase { ... 公共类CommandReference:PropertyChangedBase {...

    public Key GestureKey
    {
        get { return _gestureKey; }
        set
        {
            if (_gestureKey == value) return;

            _gestureKey = value;
            NotifyOfPropertyChange(() => GestureKey);
        }
    }
    private Key _gestureKey;        
}

/// <summary>A command whose primary purpose is to relay its functionality to other objects by invoking delegates.</summary>
public class VmCommand : CommandReference, ICommand
{
    ...

    /// <summary>Action to be called when the Execute method of the command gets called</summary>
    public Action ExecuteDelegate { get; protected set; }

    /// <summary>Predicate to execute when the CanExecute of the command gets called (default is <c>true</c>)</summary>
    public Func<bool> CanExecuteDelegate { get; protected set; }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM