我有一个Web表单WebUserControl,它有一个名为ShowAccessLevels
的布尔属性:
Public Property ShowAccessLevels As Boolean
Get
Dim a As Object = ViewState("_ShowAccessLevels")
If a Is Nothing Then
a = False
End If
Return Convert.ToBoolean(a)
End Get
Set(value As Boolean)
ViewState("_ShowAccessLevels") = value
End Set
End Property
当调用Setter时,如果值已更改,我需要根据值执行一些内部逻辑来显示/隐藏字段:
Private Sub ShowAccessLevelsChanged()
If value = False Then
' do stuff here
Else
' do stuff here
End If
End Sub
我知道我可以从Setter调用该方法,但我不确定这是否是最佳做法:
Set(value As Boolean)
If ViewState("_ShowAccessLevels") <> value Then
ViewState("_ShowAccessLevels") = value
ShowAccessLevelsChanged()
End Set
我将需要许多不同属性的方法,因此每次创建一个新方法都会感到笨拙。我之前已经问过similar question,但我无法确定最终解决方案是否与专家和this MSDN article提供的建议相符。
请注意,我不需要在控件之外提升事件,仅用于内部方法,这就是我努力采用两种来源以满足我的需求的原因。
如果我实施INotifyPropertyChanged
,那么我最终会添加这些内容,但无法解决如何将逻辑与我的属性相关联的问题:
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
我很感激任何指示。
答案 0 :(得分:1)
我就是这样做的:
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _
Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
' Use a writable private backing field for your property.
Private _accessLevels As Boolean = False
Public Property AccessLevels As Boolean
Get
Return _accessLevels
End Get
Set(value As Boolean)
RefreshAccessLevels(value)
End Set
End Property
' Next create a method to refresh the property, or optionally pass it an
' arbitrary value. Call the NotifyPropertyChanged method after updating.
Public Sub RefreshAccessLevels(Optional ByVal newValue As Object = Nothing)
If newValue IsNot Nothing Then
_accessLevels = Convert.ToBoolean(newValue)
Else
newValue = ViewState("_ShowAccessLevels")
_accessLevels = If(newValue Is Nothing, False, Convert.ToBoolean(newValue))
End If
NotifyPropertyChanged("AccessLevels")
End Sub
' Handle the PropertyChanged event if you need to refresh controls manually
Private Sub HandlePropertyChanged(sender As Object, e As PropertyChangedEventArgs) Handles Me.PropertyChanged
Select Case e.PropertyName
Case "ShowAccessLevels"
' Call some refresh logic here...
Case "SomeOtherProperty"
' Etc...
End Select
End Sub
这样,每次更新后都会正确刷新绑定控件,并且只需要一个方法来刷新值。对于具有getter和setter且没有ViewState恶作剧的更传统的属性,你只需在你的setter中调用NotifyPropertyChanged而不带参数。
Private _accessLevels As Boolean = False
Public Property AccessLevels As Boolean
Get
Return _accessLevels
End Get
Set(value As Boolean)
_accessLevels = value
NotifyPropertyChanged()
End Set
End Property
CallerMemberName属性负责将调用成员的名称转发给NotifyPropertyChanged方法。
这基本上是MVVM和WPF中任何视图模型的基本工作。定义一个实现INotifyPropertyChanged的类,定义数据绑定所需的所有数据对象,实例化该视图模型,将视图(表单)绑定到实例的属性,并仅从模型更新属性(通用术语)为该计划...)。这里的想法是关注点的分离。您永远不必直接通过MVVM更新表单,表单根据视图模型状态自行更新。
答案 1 :(得分:1)
无法弄清楚如何将逻辑与我的属性相关联......我很感激任何指针
INotifyPropertyChanged
的工作方式有点像使用ShowAccessLevelsChanged
,但更通用的形式除外:
Set(value As Boolean)
If _AccessLevel <> value Then
_AccessLevel = value
RaiseEvent PropertyChanged(Me,
New PropertyChangedEventArgs("AccessLevel "))
End If
End Set
INotifyPropertyChanged
最常用于通知外部属性值已更改的内容。例如,用作BindingList(Of T)
的{{1}}会观看DataSource
事件,并因此更新控件。
不需要来触发事件只是为了在本地捕获和处理它;我认为更多笨重。但是,作为各种变化的调度员的一个程序的模型可能是有价值的:
PropertyChanged
Set(value As Boolean)
If (value <> _ShowAccessLevels) Then
_ShowaccessLevels = value
UpdateForChange()
End If
End Set
Private Sub UpdateForChange(<CallerMemberName> Optional propname As String = "")
Select Case propname
Case "FooVisible"
Me.Foo.Visible = FooVisible ' a simple change
Case "Bar"
BuildBarList(Me.Bar) ' more involved
Case "ShowAccessLevel"
UpdateAccess(Me.AccessLevel) ' very involved (?)
...
,因为这将涉及拳击和更多clunk。作为本地过程,属性和支持字段都可以直接。 value
与FooBar
相关联。_FooBar
将调用成员名称传递给更新程序。它与<CallerMemberName>
相同,但如果将其粘贴到另一个setter,则不会引入错误。它需要NET 4.5并导入UpdateForChange("Foo")
,但没有它就能很好地工作。System.Runtime.CompilerServices
甚至是道具名称,因此笨重的因素仍在减少。当value
或BackColor
等属性发生变化时,子类控件中常见的情况是这样。
不排除ShowScrollBars
这并不是说您的应用无法从INotifyPropertyChanged
中受益。 OP代码出现以使用INotifyPropertyChanged
来通知某个属性发生变化的地方。问题中的链接描述了应该如何使用ViewState
:
- 这个类将它作为公共事件实现,并在外部参与者感兴趣的道具改变时提高它
- 外部类将添加INotifyPropertyChanged
事件处理程序并进行响应。
该问题专门询问本地处理/通知,但不包括外部通知(并且没有标记为MV ??)。