Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lawrence_shaun_introducing_net_maui_build_and_deploy_crosspl.pdf
Скачиваний:
36
Добавлен:
26.06.2023
Размер:
5.15 Mб
Скачать

Chapter 4 An Architecture to Suit You

Figure 4-4.  The clock widget rendered in the application running on macOS

You have looked at ways to optimize your codebase when using MVVM but I would like to provide some further details on how you can leverage the power of the community in order to further improve your experience.

MVVM Enhancements

There are two key parts I will cover regarding how you can utilize existing packages to reduce the amount of code you are required to write.

MVVM Frameworks

There are several MVVM frameworks that can expand on this by providing a base class implementation for you with varying levels of other extra features. To list a few,

•\ CommunityToolkit.Mvvm

•\ MVVMLight

•\ FreshMVVM

•\ Prism

101

Chapter 4 An Architecture to Suit You

•\ Refractored.MVVMHelpers

•\ ReactiveUI

These packages will ultimately provide you with a base class very similar to the BaseViewModel class that you created earlier. For example, the Prism library provides the BindableBase class that you could use. It offers yet another optimization in terms of less code that you need to write and ultimately maintain.

You can go a step further, but you need to believe…

Magic

Yes, that’s right: magic is real! These approaches involve auto generating the required boilerplate code so that we as developers do not have to do it. There are two main packages that offer this functionality. They provide it through different mechanisms, but they work equally well.

•\

Fody: IL generation, https://github.com/Fody/Home

•\

CommunityToolkit.Mvvm: Source generators (yes, this

 

gets a second mention), https://learn.microsoft.

 

com/dotnet/communitytoolkit/mvvm/

In the past, I was skeptical of using such packages. I felt like I was losing control of parts that I needed to hold on to. Now I can appreciate that I was naïve, and this is impressive.

Let’s look at how these packages can help to further reduce the code. This example uses CommunityToolkit.Mvvm, which provides the ObservableObject base class and a wonderful way of adding attributes

([ObservableProperty]) to the fields you wish to trigger PropertyChanged events when their value changes. This will then generate a property with the same name as the field but with a capitalized first character, so time becomes Time.

102

Chapter 4 An Architecture to Suit You

public partial class ClockWidgetViewModel : ObservableObject

{

[ObservableProperty] private DateTime time;

public ClockWigetViewModel()

{

SetTime(DateTime.Now);

}

public void SetTime(DateTime dateTime)

{

Time = dateTime;

scheduler.ScheduleAction(

TimeSpan.FromSeconds(1),

() => SetTime(DateTime.Now));

}

}

That’s 17 lines down to 2 from the original example! The part that I really like is that it reduces all the noise of the boilerplate code so there is a bigger emphasis on the code that we need to write as developers.

You may have noticed that you are still referring to the Time property in the code but you haven’t supplied the definition for this property. This is where the magic comes in! If you right-click the Time property and select Go to Definition… it will open the following source code so you can view what the toolkit has created for you:

// <auto-generated/> #pragma warning disable #nullable enable

namespace WidgetBoard.ViewModels

103

Chapter 4 An Architecture to Suit You

{

partial class ClockWidgetViewModel

{

/// <inheritdoc cref="time"/> [global::System.CodeDom.Compiler. GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators. ObservablePropertyGenerator", "8.0.0.0")] [global::System.Diagnostics.CodeAnalysis. ExcludeFromCodeCoverage]

public global::System.DateTime Time

{

get => time; set

{

if (!global::System.Collections.Generic. EqualityComparer<global::System.DateTime>. Default.Equals(time, value))

{

OnTimeChanging(value);

OnPropertyChanging(global::CommunityToo lkit.Mvvm.ComponentModel.__Internals.__ KnownINotifyPropertyChangingArgs.Time); time = value;

OnTimeChanged(value);

OnPropertyChanged(global::CommunityTool kit.Mvvm.ComponentModel.__Internals.__ KnownINotifyPropertyChangedArgs.Time);

}

}

}

104