.NET MAUI – Forget Me Not – Part 4

This is part 4 in an ongoing series in which I will build and dissect a non-trivial app. For details, please see the first in this series.

Part 3 ended with a teaser about the Preferences Page. As you’ll remember, we start with the Preference Model class:

namespace ForgetMeNot.Model;

[ObservableObject]
public partial class Preference
{
    [ObservableProperty] private string preferencePrompt;
    [ObservableProperty] private string preferenceValue;

}

I explained about ObservableProperties, so I won’t review that here. Let’s see how this model class is used. There are two important related classes: Preferences.xaml and PreferencesViewModel.cs

The Preferences View

The view/page starts with a label explaining that you can add as many types of preferences as you like. We start you with a set of preference prompts (e.g., favorite music, favorite books, etc.) but you are not only free to add your own, you are free to modify ours. All the fields, both prompt and value are free form editable fields.

We’ll start with a couple styles

<Style x:Key="PreferenceStyle" TargetType="Entry">
    <Setter Property="BackgroundColor" Value="AntiqueWhite" />
    <Setter Property="HorizontalOptions" Value="Start" />
    <Setter Property="VerticalOptions" Value="Center" />
    <Setter Property="FontSize" Value="10" />
    <Setter Property="TextColor" Value="Black" />
    <Setter Property="VerticalTextAlignment" Value="Center" />
    <Setter Property="WidthRequest" Value="400" />
</Style>

This first one should be pretty straightforward if you are a Xamarin.Forms programmer. Our Entries will use this style. The second one may be a bit new, even though VisualStates are now available in XF.

<Style TargetType="Entry">
    <Setter Property="FontSize" Value="18" />
    <Setter Property="VisualStateManager.VisualStateGroups">
        <VisualStateGroupList>
            <VisualStateGroup x:Name="CommonStates">
                <VisualState x:Name="Normal">
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="White" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Focused">
                    <VisualState.Setters>
                        <Setter Property="BackgroundColor" Value="Wheat" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateGroupList>
    </Setter>
</Style>

The short version of this is that the appearance of the entry will change based on the “state” of the entry. If it is in normal state, the background is white, if it is has focus, however, the background is wheat.

The body of the page has a label that explains how the page works, and a button to save your preferences (the button is at both the top and bottom of the page for the user’s convenience). This is all followed by a CollectionView. Let’s focus on that:

<CollectionView
    Margin="20,20,10,10"
    ItemsSource="{Binding Preferences}"
    SelectionMode="None">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Grid ColumnDefinitions="*,2*">
                <Entry
                    Grid.Column="0"
                    FontSize="10"
                    HorizontalOptions="Start"
                    HorizontalTextAlignment="Start"
                    Text="{Binding PreferencePrompt, Mode=TwoWay }"
                    TextColor="{OnPlatform Black, iOS=White}" />
                <Entry
                    Grid.Column="1"
                    FontSize="10"
                    HeightRequest="32"
                    HorizontalOptions="Start"
                    HorizontalTextAlignment="Start"
                    Text="{Binding PreferenceValue, Mode=TwoWay}"
                    TextColor="{OnPlatform Black, iOS=White}" 
                    WidthRequest="350" />
            </Grid>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

The ItemsSource for the collection view is a property in the ViewModel. The DataTemplate defines that each entry in the ItemsSource collection will be displayed in a pair of Entry fields. The first will use the item’s PreferencePrompt property and the second will use the PreferenceValue property. Again, all of this will be very familiar if you are an XF programmer. In fact, most of what you’ll see in MAUI will be very familiar — .NET MAUI really is the next incarnation of Xamarin.Forms.

The save button invokes the SavePreferencesCommand, which we’ll also see in the ViewModel.

The ViewModel

PreferencesViewModel has an ObservableProperty and RelayCommands so we’ll mark it as an ObservableObject

[ObservableObject]
public partial class PreferencesViewModel
{
    [ObservableProperty] private List<Preference> preferences;

    public PreferencesViewModel()
    {
        Preferences = PreferencesService.GetPreferences();
    }

    [RelayCommand]
    private async Task SavePreferencesAsync()
    {
        PreferencesService.Save(preferences);
    }
    
}

Nothing surprising or new here except the RelayCommand and the contents of the constructor.

The RelayCommand attributes marks SavePreferencesAsync() as the method called by the SavePreferencesCommand command. The naming is by convention and that is how MAUI associates the bound command in the XAML with the implementing method in the ViewModel. Again, a huge reduction in boilerplate code.

The constructor sets Preferences (which as you see is a list of Preference objects) by invoking GetPreferences on the PreferenceService.

GetPreferences will return a list of Preference objects by going to the client API service. For now, I’m just mocking that the easy way:

 public static  List<Preference> GetPreferences()
 {
     return GetPreferencesMock();
 }

GetPreferencesMock does not use a “real” mocking object, it just spins up a few preferences and returns them in a list.

