I am currently learning .NET and WinUI3, and noticed that when changing the SelectedItem of a ListView and calling PropertyChanged, PropertyChanged calls the property’s setter. Am I doing something wrong?
public class MainViewModel : BindableBase
{
#region Fields
private string selectedMedium;
public MediaItem SelectedMediaItem
{
get
{
Debug.WriteLine("This is SelectedMediaItem's getter.");
return selectedMediaItem;
}
set
{
Debug.WriteLine("Calling SetProperty from SelectedMediaItem setter");
SetProperty(ref selectedMediaItem, value);
Debug.WriteLine("Done calling SetProperty");
}
}
}
public class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
Debug.WriteLine($"Invoking PropertyChanged from OnPropertyChanged, property being changed is: {propertyName}");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Debug.WriteLine("Done Invoking PropertyChanged");
}
protected bool SetProperty<T>(ref T originalValue, T newValue, [CallerMemberName] string propertyName = null)
{
if (Equals(originalValue, newValue))
{
Debug.WriteLine($"Values are the same, property name is {propertyName}, original value is {(originalValue as MyMediaCollection.Model.MediaItem)?.Name}, new value is {(newValue as MyMediaCollection.Model.MediaItem)?.Name}");
return false;
}
Debug.WriteLine($"Values are not the same(good), property name is {propertyName}, original value is {(originalValue as MyMediaCollection.Model.MediaItem)?.Name}, new value is {(newValue as MyMediaCollection.Model.MediaItem)?.Name}");
originalValue = newValue;
Debug.WriteLine("Calling OnPropertyChanged from SetProperty");
OnPropertyChanged(propertyName);
return true;
}
}
XAML:
<ListView
Grid.Row="1"
ItemsSource="{x:Bind ViewModel.Items}"
SelectedItem="{x:Bind ViewModel.SelectedMediaItem, Mode=TwoWay}"
Background="LightGoldenrodYellow">
<ListView.HeaderTemplate>
<DataTemplate>
<Grid ColumnDefinitions="100,*">
<Border BorderBrush="BlueViolet"
BorderThickness="0,0,0,1">
<TextBlock Text="Medium"
Margin="5,0,0,0"
FontWeight="Bold"/>
</Border>
<Border Grid.Column="1"
BorderBrush="BlueViolet"
BorderThickness="0,0,0,1">
<TextBlock Text="Title"
Margin="5,0,0,0"
FontWeight="Bold"/>
</Border>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:MediaItem">
<Grid
ColumnDefinitions="100, *">
<TextBlock Text="{x:Bind Path=MediumInfo.Name}"/>
<TextBlock Grid.Column="1" Text="{x:Bind Path=Name}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The following is the output when selecting an item inside the ListView:
This is SelectedMediaItem's getter.
Calling SetProperty from SelectedMediaItem setter
Values are not the same(good), property name is SelectedMediaItem, original value is , new value is The Mummy
Calling OnPropertyChanged from SetProperty
Invoking PropertyChanged from OnPropertyChanged, property being changed is: SelectedMediaItem
This is SelectedMediaItem's getter.
Calling SetProperty from SelectedMediaItem setter
Values are the same, property name is SelectedMediaItem, original value is The Mummy, new value is The Mummy
Done calling SetProperty
Done Invoking PropertyChanged
Done calling SetProperty
As you can see, in between the Lines “Invoking…” and “Done Invoking…”, SelectedMediaItem’s setter is called again.
Not sure what I can try to debug, but I definitely was not expecting the PropertyChanged event to call the property’s setter. Is that normal behaviour or am I just doing something wrong. Or am I completely misunderstanding this and totally wrong about everything haha.