1

Binding checkbox in WPF is common issue, but I am still not finding example code which is easy to follow for beginners. I have check box list in WPF to select favorite sports’ name. The number of checkboxes is static in my case. Can anyone show me how to implement ViewModel for this issue?

FavoriteSportsView.xaml:

  <StackPanel Height="50" HorizontalAlignment="Left" VerticalAlignment="Top" 
  Width="150">

  <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"  
  Command="{Binding Path=SportsResponseCommand}" 
  CommandParameter="Football" 
  Content="Football" 
  Margin="5" />

  <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" 
  Command="{Binding Path=SportsResponseCommand}" 
  CommandParameter="Hockey" 
  Content="Hockey" 
  Margin="5" />

  <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" 
  Command="{Binding Path=SportsResponseCommand}" 
  CommandParameter="Golf" 
  Content="Golf" 
  Margin="5" />
  </StackPanel>

FavoriteSportsViewModel.cs

  public class FavoriteSportsViewModel.cs {

    //Since I am using the same IsChecked in all check box options, I found all check 
    //boxes gets either checked or unchecked when I just check or uncheck one option.
    //How do i resolve this issue? I don't think i need seprate IsChecked for each 
    //check box option.

    private bool _isChecked;
    public bool IsChecked{
      get {
           return _isChecked;
       }

      set { if (value != _isChecked) 
             _isChecked = value;
            this.OnPropertyChanged("IsChecked");
       }
    }


    //How do i detect parameter in this method?
    private ICommand _sportsResponseCommand;
    public ICommand SportsResponseCommand
    {
        get
        {
            if (_sportsResponseCommand== null)
                _sportsResponseCommand= new
                    RelayCommand(a => DoCollectSelectedGames(), p => true);
            return _sportsResponseCommand;
        }
        set
        {
            _sportsResponseCommand= value;

        }

    }

    private void DoCollectSelectedGames(){ 
      //Here i push all selected games in an array
    }


    public abstract class ViewModelBase : INotifyPropertyChanged
    {
       public event PropertyChangedEventHandler PropertyChanged;
       public void OnPropertyChanged(string propertyName)
       {
         if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       }
    }

  }

I'm not sure how to do the following in above ViewModel: 1. How do I implement single method to handle all my options? 2. how do I detect each one of the checkboxes to see whether checked or not 3. How do i utlize CommandParameter? 4. How do i implement SportsResponseCommand correctly

1
  • Is using a checkbox list an option for you? Commented Sep 26, 2011 at 15:51

4 Answers 4

3

Your view model should look something like this:

public class MyViewModel : INotifyPropertyChanged
{
    //INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    //bindable property
    private bool _football;
    public bool Football
    {
        get { return _football; }
        set
        {
            if (value != _football)
            {
                _football = value;
                this.OnPropertyChanged("Football");
            }
        }
    }

    //... and the same for Golf and Hockey
}

Then you associate your view model with the view by setting the DataContext property (this will most likely be in the Window or UserControl code behind, though there are a lot of ways to achieve this).

Finally, update your bindings so that they look like:

<CheckBox IsChecked="{Binding Football, Mode=TwoWay}"  
 Content="Football" 
 Margin="5" />

<CheckBox IsChecked="{Binding Golf, Mode=TwoWay}"   
 Content="Football" 
 Margin="5" />

As a final comment, you shouldn't really need to bind the Command property - you can just write whatever code you need to run in the property setter on the view model.

Sign up to request clarification or add additional context in comments.

1 Comment

Beat me to it, but you should remove the Command/CommandParameter from the CheckBox XAML
1

I highly recommend you to read this http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
I describe a solution below I tried to not modify your XAML code but it is not the only way (or the best approach) but contains all necessary elements!

At first step you need your model I call it Model_Sport

    public class Model_Sport : INotifyPropertyChanged
    {
        #region  Constructor

        public Model_Sport(string name, ICommand command)
        {
            Name = name;
            SportsResponseCommand = command;
        }

        #endregion

        static readonly PropertyChangedEventArgs _NameEventArgs = new PropertyChangedEventArgs("Name");
        private string _Name = null;
        public string Name
        {
            get { return _Name; }
            set
            {
                _Name = value;
                OnPropertyChanged(_NameEventArgs);
            }
        }

        static readonly PropertyChangedEventArgs _SportsResponseCommandEventArgs = new PropertyChangedEventArgs("SportsResponseCommand");
        private ICommand _SportsResponseCommand = null;
        public ICommand SportsResponseCommand
        {
            get { return _SportsResponseCommand; }
            set
            {
                _SportsResponseCommand = value;
                OnPropertyChanged(_SportsResponseCommandEventArgs);
            }
        }

        static readonly PropertyChangedEventArgs _IsCheckedEventArgs = new PropertyChangedEventArgs("IsChecked");
        private bool _IsChecked = false;
        public bool IsChecked
        {
            get { return _IsChecked; }
            set
            {
                _IsChecked = value;
                OnPropertyChanged(_IsCheckedEventArgs);
            }
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, eventArgs);
            }
        }

        #endregion
    }

