更改 UserControl 属性 值时如何执行内部逻辑
How to execute internal logic when UserControl property value is changed
我有一个 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时,如果值发生变化,我需要根据值对Show/Hide字段执行一些内部逻辑:
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 has been asked before, but I can't figure out if the final solution matches what the expert and this MSDN article 建议。
请注意,我不需要在控件之外引发事件,它仅供内部方法使用,这就是为什么我努力采用这两种来源来满足我的需要。
如果我实施 INotifyPropertyChanged
,那么我会添加这些内容,但无法弄清楚如何 link 我的逻辑 属性:
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
如有任何指点,我将不胜感激。
我会这样做:
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 的 class,定义数据绑定所需的所有数据对象,实例化该视图模型,将您的视图(您的表单)绑定到实例的 属性,并仅更新您的属性模型(程序的总称...)。这里的想法是关注点分离。您永远不必直接通过 MVVM 更新表单,表单会根据视图模型状态自行更新。
cannot work out how to link the logic with my property ... I'd appreciate any pointers please
INotifyPropertyChanged
的工作方式有点像您可能使用 ShowAccessLevelsChanged
的方式,除了更通用的形式:
Set(value As Boolean)
If _AccessLevel <> value Then
_AccessLevel = value
RaiseEvent PropertyChanged(Me,
New PropertyChangedEventArgs("AccessLevel "))
End If
End Set
INotifyPropertyChanged
最常用于通知某些 外部 属性 值已更改。例如,用作 DataSource
的 BindingList(Of T)
将监视 PropertyChanged
事件并因此更新控件。
不需要触发事件只是为了在本地捕获和处理它;我认为这 more 很笨重。但是一个过程作为各种变化的调度程序的模型可能是有价值的:
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 (?)
...
- 私人活动不会增加本地通知的组合。当您可以直接调用本地过程时,引发事件以便本地处理程序可以调用另一个方法是很麻烦的。
- 简单的更改可以直接在过程中处理,或者当道具更改涉及多行代码时,它可以调用专门的帮助程序。
- 没有必要通过
value
因为这将涉及拳击和更多的笨拙。作为本地过程,属性 和支持字段都可以直接 使用。
- 此外,原始代码似乎将支持字段名称与 属性 名称混为一谈:尤其是外部参与者可能不会将
FooBar
与 _FooBar
相关联。
- 甚至不需要传递已更改的 属性 的名称:上面显示使用
<CallerMemberName>
会将调用成员名称传递给更新程序。它与 UpdateForChange("Foo")
相同,但如果您将其粘贴到另一个 setter,则不会引入错误。它需要 NET 4.5 并导入 System.Runtime.CompilerServices
但没有它也能很好地工作。
- 如果涉及大部分反应,那么每个 setter 都可以呼叫个人、专门的助手。仍然没有理由装箱并传递
value
甚至 propname,所以笨拙的因素仍然减少了。
当 BackColor
或 ShowScrollBars
等 属性 发生变化时,子 classed 控件必须执行类似的操作是很常见的。
还不排除INotifyPropertyChanged
这并不是说您的应用无法从 INotifyPropertyChanged
中受益。 OP 代码 出现 使用 ViewState
通知某事,某处 属性 发生了变化。问题中的链接描述了如何使用 INotifyPropertyChanged
:
- 这个 class 会将它实现为一个 public 事件,并在外部参与者感兴趣的道具发生变化时引发它
- 外部 class(es) 将添加 PropertyChanged
事件处理程序并响应。
这个问题专门询问了本地 handling/notifications 并且排除了外部通知(并且没有为 MV 标记??)。
我有一个 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时,如果值发生变化,我需要根据值对Show/Hide字段执行一些内部逻辑:
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 has been asked before, but I can't figure out if the final solution matches what the expert and this MSDN article 建议。
请注意,我不需要在控件之外引发事件,它仅供内部方法使用,这就是为什么我努力采用这两种来源来满足我的需要。
如果我实施 INotifyPropertyChanged
,那么我会添加这些内容,但无法弄清楚如何 link 我的逻辑 属性:
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
如有任何指点,我将不胜感激。
我会这样做:
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 的 class,定义数据绑定所需的所有数据对象,实例化该视图模型,将您的视图(您的表单)绑定到实例的 属性,并仅更新您的属性模型(程序的总称...)。这里的想法是关注点分离。您永远不必直接通过 MVVM 更新表单,表单会根据视图模型状态自行更新。
cannot work out how to link the logic with my property ... I'd appreciate any pointers please
INotifyPropertyChanged
的工作方式有点像您可能使用 ShowAccessLevelsChanged
的方式,除了更通用的形式:
Set(value As Boolean)
If _AccessLevel <> value Then
_AccessLevel = value
RaiseEvent PropertyChanged(Me,
New PropertyChangedEventArgs("AccessLevel "))
End If
End Set
INotifyPropertyChanged
最常用于通知某些 外部 属性 值已更改。例如,用作 DataSource
的 BindingList(Of T)
将监视 PropertyChanged
事件并因此更新控件。
不需要触发事件只是为了在本地捕获和处理它;我认为这 more 很笨重。但是一个过程作为各种变化的调度程序的模型可能是有价值的:
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 (?)
...
- 私人活动不会增加本地通知的组合。当您可以直接调用本地过程时,引发事件以便本地处理程序可以调用另一个方法是很麻烦的。
- 简单的更改可以直接在过程中处理,或者当道具更改涉及多行代码时,它可以调用专门的帮助程序。
- 没有必要通过
value
因为这将涉及拳击和更多的笨拙。作为本地过程,属性 和支持字段都可以直接 使用。 - 此外,原始代码似乎将支持字段名称与 属性 名称混为一谈:尤其是外部参与者可能不会将
FooBar
与_FooBar
相关联。 - 甚至不需要传递已更改的 属性 的名称:上面显示使用
<CallerMemberName>
会将调用成员名称传递给更新程序。它与UpdateForChange("Foo")
相同,但如果您将其粘贴到另一个 setter,则不会引入错误。它需要 NET 4.5 并导入System.Runtime.CompilerServices
但没有它也能很好地工作。 - 如果涉及大部分反应,那么每个 setter 都可以呼叫个人、专门的助手。仍然没有理由装箱并传递
value
甚至 propname,所以笨拙的因素仍然减少了。
当 BackColor
或 ShowScrollBars
等 属性 发生变化时,子 classed 控件必须执行类似的操作是很常见的。
还不排除INotifyPropertyChanged
这并不是说您的应用无法从 INotifyPropertyChanged
中受益。 OP 代码 出现 使用 ViewState
通知某事,某处 属性 发生了变化。问题中的链接描述了如何使用 INotifyPropertyChanged
:
- 这个 class 会将它实现为一个 public 事件,并在外部参与者感兴趣的道具发生变化时引发它
- 外部 class(es) 将添加 PropertyChanged
事件处理程序并响应。
这个问题专门询问了本地 handling/notifications 并且排除了外部通知(并且没有为 MV 标记??)。