wpf - 属性与变量作为 ByRef 参数

标签 wpf vb.net inotifypropertychanged 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>

如您所见,此窗口仅包含两个文本框和一个按钮。文本框绑定(bind)到属性 Text1Text2并且按钮应该执行命令TestCommand .

执行命令时,两个属性 Text1Text2被赋予一个值。而且由于这两个属性都提高了PropertyChanged事件,这些值应该显示在我的窗口中。

但只有值“Text2”显示在我的窗口中。

房产值(value)Text1是“Text1”,但似乎 PropertyChanged此属性的事件在属性获得其值之前引发。

有什么办法可以改变SetProperty在我的基类中提高 PropertyChanged 的函数房产升值后?

感谢您的帮助。

最佳答案

实际发生了什么?

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

当你这样做 Me.SetProperty(Of String)(_text2, value) , 发生的是对字段 _text2 的引用被传递而不是它的值,所以 SetProperty函数可以修改引用中的内容,并修改字段。

但是,当您执行 Me.SetProperty(Of String)(_text1.Text, value) ,编译器看到一个属性的getter,所以它会首先调用_text1的Get属性,然后将返回值的引用作为参数传递。所以当你的函数SetProperty正在接收 ByRef参数,它是 getter 的返回值,而不是实际的字段值。

据我了解here ,如果你说你的属性是 ByRef,当你退出函数调用时,编译器会自动更改字段 ref ......所以这可以解释为什么它在你的事件之后发生变化......

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

关于wpf - 属性与变量作为 ByRef 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40847193/

相关文章:

wpf - 如何在 MainWindow 上显示不同的 View

C#、WPF、MVVM 和 INotifyPropertyChanged

c# - MVVM INotifyPropertyChanged 与基类 PropertyChange 冲突

mvvm - 为什么在 mvvmlight 的默认实现中有一个公共(public)常量字符串属性?

c# - 替换 WPF 中的部分默认模板

c# - 一个简单的 Wpf MVVM 绑定(bind)问题

c# - 如何使用 StaticResource 在 XAML 中定义 DataContext

c# 创建 thead 和 tbody

.net - VB.NET Me.Close() 导致应用程序抛出 "has stopped working"消息

mysql - 如何选择超过 4 个条件的记录