Ioannis Panagopoulos blog

Tutorials on HTML5, Javascript, WinRT and .NET

Going from Model-View-Presenter to MV-VM with WPF Commands (Part #3: MVVM and Commands)

by Ioannis Panagopoulos

In previous posts (Part 1 and Part2) I have presented the implementation of a toy application using the Model-View-Presenter pattern and Routed Commands. In this final post, I will present the migration to MVVM. In Part2, we have reached a point where we have managed to partly centralize the logic that is needed to be implemented for each Command but we were not yet fully satisfied with the wiring that needed to be done in the code-behind file. So, we will try to tackle this problem:

Approach #4 Our first ViewModel for MVVM

Our first ViewModel is an implementation that looks a lot like the presenter. The code is as follows:

    public class ViewModel
    {
        private Client _selectedClient = null;
        public Client SelectedClient
        {
            get { return _selectedClient; }
            set { _selectedClient = value; }
        }
        public ObservableCollection<Client> Clients
        {
            get { return ClientRepository.GetClients(); }
        }
        public void AddClientCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ClientRepository.AddClient(new Client());
        }
        public void AddClientCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }
        public void DeleteClientCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (_selectedClient != null)
            {
                ClientRepository.DeleteClient(_selectedClient);
            }
        }
        public void DeleteClientCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (_selectedClient != null);
        }
        public void ResetClientCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (_selectedClient != null)
            {
                _selectedClient.FirstName = "RESET";
                _selectedClient.LastName = "RESET";
                _selectedClient.Phone = "9999999999";
            }
        }
        public void ResetClientCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = (_selectedClient != null);
        }
    }

The whole idea behind the MVVM model is the use of a ViewModel class that will provide everything needed to the View through the use of Bindings. Therefore, we want to have a code-behind file that contains the following:

public partial class Window4 : Window
{
    ViewModel model = new ViewModel();

    public Window4()
    {
        InitializeComponent();

        this.DataContext = model;

        this.CommandBindings.Add(new CommandBinding(ClientCommands.AddClient, 
                    model.AddClientCommand_Executed, model.AddClientCommand_CanExecute));
        this.CommandBindings.Add(new CommandBinding(ClientCommands.DeleteClient, 
                    model.DeleteClientCommand_Executed, model.DeleteClientCommand_CanExecute));
        this.CommandBindings.Add(new CommandBinding(ClientCommands.ResetClient, 
                    model.ResetClientCommand_Executed, model.ResetClientCommand_CanExecute));
       
    }
}

That is we initialize the ViewModel, we set the Window's DataContext to the model and associate the commands with methods of the ViewModel. The xaml file is similar to the previous approach but it does not define the Command bindings (since they are defined in code)  and the handler for the ListBox SelectionChanged event is substituted with a binding of the SelectedItem property to the SelectedClient property of the ViewModel.

Are we finished? Not quite so. Although we have managed to take most of the code out of the code-behind file, achieving a separation between GUI and logic, there are still the binding definitions that need to be specified in every window that uses Commands. We would really like to avoid writing those as well. That leads us to:

Approach #5 The final MVVM model

Up to this point we have been working with Routed Commands. As previously stated, Routed Commands are fired from controls and bubble up the visual tree until they find a control that holds the binding that implements their logic. What we want to do to the view is the following. We want to avoid defining the Command Bindings and assocate the MenuItems with something like this:

 

<MenuItem x:Name="MenuItemAddClient"  Header="{Binding Path=AddClientText}" 
          Command="{Binding Path=AddClient}" />
<MenuItem x:Name="MenuItemDeleteClient" Header="{Binding Path=DeleteClientText}" 
          Command="{Binding Path=DeleteClient}" />
<MenuItem x:Name="MenuItemEditClient" Header="{Binding Path=ResetClientText}" 
          Command="{Binding Path=ResetClient}" />

That is, we bind the command's implemementaion to the MenuItems directly in the xaml file. There is no routing of the commands to other visual elements.

