I have a MAUI mobile app that uses CommunityToolkit.Mvvm. On a page, there is a ListView:
<ListView
Grid.Row="0"
ItemsSource="{Binding Features}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewmodel:FeatureListItem">
<ViewCell>
<Grid
RowDefinitions="*,1"
ColumnDefinitions="10*,*">
<Label x:Name="txtDescription" Text="{Binding DescriptionText}" BackgroundColor="Transparent" TextColor="Black" Grid.Row="0" Grid.Column="0" />
<Label x:Name="txtIcon" Text="{Binding IconText}" BackgroundColor="Transparent" TextColor="Black" Style="{StaticResource ToolbarItemIconStyle}" Grid.Row="0" Grid.Column="1" />
...
Features is a list of FeatureListItem:
public class FeatureListItem
{
public string DescriptionText { get; set; }
public string IconText { get; set; }
public IRelayCommand Command { get; set; }
public FeatureListItem(string descriptionText, string iconText, IRelayCommand command)
{
DescriptionText = descriptionText;
IconText = iconText;
Command = command;
}
}
In the viewmodel constructor, the Features list is initialized :
Features = new List<FeatureListItem>
{
new FeatureListItem(ToggleLoginText, ToggleLoginIcon, ToggleLoginCommand),
...
};
IsLoggedIn = App.UserContext?.IsLoggedOn ?? false;
ToggleLoginIcon = IsLoggedIn ? MaterialDesignFontHelper.Logout : MaterialDesignFontHelper.Login;
ToggleLoginText = IsLoggedIn ? _textSignOut : _textSignIn;
Properties used in the code above:
[ObservableProperty]
private List<FeatureListItem> _features;
[ObservableProperty]
private string _toggleLoginIcon = MaterialDesignFontHelper.Login;
private const string _textSignIn = "Sign In";
private const string _textSignOut = "Sign Out";
[ObservableProperty]
private string _toggleLoginText = _textSignIn;
The problem is that when ToggleLoginText and ToggleLoginIcon are changed programmatically, txtDescription and txtIcon in the UI do not change. I guess, it is because DescriptionText and IconText in FeatureListItem are not observable. I tried to derive FeatureListItem from ObservableObject and make the properties observable:
public partial class FeatureListItem : ObservableObject
{
[ObservableProperty]
private string _descriptionText;
[ObservableProperty]
private string _iconText;
But it did not help. What am I missing?
As @ToomakerSteve mentioned in his comment, I was observing and changing wrong properties. As _toggleLoginIcon and _toggleLoginText are used only once to initialize FeatureListItem with its properties, no need to observe or change them. Instead, I had to change properties of FeatureListItem _descriptionText and _iconText:
FeatureListItem loginFeature = Features.FirstOrDefault(); // Login feature is the first element in the list
loginFeature.IconText = IsLoggedIn ? MaterialDesignFontHelper.Logout : MaterialDesignFontHelper.Login;
loginFeature.DescriptionText = IsLoggedIn ? _textSignOut : _textSignIn;
This way the UI is updated properly.