Now you need a way to delegate your command “SportsResponseCommand”, DelegateCommand object will help you to do that

    public class DelegateCommand : ICommand
    {
        private readonly Action<object> _ExecuteMethod;
        private readonly Func< object, bool> _CanExecuteMethod;

        #region Constructors

        public DelegateCommand(Action<object>executeMethod, Func<object, bool> canExecuteMethod)
        {
            if (null == executeMethod)
            {
                throw new ArgumentNullException("executeMethod", "Delegate Command Delegates Cannot Be Null");
            }

            _ExecuteMethod = executeMethod;
            _CanExecuteMethod = canExecuteMethod;

        }

        public DelegateCommand(Action<object>executeMethod) : this(executeMethod, null) { }

        #endregion


        #region Methods

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

        public void Execute(object parameter)
        {
            if (_ExecuteMethod == null) return;
            _ExecuteMethod(parameter);
        }

        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute(parameter);
        }

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

        void ICommand.Execute(object parameter)
        {
            Execute(parameter);
        }

        #endregion

    }

Now “ViewModel”

    public class ViewModel
    {
        #region property

        public Dictionary<string, Model_Sport> Sports { get; set; }
        public DelegateCommand SportsResponseCommand { get; set; }

        #endregion

        public ViewModel()
        {
            Sports = new Dictionary<string, Model_Sport>();
            SportsResponseCommand = new DelegateCommand(p => execute_SportsResponseCommand(p));

            buildSports();
        }

        private void buildSports()
        {
            Model_Sport football = new Model_Sport("Football", SportsResponseCommand);
            Model_Sport golf = new Model_Sport("Golf", SportsResponseCommand);
            Model_Sport hockey = new Model_Sport("Hockey", SportsResponseCommand);

            football.IsChecked = true; // just for test

            Sports.Add(football.Name, football);
            Sports.Add(golf.Name, golf);
            Sports.Add(hockey.Name, hockey);
        }

        private void execute_SportsResponseCommand(object p)
        {
            // TODO :what ever you want
            MessageBox.Show(p.ToString());
        }

    }

Now View Remember to set datacontext for your Window public MainWindow() {

        InitializeComponent();
        this.DataContext = new ViewModel();


    }

Then in XAML

    <StackPanel  HorizontalAlignment="Left" VerticalAlignment="Top" >

        <CheckBox DataContext="{Binding Path=Sports[Football]}"
            IsChecked="{Binding IsChecked, Mode=TwoWay}"   
                    Command="{Binding Path=SportsResponseCommand}"  
                    CommandParameter="Football"    
                    Content="Football"   
                    Margin="5" />

        <CheckBox DataContext="{Binding Path=Sports[Hockey]}"
            IsChecked="{Binding IsChecked, Mode=TwoWay}"  
            Command="{Binding Path=SportsResponseCommand}"    
            CommandParameter="Hockey"    
            Content="Hockey"   
            Margin="5" />

        <CheckBox DataContext="{Binding Path=Sports[Golf]}" IsChecked="{Binding IsChecked, Mode=TwoWay}" 
                    Command="{Binding Path=SportsResponseCommand}"
                    CommandParameter="Golf"   
                    Content="Golf" 
                    Margin="5" />
    </StackPanel>

3 Comments

Thank you Fred Jand for detail implementation. I have read that it would be good if don't implement INotifyPropertyChanged in Model. Do you agree with this statement? What is your opnion over using RelayCommand instead of DelegateCommand? Do you see any disadvantages?
Actually RelayCommand and DelgateCommad are almost the same entities RelayCommand is a simplified variation of the DelegateCommand found in the Microsoft Composite Application Library. What I put here actually is a RelayCommand if you want the more real delegatecommand implementation look at msdn.microsoft.com/en-us/library/ff654132.aspx#Y0 Note that they are just names and different variations of both are developed during the years! The point is that they have the exact same concept. You can create your own version of delegatecommand or relaycommand ! as I did in this example :)
About “INotifyPropertyChanged” it depends on the application! If model represents something that changed independently and has side effects on other part of application (except the viewmodel) you better to have INotifyPropertyChanged in your model. But if only one ViewModel present your model you can let ViewModel to handle the change. Note that INotifyPropertyChanged does exist before WPF and MVVM pattern (before the existence of viewmodel concept)
0

If you just want a property in your ViewModel to get updated when the IsChecked changes, replace the Binding for IsChecked to a boolean property in your ViewModel that raises NotifyPropertyChanged on its "set".

Now if you want to perform an action everytime IsChecked changes for one of the 3 CheckBoxes:

First of all, replace your CommandParameter with "{Binding RelativeSource={RelativeSource Mode=Self}}"

In your ViewModel (that should implement INotifyPropertyChanged), create an ICommand (SportsResponseCommand) that takes a CheckBox in parameter.

In the command's method, check for the Content of your CheckBox, and for the "IsChecked" property then do your stuff with them.

If you have further questions let me know.

Comments

0

You can assign a view model by using this

 //for the view

partial class MainView:Window
 {
         InitializeComponent();
         this.DataContext=new MainViewModel();

 }

//ViewModel Code

public class MainViewModel: INotifyPropertyChanged
{
  //INotifyPropertyChanged implementation
  public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
    if (this.PropertyChanged != null)
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

//bindable property
private bool _football;
public bool Football
{
    get { return _football; }
    set
    {
        if (value != _football)
        {
            _football = value;
            this.OnPropertyChanged("Football");
        }
    }
}

//... and the same for Golf and Hockey
}`

and then you can implement Binding in XAML as

<CheckBox IsChecked="{Binding Football, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}" CommandParameter="Football" Content="Football" Margin="5" />

<CheckBox IsChecked="{Binding Golf, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}" CommandParameter="Football" Content="Football" Margin="5" />

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.