Skip to content

Inheritance support for Command properties #1036

@egvijayanand

Description

@egvijayanand

Overview

A command is a syntactic sugar for methods defined in the ViewModel.

It is made available as a property to enable binding.

As the ViewModel can inherit, so can commands.

This request aims to include the inheritance modifier in the command property, as outlined in the method definition.

Support for the following: abstract, virtual, override, and sealed.

This can be enabled as an explicit opt-in through a RelayCommand attribute property.

API breakdown

  • A Boolean property for the RelayCommand attribute
  • Update Command SG to infer the inheritance modifiers when the attribute above is set to true
// Base class
public virtual IRelayCommand InitializeCommand { get; } // Source generated

// The attribute property name can be formalized
[RelayCommand(Inherit = true)] // Instructing the command property to include the modifier
protected virtual void Initialize() {}

// Derived class
public override IRelayCommand InitializeCommand { get; } // Source generated

[RelayCommand]
protected override void Initialize() {}

Usage example

This ensures that the ViewModel types inherited from BaseViewModel can optionally override the InitializeCommand definition, if necessary.

For example: If logging is to be implemented, the base definition is sufficient for most scenarios. However, for special cases, additional logic will need to be incorporated.

namespace MyApp.ViewModels;

public class BaseViewModel
{
    public virtual IAsyncRelayCommand InitializeCommand { get; }

    public BaseViewModel()
    {
        InitializeCommand = new AsyncRelayCommand(InitializeAsync);
    }

    //[RelayCommand]
    protected virtual Task InitializeAsync()
    {
        // Base command implementation
    }
}

public class ProjectViewModel : BaseViewModel
{
    public override IAsyncRelayCommand InitializeCommand { get; }

    public ProjectViewModel()
    {
        InitializeCommand = new AsyncRelayCommand(InitializeAsync);
    }

    //[RelayCommand]
    protected override Task InitializeAsync()
    {
        // Derived command implementation
        // Can invoke base implementation, if necessary
        // base.InitializeAsync();
    }
}

Breaking change?

No

Alternatives

Manual command infra. Tedious and cumbersome.

Additional context

There is a breaking change in .NET MAUI, Behaviors no longer automatically inherit the BindingContext of their parent.

In one of the projects, EventToCommandBehavior was mapped to invoke a Command on the Page Load event.

As I migrate to the latest version, I will move this Behavior mapping to the base definition for minimal changes, and override the Command in Derived types if additional logic is needed, instead of manually modifying the affected Pages and ViewModels.

Help us help you

No, just wanted to propose this

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature request 📬A request for new changes to improve functionality

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions