如何实现INotifyPropertyChanged以进行Xamarin绑定更新?

时间:2017-07-12 05:58:51

标签: xamarin xamarin.forms

我有这段代码:

        wordGrid.BindingContext = AS.phrase;
        AS.phrase = new PSCViewModel() { English = "abcd" };
        AS.phrase.English = "JJJJ";

在第一行设置BindingContext时,我在视图中看不到任何内容。有了它,它可以工作,我看到" JJJJ"。

这是我的viewModel:

public class PSCViewModel : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;
    int id;
    string english;

    public PSCViewModel()
    {
    }

    public int Id
    {
        get { return id; }
        set
        {
            if (value != id)
            {
                id = value;
                onPropertyChanged("ID");
            }
        }
    }

    public string English
    {
        get { return english; }
        set
        {
            if (value != english)
            {
                english = value;
                onPropertyChanged("English");
            }
        }
    }

    private void onPropertyChanged(string v)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(v));
        }
    }

}

有人能看出为什么对英文字段的更改不会导致显示JJJJ的新值吗?

3 个答案:

答案 0 :(得分:1)

一个好的开始是阅读MVVM模式以及如何在Xamarin Forms中实现它。 Xamarin有关于这个主题的自己的教程:

https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/

基本上你要做的是创建一个ViewModel,它充当整个页面的BindingContext。在该ViewModel中,您可以定义绑定到控件的属性,例如LabelsListViewsTextBoxes。在您的情况下,ViewModel将包含一个名为Phrase的string属性,该属性绑定到名为wordGrid的控件。

public class PhraseViewModel
{
    public string Phrase {get; set;}
}

可以在XAML中绑定到例如标签如:

<Label Text="{Binding Phrase}" />

答案 1 :(得分:1)

您可能已在System.ComponentModel

中找到了definition

这是MVVM的全部内容。您的ViewModel必须实现INotifyPropertyChanged。其中只有一个事件:PropertyChangedEventHandler PropertyChanged

我通常在ViewModel中定义一个raise方法,如下所示:

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

然后,ViewModel中的所有属性都必须具有这样的getter / setter:

public string AProperty
{
  get { return aProperty;}
  set 
  {
    if(value != aProperty)
    {
      aProperty = value;
      RaisePropertyChanged("AProperty");
    }
  }
}

现在,当您将View与ViewModel绑定时,它将订阅PropertyChanged事件并传播更改。就是这样!

答案 2 :(得分:1)

这就是我实现INotifyPropertyChanged的方式。

    public class Bindable : INotifyPropertyChanged
    {
        private Dictionary<string, object> _properties = new Dictionary<string, object>();

        /// <summary>
        /// Gets the value of a property
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        protected T Get<T>([CallerMemberName] string name = null)
        {
            object value = null;
            if (_properties.TryGetValue(name, out value))
                return value == null ? default(T) : (T)value;
            return default(T);
        }

        /// <summary>
        /// Sets the value of a property
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="name"></param>
        protected void Set<T>(T value, [CallerMemberName] string name = null)
        {
            if (Equals(value, Get<T>(name)))
                return;
            _properties[name] = value;
            OnPropertyChanged(name);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

这是一个描述如何使用

的示例类
    public class Transaction : Bindable
    {
        public Transaction()
        {
            this.TransactionDate = DateTimeOffset.Now;
            this.TransactionType = TransactionType.Add; //enum
            this.Quantity = 0;
            this.IsDeleted = false;
            this.Item = null; //object defined elsewhere
        }

        public Guid Id { get { return Get<Guid>(); } private set { Set<Guid>(value); } }
        public DateTimeOffset? TransactionDate { get { return Get<DateTimeOffset?>(); } set { Set<DateTimeOffset?>(value); } }
        public TransactionType TransactionType { get { return Get<TransactionType>(); } set { Set<TransactionType>(value); } }
        public double? Quantity { get { return Get<double?>(); } set { Set<double?>(value); } }
        public bool? IsDeleted { get { return Get<bool?>(); } set { Set<bool?>(value); } }
        public byte[] RowVersion { get { return Get<byte[]>(); } private set { Set<byte[]>(value); } }

        public virtual Guid? ItemId { get { return Get<Guid?>(); } set { Set<Guid?>(value); } }
        public virtual Item Item { get { return Get<Item>(); } set { Set<Item>(value); } }
    }