Cook up a Storm with WinUI 3.0

Saving and loading Reminders

Our Plant Nanny has a considerable problem. Sure, it will remind you of your watering duties while you have the application running. But once you close it, the reminder is gone like ice cream on a hot summer day.

Not to worry. We can save that reminder and load it up when the application starts again. First, we need to make some changes to our XAML Layout.

C#
<StackPanel Orientation="Vertical">
    <TextBlock Text="Set Reminder Time" Margin="10"/>
    <TextBox x:Name="TimeInput" PlaceholderText="HH:mm" Margin="10"/>
    <Button Content="Set Reminder" Click="SetReminder_Click" Margin="10"/>
    <Button Content="Delete Selected Reminder" Click="DeleteSelectedReminder_Click" Margin="10"/>
    <TextBlock x:Name="ReminderTextBlock" Text=""></TextBlock>
</StackPanel>

This code adds a vertical stack panel that contains a text block asking for the reminder time, a text box for the user to input the time, and a button to set the reminder. Make sure to save your XAML file.

Step 2: Setting up the Reminder Logic

Let's head over to the code-behind file (usually named MainWindow.xaml.cs) where we'll implement the reminder functionality.

Inside the MainWindow class, add the following code:

C#
public sealed partial class MainWindow : Window
{
    public string activeReminder;
    public ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    //...

Here, we declare a variable activeReminder to store the currently set reminder and create an ApplicationDataContainer to save our reminder. Both of these variables are outside the methods, so they are global to the MainWindow.

Next, inside the constructor of the MainWindow class, add the following line:

C#
ReminderTextBlock.ItemsSource = reminders;

This line sets the ItemsSource property of a text block named ReminderTextBlock to a collection of reminders. We'll define this collection later.

Step 3: Loading the Reminder on Application Activation

To ensure that our reminder is loaded when the application activates, we'll handle the MainWindow_Activated event. Add the following code to your class:

C#
private void MainWindow_Activated(object sender, WindowActivatedEventArgs e)
{
    if (e.WindowActivationState != WindowActivationState.Deactivated)
    {
        LoadReminder();
        // To ensure the method is only called once, remove the event handler
        this.Activated -= MainWindow_Activated;
    }
}

This code checks if the window activation state is not deactivated and calls the LoadReminder() method. We also remove the event handler to make sure it's only called once.

Step 4: Setting the Reminder

Now, let's implement the logic for setting the reminder when the user clicks the "Set Reminder" button. Add the following code:

C#
private void SetReminder_Click(object sender, RoutedEventArgs e)
{
    string time = TimeInput.Text;
    if (TimeSpan.TryParse(time, out var _))
    {
        activeReminder = time;
        SetReminder(time);
        SaveReminders();
    }
    else
    {
        Debug.WriteLine("Invalid time format. Please enter a valid time in the format 'HH:mm'.");
    }
}

This code retrieves the time input from the text box and checks if it can be parsed as a valid TimeSpan. If it is valid, we set the activeReminder variable, call the SetReminder() method, and save the reminders. If the time format is invalid, we output a helpful message.

Step 5: Loading the Reminder from Local Settings

Now, let's implement the LoadReminder() method to load any previously saved reminders when the application activates. Add the following code:

C#
private void LoadReminder()
{
    if (localSettings.Values.ContainsKey("Reminder"))
    {
        string savedReminder = localSettings.Values["Reminder"].ToString();
        string[] loadedReminder = savedReminder.Split(',');

        // Run on a different thread to not block the UI
        Task.Run(() =>
        {
            foreach (string reminder in loadedReminder)
            {
                if (string.IsNullOrWhiteSpace(reminder))
                {
                    continue;
                }
                if (TimeSpan.TryParse(reminder, out var _))
                {
                    // Switch back to the main thread to update the UI
                    DispatcherQueue.TryEnqueue(UpdateUI);

                    void UpdateUI()
                    {
                        activeReminder = loadedReminder;
                        SetReminder(loadedReminder);
                    }
                }
            }
        });
    }
}

This code checks if a reminder exists in the local settings. If it does, it splits the saved reminder into an array of individual reminders. Then, it iterates through each reminder, checks if it's a valid TimeSpan, and updates the UI with the loaded reminders.

Step 6: Saving the Reminder

To persist the reminders between application sessions, we need to implement the SetReminder() and SaveReminder() methods. Add the following code:

C#
private void SetReminder(string time)
{
    // Implement the logic to set the reminder using the provided time
    // ...

    SaveReminder();
}

private void SaveReminder()
{
    string savedReminder = string.Join(",", reminders);
    localSettings.Values["Reminder"] = savedReminder;
}

In the SetReminder() method, you can implement the logic to set the actual reminder using the provided time. Feel free to add your own logic or integrate with external services.

The SaveReminder() method converts the collection of reminders into a comma-separated string and saves it in the local settings.

Step 7: Enhancements and Future Improvements

Congratulations! You've successfully implemented the core functionality to set, load, and save reminders in your WinUI 3 desktop app. This is just the beginning, and there's a lot more you can do to enhance the user experience and add more features.

For example, you could implement a feature to delete selected reminders by handling the event of a delete button. You can refer to the provided code in the DeleteSelectedReminder_Click method as a starting point.

Remember to keep exploring WinUI 3 and experimenting with different functionalities to take your app to the next level. And don't forget to save your progress and enjoy the process - after all, coding can be as rewarding as baking the perfect cake!

That's it for this tutorial. I hope you found it helpful and entertaining. If you have any questions, feel free to ask.