如何将 ApplicationCommand 绑定到 ViewModel?

发布于 2024-12-08 09:56:51 字数 588 浏览 4 评论 0原文

我已经通过 MVVM-Light 成功使用了一些自定义命令,但我希望我的应用程序不仅在窗口级别,而且在详细项目级别响应标准应用程序命令。

我有一个 TreeView,我希望能够在其中复制和粘贴节点。每个 TreeViewItem 都有自己的 ViewModel,它们通过 XAML 中的 HierarchicalDataTemplates 显示,因为有多个不同类型。我在 ViewModel 类上实现了复制、粘贴以及 CanCopy 和 CanPaste 的方法。如果合适的话,我可以很容易地实现指向这些的 MVVM-Light RelayCommands,但这似乎不对。

我想使用菜单、Ctrl+C 和 Ctrl+V 或最终使用上下文菜单来访问命令。我也不想破坏 UI 中其他元素(例如文本框)的复制/粘贴功能。为此目的使用内置的应用程序命令似乎是合适的。但是,我只看到在 UserControl 代码隐藏中处理这些示例。我没有(或需要)UserControl,也不是真正遵循 MVVM。

有没有办法可以将 ApplicationCommand.CopyApplicationCommand.Paste 命令绑定到我的 ViewModel,即数据模板中?

I have successfully used a few custom commands using MVVM-Light, but I want my application to respond to the standard ApplicationCommands, not just at a Window level, but at a detailed item level as well.

I have a TreeView that I want to be able to copy and paste nodes in. Each TreeViewItem has its own ViewModel, and they are displayed via HierarchicalDataTemplates in XAML as there are several different types. I have implemented methods to copy, paste, as well as CanCopy and CanPaste on my ViewModel classes. If appropriate, I could implement MVVM-Light RelayCommands pointing to these easily enough, but that doesn't seem right.

I would like to access the commands using a menu, Ctrl+C and Ctrl+V, or eventually a context menu. I also don't want to break copy/paste functionality for other elements in my UI, such as TextBoxes. It seems appropriate to use the built-in ApplicationCommands for this purpose. However, I am only seeing examples of these being handled in a UserControl code-behind. I don't have (or otherwise need) a UserControl, nor is that really following MVVM.

Is there a way I can bind ApplicationCommand.Copy and ApplicationCommand.Paste commands to my ViewModels, i.e., in the data templates?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

豆芽 2024-12-15 09:56:51

我已经使用附加到 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>

I have resolved this using Behaviors attached to the TreeView. The TreeViewItems or Templates to not seem to get the commands routed to them. Fortunately, the TreeView also has a SelectedItem property that can be used to get the ViewModel!

(Behaviors are conceptually similar to the solution in the link in @Natxo's answer, but it doesn't resolve everything.)

The Behavior class:

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;
        }
    }
}

The 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>
久光 2024-12-15 09:56:51

我相信您正在寻找CommandBindings。我对某些文本框使用类似的内容:

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

请注意,PreviewCanExecutePreviewExecuted 也可用。

编辑:查看此处的示例,使其符合 MVVM 标准。

I believe that you are looking for CommandBindings. I use something similar for some textboxes:

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

Note that PreviewCanExecute and PreviewExecuted are also available.

Edit: Check out the sample here to make it MVVM compliant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文