| MAUI-CommunityToolkit-5 :👈 | 👉:MAUI-CommunityToolkit-7 |
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.
Source Generators are compiler-time tools that create code automatically. In MVVM Toolkit, they generate:
INotifyPropertyChanged plumbingdotnet add package CommunityToolkit.Mvvm
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:
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:
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.
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.
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.
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.");
}
}
<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>
You are now capable of using advanced MVVM Toolkit features efficiently in .NET MAUI.
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";
}
}
Given:
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(SaveCommand))]
private bool isValid;
[ICommand(CanExecute = nameof(CanSave))]
private void Save() { }
private bool CanSave() => IsValid;
[ObservableProperty] private string title;Generates:
[ObservableProperty] [NotifyPropertyChangedFor(nameof(FullName))] private string firstName;
| MAUI-CommunityToolkit-5 :👈 | 👉:MAUI-CommunityToolkit-7 |