1

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?

David Shochet
  • 5,035
  • 11
  • 57
  • 105
  • 1
    *"when ToggleLoginText and ToggleLoginIcon are changed programmatically, txtDescription and txtIcon in the UI do not change. "* Perhaps I'm missing something, but **why** do you expect a change to `ToggleLoginText` to update a UI element that is bound to `DescriptionText`? `new FeatureListItem(ToggleLoginText, ToggleLoginIcon, ToggleLoginCommand)` is a **one-time** action. Once that item is created, you have to change the bound property (`DescriptionText`) **directly**. You'll need to explain in more detail what you are trying to do. And add the code where you change `ToggleLoginText`. – ToolmakerSteve Aug 15 '22 at 18:18
  • @ToolmakerSteve Thank you very much, it works now. If you make your suggestion an answer, I will mark it as such. – David Shochet Aug 15 '22 at 19:23
  • Go ahead and create Your Answer below, showing the exact code that worked. I'm not sure exactly what you did, given that DescriptionText is in an item model. – ToolmakerSteve Aug 15 '22 at 19:36

1 Answers1

0

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.

David Shochet
  • 5,035
  • 11
  • 57
  • 105