INotify Property Changed. Property Changed Событие
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Возникает при смене значения свойства.
public: event System::ComponentModel::PropertyChangedEventHandler ^ PropertyChanged;
event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
member this.PropertyChanged : System.ComponentModel.PropertyChangedEventHandler
Event PropertyChanged As PropertyChangedEventHandler
Тип события
Примеры
В следующем примере кода показано, как реализовать PropertyChanged событие INotifyPropertyChanged интерфейса .
// This is a simple customer class that // implements the IPropertyChange interface. public class DemoCustomer : INotifyPropertyChanged < // These fields hold the values for the public properties. private Guid idValue = Guid.NewGuid(); private string customerNameValue = string.Empty; private string phoneNumberValue = string.Empty; public event PropertyChangedEventHandler PropertyChanged; // This method is called by the Set accessor of each property. // The CallerMemberName attribute that is applied to the optional propertyName // parameter causes the property name of the caller to be substituted as an argument. private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") < if (PropertyChanged != null) < PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); >> // The constructor is private to enforce the factory pattern. private DemoCustomer() < customerNameValue = "Customer"; phoneNumberValue = "(312)555-0100"; >// This is the public factory method. public static DemoCustomer CreateNewCustomer() < return new DemoCustomer(); >// This property represents an ID, suitable // for use as a primary key in a database. public Guid ID < get < return this.idValue; >> public string CustomerName < get < return this.customerNameValue; >set < if (value != this.customerNameValue) < this.customerNameValue = value; NotifyPropertyChanged(); >> > public string PhoneNumber < get < return this.phoneNumberValue; >set < if (value != this.phoneNumberValue) < this.phoneNumberValue = value; NotifyPropertyChanged(); >> > >
' This class implements a simple customer type ' that implements the IPropertyChange interface. Public Class DemoCustomer Implements INotifyPropertyChanged ' These fields hold the values for the public properties. Private idValue As Guid = Guid.NewGuid() Private customerNameValue As String = String.Empty Private phoneNumberValue As String = String.Empty Public Event PropertyChanged As PropertyChangedEventHandler _ Implements INotifyPropertyChanged.PropertyChanged ' This method is called by the Set accessor of each property. ' The CallerMemberName attribute that is applied to the optional propertyName ' parameter causes the property name of the caller to be substituted as an argument. Private Sub NotifyPropertyChanged( Optional ByVal propertyName As String = Nothing) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) End Sub ' The constructor is private to enforce the factory pattern. Private Sub New() customerNameValue = "Customer" phoneNumberValue = "(312)555-0100" End Sub ' This is the public factory method. Public Shared Function CreateNewCustomer() As DemoCustomer Return New DemoCustomer() End Function ' This property represents an ID, suitable ' for use as a primary key in a database. Public ReadOnly Property ID() As Guid Get Return Me.idValue End Get End Property Public Property CustomerName() As String Get Return Me.customerNameValue End Get Set(ByVal value As String) If Not (value = customerNameValue) Then Me.customerNameValue = value NotifyPropertyChanged() End If End Set End Property Public Property PhoneNumber() As String Get Return Me.phoneNumberValue End Get Set(ByVal value As String) If Not (value = phoneNumberValue) Then Me.phoneNumberValue = value NotifyPropertyChanged() End If End Set End Property End Class
Комментарии
Событие PropertyChanged может указать, что все свойства объекта изменились, используя null или String.Empty в качестве имени свойства в PropertyChangedEventArgs. Обратите внимание, что в приложении UWP необходимо использовать null вместо String.Empty .
Inotifypropertychanged c как использовать
В прошлой теме использовался объект Phone для привязки к текстовым блокам. Однако если мы изменим его, содержимое текстовых блоков не изменится. Например, добавим в окно приложения кнопку:
" Grid.Row="1" /> " Grid.Column="1" Grid.Row="1" /> " Grid.Column="2" Grid.Row="1" />
И в файле кода для этой кнопки определим обработчик, в котором будет меняться свойства ресурса:
private void Button_Click(object sender, RoutedEventArgs e) < Phone phone = (Phone)this.Resources["nexusPhone"]; phone.Company = "LG"; // Меняем с Google на LG >
Сколько бы мы не нажимали на кнопку, текстовые блоки, привязанные к ресурсу, не изменятся. Чтобы объект мог полноценно реализовать механизм привязки, нам надо реализовать в его классе интерфейс INotifyPropertyChanged. И для этого изменим класс Phone следующим образом:
using System.ComponentModel; using System.Runtime.CompilerServices; class Phone : INotifyPropertyChanged < private string title; private string company; private int price; public string Title < get < return title; >set < title = value; OnPropertyChanged("Title"); >> public string Company < get < return company; >set < company = value; OnPropertyChanged("Company"); >> public int Price < get < return price; >set < price = value; OnPropertyChanged("Price"); >> public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged([CallerMemberName]string prop = "") < if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop)); >>
Когда объект класса изменяет значение свойства, то он через событие PropertyChanged извещает систему об изменении свойства. А система обновляет все привязанные объекты.
Inotifypropertychanged c как использовать
Если в качестве цели привязки обязательно должен выступать объект класса BindableObject, то источником привязке может быть любой объект, в том числе самого стандартного класса. Однако если источником является простой класс, не представляющий BindableObject, то мы можем столкнуться с проблемой обновления данных при привязке. Например, пусть у нас в главном проекте есть класс Phone:
public class Phone < public string Title < get; set; >public string Company < get; set; >public int Price < get; set; >>
Тогда осущестим привязку к объекту класса Phone:
using System; using Xamarin.Forms; namespace HelloApp < public partial class MainPage : ContentPage < Phone phone; public MainPage() < phone = new Phone < Title = "iPhone 7", Company = "Apple", Price = 56000 >; Grid grid = new Grid < RowDefinitions = < new RowDefinition < Height = 50 >, new RowDefinition < Height = 50 >, new RowDefinition < Height = 50 >>, ColumnDefinitions = < new ColumnDefinition < Width = new GridLength(0.8, GridUnitType.Star) >, new ColumnDefinition < Width = new GridLength(1.1, GridUnitType.Star) >, new ColumnDefinition < Width = new GridLength(1.1, GridUnitType.Star) >> >; Label titleHeaderLabel = new Label < Text = "Модель" >; Label companyHeaderLabel = new Label < Text = "Компания" >; Label priceHeaderLabel = new Label < Text = "Цена" >; Label titleValueLabel = new Label(); Binding titleBinding = new Binding < Source = phone, Path = "Title" >; titleValueLabel.SetBinding(Label.TextProperty, titleBinding); Label companyValueLabel = new Label(); Binding companyBinding = new Binding < Source = phone, Path = "Company" >; companyValueLabel.SetBinding(Label.TextProperty, companyBinding); Label priceValueLabel = new Label(); Binding priceBinding = new Binding < Source = phone, Path = "Price" >; priceValueLabel.SetBinding(Label.TextProperty, priceBinding); Button updateButton = new Button < Text = "Обновить" >; updateButton.Clicked += UpdateButton_Clicked; grid.Children.Add(titleHeaderLabel, 0, 0); grid.Children.Add(companyHeaderLabel, 1, 0); grid.Children.Add(priceHeaderLabel, 2, 0); grid.Children.Add(titleValueLabel, 0, 1); grid.Children.Add(companyValueLabel, 1, 1); grid.Children.Add(priceValueLabel, 2, 1); grid.Children.Add(updateButton, 2, 2); Content = grid; > private void UpdateButton_Clicked(object sender, EventArgs e) < phone.Price += 4000; >> >
Здесь на странице три элемента Label привязаны к разным свойствам объекта Phone. В итоге при запуске приложения все три метки отобразят значения свойств Phone:

