Part 24 - Binding to Commands and CommandParameters

Sign in to queue

Description

Download the source code for this lesson at http://absolutebeginner.codeplex.com/

We’ve already discussed several facets of the Model-View-ViewModel design pattern, or rather MVVM.  In this lesson I want to add one more piece to the puzzle so that we can employ it in our upcoming project.

MVVM provides a clean separation of concerns between the data model and the view.  This is accomplished through the ViewModel class which is responsible for publishing methods that return collections of our data model to the view so that the view can bind to it and display it.

That covers the *display* of data. 

What if, for example, we want to not only bind data in our view, but also bind the Click event of a button to a method defined on our data model? 

Commands allow us to do that.

It is easier to show you what I mean than to explain it in theory without a concrete example in front of you.

I’ll create an app that might be used to check in cars at a Car rental company.  Customers drop off their cars in an airport, the Car rental employee sees a list of cars scheduled to be returned today, they click a button next to the car that they receive and see a message with the check in time.  This is far from a complete example, but it will allow us to see a simple example of Commands in action.

I’ll start by creating a new project called “BindingToCommands”.  I’ll immediate add a Car class:

public class Car
{
  public int ID { get; set; }
  public string Make { get; set; }
  public string Model { get; set; }
  public string CheckedInDateTime { get; set; }
}


Note: Ideally we would store CheckedInDateTime as a DateTime, not a string.  I did this because I want to format the string nicely.  As you’ll learn in the next lesson, we can create a ValueConverter for the purpose of formatting the date nicely while keeping the value as a DateTime.

Next I create a simple CarDataSource like so:

public class CarDataSource
{
  private static ObservableCollection<Car> _cars
      = new ObservableCollection<Car>();

  public static ObservableCollection<Car> GetCars()
  {
    if (_cars.Count == 0)
    {
      _cars.Add(new Car() { ID = 1, Make = "Olds", Model = "Cutlas" });
      _cars.Add(new Car() { ID = 2, Make = "Geo", Model = "Prism" });
      _cars.Add(new Car() { ID = 3, Make = "Ford", Model = "Pinto" });
    }
    return _cars;
  }
}

In the MainPage.xaml, I’ll call the static GetCars() method to wire up the Default View Model for the page:

private ObservableCollection<Car> _carsViewModel =
      CarDataSource.GetCars();

public ObservableCollection<Car> CarsViewModel {
  get { return this._carsViewModel; }
}

… and then binding to the view model in XAML like so:

<Page
  . . .
  DataContext="{Binding CarsViewModel,
      RelativeSource={RelativeSource Self}}">

Then I’ll implement the layout and make sure the binding works.

<StackPanel Margin="20,40,20,40">
  <ListView x:Name="myListView" ItemsSource="{Binding}" >
    <ListView.ItemTemplate>
      <DataTemplate x:Name="dataTemplate">
        <StackPanel Orientation="Horizontal">
          <StackPanel Orientation="Vertical" Margin="0,0,20,0">
            <TextBlock Text="{Binding Make}" FontSize="24" />
            <TextBlock Text="{Binding Model}" FontSize="24" />
          </StackPanel>
                       
          <Button Content="Check In"
                  Width="100"
                  Height="50"
                  Margin="0,0,20,0" />

          <TextBlock Text="{Binding CheckedInDateTime}" FontSize="24" />

        </StackPanel>
      </DataTemplate>
    </ListView.ItemTemplate>

  </ListView>
</StackPanel>

This produces the following visual result:

clip_image002

With the preliminary work out of the way, we can turn our focus to implementing the Command.  The first order of business is to implement the command that represents a “check in” for a car.  I’ll create a class called CheckInButtonClick that implements ICommand.  Then, I’ll use the Control + [dot] keyboard combination to implement the ICommand interface:

clip_image004

This provides a stubbed out set of methods and the event declaration like so:

    public class CheckInButtonClick : ICommand
    {

      public bool CanExecute(object parameter)
      {
        throw new NotImplementedException();
      }

      public event EventHandler CanExecuteChanged;

      public void Execute(object parameter)
      {
        throw new NotImplementedException();
      }
    }

First, I need to merely answer the question “can this be executed”?  Here I could write logic to decide whether or not this command can be executed based on the current state of the Car object that is passed in as a parameter.  Ultimately, I’ll return a bool.  In our case, since I’m going to keep this simple, I’ll merely return true.  This command can always be executed regardless of the state of the object.

public class CheckInButtonClick : ICommand
{
  public bool CanExecute(object parameter)
  {
    return true;
  }
        . . .
}

In actuality, I would probably want to check to see whether if this instance of Car has already been checked in prior to allowing it a second time.  I’ll leave the implementation of that business rule to you for experimentation.

Now, I need to associate the command with my Car class:

        public ICommand CheckedInCommand { get; set; }

        public Car()
        {
            CheckedInCommand = new CheckInButtonClick();
        }

I create an auto-implemented property of type ICommand, then in the Constructor, set the property to an instance of the CheckInButtonClick() command class.  Now I have a class that can be Commanded, in other words, that I can bind a Command to it.

