MAUI-CommunityToolkit-2 :👈 👉:MAUI-CommunityToolkit-4

๐Ÿ“… Hour 3 โ€“ Commands: RelayCommand & AsyncRelayCommand

๐Ÿ“… Hour 3 โ€“ Commands: RelayCommand & AsyncRelayCommand

๐ŸŽ›๏ธ 1. What Are Commands?

Commands are an MVVM-friendly way to handle user interactions without writing code-behind. A Command is an object that implements ICommand and allows executing logic from UI elements like:

  • ๐Ÿ”˜ Buttons
  • ๐Ÿ“Œ Menu items
  • โžก๏ธ Gesture recognizers

Why use commands instead of Click events?

  • ๐Ÿ“ฆ Keeps UI and logic separate
  • ๐Ÿ” Allows UI to update when command states change
  • ๐Ÿงช Easier to test
  • ๐Ÿ— Supports MVVM pattern properly

โšก 2. RelayCommand โ€“ The Basic Command

RelayCommand is a simple command used for synchronous actions.

Basic Example:

public partial class CounterViewModel : ObservableObject
{
    [ObservableProperty]
    private int count;

    public RelayCommand IncreaseCommand { get; }

    public CounterViewModel()
    {
        IncreaseCommand = new RelayCommand(() =>
        {
            Count++;
        });
    }
}

โœ” Bind this in XAML:

<Button Text="Increase" Command="{Binding IncreaseCommand}" />

๐Ÿ’ก Every click increments the count using MVVM-friendly logic.


๐Ÿ“จ 3. RelayCommand with Parameters

Example:

public RelayCommand<int> AddCommand { get; }

public CounterViewModel()
{
    AddCommand = new RelayCommand<int>((value) =>
    {
        Count += value;
    });
}

XAML binding:

<Button Text="+5" Command="{Binding AddCommand}" CommandParameter="5" />

๐ŸŽ‰ Now you can pass custom values from UI.


โณ 4. AsyncRelayCommand โ€“ For Async Methods

Use AsyncRelayCommand when your logic is asynchronous, such as:

  • ๐ŸŒ API calls
  • โณ Long operations
  • ๐Ÿ’พ Database access

Example:

public partial class DataViewModel : ObservableObject
{
    [ObservableProperty]
    private string message;

    public IAsyncRelayCommand LoadCommand { get; }

    public DataViewModel()
    {
        LoadCommand = new AsyncRelayCommand(LoadDataAsync);
    }

    private async Task LoadDataAsync()
    {
        Message = "Loading...";
        await Task.Delay(2000);
        Message = "Data Loaded Successfully!";
    }
}

XAML:

<Button Text="Load" Command="{Binding LoadCommand}" />

๐Ÿ’ก AsyncRelayCommand automatically disables itself while running.


๐Ÿšฆ 5. CanExecute Logic (Enable/Disable Button)

Commands can control whether buttons are enabled using CanExecute.

Example:

public RelayCommand SubmitCommand { get; }

public LoginViewModel()
{
    SubmitCommand = new RelayCommand(
        Submit,
        () => !string.IsNullOrEmpty(Username)
    );
}

XAML:

<Button Text="Submit" Command="{Binding SubmitCommand}" />

๐Ÿ’ก The button becomes disabled when Username is empty.


๐Ÿงฒ 6. Using [ICommand] Attribute (Advanced Auto-Generation)

MVVM Toolkit can create commands automatically with the [ICommand] attribute.

Example:

public partial class NumberViewModel : ObservableObject
{
    [ObservableProperty]
    private int total;

    [ICommand]
    private void Add(int value)
    {
        Total += value;
    }
}

โœ” This automatically generates an AddCommand.

XAML:

<Button Text="Add 10" Command="{Binding AddCommand}" CommandParameter="10" />

๐Ÿ› ๏ธ 7. Hands-On Practice for Hour 3

  • ๐Ÿ”˜ Create a simple IncreaseCommand
  • โž• Add parameter support using RelayCommand<T>
  • โณ Create an AsyncRelayCommand that loads fake data
  • ๐Ÿšฆ Implement CanExecute logic to disable a button
  • โšก Use [ICommand] attribute to generate a command
  • ๐Ÿ“ฑ Bind commands to MAUI/WPF UI buttons

๐Ÿ“š 8. Hour 3 Practice ViewModel (Recommended)

public partial class DemoViewModel : ObservableObject
{
    [ObservableProperty]
    private int counter;

    [ObservableProperty]
    private bool isBusy;

    public RelayCommand IncreaseCommand { get; }
    public RelayCommand<int> AddAmountCommand { get; }
    public IAsyncRelayCommand LoadCommand { get; }

    public DemoViewModel()
    {
        IncreaseCommand = new RelayCommand(() => Counter++);
        
        AddAmountCommand = new RelayCommand<int>((value) => Counter += value);

        LoadCommand = new AsyncRelayCommand(LoadAsync);
    }

    private async Task LoadAsync()
    {
        IsBusy = true;
        await Task.Delay(2000);
        Counter += 10;
        IsBusy = false;
    }
}

๐ŸŽ‰ Covers all command types!


