答案:是的,有。
接口INotifyPropertyChanged 正在这样做,它位于System.ComponentModel 命名空间中。
该接口包含一个PropertyChanged事件,该事件会在属性改变时触发。
C# 4 及以下示例
public class DataCS4 : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
// Represent an Observable
private int firstNumber;
public int FirstNumber
{
get { return firstNumber; }
set
{
if (value == firstNumber)
return;
this.firstNumber = value;
OnPropertyChanged("FirstNumber");
OnPropertyChanged("Sum");
}
}
// Represent an Observable
private int secondNumber;
public int SecondNumber
{
get { return secondNumber; }
set
{
if (value == secondNumber)
return;
this.secondNumber = value;
OnPropertyChanged("SecondNumber");
OnPropertyChanged("Sum");
}
}
// Represent Computed
public int Sum { get { return FirstNumber + SecondNumber; } }
}
这是对两个整数求和的非常简单的示例
我们有FirstNumber 属性,(我们可以将其视为可观察到的淘汰赛)
我们还有SecondNumber 属性(我们可以将其视为 Knockout observable)
并且我们有 Sum 属性(我们可以将其视为 Knockout Computed)。
现在,每次我们更改 FirstNumber 或 SecondNumber(通过调用其相应的 set 函数)时,我们都会通知所有订阅者这些属性(通过调用 OnPropertyChanged 方法完成)
我们还为Sum 属性调用OnPropertyChanged,以通知该属性的订阅者该属性的值已更改。
注意这是使用 WPF + MVVM 模式时非常常见的模式。
在使用 C# 5.0 或 C# 6.0 时,您可以从它们的新功能中受益,让代码变得更简单
C# 5.0 示例
public class DataCS5 : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
// Represent an Observable
private int firstNumber;
public int FirstNumber
{
get { return firstNumber; }
set
{
if (value == firstNumber)
return;
this.firstNumber = value;
OnPropertyChanged();
OnPropertyChanged("Sum");
}
}
// Represent an Observable
private int secondNumber;
public int SecondNumber
{
get { return secondNumber; }
set
{
if (value == secondNumber)
return;
this.secondNumber = value;
OnPropertyChanged();
OnPropertyChanged("Sum");
}
}
// Represent Computed
public int Sum { get { return FirstNumber + SecondNumber; } }
}
这里有两个变化
-
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null),所以通过把这个属性放在方法的参数之前,编译器会自动知道调用这个方法的属性的名称,而不需要手动传递属性名称,所以我们可以编写如下语句。
-
OnPropertyChanged(); 代表第二次修改。
注意:CallerMemberName 属性存在于 System.Runtime.CompilerServices 命名空间中
C# 6.0 示例
使用 C# 6.0,我们可以简化 OnPropertyChanged 方法的实现。
public class DataCS6 : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// C# 6.0
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
// Represent an Observable
private int firstNumber;
public int FirstNumber
{
get { return firstNumber; }
set
{
if (value == firstNumber)
return;
this.firstNumber = value;
OnPropertyChanged();
OnPropertyChanged("Sum");
}
}
// Represent an Observable
private int secondNumber;
public int SecondNumber
{
get { return secondNumber; }
set
{
if (value == secondNumber)
return;
this.secondNumber = value;
OnPropertyChanged();
OnPropertyChanged("Sum");
}
}
// Represent Computed
public int Sum => FirstNumber + SecondNumber;
}
Reference
更新
回应以下评论:
有趣!但是在这里你必须自己管理你的依赖。您必须触发 Sum 的属性更改。在淘汰赛中,它会自行确定哪些属性将触发在计算上更改的属性。有什么办法吗?
我想你可以有两个选择(至少)
-
PropertyChanged library on GitHub.
这个库的描述是:
在编译时将 INotifyPropertyChanged 代码注入属性
这是从Nuget下载库后的新代码
[PropertyChanged.ImplementPropertyChanged]
public class Data
{
public int FirstNumber { get; set; }
public int SecondNumber { get; set; }
public int Sum => SecondNumber + FirstNumber;
}
2.PostSharp Library
干杯!。