For this approach to work we need to make the AddClient, DeleteClient and ResetClient commands implement the ICommand interface. Or, because all commands will share some functionaliy in common, we can create the following class that implements the ICommand interface and delegates the behavior according to the command:

public class SimpleCommand:ICommand
    {
        public Predicate<object> CanExecuteDelegate { get; set; }
        public Action<object> ExecuteDelegate { get; set; }

        #region ICommand Members

        public bool CanExecute(object parameter)
        {
            if (CanExecuteDelegate!=null) return CanExecuteDelegate(parameter);
            return true;
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            if (ExecuteDelegate!=null) ExecuteDelegate(parameter);
        }

        #endregion
    }

The new ViewModel is as follows. Note the implementation of the commands compared to the previous version, where each command defines its own delegate methods that implements its logic.

 

    public class ViewModel2
    {
        private Client _selectedClient = null;
        public Client SelectedClient
        {
            get { return _selectedClient; }
            set { _selectedClient = value; }
        }

        public ObservableCollection<Client> Clients
        {
            get { return ClientRepository.GetClients(); }
        }

        private string _addClientText="Add Client";
        public string AddClientText
        {
            get { return _addClientText; }
            set { _addClientText = value; }
        }

        private string _deleteClientText="Delete Client";
        public string DeleteClientText
        {
            get { return _deleteClientText; }
            set { _deleteClientText = value; }
        }

        private string _resetClientText="Reset Client";
        public string ResetClientText
        {
            get { return _resetClientText; }
            set { _resetClientText = value; }
        }

        private SimpleCommand _addClient = new SimpleCommand();

        public SimpleCommand AddClient
        {
            get { return _addClient; }
            set { _addClient = value; }
        }

        private SimpleCommand _resetClient = new SimpleCommand();

        public SimpleCommand ResetClient
        {
            get { return _resetClient; }
            set { _resetClient = value; }
        }
        private SimpleCommand _deleteClient = new SimpleCommand();

        public SimpleCommand DeleteClient
        {
            get { return _deleteClient; }
            set { _deleteClient = value; }
        }

        public ViewModel2()
        {
            AddClient.CanExecuteDelegate += new Predicate<object>(AddClientCommand_CanExecute);
            AddClient.ExecuteDelegate += new Action<object>(AddClientCommand_Executed);

            ResetClient.CanExecuteDelegate += new Predicate<object>(ResetClientCommand_CanExecute);
            ResetClient.ExecuteDelegate += new Action<object>(ResetClientCommand_Executed);

            DeleteClient.CanExecuteDelegate += new Predicate<object>(DeleteClientCommand_CanExecute);
            DeleteClient.ExecuteDelegate += new Action<object>(DeleteClientCommand_Executed);
        }
        public void AddClientCommand_Executed(object sender)
        {
            ClientRepository.AddClient(new Client());
        }
        public bool AddClientCommand_CanExecute(object sender)
        {
            return true;
        }
        public void DeleteClientCommand_Executed(object sender)
        {
            if (_selectedClient != null)
            {
                ClientRepository.DeleteClient(_selectedClient);
            }
        }
        public bool DeleteClientCommand_CanExecute(object sender)
        {
            return (_selectedClient != null);
        }
        public void ResetClientCommand_Executed(object sender)
        {
            if (_selectedClient != null)
            {
                _selectedClient.FirstName = "RESET";
                _selectedClient.LastName = "RESET";
                _selectedClient.Phone = "9999999999";
            }
        }
        public bool ResetClientCommand_CanExecute(object sender)
        {
            return (_selectedClient != null);
        }
    }

 And that is all. The code-behind file now is as simple as this:

    public partial class Window5 : Window
    {
        ViewModel2 model = new ViewModel2();

        public Window5()
        {
            InitializeComponent();
            this.DataContext = model;          
        }
    }

and all the wiring is performed in the ViewModel. This is the maximum separation achieved with the MVVM pattern.

The project with all the approaches can be downloaded here.

 kick it on DotNetKicks.comShout it

blog comments powered by Disqus
hire me