当前位置:  开发笔记 > 编程语言 > 正文

WPF MVVM应用程序中的键盘事件?

如何解决《WPFMVVM应用程序中的键盘事件?》经验,为你挑选了4个好方法。

如何在不使用代码隐藏的情况下处理Keyboard.KeyDown事件?我们正在尝试使用MVVM模式,并避免在代码隐藏文件中编写事件处理程序.



1> karlipoppins..:

为了获得更新的答案,.net 4.0框架使您可以通过将KeyBinding命令绑定到viewmodel中的命令来很好地完成此操作.

所以......如果你想听Enter键,你会做这样的事情:


    
        
    


这绝对是.net 4的正确方法.需要更多的赞成
这也适用于鼠标点击,BTW.示例:
这绝对应该是公认的答案
因此,OP最初会询问,如何将此链接到任何输入的文本?IE浏览器.OnKeyDown事件?

2> Pieter Breed..:

哇 - 有一千个答案,在这里我要再加一个......

在'为什么 - 我没有意识到 - 这个 - 前额 - 一巴掌'的方式中,真正明显的事情是代码隐藏和ViewModel坐在同一个房间里可以说话,所以没有理由他们为什么不被允许进行对话.

如果你考虑一下,XAML已经与ViewModel的API紧密结合,所以你也可以从后面的代码中依赖它.

服从或忽略的其他明显规则仍然适用(接口,空检查< - 特别是如果你使用Blend ......)

我总是在代码隐藏中创建一个属性,如下所示:

private ViewModelClass ViewModel { get { return DataContext as ViewModelClass; } }

这是客户端代码.空检查用于帮助控制托管,就像在混合中一样.

void someEventHandler(object sender, KeyDownEventArgs e)
{
    if (ViewModel == null) return;
    /* ... */
    ViewModel.HandleKeyDown(e);
}

像你想要的那样在你背后的代码中处理你的事件(UI事件是以UI为中心的,所以没关系)然后在ViewModelClass上有一个可以响应该事件的方法.这些担忧仍然存在分歧.

ViewModelClass
{
    public void HandleKeyDown(KeyEventArgs e) { /* ... */ }
}

所有这些其他附加的属性和伏都教非常酷,这些技术对其他一些东西非常有用,但在这里你可以通过更简单的东西逃脱...


总是抓取`ViewModel`的本地副本而不是每次调用属性...`var vm = ViewModel;`,从那里使用**vm**而不是`ViewModel`.

3> Paul..:

我通过使用具有3个依赖项属性的附加行为来完成此操作; 一个是要执行的命令,一个是传递给命令的参数,另一个是导致命令执行的键.这是代码:

