Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ApplicationCommands in MVVM

Tags:

c#

mvvm

wpf

I would like to use ApplicationCommands.Cut, copy, paste, save,... They seem interesting because of the command routing, keybindings and the fact that some controls use them. I understand how I can bind to relay/delegatecommands on my VM but I can't seem to get my head around the Application commands. I found a couple of old answers but no other information and I am kind of reluctant of following those routes.

This seems like something common but yet informations seems to be very limited. How is this commonly achieved? (With or without using PRISM, MVVM Light, ...)

Old answers:

How to bind ApplicationCommands to a ViewModel but this seems strange to me to solve this using a behavior

WPF - Handle an ApplicationCommand in the ViewModel but I don't think that's MVVM in the accepted answer.

Using attached properties in an old article: CommandBindings with MVVM referencing another article.

like image 342
Jef Patat Avatar asked Nov 08 '22 21:11

Jef Patat


1 Answers

It has been a while since I asked this question but it looks like a lot of people are looking at it. I ended up using a behavior which connects the VM command list to the FrameworkElement. This seems to be the most flexible and resusable solution.

public class AttachCommandBindingsBehavior : Behavior<FrameworkElement>
{
    public ObservableCollection<CommandBinding> CommandBindings
    {
        get
        {
            return (ObservableCollection<CommandBinding>)GetValue(CommandBindingsProperty);
        }
        set
        {
            SetValue(CommandBindingsProperty, value);
        }
    }
    public static readonly DependencyProperty CommandBindingsProperty = DependencyProperty.Register("CommandBindings", typeof(ObservableCollection<CommandBinding>), typeof(AttachCommandBindingsBehavior), new PropertyMetadata(null, OnCommandBindingsChanged));

    private static void OnCommandBindingsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        AttachCommandBindingsBehavior attachCommandBindingsBehavior = (AttachCommandBindingsBehavior)sender;

        if (attachCommandBindingsBehavior == null)
            return;

        ObservableCollection<CommandBinding> commandBindings = (ObservableCollection<CommandBinding>)e.NewValue;

        if (commandBindings != null)
        {
            if (attachCommandBindingsBehavior.CommandBindings != null)
                attachCommandBindingsBehavior.CommandBindings.CollectionChanged -= attachCommandBindingsBehavior.CommandBindings_CollectionChanged;

            attachCommandBindingsBehavior.CommandBindings.CollectionChanged += attachCommandBindingsBehavior.CommandBindings_CollectionChanged;
        }
    }

    void CommandBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        ObservableCollection<CommandBinding> collection = (ObservableCollection<CommandBinding>)sender;

        if (collection != null)
        {
            foreach (CommandBinding commandBinding in collection)
                AssociatedObject.CommandBindings.Add(commandBinding);
        }
    }
}

In xaml you can then do this:

<i:Interaction.Behaviors>
    <localBehaviors:AttachCommandBindingsBehavior CommandBindings="{Binding CommandBindings}"/>
</i:Interaction.Behaviors>
like image 166
Jef Patat Avatar answered Nov 14 '22 23:11

Jef Patat