Однако если мы нажмем на кнопку, то мы никаких изменений не увидим. Хотя обработчик кнопки изменит значение свойства Price объекта Phone. Однако соответствующий элемент Label не изменит свой тест, так как он просто не будет знать, что привязанное свойство Price изменилось.
И чтобы уведомить цель привязки об изменении значений источник привязки должен реализовать интерфейс INotifyPropertyChanged . Для этого изменим класс Phone следующим образом:
using System.ComponentModel; namespace HelloApp < public class Phone : INotifyPropertyChanged < private string title; private string company; private int price; public string Title < get < return title; >set < if (title != value) < title = value; OnPropertyChanged("Title"); >> > public string Company < get < return company; >set < if (company != value) < company = value; OnPropertyChanged("Company"); >> > public int Price < get < return price; >set < if (price != value) < price = value; OnPropertyChanged("Price"); >> > public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string prop = "") < if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop)); >> >
При этом в коде самой страницы MainPage ничего менять не надо. И если теперь мы нажмем на кнопку, то элемент Label мгновенно отреагирует на изменение свойства Price объекта Phone.
Аналогичный пример в XAML:
Здесь объект Phone определяется как статический ресурс. Затем мы можем задать его как контекст для всего элемента Grid, а в отдельных элементах Label прописать привязку к свойствам этого объекта.
А в классе связанного кода пропишем обработчик кнопки, который будет менять значение свойства Price:
using System; using Xamarin.Forms; namespace HelloApp < public partial class MainPage : ContentPage < public MainPage() < InitializeComponent(); >private void UpdateButton_Clicked(object sender, EventArgs e) < var phone = this.Resources["phone"] as Phone; phone.Price += 4000; >> >
INotify Property Changed Интерфейс
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Сообщает клиенту об изменении значения свойства.
public interface class INotifyPropertyChanged
public interface INotifyPropertyChanged
type INotifyPropertyChanged = interface
Public Interface INotifyPropertyChanged
Производный
Примеры
В следующем примере кода показано, как реализовать INotifyPropertyChanged интерфейс . При выполнении этого примера вы заметите, что связанный DataGridView элемент управления отражает изменения в источнике данных без необходимости сбрасывать привязку.
При использовании атрибута CallerMemberName в вызовах метода NotifyPropertyChanged нет необходимости указывать имя свойства в качестве строкового аргумента. Дополнительные сведения см. в разделе Сведения о вызывающем объекте.
Замените код в Form1 следующим кодом, а затем измените пространство имен на имя проекта. В качестве альтернативы можно присвоить проекту имя пространства имен ниже при его создании.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Runtime.CompilerServices; using System.Windows.Forms; // Either change the following namespace to the name of your project, // or name your project with the following name when you create it. namespace TestNotifyPropertyChangedCS < // This form demonstrates using a BindingSource to bind // a list to a DataGridView control. The list does not // raise change notifications. However the DemoCustomer type // in the list does. public partial class Form1 : Form < // This button causes the value of a list element to be changed. private Button changeItemBtn = new Button(); // This DataGridView control displays the contents of the list. private DataGridView customersDataGridView = new DataGridView(); // This BindingSource binds the list to the DataGridView control. private BindingSource customersBindingSource = new BindingSource(); public Form1() < InitializeComponent(); // Set up the "Change Item" button. this.changeItemBtn.Text = "Change Item"; this.changeItemBtn.Dock = DockStyle.Bottom; this.changeItemBtn.Click += new EventHandler(changeItemBtn_Click); this.Controls.Add(this.changeItemBtn); // Set up the DataGridView. customersDataGridView.Dock = DockStyle.Top; this.Controls.Add(customersDataGridView); this.Size = new Size(400, 200); >private void Form1_Load(object sender, EventArgs e) < // Create and populate the list of DemoCustomer objects // which will supply data to the DataGridView. BindingListcustomerList = new BindingList(); customerList.Add(DemoCustomer.CreateNewCustomer()); customerList.Add(DemoCustomer.CreateNewCustomer()); customerList.Add(DemoCustomer.CreateNewCustomer()); // Bind the list to the BindingSource. this.customersBindingSource.DataSource = customerList; // Attach the BindingSource to the DataGridView. this.customersDataGridView.DataSource = this.customersBindingSource; > // Change the value of the CompanyName property for the first // item in the list when the "Change Item" button is clicked. void changeItemBtn_Click(object sender, EventArgs e) < // Get a reference to the list from the BindingSource. BindingListcustomerList = this.customersBindingSource.DataSource as BindingList; // Change the value of the CompanyName property for the // first item in the list. customerList[0].CustomerName = "Tailspin Toys"; customerList[0].PhoneNumber = "(708)555-0150"; > > // This is a simple customer class that // implements the IPropertyChange interface. public class DemoCustomer : INotifyPropertyChanged < // These fields hold the values for the public properties. private Guid idValue = Guid.NewGuid(); private string customerNameValue = String.Empty; private string phoneNumberValue = String.Empty; public event PropertyChangedEventHandler PropertyChanged; // This method is called by the Set accessor of each property. // The CallerMemberName attribute that is applied to the optional propertyName // parameter causes the property name of the caller to be substituted as an argument. private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") < PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); >// The constructor is private to enforce the factory pattern. private DemoCustomer() < customerNameValue = "Customer"; phoneNumberValue = "(312)555-0100"; >// This is the public factory method. public static DemoCustomer CreateNewCustomer() < return new DemoCustomer(); >// This property represents an ID, suitable // for use as a primary key in a database. public Guid ID < get < return this.idValue; >> public string CustomerName < get < return this.customerNameValue; >set < if (value != this.customerNameValue) < this.customerNameValue = value; NotifyPropertyChanged(); >> > public string PhoneNumber < get < return this.phoneNumberValue; >set < if (value != this.phoneNumberValue) < this.phoneNumberValue = value; NotifyPropertyChanged(); >> > > >
Imports System Imports System.Collections.Generic Imports System.ComponentModel Imports System.Drawing Imports System.Runtime.CompilerServices Imports System.Windows.Forms ' This form demonstrates using a BindingSource to bind ' a list to a DataGridView control. The list does not ' raise change notifications. However the DemoCustomer type ' in the list does. Public Class Form1 Inherits System.Windows.Forms.Form ' This button causes the value of a list element to be changed. Private changeItemBtn As New Button() ' This DataGridView control displays the contents of the list. Private customersDataGridView As New DataGridView() ' This BindingSource binds the list to the DataGridView control. Private customersBindingSource As New BindingSource() Public Sub New() InitializeComponent() ' Set up the "Change Item" button. Me.changeItemBtn.Text = "Change Item" Me.changeItemBtn.Dock = DockStyle.Bottom AddHandler Me.changeItemBtn.Click, AddressOf changeItemBtn_Click Me.Controls.Add(Me.changeItemBtn) ' Set up the DataGridView. customersDataGridView.Dock = DockStyle.Top Me.Controls.Add(customersDataGridView) Me.Size = New Size(400, 200) End Sub Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Me.Load ' Create and populate the list of DemoCustomer objects ' which will supply data to the DataGridView. Dim customerList As New BindingList(Of DemoCustomer) customerList.Add(DemoCustomer.CreateNewCustomer()) customerList.Add(DemoCustomer.CreateNewCustomer()) customerList.Add(DemoCustomer.CreateNewCustomer()) ' Bind the list to the BindingSource. Me.customersBindingSource.DataSource = customerList ' Attach the BindingSource to the DataGridView. Me.customersDataGridView.DataSource = Me.customersBindingSource End Sub ' This event handler changes the value of the CompanyName ' property for the first item in the list. Private Sub changeItemBtn_Click(ByVal sender As Object, ByVal e As EventArgs) ' Get a reference to the list from the BindingSource. Dim customerList As BindingList(Of DemoCustomer) = _ CType(customersBindingSource.DataSource, BindingList(Of DemoCustomer)) ' Change the value of the CompanyName property for the ' first item in the list. customerList(0).CustomerName = "Tailspin Toys" customerList(0).PhoneNumber = "(708)555-0150" End Sub End Class ' This class implements a simple customer type ' that implements the IPropertyChange interface. Public Class DemoCustomer Implements INotifyPropertyChanged ' These fields hold the values for the public properties. Private idValue As Guid = Guid.NewGuid() Private customerNameValue As String = String.Empty Private phoneNumberValue As String = String.Empty Public Event PropertyChanged As PropertyChangedEventHandler _ Implements INotifyPropertyChanged.PropertyChanged ' This method is called by the Set accessor of each property. ' The CallerMemberName attribute that is applied to the optional propertyName ' parameter causes the property name of the caller to be substituted as an argument. Private Sub NotifyPropertyChanged( Optional ByVal propertyName As String = Nothing) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) End Sub ' The constructor is private to enforce the factory pattern. Private Sub New() customerNameValue = "Customer" phoneNumberValue = "(312)555-0100" End Sub ' This is the public factory method. Public Shared Function CreateNewCustomer() As DemoCustomer Return New DemoCustomer() End Function ' This property represents an ID, suitable ' for use as a primary key in a database. Public ReadOnly Property ID() As Guid Get Return Me.idValue End Get End Property Public Property CustomerName() As String Get Return Me.customerNameValue End Get Set(ByVal value As String) If Not (value = customerNameValue) Then Me.customerNameValue = value NotifyPropertyChanged() End If End Set End Property Public Property PhoneNumber() As String Get Return Me.phoneNumberValue End Get Set(ByVal value As String) If Not (value = phoneNumberValue) Then Me.phoneNumberValue = value NotifyPropertyChanged() End If End Set End Property End Class
Комментарии
Интерфейс INotifyPropertyChanged используется для уведомления клиентов(обычно привязывая клиентов) об изменении значения свойства.
Например, рассмотрим Person объект со свойством с именем FirstName . Чтобы предоставить универсальное уведомление об изменении свойства, Person тип реализует INotifyPropertyChanged интерфейс и вызывает PropertyChanged событие при FirstName изменении.
Чтобы уведомление об изменениях произошло в привязке между привязанным клиентом и источником данных, связанный тип должен иметь одно из следующих значений:
- Реализуйте INotifyPropertyChanged интерфейс (предпочтительный).
- Укажите событие изменения для каждого свойства привязанного типа.
Не используйте оба механизма сразу.