使用MVVM的Silverlight的所有示例都使用名为IPropertyChanged的接口。它背后的概念是什么?为什么我们需要在设置某个值时引发事件?
例如: -
public class UserNPC:INotifyPropertyChanged
{
private string name;
public string Name {
get { return name; }
set { name = value; onPropertyChanged(this, "Name"); }
}
public int grade;
public int Grade {
get { return grade; }
set { grade = value; onPropertyChanged(this, "Grade"); }
}
// Declare the PropertyChanged event
public event PropertyChangedEventHandler PropertyChanged;
// OnPropertyChanged will raise the PropertyChanged event passing the
// source property that is being updated.
private void onPropertyChanged(object sender, string propertyName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
}
}
}
INotifyPropertyChanged的确切目的是什么?
答案 0 :(得分:15)
您有以下依赖项:
查看→绑定→模型
现在,概念如下:
如果 Model 对象中的某些数据发生更改,则需要引发PropertyChanged
事件。为什么?因为 Binding 对象已使用数据对象的PropertyChanged
事件注册了一个方法。
因此,当您的 Model 对象中发生更改时,您需要做的就是提升事件并完成。
当您这样做时, Binding 对象会通过您的事件获得有关更改的通知。 Binding 对象依次让 View 对象知道发生了什么。然后, View 对象可以在必要时更新UI。
代码示例
这里有一个可编辑的例子。设置几个断点,使用 F11 逐步执行代码,看看幕后发生了什么。请注意,此示例具有以下依赖项:视图→模型。我遗漏了Binding对象。
using System;
using System.ComponentModel;
namespace INotifyPropertyChangedDemo
{
class Program
{
static void Main(string[] args)
{
// Create 2 listeners.
View1 view1 = new View1();
View2 view2 = new View2();
// Create 1 data object.
Model model = new Model();
// Connect listener with data object.
model.PropertyChanged += new PropertyChangedEventHandler(view1.MyPropertyChangedEventHandler);
model.PropertyChanged += new PropertyChangedEventHandler(view2.MyPropertyChangedEventHandler);
// Let data object publish change notification.
model.FirstName = "new name";
// Check whether all listeners got notified.
// ... via console.
}
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
if (firstName != value)
{
firstName = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("FirstName"));
}
}
}
}
}
public class View1
{
public void MyPropertyChangedEventHandler(object source, PropertyChangedEventArgs arg)
{
Console.WriteLine("Listener 1: Changed Property: {0}", arg.PropertyName);
string newValue = ((Model) source).FirstName;
Console.WriteLine("Listener 1: Changed Property Value: {0}", newValue);
}
}
public class View2
{
public void MyPropertyChangedEventHandler(object source, PropertyChangedEventArgs arg)
{
Console.WriteLine("Listener 2: Changed Property: {0}", arg.PropertyName);
string newValue = ((Model)source).FirstName;
Console.WriteLine("Listener 2: Changed Property Value: {0}", newValue);
}
}
}
}
答案 1 :(得分:5)
WPF中的MVVM& Silverlight是通过将UI元素绑定到视图模型来实现的。但是,当视图模型发生变化时,UI将如何知道更新自身?
INotifyPropertyChanged
只是公开了一个UI可以“监听”的事件,所以当一个控件“听到”它所绑定的属性发生了变化时,它就可以“自我更新”。
例如,假设您有TextBlock
显示股票价格,并且它绑定到视图模型的string Price
属性。反过来,视图模型使用服务每30秒更新一次股票价格。因此,Price
属性每30秒更改一次:30秒前它是“$ 29.20”现在是“$ 29.12”,从现在开始30秒将是“$ 28.10”。加载TextBlock
时会应用TextBlock
绑定,但Price
每次更改时都不会应用INotifyPropertyChanged
绑定。但是,如果您实施Price
并在TextBlock
设置器中提升属性“价格”的事件,则Price
可以连接到该事件,从而“知道”何时返回并“重新读取”{{1}}属性并更新显示的文本。
答案 2 :(得分:3)
大多数Silverlight控件通过简单地订阅PropertyChanged事件来监听他们显示的数据的更改。
e.g。控件在幕后做了类似的事情:
public void Loaded()
{
if (myDataObject is INotifyPropertyChanged)
{
(myDataObject as INotifyPropertyChanged).PropertyChanged +=new PropertyChangedEventHandler(onPropertyChanged);
}
}
这也是使用ObservableCollection而不是Silverlight应用程序中更简单列表的原因。它们实现了INotifyPropertyChanged,因此控件显示集合能够看到列表中的更改以及列表中的各个项目。
答案 3 :(得分:0)
我最近为了好玩而创建了一个3层程序,并希望确保所有部分尽可能分开。
在我的GUI中,用户可以输入他们想要的名称,但是,我的业务类中有逻辑将所有名称更改为Title Case。然而,这是有效的,GUI从未被告知商业类的更新。
所以我当时的工作很简单......但看起来并不正确。类似于以下内容
var _person = new Person();
// In some form event handler like button click
_person.Name = txtName.Text;
txt.Name.Text = _person.Name;
这完成了更新GUI的工作,同时将其与业务逻辑分开。我想要的是创建一个事件,当业务逻辑从GUI中输入的内容改变了值时将触发该事件,并且GUI将监听该事件。
所以现在我会有类似......
var _person = new Person();
// In some form event handler like button click
_person.Name = txtName.Text;
// In the GUI class
public void OnInternalPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
txtName.Text = _person.Name;
}
注意:我没有对所有属性更改执行此操作...只是偏离用户期望的属性...将所有小写名称更改为Title Case,并向用户显示。