Подтвердить что ты не робот

Как связать ApplicationCommands с ViewModel?

Я успешно использовал несколько пользовательских команд с использованием MVVM-Light, но хочу, чтобы мое приложение отвечало на стандартные ApplicationCommands, а не только на уровне Window, но и на уровне детализации.

У меня есть TreeView, который я хочу, чтобы иметь возможность копировать и вставлять узлы. Каждый TreeViewItem имеет свой собственный ViewModel, и они отображаются через HierarchicalDataTemplates в XAML, так как существует несколько разных типов. Я применил методы для копирования, вставки, а также CanCopy и CanPaste на мои классы ViewModel. В случае необходимости я мог бы реализовать MVVM-Light RelayCommands, указывающие на это достаточно легко, но это не кажется правильным.

Я хотел бы получить доступ к командам с помощью меню, Ctrl + C и Ctrl + V или, в конечном итоге, контекстного меню. Я также не хочу нарушать функции копирования/вставки для других элементов моего пользовательского интерфейса, например TextBoxes. Для этой цели целесообразно использовать встроенные ApplicationCommands. Тем не менее, я вижу только примеры того, как они обрабатываются в коде UserControl. У меня нет (или нет необходимости) UserControl, и это действительно не соответствует MVVM.

Есть ли способ привязать команды ApplicationCommand.Copy и ApplicationCommand.Paste к моим ViewModels, т.е. в шаблонах данных?

4b9b3361

Ответ 1

Я разрешил это, используя Behaviors, прикрепленные к TreeView. TreeViewItems или Шаблоны, похоже, не получат команды, направляемые им. К счастью, TreeView также имеет свойство SelectedItem, которое можно использовать для получения ViewModel!

(Поведение концептуально похоже на решение в ссылке в ответе @Natxo, но оно не разрешает все.)

Класс поведения:

public class TreeViewClipboardBehavior : Behavior<TreeView>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        CommandBinding CopyCommandBinding = new CommandBinding(
            ApplicationCommands.Copy,
            CopyCommandExecuted,
            CopyCommandCanExecute);
        AssociatedObject.CommandBindings.Add(CopyCommandBinding);

        CommandBinding CutCommandBinding = new CommandBinding(
            ApplicationCommands.Cut,
            CutCommandExecuted,
            CutCommandCanExecute);
        AssociatedObject.CommandBindings.Add(CutCommandBinding);

        CommandBinding PasteCommandBinding = new CommandBinding(
            ApplicationCommands.Paste,
            PasteCommandExecuted,
            PasteCommandCanExecute);
        AssociatedObject.CommandBindings.Add(PasteCommandBinding);
    }

    private void CopyCommandExecuted(object target, ExecutedRoutedEventArgs e)
    {
        NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase;
        if (item != null && item.CanCopyToClipboard)
        {
            item.CopyToClipboard();
            e.Handled = true;
        }
    }

    private void CopyCommandCanExecute(object target, CanExecuteRoutedEventArgs e)
    {
        NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase;
        if (item != null)
        {
            e.CanExecute = item.CanCopyToClipboard;
            e.Handled = true;
        }
    }

    private void CutCommandExecuted(object target, ExecutedRoutedEventArgs e)
    {
        NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase;
        if (item != null && item.CanCutToClipboard)
        {
            item.CutToClipboard();
            e.Handled = true;
        }
    }

    private void CutCommandCanExecute(object target, CanExecuteRoutedEventArgs e)
    {
        NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase;
        if (item != null)
        {
            e.CanExecute = item.CanCutToClipboard;
            e.Handled = true;
        }
    }


    private void PasteCommandExecuted(object target, ExecutedRoutedEventArgs e)
    {
        NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase;
        if (item != null && item.CanPasteFromClipboard)
        {
            item.PasteFromClipboard();
            e.Handled = true;
        }
    }

    private void PasteCommandCanExecute(object target, CanExecuteRoutedEventArgs e)
    {
        NestingItemTreeViewModelBase item = AssociatedObject.SelectedItem as NestingItemTreeViewModelBase;
        if (item != null)
        {
            e.CanExecute = item.CanPasteFromClipboard;
            e.Handled = true;
        }
    }
}

XAML

<TreeView Grid.Row="2" ItemsSource="{Binding SystemTreeRoot}">
    <i:Interaction.Behaviors>
        <local:TreeViewClipboardBehavior/>
    </i:Interaction.Behaviors>
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:MyViewModel}" ItemsSource="{Binding Children}">
            <!-- Template content -->
        </HierarchicalDataTemplate>
</TreeView>

Ответ 2

Я считаю, что вы ищете CommandBindings. Я использую нечто похожее для некоторых текстовых полей:

    <DataTemplate x:Key="textBoxTemplate" >
        <TextBox>
            <TextBox.CommandBindings>
                <CommandBinding Command="ApplicationCommand.Copy" 
                                Executed="CommandBinding_Executed"
                                CanExecute="CommandBinding_CanExecute">
                </CommandBinding>
            </TextBox.CommandBindings>
        </TextBox>
    </DataTemplate>

Обратите внимание, что PreviewCanExecute и PreviewExecuted также доступны.

Изменить: просмотрите образец здесь, чтобы сделать его совместимым с MVVM.