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似乎证实了这种奇怪的行为.