简体   繁体   English

在用户控件(MVVM)中处理输入手势

[英]Handling input gestures in a user control (MVVM)

Using the MVVM pattern, how do I handle key gestures? 使用MVVM模式,如何处理按键手势?

UserControl.InputBindings won't work as it isn't focusable. UserControl.InputBindings无法工作,因为它无法聚焦。

I have defined an ICommand that should be called when the proper key is typed, but am at a loss as how to connect the command with the View. 我定义了一个ICommand,当键入正确的键时应该调用该ICommand,但是如何将命令与View连接起来却迷茫了。

Thanks, Stefan 谢谢,Stefan

I solved this problem by creating a DelegateCommand class. 我通过创建DelegateCommand类解决了这个问题。 It looks exactly like the RelayCommand (See Josh Smith), with the exception that it allows for updating the callbacks. 它看起来完全像RelayCommand(请参见Josh Smith),但它允许更新回调。

public class DelegateCommand : ICommand
{
    Action<object> _execute;
    Predicate<object> _canExecute;

    #region Constructors

    public DelegateCommand()
    {

    }

    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    public void Delegate(Action<object> execute)
    {
        _execute = execute;
    }

    public void Delegate(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? _execute != null : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        if (CanExecute(parameter))
            _execute(parameter);
    }

    #endregion // ICommand Members
}

Then I created a class to hold static application commands. 然后,我创建了一个用于容纳静态应用程序命令的类。

public class CustomCommands
{
    private readonly static DelegateCommand admin;

    static CustomCommands()
    {
        admin = new DelegateCommand();
    }

    public static DelegateCommand AdminCommand
    {
        get { return admin; }
    }
}

Then I added a key binding to the main window since user controls don't receive key gestures. 然后,由于用户控件未收到按键手势,我向主窗口添加了按键绑定。

<Window.InputBindings>
    <KeyBinding Key="A" Modifiers="Control" Command="my:CustomCommands.AdminCommand"/>
</Window.InputBindings>

Then, in my ViewModel I can handle the event like this: 然后,在我的ViewModel中,我可以像这样处理事件:

public class OfflineViewModel : ViewModelBase
{
    public OfflineViewModel()
    {
        CustomCommands.AdminCommand.Delegate(ShowAdmin);
    }

    public override void Removed()
    {
        base.Removed();

        ReleaseAdminCommand();
    }

    public override void Hidden()
    {
        base.Hidden();

        ReleaseAdminCommand();
    }

    void HookAdminCommand()
    {
        CustomCommands.AdminCommand.Delegate(ShowAdmin);
    }

    void ReleaseAdminCommand()
    {
        // Remove handling
        CustomCommands.AdminCommand.Delegate(null, null);
    }

    void ShowAdmin(object parameter)
    {
        Navigation.Push(new AdminViewModel());
    }
}

Optionally I could use events inside the DelegateCommand. (可选)我可以在DelegateCommand内部使用事件。

This works for me (.Net 4.0) 这对我有效(.Net 4.0)

<UserControl>
    <UserControl.InputBindings>
        <KeyBinding Gesture="CTRL+C" Command="{Binding CancelCommand}" />
        <KeyBinding Gesture="F5" Command="{Binding StartCommand}" />
        <KeyBinding Gesture="CTRL+F5" Command="{Binding FreshStartCommand}" />
        <KeyBinding Gesture="F10" Command="{Binding ContinueCommand}" />
        <KeyBinding Gesture="F9" Command="{Binding RepeatCommand}" />
        <KeyBinding Gesture="ALT+F4" Command="{Binding CloseCommand}" />
        <KeyBinding Gesture="CTRL+N" Command="{Binding NewUUTCommand}" />
    </UserControl.InputBindings>

    ....

    <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Center">
        <Button x:Name="BtnStart" Content="STARTEN" Command="{Binding StartCommand}"/>
        <Button Content="STOP" Command="{Binding StopCommand}"/>
    </StackPanel>

    ....

    <FocusManager.FocusedElement>
        <Binding ElementName="BtnStart"/>
    </FocusManager.FocusedElement>
</UserControl>

The trick is to ensure that the focus is set into the UserControl. 技巧是确保将焦点设置到UserControl中。 For me, this wasn't happening automatically. 对我来说,这不是自动发生的。 Once the focus is set then the KeyBinding works. 一旦设置了焦点,则KeyBinding将起作用。 (Note the focus is set right at the end as the element has to be defined first) (注意,焦点必须设置在最后,因为必须先定义元素)

For completeness, here is the ViewModel code. 为了完整起见,这是ViewModel代码。

public ICommand StartCommand
{
    get
    {
        if (this._startCommand == null)
        {
            this._startCommand = new Mvvm.RelayCommand(parm => DoStart(), parm => DoCanStart());
        } return this._startCommand;
    }
}

private bool DoCanStart()
{
    return !IsRunning && ReadyToRun;
}

private void DoStart()
{
    log.Debug("Start test");
    ...
}

Look at this example: http://tomlev2.wordpress.com/2009/03/17/wpf-using-inputbindings-with-the-mvvm-pattern/ 请看以下示例: http : //tomlev2.wordpress.com/2009/03/17/wpf-using-inputbindings-with-the-mvvm-pattern/

It binds it to DataContext of the root element with XML markup. 它使用XML标记将其绑定到DataContext of the root element Hope, it helps you. 希望对您有帮助。

This solution has a limitation : it works only for the DataContext of the XAML root. 此解决方案有一个局限性:它仅适用于XAML根的DataContext。 So you can't use it, for instance, to define an InputBinding on a control whose DataContext is also redefined, because the markup extension will access the root DataContext. 因此,例如,您不能使用它在其DataContext也被重新定义的控件上定义InputBinding,因为标记扩展将访问根DataContext。

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

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