public static class CreateKeyDownCommandBinding
{
    /// 
    /// Command to execute.
    /// 
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command",
        typeof(CommandModelBase),
        typeof(CreateKeyDownCommandBinding),
        new PropertyMetadata(new PropertyChangedCallback(OnCommandInvalidated)));

    /// 
    /// Parameter to be passed to the command.
    /// 
    public static readonly DependencyProperty ParameterProperty =
        DependencyProperty.RegisterAttached("Parameter",
        typeof(object),
        typeof(CreateKeyDownCommandBinding),
        new PropertyMetadata(new PropertyChangedCallback(OnParameterInvalidated)));

    /// 
    /// The key to be used as a trigger to execute the command.
    /// 
    public static readonly DependencyProperty KeyProperty =
        DependencyProperty.RegisterAttached("Key",
        typeof(Key),
        typeof(CreateKeyDownCommandBinding));

    /// 
    /// Get the command to execute.
    /// 
    /// 
    /// 
    public static CommandModelBase GetCommand(DependencyObject sender)
    {
        return (CommandModelBase)sender.GetValue(CommandProperty);
    }

    /// 
    /// Set the command to execute.
    /// 
    /// 
    /// 
    public static void SetCommand(DependencyObject sender, CommandModelBase command)
    {
        sender.SetValue(CommandProperty, command);
    }

    /// 
    /// Get the parameter to pass to the command.
    /// 
    /// 
    /// 
    public static object GetParameter(DependencyObject sender)
    {
        return sender.GetValue(ParameterProperty);
    }

    /// 
    /// Set the parameter to pass to the command.
    /// 
    /// 
    /// 
    public static void SetParameter(DependencyObject sender, object parameter)
    {
        sender.SetValue(ParameterProperty, parameter);
    }

    /// 
    /// Get the key to trigger the command.
    /// 
    /// 
    /// 
    public static Key GetKey(DependencyObject sender)
    {
        return (Key)sender.GetValue(KeyProperty);
    }

    /// 
    /// Set the key which triggers the command.
    /// 
    /// 
    /// 
    public static void SetKey(DependencyObject sender, Key key)
    {
        sender.SetValue(KeyProperty, key);
    }

    /// 
    /// When the command property is being set attach a listener for the
    /// key down event.  When the command is being unset (when the
    /// UIElement is unloaded for instance) remove the listener.
    /// 
    /// 
    /// 
    static void OnCommandInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        UIElement element = (UIElement)dependencyObject;
        if (e.OldValue == null && e.NewValue != null)
        {
            element.AddHandler(UIElement.KeyDownEvent,
                new KeyEventHandler(OnKeyDown), true);
        }

        if (e.OldValue != null && e.NewValue == null)
        {
            element.RemoveHandler(UIElement.KeyDownEvent,
                new KeyEventHandler(OnKeyDown));
        }
    }

    /// 
    /// When the parameter property is set update the command binding to
    /// include it.
    /// 
    /// 
    /// 
    static void OnParameterInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        UIElement element = (UIElement)dependencyObject;
        element.CommandBindings.Clear();

        // Setup the binding
        CommandModelBase commandModel = e.NewValue as CommandModelBase;
        if (commandModel != null)
        {
            element.CommandBindings.Add(new CommandBinding(commandModel.Command,
            commandModel.OnExecute, commandModel.OnQueryEnabled));
        }
    }

    /// 
    /// When the trigger key is pressed on the element, check whether
    /// the command should execute and then execute it.
    /// 
    /// 
    /// 
    static void OnKeyDown(object sender, KeyEventArgs e)
    {
        UIElement element = sender as UIElement;
        Key triggerKey = (Key)element.GetValue(KeyProperty);

        if (e.Key != triggerKey)
        {
            return;
        }

        CommandModelBase cmdModel = (CommandModelBase)element.GetValue(CommandProperty);
        object parameter = element.GetValue(ParameterProperty);
        if (cmdModel.CanExecute(parameter))
        {
            cmdModel.Execute(parameter);
        }
        e.Handled = true;
    }
}

要从xaml中使用它,您可以执行以下操作:


    Enter

编辑: CommandModelBase是我用于所有命令的基类.它基于Dan Crevier关于MVVM的文章中的CommandModel类(此处).这是我与CreateKeyDownCommandBinding一起使用的略微修改版本的源代码:

public abstract class CommandModelBase : ICommand
    {
        RoutedCommand routedCommand_;

        /// 
        /// Expose a command that can be bound to from XAML.
        /// 
        public RoutedCommand Command
        {
            get { return routedCommand_; }
        }

        /// 
        /// Initialise the command.
        /// 
        public CommandModelBase()
        {
            routedCommand_ = new RoutedCommand();
        }

        /// 
        /// Default implementation always allows the command to execute.
        /// 
        /// 
        /// 
        public void OnQueryEnabled(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = CanExecute(e.Parameter);
            e.Handled = true;
        }

        /// 
        /// Subclasses must provide the execution logic.
        /// 
        /// 
        /// 
        public void OnExecute(object sender, ExecutedRoutedEventArgs e)
        {
            Execute(e.Parameter);
        }

        #region ICommand Members

        public virtual bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public abstract void Execute(object parameter);

        #endregion
    }

非常欢迎提出改进意见和建议.



4> djcouchycouc..:

有点晚了,但到了.

微软的WPF团队最近发布了他们的WPF MVVM Toolkit的早期版本 .在其中,您将找到一个名为CommandReference的类,它可以处理键绑定之类的事情.查看他们的WPF MVVM模板,看看它是如何工作的.


我昨天只是尝试了,我认为这是绑定密钥的最简洁方法.不幸的是,没有办法一次绑定所有键(或者我无法弄清楚如何),而且我需要整个键盘,所以你必须为每个键创建一个绑定,然后在移位时再次创建所有键按下,然后按下Ctrl时再次...它变长.我们选择在后面的代码中使用KeyUp hander来调用VM中的方法.像5行代码而不是所有那些绑定.VM仍然没有意识到View.谢谢你的回复
推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有