WPF - Handle an ApplicationCommand in the ViewModel - wpf

I bet this has been answered many times over, but...
For a simple situation where a button on a UserControl has its command property set to something like Find (ApplicationCommands.Find) how would the ViewModel handle that command? I usually see command handlers wired up with a CommandBinding that gets added to a CommandBindings collection on a UIElement, but my ViewModel doesn't derive from UIElement (should it?). The commands themselves don't expose events to notify when they've been executed, so where should I wire up to get that information?
EDIT: I'd like to use stock WPF to solve the problem if possible. I know there are many available frameworks for this sort of thing but would like to keep the code simple.
EDIT2: Including some sample code.
<UserControl>
<UserControl.DataContext>
<local:MyViewModel/>
</UserControl.DataContext>
<Button Command="Find"/>
</UserControl>
Where:
class MyViewModel
{
// Handle commands from the view here.
}
I could add a CommandBinding to the UserControl which would handle Executed, then call a hypothetical Find method in MyViewModel which does the actual work, but that's extra and unnecessary code. I'd prefer if the ViewModel itself handled the Find command. One possible solution would be to have MyViewModel derive from UIElement however that seems counter intuitive.

The purpose of commands is to decouple the code which generates the order from the code which executes it. Therefore: if you want tight coupling, you should better do it through events:
<UserControl ... x:Class="myclass">
...
<Button Click="myclass_find" .../>
...
</UserControl>
For loose coupling you need to add a CommandBinding to your UserControl:
<UserControl ... >
<UserControl.DataContext>
<local:MyViewModel/>
</UserControl.DataContext>
<UserControl.CommandBindings>
<Binding Path="myFindCommandBindingInMyViewModel"/>
</UserControl.CommandBindings>
...
<Button Command="ApplicationComamnd.Find" .../>
...
</UserControl>
(not sure about the syntax)
Or you can add a CommandBinding to your UserControl's CommandBindings in the constructor, taking the value from the ViewNodel:
partial class MyUserControl : UserControl
{
public MyUSerControl()
{
InitializeComponent();
CommandBinding findCommandBinding =
((MyViewModel)this.DataContext).myFindCommandBindingInMyViewModel;
this.CommandBindings.Add(findCommandBinding);
}
}

Related

WPF mvvm DataTemplates change View from UserControl

I am new to WPF and the MVVM pattern. I am trying to build a 'step by step' or 'wizard' like application.
So the user should first login then select some data and finally the selected data should be stored somewhere. (This flow never changes!)
However I decided to use DataTemplates and different ViewModels for each Template and a MainViewModel for the Window which populates the Templates. (Think this should be ok regarding to different Posts here)
But now my problems are starting. I know how I can change the current view from the MainViewModel BUT I want to change the current View from the inner ViewModel. And I want to be able to collect data from one inner ViewModel to another and I have no clue how this can work.
MainViewModel:
public class MainWindowViewModel : ViewModelBase
{
public ViewModelBase CurrentView {get; set;}
public MainWindowViewModel()
{
CurrentView = new ViewModelA;
}
}
XAML:
<Window x:Class="PUSEImporter.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:PUSEImporter.ViewModel"
xmlns:V="clr-namespace:PUSEImporter.View">
<Window.DataContext>
<VM:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type VM:ViewModelA}">
<V:Detail />
</DataTemplate>
<DataTemplate DataType="{x:Type VM:ViewModelB}">
<V:Overview />
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding CurrentView}"/>
</Window>
So think about a button in ViewModelA (or the View from ViewModelA) and now I want to switch to ViewModelB when someone clicks on the button. And not enough the data which is collected by ViewModelA should also be available in ViewModelB.
Is this possible and the preferred way of using this techniques or do I misunderstand some concepts?
(And if this is true how should i handle things like that?)
Thanks in advance!
There are many ways to achieve what you want. In MVVM, there's one view model to each view... therefore, if your main view has a child view, then your main view model should have a property of the type of another view model. In this instance, you can add a delegate to the child view model and register a handler for it in the main view model.
This will enable you to effectively pass a signal to the main view model from the child view model, which you can react to in the parent view model in any way you want to. Rather than explain the whole story again here, please see my answers from the Passing parameters between viewmodels and How to call functions in a main view model from other view models? posts here on Stack Overflow for more information on how to achieve this.

how to load wpf usercontrol in MVVM pattern

