Componentone Toolbar for WPF and Silverlight
Commanding with C1Toolbar (WPF Tutorial) / Part 3: Using Commands in MVVM
In This Topic
    Part 3: Using Commands in MVVM
    In This Topic

    Commanding is an essential part of the MVVM (Model-View-ViewModel) design pattern where the separation of UI from business logic is key. Toolbar for WPF supports the command framework and can be used with the popular MVVM pattern. In MVVM-designed applications, command targets are often implemented in the ViewModel, which are not part of the UI element tree. Therefore, the RoutedCommand is not a good implementation of ICommand to use in MVVM. You should use a special implementation such as DelegateCommand or RelayCommand, which enables your View to bind to objects that are not part of the UI element tree.

    The following steps show how to create the same custom command implemented in Part 2 using the RelayCommand class and C1Toolbar.

    1. Create a new class named MainViewModel, which implements the INotifyPropertyChanged interface. This class will act as the ViewModel for our View containing C1Toolbar.

      C#
      Copy Code
      class MainViewModel : System.ComponentModel.INotifyPropertyChanged
      {
          private string textValue = "";
          public string TextValue
          {
              get
              {
                  return textValue;
              }
              set
              {
                  textValue = value;
                  OnPropertyChanged("TextValue");
              }
          }
      
          private RelayCommand clearCommand;
          public ICommand ClearCommand
          {
              get
              {
                  if (clearCommand == null)
                  {
                      clearCommand = new RelayCommand(param => this.Clear(), param => this.CanClear());
                  }
                  return clearCommand;
              }
          }
      
          private bool CanClear()
          {
              return textValue.Length > 0;
          }
      
          private void Clear()
          {
              TextValue = "";
          }
      
          public event PropertyChangedEventHandler PropertyChanged;
      
          protected void OnPropertyChanged(string propertyName)
          {
              PropertyChangedEventHandler handler = PropertyChanged;
      
              if (handler != null)
              {
                  handler(this, new PropertyChangedEventArgs(propertyName));
              }
          }
      
      }
      

       

      This class uses the RelayCommand, which is a lightweight variation of the DelegateCommand. Both ICommand implementations allow you to delegate commanding logic to methods passed as parameters with command targets that are not part of the UI element tree. The RelayCommand and DelegateCommand classes are not part of the WPF framework and can be found online and with various MVVM toolkits.

    2. Add the RelayCommand class to your project.

      C#
      Copy Code
      /// <summary>
      ///     This class allows delegating the commanding logic to methods passed as parameters,
      ///     and enables a View to bind commands to objects that are not part of the element tree.
      /// </summary>
      public class RelayCommand : ICommand
      {
          #region Fields
      
          readonly Action<object> _execute;
          readonly Predicate<object> _canExecute;
      
          #endregion // Fields
      
          #region Constructors
      
          public RelayCommand(Action<object> execute)
              : this(execute, null)
          {
          }
      
          public RelayCommand(Action<object> execute, Predicate<object> canExecute)
          {
              if (execute == null)
                  throw new ArgumentNullException("execute");
      
              _execute = execute;
              _canExecute = canExecute;
          }
          #endregion // Constructors
      
          #region ICommand Members
      
          [DebuggerStepThrough]
          public bool CanExecute(object parameter)
          {
              return _canExecute == null ? true : _canExecute(parameter);
          }
      
          public event EventHandler CanExecuteChanged
          {
              add { CommandManager.RequerySuggested += value; }
              remove { CommandManager.RequerySuggested -= value; }
          }
      
          public void Execute(object parameter)
          {
              _execute(parameter);
          }
      
          #endregion // ICommand Members
      }
      

       

    3. To bind to the ViewModel, add the following XAML at the top of your View containing C1Toolbar:

      XAML
      Copy Code
      <Window.Resources>
          <local:MainViewModel x:Key="viewModel" />
      </Window.Resources>
      <Window.DataContext>
          <Binding Source="{StaticResource viewModel}"/>
      </Window.DataContext>
      

       

      This adds your ViewModel as a resource which is then bound to the DataContext of the Window or UserControl.

    4. Then add the following toolbar group to the C1Toolbar you created in Part 1.

      XAML
      Copy Code
      <c1:C1ToolbarGroup Header="Application">
          <c1:C1ToolbarButton LabelTitle="Clear Text" Command="{Binding ClearCommand}" LargeImageSource="/Resources/delete.png"/>
      </c1:C1ToolbarGroup>
      

       

      This toolbar group contains one C1ToolbarButton with its Command property bound to the ClearCommand defined in the ViewModel.

    5. Since this command should follow MVVM best practices, the TextBox Text property should also be bound to a value from the ViewModel if we wish to apply business logic to it. Bind the Text property to the TextValue property which is also defined in the ViewModel.

      XAML
      Copy Code
      <TextBox Grid.Row="1" Text="{Binding TextValue, UpdateSourceTrigger=PropertyChanged}" Height="23" HorizontalAlignment="Left" Margin="12,17,0,0" Name="textBox1" VerticalAlignment="Top" Width="165" />
      

       

      By setting the UpdateSourceTrigger to PropertyChanged, the TextValue property on the ViewModel will be updated any time there is a change in Text value, as opposed to only when the TextBox loses focus.

    6. Run the application and observe the custom RelayCommand in action.

       

       

    There are many benefits that you get by following the MVVM design pattern due to the loose coupling of UI from business logic.