wpf – 属性与变量为ByRef参数

我创建了一个实现INotifyPropertyChanged接口的基类.此类还包含一个通用函数SetProperty,用于设置任何属性的值,并在必要时引发PropertyChanged事件.
Public Class BaseClass
    Implements INotifyPropertyChanged

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Protected Function SetProperty(Of T)(ByRef storage As T,value As T,<CallerMemberName> Optional ByVal propertyName As String = nothing) As Boolean
        If Object.Equals(storage,value) Then
            Return False
        End If

        storage = value
        Me.OnPropertyChanged(propertyName)
        Return True
    End Function

    Protected Overridable Sub OnPropertyChanged(<CallerMemberName> Optional ByVal propertyName As String = nothing)
        If String.IsNullOrEmpty(propertyName) Then
            Throw New ArgumentNullException(NameOf(propertyName))
        End If

        RaiseEvent PropertyChanged(Me,New PropertyChangedEventArgs(propertyName))
    End Sub

End Class

然后我有一个类,应该保存一些数据.为简单起见,它只包含一个属性(在本例中).

Public Class Item
    Public Property Text As String
End Class

然后我有一个继承自基类并使用数据保持类的第三个类.第三个类应该是WPF窗口的viewmodel.

我没有列出RelayCommand类的代码,因为你可能都有自己的实现.请记住,当执行命令时,此类执行给定的函数.

Public Class viewmodel
    Inherits BaseClass

    Private _text1 As Item   'data holding class
    Private _text2 As String   'simple variable
    Private _testCommand As ICommand = New RelayCommand(AddressOf Me.Test)

    Public Sub New()
        _text1 = New Item
    End Sub

    Public Property Text1 As String
        Get
            Return _text1.Text
        End Get
        Set(ByVal value As String)
            Me.SetProperty(Of String)(_text1.Text,value)
        End Set
    End Property

    Public Property Text2 As String
        Get
            Return _text2
        End Get
        Set(ByVal value As String)
            Me.SetProperty(Of String)(_text2,value)
        End Set
    End Property

    Public ReadOnly Property TestCommand As ICommand
        Get
            Return _testCommand
        End Get
    End Property

    Private Sub test()
        Me.Text1 = "Text1"
        Me.Text2 = "Text2"
    End Sub

End Class

然后我有我的WPF窗口,它使用viewmodel类作为其DataContext.

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:viewmodel />
    </Window.DataContext>

    <StackPanel Orientation="Horizontal">
        <TextBox Text="{Binding Text1}" Height="24" Width="100" />
        <TextBox Text="{Binding Text2}" Height="24" Width="100" />
        <Button Height="24" Content="Fill" Command="{Binding TestCommand}" />
    </StackPanel>
</Window>

如您所见,此窗口仅包含两个TextBox一个按钮. TextBoxes绑定到属性Text1和Text2,按钮应该执行命令TestCommand.

执行该命令时,属性Text1和Text2都被赋予一个值.由于这两个属性都会引发PropertyChanged事件,因此这些值应该显示在我的窗口中.

但是我的窗口中只显示值“Text2”.

属性Text1的值是“Text1”,但似乎在属性获取其值之前引发了此属性的PropertyChanged事件.

有没有办法在我的基类中更改SetProperty函数以在属性获得其值后引发PropertyChanged?

谢谢您的帮助.

究竟发生了什么?

这不起作用,因为属性不像字段那样运行.

当你执行Me.SetProperty(Of String)(_ text2,value)时,会发生对字段_text2的引用而不是其值的传递,因此SetProperty函数可以修改引用内的内容,并修改字段.

但是,当您执行Me.SetProperty(Of String)(_ text1.Text,编译器会看到属性的getter,因此它将首先调用_text1的Get属性,然后将引用传递给返回值作为参数.因此,当您的函数SetProperty正在接收ByRef参数时,它是来自getter的返回值,而不是实际的字段值.

根据我的理解here,如果你说你的属性是ByRef,编译器将在你退出函数调用自动更改字段引用…这样就可以解释为什么它在你的事件发生后会发生变化……

This other blog似乎证实了这种奇怪的行为.

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...