In an earlier post I talked about boxing during calls to SetProperty. If the property passed to SetProperty is a member of a class or a column on a datarow it gets unboxed and boxed and the call to NotifyPropertyChanged occurs before the property gets updated, causing the property's value to lag behind the control's value.
I came across the third scenario where this can happen. One of my colleagues had accidently declared the backing private member as a property. This causes the same symptoms as described in the earlier post.
Private Property _BadProperty As String
Public Property BadProperty As String
Get
Return _BadProperty
End Get
Set(value As String)
SetProperty(_BadProperty, value)
End Set
End Property
Public Property BadProperty As String
Get
Return _BadProperty
Set(value As String)
End Set
End Property
Here is a short demonstration of the problem. It's written in Visual Basic because the problem does not occur in C#.
<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:PrivateProperty"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DataContext="{d:DesignInstance local:MainWindow}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="22"/>
<RowDefinition Height="22"/>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Good"/>
<TextBox Grid.Row="1" Grid.Column="0" Text="{Binding GoodProperty, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding GoodProperty}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Bad"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding BadProperty, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding BadProperty}"/>
</Grid>
</Window>
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:PrivateProperty"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DataContext="{d:DesignInstance local:MainWindow}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="22"/>
<RowDefinition Height="22"/>
<RowDefinition Height="22"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Good"/>
<TextBox Grid.Row="1" Grid.Column="0" Text="{Binding GoodProperty, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding GoodProperty}"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="Bad"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding BadProperty, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding BadProperty}"/>
</Grid>
</Window>
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Class MainWindow
Inherits Window
Implements
INotifyPropertyChanged
Private _GoodProperty As String
Public Property GoodProperty As String
Get
Return _GoodProperty
End Get
Set(value As String)
SetProperty(_GoodProperty, value)
End Set
End Property
Private Property _BadProperty As String
Public Property BadProperty As String
Get
Return _BadProperty
End Get
Set(value As String)
SetProperty(_BadProperty, value)
End Set
End Property
Public Event PropertyChanged As
PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public Function SetProperty(Of T)(ByRef storage As T, value As T,
<CallerMemberName> Optional PropertyName As String = "") As Boolean
If Object.Equals(storage, value) Then Return False
storage = value
NotifyPropertyChanged(PropertyName)
Return True
End Function
Public Sub NotifyPropertyChanged(PropertyName As String)
RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs(PropertyName))
End Sub
End Class
Inherits Window
Public Property GoodProperty As String
Get
Return _GoodProperty
Set(value As String)
End Set
End Property
Public Property BadProperty As String
Get
Return _BadProperty
Set(value As String)
End Set
End Property
If Object.Equals(storage, value) Then Return False
storage = value
NotifyPropertyChanged(PropertyName)
Return True
End Function
Public Sub NotifyPropertyChanged(PropertyName As String)
End Class
No comments:
Post a Comment