private static List<Preference> GetPreferencesMock()
{
    List<Preference> preferences  = new();
    Preference preference = new Preference
    {
        PreferencePrompt = "Shirt size",
        PreferenceValue = "XXL"
    };
    preferences.Add(preference);

    preference = new()
    {
        PreferencePrompt = "Pants size",
        PreferenceValue = "40"
    };
    preferences.Add(preference);

Not elegant, I admit, but it works and it is temporary. Once we have the API we’ll junk the Mock (or comment it out in case we need it for testing later).

We’re using tabs in this app, and when you click on the Preferences tab you go to the Preferences page:

Note that the user can fill in any answer they want in response to the prompt, and they can even edit the prompt!

Unknown's avatar

About Jesse Liberty

** Note ** Jesse is currently looking for a new position. You can learn more about him at https://jesseliberty.bio Thank you. Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET, is now available wherever you buy your books. Liberty was a Team Lead and Senior Software Engineer for various corporations, a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a 13 year Microsoft MVP.
This entry was posted in Essentials. Bookmark the permalink.

80 Responses to .NET MAUI – Forget Me Not – Part 4

  1. Donnell Urse's avatar Donnell Urse says:

    Hey there, You’ve performed an excellent job. I will definitely digg it and personally recommend to my friends. I am sure they’ll be benefited from this website.

  2. Currently it seems like WordPress is the best blogging platform available right now. (from what I’ve read) Is that what you are using on your blog?

  3. At this time it seems like BlogEngine is the preferred blogging platform available right now. (from what I’ve read) Is that what you are using on your blog?

  4. May I simply just say what a relief to find someone that actually knows what they’re discussing over the internet. You definitely realize how to bring an issue to light and make it important. More and more people need to look at this and understand this side of the story. I was surprised that you’re not more popular since you definitely possess the gift.

  5. Excellent pieces. Keep posting such kind of info on your site. Im really impressed by your blog.

  6. Hey I know this is off topic but I was wondering if you knew of any widgets I could add to my blog that automatically tweet my newest twitter updates. I’ve been looking for a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this. Please let me know if you run into anything. I truly enjoy reading your blog and I look forward to your new updates.

  7. Hello there, You have done an incredible job. I’ll definitely digg it and individually recommend to my friends. I’m sure they’ll be benefited from this website.

  8. Glayds Osei's avatar Glayds Osei says:

    Currently it looks like Expression Engine is the preferred blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  9. May I simply just say what a comfort to discover somebody who really knows what they’re discussing online. You certainly know how to bring an issue to light and make it important. More people really need to look at this and understand this side of your story. I was surprised you are not more popular since you most certainly possess the gift.

  10. Currently it sounds like Expression Engine is the best blogging platform out there right now. (from what I’ve read) Is that what you’re using on your blog?

  11. Tawny's avatar Tawny says:

    May I simply just say what a comfort to find somebody that actually understands what they are talking about on the net. You definitely understand how to bring an issue to light and make it important. More people ought to check this out and understand this side of your story. I was surprised you aren’t more popular because you surely possess the gift.

  12. Dalila's avatar Dalila says:

    At this time it looks like Drupal is the best blogging platform available right now. (from what I’ve read) Is that what you are using on your blog?

  13. Ozell's avatar Ozell says:

    At this time it seems like BlogEngine is the top blogging platform out there right now. (from what I’ve read) Is that what you’re using on your blog?

  14. Temple's avatar Temple says:

    Hey there, You have done an excellent job. I’ll definitely digg it and individually recommend to my friends. I am sure they’ll be benefited from this site.

  15. Julio's avatar Julio says:

    Currently it looks like WordPress is the preferred blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  16. Naoma's avatar Naoma says:

    Currently it appears like Drupal is the top blogging platform available right now. (from what I’ve read) Is that what you are using on your blog?

  17. Excellent article. Keep posting such kind of information on your site. Im really impressed by your site.

  18. Hey I know this is off topic but I was wondering if you knew of any widgets I could add to my blog that automatically tweet my newest twitter updates. I’ve been looking for a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this. Please let me know if you run into anything. I truly enjoy reading your blog and I look forward to your new updates.

  19. Hi there, You have performed an incredible job. I will definitely digg it and individually suggest to my friends. I am sure they’ll be benefited from this website.

  20. Wow that was odd. I just wrote an very long comment but after I clicked submit my comment didn’t show up. Grrrr… well I’m not writing all that over again. Regardless, just wanted to say great blog!

  21. Can I simply say what a comfort to discover somebody that really understands what they’re talking about over the internet. You definitely know how to bring a problem to light and make it important. More and more people should read this and understand this side of the story. I can’t believe you aren’t more popular since you certainly have the gift.

  22. Hi there, You’ve done an incredible job. I’ll definitely digg it and in my opinion recommend to my friends. I’m confident they’ll be benefited from this website.

  23. Excellent article. Keep posting such kind of info on your page. Im really impressed by it.

  24. Currently it seems like BlogEngine is the preferred blogging platform out there right now. (from what I’ve read) Is that what you are using on your blog?

  25. Right now it appears like Movable Type is the best blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  26. Aw, this was an extremely good post. Finding the time and actual effort to create a very good article… but what can I say… I hesitate a whole lot and never seem to get anything done.

  27. Right now it sounds like Movable Type is the best blogging platform available right now. (from what I’ve read) Is that what you’re using on your blog?

  28. Aw, this was an incredibly good post. Finding the time and actual effort to generate a very good article… but what can I say… I put things off a whole lot and don’t manage to get nearly anything done.

  29. May I just say what a relief to discover someone who truly knows what they are discussing online. You definitely understand how to bring a problem to light and make it important. A lot more people have to check this out and understand this side of the story. I was surprised that you’re not more popular given that you definitely have the gift.

  30. At this time it appears like Expression Engine is the top blogging platform out there right now. (from what I’ve read) Is that what you’re using on your blog?

Leave a Reply

Your email address will not be published. Required fields are marked *