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
  • βœ” INotifyPropertyChanged plumbing
  • βœ” 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

  1. 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
  2. Which attribute automatically generates properties and change notifications?
    a) [AutoProperty]
    b) [BindProperty]
    c) [ObservableProperty]
    d) [NotifyProperty]
  3. Which attribute links a property to another dependent property?
    a) [DependsOn]
    b) [NotifyPropertyChangedFor]
    c) [AutoNotify]
    d) [SyncProperty]
  4. What command type is generated when a method marked with [ICommand] returns Task?
    a) RelayCommand
    b) AsyncRelayCommand
    c) TaskCommand
    d) AutoCommand
  5. 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

  1. True / False: Partial methods work only with properties generated by [ObservableProperty].
  2. True / False: [ICommand] can generate both synchronous and asynchronous commands.
  3. True / False: [NotifyCanExecuteChangedFor] automatically triggers command re-evaluation.
  4. True / False: Source generators run at runtime.
  5. True / False: Advanced attributes reduce the amount of manual code dramatically.

✍️ Section C – Short Answer Questions

  1. Explain why source generators make MVVM code easier to maintain.
  2. Write a short example of [ObservableProperty] generating a backing field and property.
  3. What is the use of [NotifyPropertyChangedFor]? Provide a simple example.
  4. Describe when you would use partial method OnXChanging.
  5. 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";
    }
}
  1. What property will update when Name changes?
  2. What will the generated command be called?
  3. Will the UI update automatically after calling UpdateNameCommand?
  4. 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;
  1. When will SaveCommand be disabled?
  2. What triggers the command's CanExecute re-check?
  3. What UI effect occurs when IsValid becomes true?

πŸ“˜ Hour 6 – Source Generators & Advanced Attributes Quiz Answer Key

βœ… Section A – Multiple Choice Answers

  1. b) Generate boilerplate code during compilation
  2. c) [ObservableProperty]
  3. b) [NotifyPropertyChangedFor]
  4. b) AsyncRelayCommand
  5. c) Add custom logic when properties change

🧠 Section B – True or False Answers

  1. True β€” Partial methods are generated only for ObservableProperty fields.
  2. True β€” [ICommand] generates both RelayCommand and AsyncRelayCommand based on method type.
  3. True β€” [NotifyCanExecuteChangedFor] triggers CanExecuteChanged automatically.
  4. False β€” Source generators run at compile time, not runtime.
  5. True β€” They eliminate a lot of manual MVVM coding.

✍️ Section C – Short Answer Solutions

  1. Source generators reduce repetitive code (properties, commands), making ViewModels smaller, easier to read, and less error‑prone.
  2. Example:
    [ObservableProperty]
    private string title;
    
    Generates:
    β€” A public Title property
    β€” PropertyChanged notifications.
  3. [NotifyPropertyChangedFor] updates dependent properties when another changes.
    Example:
    [ObservableProperty]
    [NotifyPropertyChangedFor(nameof(FullName))]
    private string firstName;
    
  4. Use OnXChanging for pre-validation (e.g., checking values before assignment).
  5. The generated command name is: LoadDataCommand.

πŸ’» Section D – Code Interpretation Answers

  1. The dependent property FullInfo will update.
  2. The generated command is UpdateNameCommand.
  3. Yes, the UI updates automatically because Name triggers PropertyChanged.
  4. OnNameChanged runs (if defined).

🧬 Section E – Attribute Behavior Answers

  1. SaveCommand is disabled when IsValid == false.
  2. Changing the property IsValid triggers automatic re-check using NotifyCanExecuteChangedFor.
  3. The UI will enable the Save button (because CanSave() returns true).

πŸŽ‰ Hour 6 Answer Key Complete

Back to Index
MAUI-CommunityToolkit-5 :👈 👉:MAUI-CommunityToolkit-7
*