Pages

Labels

Tuesday, February 12, 2013

MVVM for Beginners2


ICommand:
As MVVM strictly condemns from writing code in the codebehind files, ICommand makes it possible to run a particular function on the ViewModel when user clicks on the Button, Hyperlink or MenuItem controls, as these controls have the Command property. We just need to bind our Command object of the ViewModel to the Command property of the control in the UI.

The standard way of creating ICommand object is to inject the commands logic via delegates passed into constructor. RelayCommand class created by the Josh Smith is the best and the easiest way to follow.

private ICommand _addCommand;
public ICommand AddCommand
        {
            get
            {
                if (_addCommand == null)
                    _addCommand = new RelayCommand(param => AddPerson());
                return _addCommand;
            }
        }

IDataErrorInfo:
To provide validations on the data, we need to implement IDataErrorInfo interface on our Model. WPF validation system has the ability to show error messages declared on a property using IDataErrorInfo.

Lets start with our Model which implements IDataErrorInfo.

 public class Person:IDataErrorInfo
    {
        public string FName { get; set; }
        public string LName { get; set; }
        public int Age { get; set; }
        public string CitizenShip { get; set; }
        public string Error
        {
            get { return null; }
        }
        public string this[string columnName]
        {
            get { return ValidateProperty(columnName); }
        }
        private string ValidateProperty(string columnName)
        {
            string errMsg = null;
            if (columnName == "FName")
                if (string.IsNullOrEmpty(FName))
                    errMsg = "First Name is required";
            if (columnName == "Age")
                if (Age <= 0 || Age >= 110)
                    errMsg = "Age should be between 0 and 110";
            return errMsg;
        }
    }

Our business logic has to be implemented in our ViewModel which implements INotifyPropertyChanged and IDataErrorInfo interfaces.
It essentially contains the properties to hold the list of Persons, Person, SelectedPerson from the list and ICommand properties to execute the Add and Remove logic.

 public class PersonViewModel:INotifyPropertyChanged, IDataErrorInfo
    {
        #region Fields
        private Person _myPerson;
        private ObservableCollection<Person> _persons;
        private Person _selectedPerson;
        private ICommand _addCommand;
        private ICommand _removeCommand; 
        #endregion
        #region Constructor
        public PersonViewModel()
        {
            Persons = new ObservableCollection<Person>();
            MyPerson = new Person();
        } 
        #endregion
       
        #region Properties
        public Person MyPerson
        {
            get { return _myPerson; }
            set { _myPerson = value; this.OnPropertyChanged("MyPerson"); }
        }
        //Collection to hold the persons list.
        public ObservableCollection<Person> Persons
        {
            get { return _persons; }
            set { _persons = value; }
        }
        
        //property to hold the selected person from the list
        public Person SelectedPerson
        {
            get { return _selectedPerson; }
            set { _selectedPerson = value; this.OnPropertyChanged("SelectedPerson"); }
        }
        public ICommand AddCommand
        {
            get
            {
                if (_addCommand == null)
                    _addCommand = new RelayCommand(param => AddPerson());
                return _addCommand;
            }
        }
        public ICommand RemoveCommand
        {
            get
            {
                if (_removeCommand == null)
                {
                    _removeCommand = new RelayCommand(param => RemovePerson(), param => CanRemovePerson());
                }
                return _removeCommand;
            }
        } 
        #endregion
        #region Methods
        
        //To check whether a person can be removed from the list. Enables/disables the Remove button based on selection
        private bool CanRemovePerson()
        {
            return this.SelectedPerson != null;
        }
        
        //To remove the selected person from the list
        private void RemovePerson()
        {
            if (SelectedPerson != null)
                this.Persons.Remove(this.SelectedPerson);
        }
       
        //logic to add the person to the Persons collection.
        private void AddPerson()
        {
            Persons.Add(this.MyPerson);
            MyPerson = new Person();
        }
        #endregion
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propName)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propName));
            }
        } 
        #endregion
        #region IDataErrorInfo
        public string Error
        {
            get { return (MyPerson as IDataErrorInfo).Error; }
        }
        public string this[string columnName]
        {
            get { return ValidateProperties(columnName); }
        }
        private string ValidateProperties(string columnName)
        {
            string errMsg = null;
            if (columnName == "MyPerson")
            {
                errMsg = (MyPerson as IDataErrorInfo).Error;
            }
            return errMsg;
        } 
        #endregion
    }


Page1     Page2     Page3

No comments:

Post a Comment