Как привязать ApplicationCommands к ViewModel? - PullRequest
12 голосов
/ 04 октября 2011

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

У меня есть 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, т.е. в шаблонах данных?

Ответы [ 2 ]

9 голосов
/ 12 октября 2011

Я решил это, используя Поведения, привязанные к 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>
3 голосов
/ 04 октября 2011

Я считаю, что вы ищете 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.

...