So if you followed my previous post you should be able to make a basic MVVM setup.
In this post I will discuss how to switch between UserControls and how to handle “ClickEvents” since we can not put the ClickHandlers inside the codebehind file! This code has to be in the ViewModel file!
To start let’s make a new UserControl into the View folder, I will name mine CarView.xaml
After this make a new ViewMode, add a class file to the ViewModel folder and name it CarViewModel.cs. This class has to inherit from ViewModelBase so do not forget to add the usings:
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command;
Before starting we should make a Car.cs class inside the Model folder, because we would like to use Objects now instead of strings, like in the previous post!
public class Car { public int Id { get; set; } public string Brand { get; set; } public string Model { get; set; } public Car() { } public Car(int id, string brand, string model) { this.Id = id; this.Brand = brand; this.Model = model; } }
Now we switch back to the CarViewModel.cs file.
Because we would like to use a Collection of Cars we need to add a ObservableCollection Property to the CarViewModel.cs class:
private ObservableCollection<Car> _CarsCollection; public ObservableCollection<Car> CarsCollection { get { return _CarsCollection; } set { _CarsCollection = value; } }
Because we are not using any Database system we are going to make a “fillCars function which we will call inside the constructor.
public CarViewModel() { _CarsCollection = fillCars(); } private ObservableCollection<Car> fillCars() { ObservableCollection<Car> cars = new ObservableCollection<Car>(); cars.Add(new Car(1, "Seat", "Ibiza")); cars.Add(new Car(2, "Audi", "A4")); return cars; }
So now our CarViewModel.cs file is ready we need to make changes to the ViewModelLocator.cs file:
To the ViewModelLocator.cs as seen in the previous blog post add following lines:
private static CarViewModel _Car; public static CarViewModel CarStatic { get { if (_Car == null) { createCar(); } return _Car; } } public CarViewModel Car { get { return CarStatic; } } public static void createCar() { if (_Car == null) { _Car = new CarViewModel(); } }
So now we can bind the ObservableCollection (from the CarViewModel.cs) to a DataGrid (from the CarView.xaml) but be sure to not forget to set the DataContext!
DataContext="{Binding Car, Source={StaticResource Locator}}">
<my:DataGrid ItemsSource="{Binding CarsCollection}"></my:DataGrid>
Ok so now we got the usercontrol ready but how do we show this control on the MainPage.xaml ?
I will explain how to show the CarView.xaml when clicked on a button!
To start we will add 2 rows to the Grid in the MainPage.xaml.
In the first row we will add a Button and in the second row a contentpresenter!
<UserControl ... ... DataContext="{Binding Main, Source={StaticResource Locator}}"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.RowDefinitions> <RowDefinition Height="10*"/> <RowDefinition Height="90*"/> </Grid.RowDefinitions> <Button Grid.Row="0" Height="25" x:Name="btnAdd" Margin="10 0 0 0" Content="Toevoegen"/> <ContentPresenter Grid.Row="1" Content="{Binding CurrentView}"/> </Grid> </UserControl>
The ContentPresenter will show the UserControl who is assigned to the CurrentView property inside the MailViewModel.cs !
So when we click on the Button we have to assign a new value to the CurrentView property.
To do this we can use the “Command” property of a Button.
Mmmmm Wait… There is no Command property in a Silverlight Button!
Well lets make it then!
Inside the Silverlight Project add a folder and name it Services.
Now add a class named ButtonService.cs, the class should look like:
public static class ButtonService { #region CommandParameter /// <summary> /// CommandParameter Attached Dependency Property /// </summary> public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached("CommandParameter", typeof(string), typeof(ButtonService), new PropertyMetadata(OnCommandParameterChanged)); /// <summary> /// Gets the CommandParameter property. /// </summary> public static string GetCommandParameter(DependencyObject d) { return (string)d.GetValue(CommandParameterProperty); } /// <summary> /// Sets the CommandParameter property. /// </summary> public static void SetCommandParameter(DependencyObject d, string value) { d.SetValue(CommandParameterProperty, value); } /// <summary> /// Handles changes to the CommandParameter property. /// </summary> private static void OnCommandParameterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { } #endregion #region Command /// <summary> /// Command Attached Dependency Property /// </summary> public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ButtonService), new PropertyMetadata(OnCommandChanged)); /// <summary> /// Gets the Command property. /// </summary> public static ICommand GetCommand(DependencyObject d) { return (ICommand)d.GetValue(CommandProperty); } /// <summary> /// Sets the Command property. /// </summary> public static void SetCommand(DependencyObject d, ICommand value) { d.SetValue(CommandProperty, value); } /// <summary> /// Handles changes to the Command property. /// </summary> private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is Button) { string parameter = d.GetValue(CommandParameterProperty) as string; Button b = d as Button; ICommand c = e.NewValue as ICommand; b.Click += delegate(object sender, RoutedEventArgs arg) { c.Execute(parameter); }; } } #endregion }
I did not write this class myself and at this time i will not explain what every line does.
The basic principe is that it makes a Attached Dependendy Property!
If u want to learn more about it read this.
So now we have to go to the MainPage.xaml and make sure we can use the command property for the button!
To do this add the following at the top of ur xaml code:
xmlns:myService="clr-namespace:mvvmTry.Services"
Make sure that mvvmTry is the correct namespace!
Now go to the button in the MainPage.xaml and change it to:
<Button Grid.Row="0" myService:ButtonService.Command="{Binding Path=OverviewCommand}" Height="25" x:Name="btnOverview" Margin="10 0 0 0" Content="Overview"/>
So when we click the Button he will be looking for a Command named “OverviewCommand” in the MainViewModel.cs class.
But we still need to define this command in this class!
To do this we simply make a new RelayCommand property (RelayCommand is part of the GalaSoft.MvvmLight (SL) project).
So open MainViewModel.cs and add
public RelayCommand OverviewCommand { get; set; }
And change the constructor to:
public MainViewModel() { _currentView = null; OverviewCommand = new RelayCommand(() => { _currentView = new CarView(); RaisePropertyChanged("CurrentView"); }); }
So when the constructor is executed it will define a command named OverviewCommand as a new RelayCommand and it will tell that if the command is raised we need to change the currentView to CarView() and call RaisePropertyChanged!
This last function tells your application that the content of your CurrentView has been changed!
If you now run your application you should see the Car Overview when u click on the button!
Thanks for reading and good luck!
Remember, if you have found any mistakes in my post, please inform me!