是否可以为可观察的属性覆盖参数关键字或创建新关键字?
Is it possible to override the Parameter keyword, or create a new Keyword, for observable properties?
在 VB.NET(不引用第 3 方库)中,我发现我正在编写很多以下代码:
Private _prop as String = "test"
Public Property Prop As String
Get
Return _prop
End Get
Set(value As String)
_prop = value
NotifyPropertyChanged()
End Set
'(add more properties here...)
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub NotifyPropertyChanged(<CallerMemberName> Optional propertyName As String = "")
If PropertyChangedEvent IsNot Nothing Then
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End If
End Sub
我希望能够做的是:
Public ObservableProperty Prop As String = "test"
并让 ObservableProperty 成为我定义的构造,它完成所有样板文件的工作。
我知道如果我不想让它成为 Observable,我可以使用相同的模式 (Public Property NonObsProp As String = "test"
),那么是否也可以让它们自动成为 observable?
受 Knockout.js 启发,减少 INPC 属性 样板的一种可能方法是定义可观察值类型。
Imports System.ComponentModel
Public Class ObservableValue(Of T)
Implements INotifyPropertyChanging, INotifyPropertyChanged
Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Shared ReadOnly __changing As PropertyChangingEventArgs = New PropertyChangingEventArgs("Value")
Private Shared ReadOnly __changed As PropertyChangedEventArgs = New PropertyChangedEventArgs("Value")
Public Sub New()
End Sub
Public Sub New(initialValue As T)
_value = initialValue
End Sub
Private _value As T
Public Property Value As T
Get
Return _value
End Get
Set(newValue As T)
If Not EqualityComparer(Of T).Default.Equals(_value, newValue) Then
RaiseValueChanging()
_value = newValue
RaiseValueChanged()
End If
End Set
End Property
Public Sub RaiseValueChanging()
RaiseEvent PropertyChanging(Me, __changing)
End Sub
Public Sub RaiseValueChanged()
RaiseEvent PropertyChanged(Me, __changed)
End Sub
Public Overrides Function ToString() As String
Return If(_value IsNot Nothing, _value.ToString(), String.Empty)
End Function
Public Shared Widening Operator CType(value As T) As ObservableValue(Of T)
Return New ObservableValue(Of T)(value)
End Operator
End Class
这可以用于定义属性 - class 不一定需要实现 INotifyPropertyChanged
,除非出于其他原因需要它。
Public Class MyViewModel
Public ReadOnly Property Prop1 As ObservableValue(Of String) = "A"
Public ReadOnly Property Prop2 As ObservableValue(Of Boolean) = False
End Class
然后你需要记住在 getting/setting 值时访问 .Value
属性(ReadOnly
有帮助,也许有更优雅的方式来公开潜在价值),例如在 WPF 绑定中:
vm.Prop1.Value = "NewValue"
<TextBlock Text="{Binding Prop1.Value}"/>
与典型的 INPC 模式相比,我还没有充分使用这种模式来发现它的缺点……甚至是优点。
@sstan 的评论为我指明了正确的方向。这不是一个完美的答案,但这是我目前能得到的最接近的答案。
本质上,这是参考 here 的方式,它建议创建一个调用 NotifyPropertyChanged
的 SetProperty
方法,减少样板代码。
类似于:
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
在 VB.NET(不引用第 3 方库)中,我发现我正在编写很多以下代码:
Private _prop as String = "test"
Public Property Prop As String
Get
Return _prop
End Get
Set(value As String)
_prop = value
NotifyPropertyChanged()
End Set
'(add more properties here...)
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Protected Overridable Sub NotifyPropertyChanged(<CallerMemberName> Optional propertyName As String = "")
If PropertyChangedEvent IsNot Nothing Then
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End If
End Sub
我希望能够做的是:
Public ObservableProperty Prop As String = "test"
并让 ObservableProperty 成为我定义的构造,它完成所有样板文件的工作。
我知道如果我不想让它成为 Observable,我可以使用相同的模式 (Public Property NonObsProp As String = "test"
),那么是否也可以让它们自动成为 observable?
受 Knockout.js 启发,减少 INPC 属性 样板的一种可能方法是定义可观察值类型。
Imports System.ComponentModel
Public Class ObservableValue(Of T)
Implements INotifyPropertyChanging, INotifyPropertyChanged
Public Event PropertyChanging As PropertyChangingEventHandler Implements INotifyPropertyChanging.PropertyChanging
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Shared ReadOnly __changing As PropertyChangingEventArgs = New PropertyChangingEventArgs("Value")
Private Shared ReadOnly __changed As PropertyChangedEventArgs = New PropertyChangedEventArgs("Value")
Public Sub New()
End Sub
Public Sub New(initialValue As T)
_value = initialValue
End Sub
Private _value As T
Public Property Value As T
Get
Return _value
End Get
Set(newValue As T)
If Not EqualityComparer(Of T).Default.Equals(_value, newValue) Then
RaiseValueChanging()
_value = newValue
RaiseValueChanged()
End If
End Set
End Property
Public Sub RaiseValueChanging()
RaiseEvent PropertyChanging(Me, __changing)
End Sub
Public Sub RaiseValueChanged()
RaiseEvent PropertyChanged(Me, __changed)
End Sub
Public Overrides Function ToString() As String
Return If(_value IsNot Nothing, _value.ToString(), String.Empty)
End Function
Public Shared Widening Operator CType(value As T) As ObservableValue(Of T)
Return New ObservableValue(Of T)(value)
End Operator
End Class
这可以用于定义属性 - class 不一定需要实现 INotifyPropertyChanged
,除非出于其他原因需要它。
Public Class MyViewModel
Public ReadOnly Property Prop1 As ObservableValue(Of String) = "A"
Public ReadOnly Property Prop2 As ObservableValue(Of Boolean) = False
End Class
然后你需要记住在 getting/setting 值时访问 .Value
属性(ReadOnly
有帮助,也许有更优雅的方式来公开潜在价值),例如在 WPF 绑定中:
vm.Prop1.Value = "NewValue"
<TextBlock Text="{Binding Prop1.Value}"/>
与典型的 INPC 模式相比,我还没有充分使用这种模式来发现它的缺点……甚至是优点。
@sstan 的评论为我指明了正确的方向。这不是一个完美的答案,但这是我目前能得到的最接近的答案。
本质上,这是参考 here 的方式,它建议创建一个调用 NotifyPropertyChanged
的 SetProperty
方法,减少样板代码。
类似于:
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value))
{
return false;
}
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}