I'm creating a wpf user control which is in mvvm pattern.
So we have : view(with no code in codebehind file), viewmodel,model,dataaccess files.
I have MainWindow.xaml as a view file, which I need to bind with MainWindowModel.cs.
Usually, in a a wpf application we can do this with onStartUp event in App.xaml file. But in user control, as we do not have App.xaml...How do I achieve it ?
Please help :(...Thanks in Advance !!!
You can use a ContentControl, with a DataTemplate to bind the UserControl (View) to the ViewModel :
<DataTemplate DataType="{x:Type vm:MyViewModel}">
<v:MyUserControl />
</DataTemplate>
...
<ContentControl Content="{Binding Current}" />
WPF will pick the DataTemplate automatically based on the type of the Content
I know this is an old, answered question, but I have a different approach. I like to make implicit relationships in the App.xaml file:
<Application.Resources>
<DataTemplate DataType="{x:Type ViewModels:KioskViewModel}">
<Views:KioskView />
</DataTemplate>
</Application.Resources>
With this, there is no need to set a DataContext anywhere.
UPDATE >>>
In response to #Vignesh Natraj's request, here is a fuller explanation:
Once you have set up the DataTemplate in a Resources element, you can display the KioskView in this example by adding an instance of the KioskViewModel anywhere in your XAML. This could be filling the MainWindow, or just inside a particular section of the screen. You could also host multiple instances of the KioskViewModel in a ListBox and it will generate multiple KioskView instances.
You can add an instance of the KioskViewModel to your XAML in a couple of ways, depending on your requirements. One way is to declare the XML namespace for the project that contains the KioskViewModel.cs file and simply add an instance of it in a ContentControl to the page where you want your view to appear. For example, if you had a UserControl called MainView and the KioskViewModel.cs file was in a Kiosk.ViewModels namespace, you could use basic XAML like this:
<UserControl x:Class="Kiosk.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:Kiosk.ViewModels">
<UserControl.Resources>
<ViewModels:KioskViewModel x:Key="KioskViewModel" />
<DataTemplate DataType="{x:Type ViewModels:KioskViewModel}">
<Views:KioskView />
</DataTemplate>
</UserControl.Resources>
<ContentControl Content="{StaticResource KioskViewModel}" />
</UserControl>
I prefer to use the MVVM design pattern with WPF, so I would have a base view model class providing useful functionality such as implementing the essential INotifyPropertyChanged interface. I then have a property called ViewModel in the main (top level) view model of type BaseViewModel. This provides me with a nice way to change the ViewModel property to any view model that has derived from BaseViewModel and therefore to be able to change the associated view from the view model.
For example, in the MainViewModel.cs class that is bound to MainView there is a field and relating property:
private BaseViewModel viewModel = new KioskViewModel();
public BaseViewModel ViewModel
{
get { return viewModel; }
set { viewModel = value; NotifyPropertyChanged("ViewModel"); }
}
As you can see, it starts off as a KioskViewModel instance, but can be changed to any other view at any time in response to user interaction. For this setup, the XAML is very similar, but instead of declaring an instance of the view model in the Resources element, we bind to the property in the MainViewModel:
<UserControl x:Class="Kiosk.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewModels="clr-namespace:Kiosk.ViewModels">
<ContentControl Content="{Binding ViewModel}" />
</UserControl>
Note that for this example, we would need to declare two (or more to make this approach useful) DataTemplates in the App.xaml file:
<Application.Resources>
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:KioskViewModel}">
<Views:KioskView />
</DataTemplate>
</Application.Resources>
I've been using MVVM Light Toolkit which has a ViewModelLocator class that you can put properties to the viewmodels in. You then create a reference to the ViewModelLocator in your Mainwindow.xaml like so:
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True"/>
In the grid panel, or whatever you're using, you can then set the datacontext like this:
<Grid DataContext="{Binding MainWindowViewModel, Source={StaticResource Locator}}">
...
</Grid>
You could also go with MEFedMVVM which potentially adds a bit more flexibility in terms of being able to swap different viewModel implementations into the view.
The flexibility in both of these libraries is that you don't have to use their ViewModel base classes if you don't want to - the ViewModelLocator and the MEFedMVVM can work with any class.
There are endless ways to do it, wich all fall in one of the two categories:"view first" or "model first".
In a "view first" mode the view (e.g. your mainwindow) is created first and then (e.g. in the codebehind) the View instantiates the ViewModel and sets it as its datacontext):
private void WindowLoaded(object sender, EventArgs args)
{
this.DataContext = ViewModelService.GetViewModelX();
}
In a "model first" mode the ViewModel is there first and then instanciated the View.
// method of the viewmodel
public void LoadView()
{
// in this example the view abstracted using an interface
this.View = ViewService.GetViewX();
this.View.SetDataContext(this);
this.View.Show();
}
The examples given here are just one way of many. You could look at the various MVVM frameworks and see how they do it.
We can use ObjectDataProvider to call a method inside an object ..as follows :
<ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}"
MethodName="ConvertTemp"
x:Key="convertTemp">
Is there anyway to do the same using DataTemplate
You can probably look at MSDN. I find it as a good resource, though it doesn't explain how to use usercontrols,you will find your way out.

