| MAUI-CommunityToolkit-5 :👈 | 👉:MAUI-CommunityToolkit-7 |
Hour 6 β Source Generators & Advanced Attributes in MVVM |
π Hour 6 β Source Generators & Advanced Attributes in MVVM
Welcome to Hour 6 of your MAUI MVVM journey. Today we explore how the CommunityToolkit.MVVM library uses β‘ Source Generators to remove boilerplate code and simplify your ViewModel development.
β¨ 1. What Are Source Generators?
Source Generators are compiler-time tools that create code automatically. In MVVM Toolkit, they generate:
- β Properties with change notification
- β
INotifyPropertyChangedplumbing - β ICommand implementations
- β Property changed callbacks
π§ Install MVVM Toolkit
dotnet add package CommunityToolkit.Mvvm
β¨ 2. Using [ObservableProperty]
Instead of manually writing a property with backing field:
private string _name;
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
β€ You write only:
[ObservableProperty]
private string name;
This generates:
- β Backing field
- β Public property Name
- β Property changed notifications
β¨ 3. Using [RelayCommand]
Instead of writing ICommand boilerplate:
public ICommand SubmitCommand { get; }
public ViewModel()
{
SubmitCommand = new RelayCommand(OnSubmit);
}
private void OnSubmit() { }
β€ Use this:
[RelayCommand]
private void Submit()
{
}
The generator creates:
- β SubmitCommand property
- β ICommand logic
β¨ 4. Using [NotifyPropertyChangedFor]
Use this attribute when changing one property should update another.
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string firstName;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string lastName;
public string FullName => firstName + " " + lastName;
β Changing first or last name triggers FullName update automatically.
β¨ 5. Using [NotifyCanExecuteChangedFor]
Use this when a command's availability changes based on a property.
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private bool isDirty;
[RelayCommand(CanExecute = nameof(CanSave))]
private void Save()
{
}
private bool CanSave() => isDirty;
β The Save button updates its enabled state automatically.
β¨ 6. Property Callbacks via Partial Methods
The generator also supports automatic callbacks:
[ObservableProperty]
private int count;
partial void OnCountChanged(int oldValue, int newValue)
{
Console.WriteLine("Changed: " + oldValue + " -> " + newValue);
}
β Called automatically when the property changes.
β¨ 7. Full Example ViewModel
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public partial class ProfileViewModel : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string firstName;
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string lastName;
public string FullName => firstName + " " + lastName;
[RelayCommand]
private void UpdateProfile()
{
StatusMessage = "Profile updated for " + FullName;
}
[ObservableProperty]
private string statusMessage;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(ClearCommand))]
private bool canClear;
[RelayCommand(CanExecute = nameof(CanClear))]
private void Clear()
{
firstName = "";
lastName = "";
}
private bool CanClear() => canClear;
partial void OnFirstNameChanged(string oldValue, string newValue)
{
Console.WriteLine("First name changed.");
}
}
β¨ 8. Simple MAUI XAML Example
<VerticalStackLayout Padding="20">
<Entry Text="{Binding FirstName}" Placeholder="First Name" />
<Entry Text="{Binding LastName}" Placeholder="Last Name" />
<Label Text="{Binding FullName}" />
<Button Text="Update"
Command="{Binding UpdateProfileCommand}" />
<Button Text="Clear"
Command="{Binding ClearCommand}" />
<Label Text="{Binding StatusMessage}" />
</VerticalStackLayout>
π Summary
- β Source Generators reduce MVVM boilerplate
- β [ObservableProperty] automates properties
- β [RelayCommand] automates commands
- β [NotifyPropertyChangedFor] links dependent properties
- β [NotifyCanExecuteChangedFor] links property β command availability
- β Partial methods provide callbacks
You are now capable of using advanced MVVM Toolkit features efficiently in .NET MAUI.
π Hour 6 β Source Generators & Advanced Attributes Quiz
π Section A β Multiple Choice Questions
-
What do source generators do in MVVM Toolkit?
a) Improve runtime speed only
b) Generate boilerplate code during compilation
c) Create XAML files
d) Replace NuGet packages -
Which attribute automatically generates properties and change notifications?
a) [AutoProperty]
b) [BindProperty]
c) [ObservableProperty]
d) [NotifyProperty] -
Which attribute links a property to another dependent property?
a) [DependsOn]
b) [NotifyPropertyChangedFor]
c) [AutoNotify]
d) [SyncProperty] -
What command type is generated when a method marked with [ICommand] returns Task?
a) RelayCommand
b) AsyncRelayCommand
c) TaskCommand
d) AutoCommand -
What is the purpose of partial methods like OnXChanged?
a) Generate XAML
b) Run UI animations
c) Add custom logic when properties change
d) Send messages across ViewModels
π§ Section B β True or False
- True / False: Partial methods work only with properties generated by [ObservableProperty].
- True / False: [ICommand] can generate both synchronous and asynchronous commands.
- True / False: [NotifyCanExecuteChangedFor] automatically triggers command re-evaluation.
- True / False: Source generators run at runtime.
- True / False: Advanced attributes reduce the amount of manual code dramatically.
βοΈ Section C β Short Answer Questions
- Explain why source generators make MVVM code easier to maintain.
- Write a short example of [ObservableProperty] generating a backing field and property.
- What is the use of [NotifyPropertyChangedFor]? Provide a simple example.
- Describe when you would use partial method OnXChanging.
- What command name is auto-generated from a method named LoadData() decorated with [ICommand]?
π» Section D β Code Interpretation
Given this code:
public partial class DemoViewModel : ObservableObject
{
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullInfo))]
private string name;
public string FullInfo => $"User: {Name}";
[ICommand]
private void UpdateName()
{
Name = "John";
}
}
- What property will update when Name changes?
- What will the generated command be called?
- Will the UI update automatically after calling UpdateNameCommand?
- Which method runs when Name changes (if defined)?
𧬠Section E β Attribute Behavior
Given:
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private bool isValid;
[ICommand(CanExecute = nameof(CanSave))]
private void Save() { }
private bool CanSave() => IsValid;
- When will SaveCommand be disabled?
- What triggers the command's CanExecute re-check?
- What UI effect occurs when IsValid becomes true?
π Hour 6 β Source Generators & Advanced Attributes Quiz Answer Key
β Section A β Multiple Choice Answers
- b) Generate boilerplate code during compilation
- c) [ObservableProperty]
- b) [NotifyPropertyChangedFor]
- b) AsyncRelayCommand
- c) Add custom logic when properties change
π§ Section B β True or False Answers
- True β Partial methods are generated only for ObservableProperty fields.
- True β [ICommand] generates both RelayCommand and AsyncRelayCommand based on method type.
- True β [NotifyCanExecuteChangedFor] triggers CanExecuteChanged automatically.
- False β Source generators run at compile time, not runtime.
- True β They eliminate a lot of manual MVVM coding.
βοΈ Section C β Short Answer Solutions
- Source generators reduce repetitive code (properties, commands), making ViewModels smaller, easier to read, and less errorβprone.
-
Example:
Generates:[ObservableProperty] private string title;
β A public Title property
β PropertyChanged notifications. -
[NotifyPropertyChangedFor] updates dependent properties when another changes.
Example:
[ObservableProperty] [NotifyPropertyChangedFor(nameof(FullName))] private string firstName; - Use OnXChanging for pre-validation (e.g., checking values before assignment).
- The generated command name is: LoadDataCommand.
π» Section D β Code Interpretation Answers
- The dependent property FullInfo will update.
- The generated command is UpdateNameCommand.
- Yes, the UI updates automatically because Name triggers PropertyChanged.
- OnNameChanged runs (if defined).
𧬠Section E β Attribute Behavior Answers
- SaveCommand is disabled when IsValid == false.
- Changing the property IsValid triggers automatic re-check using NotifyCanExecuteChangedFor.
- The UI will enable the Save button (because CanSave() returns true).
π Hour 6 Answer Key Complete
| MAUI-CommunityToolkit-5 :👈 | 👉:MAUI-CommunityToolkit-7 |