Обработка жестов ввода в пользовательском элементе управления (MVVM) - PullRequest
2 голосов
/ 05 мая 2011

Используя шаблон MVVM, как мне обрабатывать жесты клавиш?

UserControl.InputBindings не будет работать, поскольку он не фокусируется.

Я определил ICommand, которая должна вызыватьсякогда правильный ключ введен, но я не знаю, как связать команду с View.

Спасибо, Стефан

Ответы [ 3 ]

3 голосов
/ 06 мая 2011

Я решил эту проблему, создав класс DelegateCommand. Он выглядит в точности как RelayCommand (см. Джош Смит), за исключением того, что он позволяет обновлять обратные вызовы.

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
}

Затем я создал класс для хранения статических команд приложения.

public class CustomCommands
{
    private readonly static DelegateCommand admin;

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

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

Затем я добавил привязку клавиш к главному окну, поскольку пользовательские элементы управления не получают жестов клавиш.

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

Затем в моей 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());
    }
}

При желании я мог бы использовать события внутри DelegateCommand.

1 голос
/ 25 апреля 2012

Это работает для меня (.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>

Хитрость заключается в том, чтобы убедиться, что фокус установлен в UserControl. Для меня это не происходит автоматически. Как только фокус установлен, KeyBinding работает. (Обратите внимание, что фокус устанавливается прямо в конце, так как элемент должен быть определен первым)

Для полноты вот код 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");
    ...
}
0 голосов
/ 05 мая 2011

Посмотрите на этот пример: http://tomlev2.wordpress.com/2009/03/17/wpf-using-inputbindings-with-the-mvvm-pattern/

Он связывает его с DataContext of the root element с разметкой XML. Надеюсь, это поможет вам.

Это решение имеет ограничение: оно работает только для DataContext корня XAML. Так что вы не можете использовать его, например, для определения InputBinding для элемента управления, чей DataContext также переопределен, потому что расширение разметки будет обращаться к корневому DataContext.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...