Click here to Skip to main content
15,884,975 members
Articles / Desktop Programming / WPF
Tip/Trick

Basic MVVM and ICommand Usage Example

Rate me:
Please Sign up or sign in to vote.
4.67/5 (60 votes)
2 Mar 2017CPOL3 min read 349.8K   4   69   24
Setting up basic MVVM in WPF and ICommand usage to allow operations on ViewModel from view.

Introduction

In this tip, we will learn about WPF Commands. Commands go very well with MVVM pattern (Model- View-ViewModel). We will also see how actually the view knows about its ViewModel and how the view invokes the operations on ViewModel which can be done by using Commands in WPF.

Background

We will follow this in a step by step approach rather than looking at the complete code at once which will help us to understand what each part of code does in a very better way.

Let’s have a look at the MVVM architecture.

Image 1

We use the standard conventions for naming the classes as follows:

  • Views are suffixed with View after the name of the View (e.g.: StudentListView)
  • ViewModels are suffixed with ViewModel after the name of the ViewModel. (e.g.: StudentListViewModel)
  • Models are suffixed with Model after the name of the Model (e.g.: StudentModel).

Using the Code

So enough of theory now, let’s dive into the code and see a working example for MVVM and how to use commands in MVVM.

Create a new WPF project in Visual Studio. Rename the MainWindow as MainWindowView to follow up our conventions.

Next, we need to create a new class with name MainWindowViewModel that will act as the ViewModel for the MainWindowView.

What we do here in MVVM is that we tell the View about what its ViewModel will be. This can be done by setting the Data Context for that view. Models are used in the ViewModel and they do not have any connection between some specific views.

Example code for setting the Datacontext goes like this.

Open the MainWindowView.xaml.cs and set the data context as follows.

MainWindowView.xaml.cs

XML
<Window x:Class="WpfExample.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:WpfExample">

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>

    <Grid>
    </Grid>
</Window>

Here the local is an alias to our namespace WpfExample. It’s required so that the framework knows where MainWindowViewModel is available.

Now we have set the MVVM pattern. Now the MainWindowView knows that’s its ViewModel is MainWindowViewModel.

We will verify this by using a simple binding.

Let's add a button to view and set the button content using a instance from ViewModel.

The View

We will add the button to the view and we will set its content using binding as follows:

MainWindowView.xaml.cs

XML
<Window x:Class=" WpfMvvmExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:WpfMvvmExample"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>

    <Grid>
        <Button Width="100" 
        Height="100" Content="{Binding ButtonContent}"/>
    </Grid>
</Window>
The ViewModel
C#
namespace WpfExample
{
    class MainWindowViewModel
    {
        public string ButtonContent
        {
            get
            {
                return "Click Me";
            }
        }
    }
}

In the above code, we are telling the View to fetch the content of button from ButtonContent property present in the ViewModel.

XML
<Button Width="100" Height="100" Content="{Binding ButtonContent}"/>

Now if we run the application, we can see that the button content is set to string Click Me”.

Image 2

So this interprets that our MVVM is working properly.

Now We Move In To the ICommand Interface

Now, let’s try to add click functionality to the button using Commands in WPF.

Commands provide a mechanism for the view to update the model in the MVVM architecture.

First, we have a look at the ICommand interface.

C#
bool CanExecute(object parameter);
void Execute(object parameter);
event EventHandler CanExecuteChanged;

We will create a sample application that displays a message box with message “HI” when a button is clicked and we will add another button that toggles whether the Hi button can be clicked.

We create a class called RelayCommand which implements ICommand interface. This class acts as Enhancement for the ICommand and extracts the boiler plate code to a separate class.

C#
public class RelayCommand : ICommand
   {
       private Action<object> execute;

       private Predicate<object> canExecute;

       private event EventHandler CanExecuteChangedInternal;

       public RelayCommand(Action<object> execute)
           : this(execute, DefaultCanExecute)
       {
       }

       public RelayCommand(Action<object> execute, Predicate<object> canExecute)
       {
           if (execute == null)
           {
               throw new ArgumentNullException("execute");
           }

           if (canExecute == null)
           {
               throw new ArgumentNullException("canExecute");
           }

           this.execute = execute;
           this.canExecute = canExecute;
       }

       public event EventHandler CanExecuteChanged
       {
           add
           {
               CommandManager.RequerySuggested += value;
               this.CanExecuteChangedInternal += value;
           }

           remove
           {
               CommandManager.RequerySuggested -= value;
               this.CanExecuteChangedInternal -= value;
           }
       }

       public bool CanExecute(object parameter)
       {
           return this.canExecute != null && this.canExecute(parameter);
       }

       public void Execute(object parameter)
       {
           this.execute(parameter);
       }

       public void OnCanExecuteChanged()
       {
           EventHandler handler = this.CanExecuteChangedInternal;
           if (handler != null)
           {
               //DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty));
               handler.Invoke(this, EventArgs.Empty);
           }
       }

       public void Destroy()
       {
           this.canExecute = _ => false;
           this.execute = _ => { return; };
       }

       private static bool DefaultCanExecute(object parameter)
       {
           return true;
       }
   }

The CommandManager.RequerySuggested is responsible for enabling and disabling of "Click to Hii" button.

TheView

XML
<Window x:Class="WpfExample.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:local="clr-namespace:WpfExample">

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Button Grid.Row="0" Command="{Binding HiButtonCommand}" 
        CommandParameter="Hai" Content="{Binding HiButtonContent}"
                Width="100"
                Height="100"  />

        <Button Grid.Row="1" Content="Toggle Can Click" 
        Command="{Binding ToggleExecuteCommand}"  Width="100" Height="100"/>
    </Grid>

