How to bind application commands to view model(WPF)?
Asked Answered
R

5

7

I have already read Josh Smiths article about binding commands to view model using RelayCommand. However I need to bind ApplicationCommands.Save to a view model so that when a user clicks the save menu item it is handled in the window. How is it possible?

Resort answered 18/5, 2011 at 17:17 Comment(0)
B
1

The best solution I'm aware of us to use a service. For example, an ICommandBindingsProvider like this:

public interface ICommandBindingsProvider
{
    CommandBindingCollection CommandBindings { get; }
}

This gets injected into your ViewModel and used like this:

public MyViewModel(ICommandBindingsProvider commandBindings)
{
    commandBindings.Add(new CommandBinding(....));
}

How the service gets injected will be dependent on what MVVM framework you're using. Most (but not all) support some sort of service injection capabilities. If you need a more concrete code example, look at Onyx which does service injection and has a service that does just this.

Battalion answered 18/5, 2011 at 17:36 Comment(2)
As I am not using any framework this is a bit problematic. I am just wondering if there is a way to do this without using a framework. For example ApplicationCommands.Save can be bind in the View. The view model can expose an ICommand which can be bound. Is there abolutely no way to connect these two(without breaking the pattern)Resort
My answer applies even if you're not using a framework, you'll just have to figure out how to inject the service. I have a blog post about services in MVVM at digitaltapestry.net/blog/… that shows one simple way to do this without a framework of any kind.Battalion
M
1

There is a good tutorial to help bind application commands.

  1. Setup your command binding collection for your view to bind to in your view model. e.g.:
public CommandBindingCollection CommandBindings { get; }

public YourViewModel()
{
//Create a command binding for the save command
var saveBinding = new CommandBinding(ApplicationCommands.Save, SaveExecuted, SaveCanExecute);

//Register the binding to the class
CommandManager.RegisterClassCommandBinding(typeof(YourViewModel), saveBinding);

//Adds the binding to the CommandBindingCollection
CommandBindings.Add(saveBinding);
}
  1. Setup attached properties. Read the article on how to do that.

  2. Then bind to it using attached properties.

<UserControl local:AttachedProperties.RegisterCommandBindings="{Binding CommandBindings}"> 
    <Window.DataContext>
        <local:YourViewModel></local:YourViewModel>
    </Window.DataContext>
</UserControl>
Moskva answered 11/7, 2014 at 6:57 Comment(0)
S
0

How is your save menu item being created? Somewhere it must be getting bound to the ApplicationCommands.Save? You can change that so that it binds to your ViewModel's save instead.

Scoff answered 18/5, 2011 at 17:26 Comment(2)
ApplicationCommands.Save is the command fired by the menu item. I just need to add a binding to the command in my view model.Resort
I assume you're suggesting he uses a command other than ApplicationCommands.Save? While a valid alternative some of the time, it's not always possible. A good example is Cut/Copy/Paste commands, where you'll want to use the built-in RoutedCommands used by the built-in controls.Battalion
P
0

Or, you place the save command binding on the viewmodel, and then databind to it, something like (pseudo code)

in the viewmodel:

...
public Command SaveCommand { get { return yourCodeHere; } }
...

in the view:

<Button Command="{Binding Path=SaveCommand}" Content="Click"/>    

Update: i just tried binding to a command in a commandbinding and it doesn't work. what i was thinking of was binding to a command.

Psychodrama answered 18/5, 2011 at 17:43 Comment(2)
I dont think this is possible in WPF. It would be really nice if the window can delegate a command to the view model like this.Resort
ack! you're correct. Now i have to find the thing that made me think this was. i could have swore there was a way to bind either to command or something in there...Psychodrama
W
0

I have used this approach successfully in the past:

Start out by defining a CommandBindings property on ViewModels (same definition as on Views).

Then for each Command implemented by ViewModel, add a CommandBinding to ViewModel's CommandBindings.

Then, when you set:

view.DataSource = viewModel;

Also set:

view.CommandBindings.AddRange(viewModel.CommandBindings);

I think may be done using a binding of the CommandBindings property (can't remember for sure).

Waxy answered 18/5, 2011 at 18:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.