15
votes

I am implementing a cart in Xamarin.Forms. In my cart page there is a ListView with data. Each of the cell contains a button to select the count of item and amount. In the cart view there is a grand total label.

My problem is the grand total is not updating while the number picker changes. The calculation method is called upon item adding view cell. I know that i need to implement INotifyProperty for this, but I'm unsure of how to do it.

I have a base view model which inherits INotifyProperty that contains an event.

 public class BaseViewModel : INotifyPropertyChanged
{
    private double  _price;
    public double Price
    {
        get 
        { 
            return _price; 
        }
        set 
        { 
            _price = value;
            OnPropertyChanged("Price");}
        } 

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

View model

    public BaseViewModel()
    {
        App.Instance.ViewModel = this;
        TempList = TempList ?? new ObservableCollection<cm_items>();
        this.Title = AppResources.AppResource.Cart_menu_title;
        this.Price = CartCell.price;
    }
3
Please have a look at this sample github.com/jamesmontemagno/Hanselman.Forms. In this repository you can find implementation of MVVM pattern and INotifyPropertyChanged interface.Tomasz Kowalczyk

3 Answers

27
votes

As a design methodology, its better to implement MVVM as a subclass and implement it to your ViewModel.

Sample Implementation:

public class ObservableProperty : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

I also strongly suggest implementing ICommand as a Dictionary structure like:

public abstract class ViewModelBase : ObservableProperty
{
    public Dictionary<string,ICommand> Commands { get; protected set; }

    public ViewModelBase()
    {
        Commands = new Dictionary<string,ICommand>();
    }
}

So all todo in your ViewModel is just inherit the ViewModelBase class and use it

class LoginViewModel : ViewModelBase
{
    #region fields
    string userName;
    string password;
    #endregion

    #region properties
    public string UserName 
    {
         get {return userName;}
        set 
        {
            userName = value;
            OnPropertyChanged("UserName");
        }
     }

    public string Password 
    {
        get{return password;}
        set
        {
            password = value;
            OnPropertyChanged("Password");
        }
    }
    #endregion

    #region ctor
    public LoginViewModel()
    {
        //Add Commands
        Commands.Add("Login", new Command(CmdLogin));
    }
    #endregion


    #region UI methods

    private void CmdLogin()
    {
        // do your login jobs here
    }
    #endregion
}

Finally: Xaml Usage:

<Entry Placeholder="Username"  Text="{Binding UserName}"/>
<Entry Placeholder="Password" Text="{Binding Password}" IsPassword="True"/>
<Button Text="Login" Command="{Binding Commands[Login]}"/>
3
votes

For example try this view model:

public abstract class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetPropertyValue<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (value == null ? field != null : !value.Equals(field))
        {
            field = value;

            var handler = this.PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
            return true;
        }
        return false;
    }
}

and in inherited classes use it like this:

    private int myProperty;
    public int MyProperty
    {
        get { return this.myProperty; }
        set { this.SetPropertyValue(ref this.myProperty, value); }
    }
2
votes

When I started Xamarin coding, the MVVM was a bit confusing until I discovered that the PropertyChangedEvent on the ViewModel fired off a signal to the View (ContentPage), and updated the Label/textbox/etc.

For those looking for the 'latest and greatest'... Here's some revised code:

private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    var handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

and on your property Setter:

public string SomeProperty
{
    get { return _somProperty; }
    set
    {
       _someProperty= value;
            OnPropertyChanged();
        }
    }
}

Nice? No? Saves having to pass the property name each time!