</Window>

TheViewModel

C#
class MainWindowViewModel
    {
        private ICommand hiButtonCommand;

        private ICommand toggleExecuteCommand { get; set; }

        private bool canExecute = true;

        public string HiButtonContent
        {
            get
            {
                return "click to hi";
            }
        }

        public bool CanExecute
        {
            get
            {
                return this.canExecute;
            }

            set
            {
                if (this.canExecute == value)
                {
                    return;
                }

                this.canExecute = value;
            }
        }

        public ICommand ToggleExecuteCommand
        {
            get
            {
                return toggleExecuteCommand;
            }
            set
            {
                toggleExecuteCommand = value;
            }
        }

        public ICommand HiButtonCommand
        {
            get
            {
                return hiButtonCommand;
            }
            set
            {
                hiButtonCommand = value;
            }
        }

        public MainWindowViewModel()
        {
            HiButtonCommand = new RelayCommand(ShowMessage, param => this.canExecute);
            toggleExecuteCommand = new RelayCommand(ChangeCanExecute);
        }

        public void ShowMessage(object obj)
        {
            MessageBox.Show(obj.ToString());
        }

        public void ChangeCanExecute(object obj)
        {
            canExecute = !canExecute;
        }
    }

Final application looks like this:

Image 3

I have attached the sample project along with this tip. Hope you find this tip helpful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Dover India pvt ltd
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionthanks Pin
pranjal mudholkar19-Mar-22 16:39
pranjal mudholkar19-Mar-22 16:39 
QuestionMessage Closed Pin
10-May-21 11:18
Member 1518573310-May-21 11:18 
SuggestionConvert example to code only(XAML free) Pin
ajaydeokar16-Jun-20 2:47
ajaydeokar16-Jun-20 2:47 
Questiona question about the MainWindowViewModel constructor ¿is it right? Pin
EdoFro25-Jan-18 10:47
EdoFro25-Jan-18 10:47 
SuggestionMicrosoft Diagram Use Pin
Member 1336587617-Aug-17 6:20
Member 1336587617-Aug-17 6:20 
SuggestionAutomate ICommand using PostSharp Pin
Antonín Procházka24-Jul-17 2:59
Antonín Procházka24-Jul-17 2:59 
QuestionHiButtonCommand = new RelayCommand(ShowMessage, param => this.canExecute); Pin
Member 131025173-Apr-17 2:02
Member 131025173-Apr-17 2:02 
AnswerRe: HiButtonCommand = new RelayCommand(ShowMessage, param => this.canExecute); Pin
Nomesh G3-Apr-17 2:36
Nomesh G3-Apr-17 2:36 
GeneralMy vote of 4 Pin
Arkitec3-Mar-17 11:12
professionalArkitec3-Mar-17 11:12 
QuestionWant more article on MVVM for beginner Pin
Tridip Bhattacharjee2-Mar-17 20:20
professionalTridip Bhattacharjee2-Mar-17 20:20 
AnswerRe: Want more article on MVVM for beginner Pin
Nomesh G13-Mar-17 1:08
Nomesh G13-Mar-17 1:08 
Suggestionusing weak references Pin
Fitim Skenderi28-Dec-16 4:21
professionalFitim Skenderi28-Dec-16 4:21 
GeneralRe: using weak references Pin
Nomesh G31-Dec-16 0:18
Nomesh G31-Dec-16 0:18 
GeneralRe: using weak references Pin
Fitim Skenderi31-Dec-16 6:19
professionalFitim Skenderi31-Dec-16 6:19 
QuestionWhat is the Destroy() function used for? Pin
Patrick Skelton11-Aug-16 5:35
Patrick Skelton11-Aug-16 5:35 
PraiseNice article Nomesh, Thank you. Pin
Member 1221602010-Jul-16 20:10
Member 1221602010-Jul-16 20:10 
Question5 poins! Pin
Bob Stoom2-Jun-16 2:05
professionalBob Stoom2-Jun-16 2:05 
QuestionA Doubt Pin
R.Binu Port Blair18-Oct-15 19:33
R.Binu Port Blair18-Oct-15 19:33 
Questiongood article Pin
devarajamca28-Mar-15 23:32
professionaldevarajamca28-Mar-15 23:32 
AnswerRe: good article Pin
Nomesh G29-Mar-15 5:48
Nomesh G29-Mar-15 5:48 
QuestionExcellent article on WPF ICommand Pin
rich123xyz29-Jan-15 14:18
rich123xyz29-Jan-15 14:18 
AnswerRe: Excellent article on WPF ICommand Pin
Nomesh G30-Jan-15 5:43
Nomesh G30-Jan-15 5:43 
Questionone more thing Pin
scott.winterrowd23-Jan-15 6:13
scott.winterrowd23-Jan-15 6:13 
AnswerRe: one more thing Pin
Nomesh G23-Jan-15 20:00
Nomesh G23-Jan-15 20:00 
Yeah, i agree with you that it would be helpful if all the namespaces used are specified in code snippet. I'll keep this in mind in my next article. Anyway for this article you can download the source code if you have problem identifying the namespace to be used.
QuestionSome feedback from a novice WPF developer Pin
scott.winterrowd23-Jan-15 6:05
scott.winterrowd23-Jan-15 6:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.