Next, I’ll want to tell the command what to do when this command is executed?  That’s what we’ll do in the Execute method.  In this case I want to set the CheckedInDateTime property to DateTime.Now.  Also, per my note, above, I want to format that for proper display.

I have two options.  I can either implement this in my model (i.e., a public method on my Car class) or the classes I use to generate by View Model (i.e., the CarDataSource class).  Which one you choose depends on how accessible you want to make your View Model and how flexible you want to make your Command.  If you were to either make your Data Source a property of the App OR make all the methods of your Data Source class static, AND you don’t mind your Command being tied specifically to your CarDataSource class, then you could implement the Execute command like so:

public async void Execute(object parameter)
{
  CarDataSource.CheckInCar((Car)parameter);
}

And in your CarDataSource, you would implement the CheckInCar() method like so:

public class CarDataSource
{
  . . .
 
  public static void CheckInCar(Car car) {
    _cars.FirstOrDefault(p => p.ID == car.ID)
         .CheckedInDateTime = String.Format("{0:t}", DateTime.Now);
  }
}

However, this approach has one obvious downside.  The Command is now coupled to the CarDataSource.  It could not be used as a more general purpose command.  That might be fine for your purpose, however another option is to make the CheckInCar() method a public property of the Car class itself:

public class Car
{
  . . .

  public void CheckInCar()
  {
    this.CheckedInDateTime = String.Format("{0:t}", DateTime.Now);
  }
}

And I can call this method from the Command’s Execute() method like so:

public async void Execute(object parameter)
{
  //CarDataSource.CheckInCar((Car)parameter);
  ((Car)parameter).CheckInCar();
}

I prefer this. 

Next, I’ll need to wire up the binding correctly.  I will want to fire the Command when I click the button, AND I’ll want to pass in the current instance of the Car to the Command’s Execute() method.  To do this, I’ll add the following XAML in the Button’s declaration:

<Button Content="Check In"
        . . .
        Command="{Binding CheckedInCommand}"
        CommandParameter="{Binding}"
        . . . />

In this case, the CommandParameter is bound to it’s parent binding which is defined in the ListView’s ItemSource:

<ListView x:Name="myListView" ItemsSource="{Binding}" >

… which in turn is bound to:

<Page
  . . .
  DataContext="{Binding CarsViewModel, RelativeSource={RelativeSource Self}}">

To me, this is a bit confusing.  It looks like I’m binding the ENTIRE CarViewModel to the CommandParameter.  However, the correct way to interpret this … the ListView’s ItemSource expects a collection.  Then each item is then bound to just one instance of that collection, therefore the CommandParameter=”{Binding}” means “bind to the current instance of the Car class”, not to the entire collection.  That was a little tricky for me to understand at first.  The key is understanding how the DataContext flows down from the page, into the ListView and then into the ItemTemplate.

Unfortunately, when I run the app, I may not get the results I was hoping for visually.  I would expect the value of CheckedInDateTime to change and then be presented on the screen when I click the Check In button.  It does not.  I assure you, the value is being changed in the data model, but because Car is not notifying the user interface of this property change, the user interface does not know it should update it’s presentation of the data.

Do you recall what we need to do to tell the user interface that a property changed? 

Yes, we need to implement the INotifyPropertyChanged interface on the Car class, then in the CheckedInDateTime setter, call the NotifyPropertyChanged() method that the interface forces us to implement.  Let’s implement that now using the Control + [dot] technique from earlier.

Note: Keep in mind that this is not part of Commands per se, however if your Commands will be updating properties, you very well may need to implement INotifyPropertyChanged to enable some user interface update like we’ll do from this point on in the lesson.

public class Car : INotifyPropertyChanged
{
  . . .

  public event PropertyChangedEventHandler PropertyChanged;

  private void NotifyPropertyChanged(string propertyName)
  {
    if (PropertyChanged != null)
    {
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

In this case, I really only care to call the NotifyPropertyChanged() method on the setter of CheckedInDateTime.  So, I’ll change the current implementation from an auto implemented property:

public DateTime CheckedInDateTime { get; set; }

To full property using the snippet: propfull [tab] [tab]

The full implementation after making the appropriate changes to the full property:

//public DateTime CheckedInDateTime { get; set; }

private string checkedInDateTime;

public string CheckedInDateTime
{
  get { return checkedInDateTime; }
  set {
    checkedInDateTime = value;
    NotifyPropertyChanged("CheckedInDateTime");
  }
}

Now when I click the Check In button, you can see the update in the user interface:

clip_image006

Recap

The beauty of a Command is that it keeps the separation of concerns in tact while allowing you to handle events triggered on the user interface that affect an instance of your view model.  We talked about the implementation of the ICommand interface and walked through a complete example.  We also looked at a practical implementation of the INotifyPropertyChanged interface.

Embed

Download

Download this episode

The Discussion

  • User profile image
    ryanthtra

    Thanks, Bob!

    While I see the use of Command objects instead of the Click event for the button in MainPage.xaml in order to keep the View and ViewModel decoupled, does that mean the Click event is pretty much obsolete when it comes to developing apps using the MVVM pattern?

Add Your 2 Cents