๐Ÿ Hour 3 Goals Completed

  • โšก Understand RelayCommand & AsyncRelayCommand
  • ๐Ÿ“จ Use commands with parameters
  • โณ Build async commands for loading operations
  • ๐Ÿšฆ Use CanExecute for button-enable logic
  • ๐Ÿช„ Generate commands automatically with [ICommand]

๐Ÿ“ Hour 3 โ€“ Commands Quiz (RelayCommand & AsyncRelayCommand)

๐Ÿ“˜ Section A โ€“ Multiple Choice Questions

  1. Which class implements ICommand for synchronous operations?
    a) AsyncRelayCommand
    b) DelegateCommand
    c) RelayCommand
    d) CommandGenerator
  2. What does AsyncRelayCommand do automatically?
    a) Refresh the UI
    b) Disables itself while running
    c) Logs exceptions automatically
    d) Cancels all other commands
  3. Which interface does every MVVM command implement?
    a) IRunnable
    b) IAction
    c) ICommand
    d) ITrigger
  4. What is the purpose of the CanExecute method?
    a) Runs the command asynchronously
    b) Validates parameters
    c) Controls whether a command is allowed to execute
    d) Logs debug information
  5. What does the [ICommand] attribute generate automatically?
    a) Only a method
    b) Only a property
    c) A full ICommand (method + generated Command property)
    d) XAML markup

๐Ÿง  Section B โ€“ True or False

  1. True / False: RelayCommand can accept parameters.
  2. True / False: AsyncRelayCommand is useful for API calls.
  3. True / False: A command without CanExecute is always enabled.
  4. True / False: The [ICommand] attribute removes the need to write any command manually.
  5. True / False: Commands should be placed inside ViewModels, not Views.

โœ๏ธ Section C โ€“ Short Answer Questions

  1. Explain the difference between RelayCommand and AsyncRelayCommand.
  2. Give an example scenario where CanExecute should return false.
  3. Write a one-line purpose of the ICommand interface.
  4. Why is command binding preferred over button click events in MVVM?
  5. What property does [ICommand] automatically generate for a method named Save()?

๐Ÿ’ป Section D โ€“ Code Output / Interpretation

Consider this ViewModel:

public partial class DemoViewModel : ObservableObject
{
    [ObservableProperty]
    private int score = 0;

    [ICommand]
    private void AddPoints(int value)
    {
        Score += value;
    }
}
  1. What is the auto-generated command name?
  2. What happens in the UI if CommandParameter="5" is used?
  3. Is this command synchronous or asynchronous?
  4. Does Score raise PropertyChanged?

๐Ÿšฆ Section E โ€“ CanExecute Logic

Given:

public RelayCommand SaveCommand { get; }

public ExampleViewModel()
{
    SaveCommand = new RelayCommand(
        Save,
        () => IsFormValid
    );
}
  1. When will the button be disabled?
  2. Which method must be called to re-evaluate CanExecute?
  3. What happens if IsFormValid changes but CanExecuteChanged isn't raised?

๐Ÿ“˜ Hour 3 โ€“ Commands Quiz Answer Key

โœ… Section A โ€“ Multiple Choice Answers

  1. c) RelayCommand
  2. b) Disables itself while running
  3. c) ICommand
  4. c) Controls whether a command is allowed to execute
  5. c) A full ICommand (method + generated Command property)

๐Ÿง  Section B โ€“ True or False Answers

  1. True โ€” ObservableObject implements INotifyPropertyChanged.
  2. True โ€” Partial methods are optional but useful.
  3. False โ€” [NotifyPropertyChangedFor] is applied to fields.
  4. True โ€” It generates field + property with notifications.
  5. False โ€” Dependent properties update automatically with the attribute.

โœ๏ธ Section C โ€“ Short Answer Solutions

  1. [ObservableProperty] generates a property with automatic PropertyChanged notifications.
    Example:
    [ObservableProperty] private string title;
  2. [NotifyPropertyChangedFor] ensures dependent properties update when another changes.
    Example: FullName updates when FirstName or LastName changes.
  3. Partial method example:
    partial void OnScoreChanged(int value)
    {
        Console.WriteLine("Score changed!");
    }
    
  4. SetProperty() updates the backing field and raises PropertyChanged automatically.
  5. OnXChanging runs before value changes.
    OnXChanged runs after value changes.
    Useful for validation, logging, or updating dependent logic.

๐Ÿ’ป Section D โ€“ Code Output / Interpretation Answers

  1. AddPointsCommand is generated.
  2. Score increases by 5 when CommandParameter="5".
  3. It is a synchronous command (RelayCommand via [ICommand]).
  4. Yes, Score raises PropertyChanged automatically.

๐Ÿšฆ Section E โ€“ CanExecute Logic Answers

  1. The button is disabled when IsFormValid == false.
  2. You must call SaveCommand.NotifyCanExecuteChanged().
  3. The button will not update its enabled/disabled state, even if IsFormValid changes.

๐ŸŽ‰ End of Hour 3 Answer Key

Back to Index
MAUI-CommunityToolkit-2 :👈 👉:MAUI-CommunityToolkit-4
*