Binding Commands Without Using the DataContext [silverlight+prism]

Hello I have a problem with binding commands to button inside datagrid.
Here should be explanation but it doesn't explain everything.
http://msdn.microsoft.com/en-us/library/dd458928.aspx
What should be in classes in namespace Infrastructure?
Can somebody show me a really basic sample of using this?
not just parts of the code...
The Prism Commanding QuickStart - included with the Prism drop should provide the simple code example you are looking for.
All data-bindings go against the current DataContext unless specified otherwise. The DataContext is inherited down the tree of controls unless a control specifically picks a DataContext.
For example your Button might look like this and would look for the SaveCommand on whatever the DataContext has:
<Button Command="{Binding SaveCommand} />
Your button could also look like this if you wanted to bind to a command exposed on your classes code-behind:
<UserControl x:Name="UserControl">
...
<Button Command="{Binding SaveCommand, ElementName=UserControl}"
...
</UserControl>
Using DelegateCommand is just a way of implementing the ICommand you bind to and that should be visibile in the Prism QuickStart.

Xamly begin a storyboard when a RoutedCommand is called?

Is there a way to begin a storyboard wen an ICommand is executed WITH XAML?
RoutedCommands involve some code-behind, but this is definitely doable.
The simplest way is to add a CommandBinding to the parent control. Something like this:
<UserControl>
<UserControl.CommandBindings>
<CommandBinding Command="ApplicationCommands.Exit" Executed="HandleExit"/>
</UserControl.CommandBindings>
</UserControl>
Then in your code-behind event handler named 'HandleExit', invoke the storyboard either by name or from the Resources collection.
Let me know if you need some more clarification.

WPF - MVVM Command binding on Sub ViewModel

I've got a VehicleViewModel that has a sub ViewModel of NotesViewModel
public IManageVehicleNotesViewModel NotesViewModel { get; set; }
On the first activation of VehicleViewModel I activate the sub ViewModel.
NotesViewModel.Activate();
The activation calls a method to init a number of Commands, I've break pointed this and its being called.
CreateCommand = new DelegateCommand<object>(OnCreateCommand, CanCreate);
However although the TextBoxes are binding on the sub View (so the DataContext is in place) none of the commands are binding - I've tried to calling RaiseCanExecuteChanged on the commands but they don't disable, enable or call the methods as expected.
I don't know whether its relevant (as the TextBoxes are binding) but I'm associating the View and ViewModel using a ResourceDictionary as so ...
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:v="clr-namespace:GTS.GRS.N3.Modules.Vehicles.Views"
xmlns:vm="clr-namespace:GTS.GRS.N3.Modules.Vehicles.Model">
<DataTemplate DataType="{x:Type vm:ManageVehicleViewModel}">
<v:ManageVehicleView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ManageVehicleNotesViewModel}">
<v:ManageVehicleNotesView />
</DataTemplate>
</ResourceDictionary>
The commands on the top level VehicleViewModel work.
Has anyone experienced anything like this? Is it the order I'm doing things? Any help gratefully received!
Cheers,
Andy
Does the CreateCommand property trigger the PropertyChanged event ? If it doesn't, the UI won't be notified when you assign it...
Try to use a tool like Snoop to check whether the Command property of the button is set
Do this and check the output to see what is going on:
<UserControl …
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase" />
<Button Command="{Binding MyCommand,
diagnostics:PresentationTraceSources.TraceLevel=High}" … />
It should report what object it's actually trying to bind to, etc. Check your output window while you are running to see what is going on with that binding.

Resources