# View Models Generated at Compile Time | WPF Controls | DevExpress Documentation

The DevExpress MVVM Framework includes a [source generator](https://github.com/dotnet/roslyn/blob/main/docs/features/source-generators.md) that produces boilerplate code for your View Models at compile time. You first need to define a stub class that implements View Model logic. Use specially designed attributes to indicate which members require extended boilerplate code. For example, you can mark fields that require standard property getter and setter implementations. Our MVVM Framework then analyzes and extends your code to generate the final View Model class. Consider the following example. 

[View Example: View Models Generated at Compile Time](https://github.com/DevExpress-Examples/wpf-mvvm-framework-view-model-generator)

- Base View Model

    - Create a partial class. Add attributes to the class and its fields/methods:

- C#

<section id="tabpanel_L1mgNjEKQN_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">using DevExpress.Mvvm.CodeGenerators;

[GenerateViewModel]
partial class ViewModel {
    [GenerateProperty]
    string username;
    [GenerateProperty]
    string status;

    [GenerateCommand]
    void Login() =&gt; Status = &quot;User: &quot; + Username;
    bool CanLogin() =&gt; !string.IsNullOrEmpty(Username);
}
</code></pre></section>

- Generated View Model

    - The generator inspects the base View Model and produces a partial class that complements your implementation with the following boilerplate code:

- Properties
- Property change notifications
- Command declarations
- [INotifyPropertyChanged](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanged), [INotifyPropertyChanging](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanging), [IDataErrorInfo](https://learn.microsoft.com/dotnet/api/system.componentmodel.idataerrorinfo), [ISupportServices](/CoreLibraries/DevExpress.Mvvm.ISupportServices) implementation

You can view and debug the generated View Model:

- C#

<section id="tabpanel_L1mgNjEKQN-1_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
        }
    }

    public string? Status {
        get =&gt; status;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(status, value)) return;
            status = value;
            RaisePropertyChanged(StatusChangedEventArgs);
        }
    }

    DelegateCommand? loginCommand;
    public DelegateCommand LoginCommand {
        get =&gt; loginCommand ??= new DelegateCommand(Login, CanLogin, true);
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
    static PropertyChangedEventArgs StatusChangedEventArgs = new PropertyChangedEventArgs(nameof(Status));
}
</code></pre></section>

## Prerequisites

Your project should meet the following requirements:

- C# 9+ (VB is not supported)
- .NET Framework v4.6.1+ or .NET Core v3.0+ (.NET 5 and later is recommended)
- Visual Studio v16.9.0+

Otherwise, use [Runtime-generated POCO View Models](/WPF/17352/mvvm-framework/viewmodels/runtime-generated-poco-viewmodels) instead.

Note

[C# 9 is officially supported in .NET 5 and newer.](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version) You may encounter issues when you use earlier versions of .NET and .NET Framework.

## Prepare Your Project

Prepare your project as outlined below to enable support for View Models generated at compile time:

1. Add a reference to **DevExpress.Mvvm.v21.1**+ or install the [DevExpress.Mvvm](https://www.nuget.org/packages/DevExpressMvvm/) NuGet package.
2. Install the [DevExpress.Mvvm.CodeGenerators](https://www.nuget.org/packages/DevExpress.Mvvm.CodeGenerators) NuGet package in your project.
3. Set the language version to **9** in the **.csproject** file:

- XML

<section id="tabpanel_L1mgNjEKQN-2_tabid-xml" role="tabpanel" data-tab="tabid-xml">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-xml">&lt;PropertyGroup&gt;
    &lt;LangVersion&gt;9&lt;/LangVersion&gt;
&lt;/PropertyGroup&gt;
</code></pre></section>

     For .NET Core projects, set the **IncludePackageReferencesDuringMarkupCompilation** property to **true**:

- XML

<section id="tabpanel_L1mgNjEKQN-3_tabid-xml" role="tabpanel" data-tab="tabid-xml">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-xml">&lt;PropertyGroup&gt;
    &lt;IncludePackageReferencesDuringMarkupCompilation&gt;true&lt;/IncludePackageReferencesDuringMarkupCompilation&gt;
&lt;/PropertyGroup&gt;
</code></pre></section>

### NuGet Package Installation Notes

We recommend that you configure the [packages.config](https://docs.microsoft.com/en-us/nuget/reference/packages-config) file to install NuGet Packages. If you use [PackageReference](https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files), follow the steps below to include the code generator in a .NET Framework project:

1. Open the project file.
2. Remove XML code used to add the package:

- XML

<section id="tabpanel_L1mgNjEKQN-4_tabid-xml" role="tabpanel" data-tab="tabid-xml">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-xml">&lt;PackageReference Include=&quot;DevExpress.Mvvm.CodeGenerators&quot;&gt;
    &lt;Version&gt;XX.Y.Z&lt;/Version&gt;
&lt;/PackageReference&gt;
</code></pre></section>
3. Download the **DevExpress.Mvvm.CodeGenerators.XX.Y.Z.dll** file from [GitHub Releases](https://github.com/DevExpress/DevExpress.Mvvm.CodeGenerators/releases) to the preferred folder.
4. Specify the path to the analyzer: 

- XML

<section id="tabpanel_L1mgNjEKQN-5_tabid-xml" role="tabpanel" data-tab="tabid-xml">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-xml">&lt;ItemGroup&gt;
    &lt;Analyzer Include=&quot;[PATH_TO_YOUR_FOLDER]\DevExpress.Mvvm.CodeGenerators.XX.Y.Z.dll&quot; /&gt;
&lt;/ItemGroup&gt;
</code></pre></section>
5. Save changes and reload the project.

## Review Generated View Model Class

You can access generated code only from Visual Studio. Use the **Peek Definition** command (F12) or search the generated file under **Dependencies** in Solution Explorer. 

![](/WPF/images/code-access-compile-viewmodel.png)

## Apply Attributes to the Base View Model Class

Declare a namespace as follows to access attributes:

 `using DevExpress.Mvvm.CodeGenerators;`

- GenerateViewModel

    - Applies to a class. Indicates that the source generator should process this class and produce View Model boilerplate code.

| Property | Type | Description |
| --- | --- | --- |
| ImplementINotifyPropertyChanging | bool | Implements [INotifyPropertyChanging](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanging). |
| ImplementIDataErrorInfo | bool | Implements [IDataErrorInfo](https://learn.microsoft.com/dotnet/api/system.componentmodel.idataerrorinfo) that allows you to validate data. |
| ImplementISupportServices | bool | Implements [ISupportServices](/CoreLibraries/DevExpress.Mvvm.ISupportServices) that allows you to include the [Services](/WPF/17444/mvvm-framework/services/getting-started) mechanism to your View Model. |
| ISupportParentViewModel | bool | Implements [ISupportParentViewModel](/CoreLibraries/DevExpress.Mvvm.ISupportParentViewModel) that allows you to establish a parent-child relationship between View Models. |

- GenerateProperty

    - Applies to a field. The source generator produces boilerplate code for the property getter and setter based on the field declaration.

| Property | Type | Description |
| --- | --- | --- |
| IsVirtual | bool | Assigns a virtual modifier to the property. |
| OnChangedMethod | string? | Specifies the name of the method invoked after the property value is changed. If the property is not specified, the method’s name should follow the **On[PropertyName]Changed** pattern. |
| OnChangingMethod | string? | Specifies the name of the method invoked when the property value is changing.  If the property is not specified, the method’s name should follow the **On[PropertyName]Changing**  pattern. |
| SetterAccessModifier | AccessModifier | Specifies an access modifier for a set accessor. The default value is the same as a property’s modifier. Available values: *Public*, *Private*, *Protected*, *Internal*, *ProtectedInternal*. |

- GenerateCommand

    - Applies to a method. The source generator produces boilerplate code for a Command based on this method. 

| Property | Type | Description |
| --- | --- | --- |
| AllowMultipleExecution | bool | Specifies the **allowMultipleExecution** parameter in the **AsyncCommand** constructor. The default value is **false**. |
| UseCommandManager | bool | Specifies the **useCommandManager** parameter in the **Command** constructor. The default value is **true**. |
| CanExecuteMethod | string? | Specifies a custom **CanExecute** method name. If the property is not specified, the method’s name should follow the **Can[ActionName]** pattern. |
| Name | string? | Specifies a custom **Command** name. The default value is **[ActionName]Command**. |

## Implement Interfaces

All View Models generated at compile time implement the [INotifyPropertyChanged](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanged) interface:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-6_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
public partial class ViewModel {
    [GenerateProperty]
    string username;
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-7_csharp" role="tabpanel" data-tab="csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1],[2]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
}
</code></pre></section>

If you implement an interface in a base View Model class, add the interface’s members to this class.

In the code sample below, the base View Model class implements [INotifyPropertyChanged](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanged). The generator analyzes the implementation and searches the **PropertyChanged** event to raise it from the generated View Model. If the base View Model class does not include the **PropertyChanged** event, the generated class is empty. 

- Base View Model

<section id="tabpanel_L1mgNjEKQN-8_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[2],[5]]" class="lang-csharp">[GenerateViewModel]
public partial class ViewModel : INotifyPropertyChanged {
    [GenerateProperty]
    string username;
    public event PropertyChangedEventHandler PropertyChanged;
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-9_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel { 
    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    public string? UserName {
        get =&gt; userName;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(userName, value)) return;
            userName = value;
            RaisePropertyChanged(UserNameChangedEventArgs);
        }
    }
}
</code></pre></section>

If you want to implement [INotifyPropertyChanging](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanging), [IDataErrorInfo](https://learn.microsoft.com/dotnet/api/system.componentmodel.idataerrorinfo), or [ISupportServices](/CoreLibraries/DevExpress.Mvvm.ISupportServices), use **GenerateViewModel** attribute properties. 

### Implement INotifyPropertyChanging

Set the **ImplementINotifyPropertyChanging** property to **true**:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-10_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1]]" class="lang-csharp">[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
public partial class ViewModel {
    [GenerateProperty]
    string username;
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-11_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1],[3],[6],[12],[19]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged, INotifyPropertyChanging {
    public event PropertyChangedEventHandler? PropertyChanged;
    public event PropertyChangingEventHandler? PropertyChanging;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);
    protected void RaisePropertyChanging(PropertyChangingEventArgs e) =&gt; PropertyChanging?.Invoke(this, e);

    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            RaisePropertyChanging(UsernameChangingEventArgs);
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
    static PropertyChangingEventArgs UsernameChangingEventArgs = new PropertyChangingEventArgs(nameof(Username));
}
</code></pre></section>

### Implement IDataErrorInfo

Set the **ImplementIDataErrorInfo** property to **true**:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-12_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1]]" class="lang-csharp">[GenerateViewModel(ImplementIDataErrorInfo = true)]
public partial class ViewModel {    
} 
</code></pre></section>

Generated View Models implement the [IDataErrorInfo](https://learn.microsoft.com/dotnet/api/system.componentmodel.idataerrorinfo) interface as follows:

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-13_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1],[3],[4]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged, IDataErrorInfo {
    public event PropertyChangedEventHandler? PropertyChanged;
    string IDataErrorInfo.Error { get =&gt; string.Empty; }
    string IDataErrorInfo.this[string columnName] { get =&gt; IDataErrorInfoHelper.GetErrorText(this, columnName); }

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);
}
</code></pre></section>

The [IDataErrorInfoHelper](/CoreLibraries/DevExpress.Mvvm.IDataErrorInfoHelper) class allows you to get an error based on specified [DataAnnotation](/WPF/16863/mvvm-framework/data-annotation-attributes) attributes.

### Implement ISupportServices

Set the **ImplementISupportServices** property to **true**:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-14_tabid-services-base" role="tabpanel" data-tab="tabid-services-base">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1]]" class="lang-csharp">[GenerateViewModel(ImplementISupportServices = true)]
public partial class ServicesViewModel {
    IMessageBoxService MessageBoxService =&gt; ServiceContainer.GetService&lt;IMessageBoxService&gt;(ServiceSearchMode.PreferParents);
    [GenerateCommand]
    void ShowMessage() =&gt; MessageBoxService.ShowMessage(&quot;Message&quot;);
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-15_tabid-services-viewmodel" role="tabpanel" data-tab="tabid-services-viewmodel">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1],[3,5]]" class="lang-csharp">partial class ServicesViewModel : INotifyPropertyChanged, ISupportServices {
    public event PropertyChangedEventHandler? PropertyChanged;
    IServiceContainer? serviceContainer;
    protected IServiceContainer ServiceContainer { get =&gt; serviceContainer ??= new ServiceContainer(this); }
    IServiceContainer ISupportServices.ServiceContainer { get =&gt; ServiceContainer; }
    protected T? GetService&lt;T&gt;() where T : class =&gt; ServiceContainer.GetService&lt;T&gt;();
    protected T GetRequiredService&lt;T&gt;() where T : class =&gt; ServiceContainer.GetRequiredService&lt;T&gt;();

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    DelegateCommand? showMessageCommand;
    public DelegateCommand ShowMessageCommand =&gt; showMessageCommand ??= new DelegateCommand(ShowMessage, null, true);
}
</code></pre></section>

Refer to the [Services in Custom ViewModels](/WPF/17450/mvvm-framework/services/services-in-custom-viewmodels) topic for more information on how to use the Service mechanism in a View Model.

### Interface Implementation Notes for Inherited View Model Classes

Your View Model can inherit from another class. In this case, implementations declared in a parent class might affect a generated View Model.

If the parent class implements **INotifyPropertyChanged** or **INotifyPropertyChanging**, the child class cannot raise neither the **PropertyChanged** nor **PropertyChanging** events. Ensure that the parent class includes the **RaisePropertyChanged** or **RaisePropertyChanging** methods that allow the child class to raise these events:

- Descendant Base View Model

<section id="tabpanel_L1mgNjEKQN-16_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[1],[5],[7]]" class="lang-csharp">public class DataObjectBase : INotifyPropertyChanged, INotifyPropertyChanging {
    public event PropertyChangedEventHandler PropertyChanged;
    public event PropertyChangingEventHandler PropertyChanging;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);
    // or protected void RaisePropertyChanged(string propertyName) =&gt; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    protected void RaisePropertyChanging(string propertyName) =&gt; PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(propertyName));
    // or protected void RaisePropertyChanging(PropertyChangingEventArgs e) =&gt; PropertyChanging?.Invoke(this, e);
}

[GenerateViewModel]
partial class ViewModel : DataObjectBase {
    [GenerateProperty]
    string username;
} 
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-17_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[6],[8]]" class="lang-csharp">partial class ViewModel {
    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            RaisePropertyChanging(nameof(Username));
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
}
</code></pre></section>

## View Model Parent-Child Relationships

Set the **ImplementISupportParentViewModel** property to **true** to establish a parent-child relationship between View Models. The [ISupportParentViewModel](/CoreLibraries/DevExpress.Mvvm.ISupportParentViewModel) interface allows you to access [Services](/WPF/17444/mvvm-framework/services/getting-started) registered in the main View Model from the child View Models. You can override the **OnParentViewModelChanged** event in a base View Model. If a base View Model class is inherited from another class, you can override the **OnParentViewModelChanged** event in the ancestor. 

Refer to the following topic for more information on the parent-child relationship: [ViewModel relationships (ISupportParentViewModel)](/WPF/17449/mvvm-framework/viewmodels/viewmodel-relationships-isupportparentviewmodel).

## Declare Fields to Generate Properties

To generate a property in your View Model, create a field in a base View Model and add the **GenerateProperty** attribute to the field. The field name should not start with a capital letter:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-18_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
public partial class ViewModel {       
    [GenerateProperty]
    string username;
}
</code></pre></section>

As a result, the generated View Model includes a property, a **RaisePropertyChanged** method, and **PropertyChangedEventArgs** for the generated property:

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-19_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
}  
</code></pre></section>

If your field includes additional attributes, the generated property copies them:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-20_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[4]]" class="lang-csharp">[GenerateViewModel]
partial class ViewModel {
    [GenerateProperty]
    [StringLength(100, MinimumLength = 5)]
    string username;
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-21_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[6]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    [System.ComponentModel.DataAnnotations.StringLengthAttribute(100, MinimumLength = 5)]
    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
}
</code></pre></section>

### Property Change Notifications

 You can define methods invoked when properties are changed. These methods should meet the following requirements:

- Their names follow the **On[PropertyName]Changed** and **On[PropertyName]Changing** pattern.
- They return **void**.
- They have no parameters or a parameter of the same type as the property.

- Base View Model

<section id="tabpanel_L1mgNjEKQN-22_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel(ImplementINotifyPropertyChanging = true)]
partial class ViewModel {
    [GenerateProperty]
    string username;

    // void OnUsernameChanged() { }
    void OnUsernameChanged(string oldUsername) {
        //...
    }
    // void OnUsernameChanging() { }
    void OnUsernameChanging(string newUsername) {
        //...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-23_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[13],[14],[17]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged, INotifyPropertyChanging {
    public event PropertyChangedEventHandler? PropertyChanged;
    public event PropertyChangingEventHandler? PropertyChanging;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);
    protected void RaisePropertyChanging(PropertyChangingEventArgs e) =&gt; PropertyChanging?.Invoke(this, e);

    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            RaisePropertyChanging(UsernameChangingEventArgs);
            OnUsernameChanging(value);
            var oldValue = username;
            username = value;
            RaisePropertyChanged(UsernameChangedEventArgs);
            OnUsernameChanged(oldValue);
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
    static PropertyChangingEventArgs UsernameChangingEventArgs = new PropertyChangingEventArgs(nameof(Username));
}
</code></pre></section>

If you want to specify a custom name, specify the **OnChangedMethod** or **OnChangingMethod** attribute property as follows:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-24_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[3],[6]]" class="lang-csharp">[GenerateViewModel]
    public partial class ViewModel {
        [GenerateProperty(OnChangedMethod = nameof(CustomName))]
        string username;

        void CustomName() { }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-25_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[12]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    public string? Username {
        get =&gt; username;
        set {
            if(EqualityComparer&lt;string?&gt;.Default.Equals(username, value)) return;
            username = value;
            RaisePropertyChanged(UserNameChangedEventArgs);
            CustomName();
        }
    }

    static PropertyChangedEventArgs UsernameChangedEventArgs = new PropertyChangedEventArgs(nameof(Username));
}
</code></pre></section>

## Turn Methods into Commands

To generate a [Command](/WPF/17441/mvvm-framework/commands) in your View Model, create a method in a base View Model and add the **GenerateCommand** attribute. The method should return **void** if you create [DelegateCommands](/WPF/17353/mvvm-framework/commands/delegate-commands).

- Base View Model

<section id="tabpanel_L1mgNjEKQN-26_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
public partial class ViewModel {
    [GenerateCommand]
    void Save() {
        //...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-27_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    DelegateCommand? saveCommand;
    public DelegateCommand SaveCommand {
        get =&gt; saveCommand ??= new DelegateCommand(Save, null, true);
    }
}
</code></pre></section>

Create a **CanExecute** method if necessary. This method name should complete the **Can[ActionName]** pattern and have the same parameters as the **Action** method. If you require a custom name, specify the **CanExecuteMethod** attribute property. 

If the source generator cannot find a method that matches the description, it passes **null** as the Command constructor’s **canExecuteMethod** parameter. 

- Base View Model

<section id="tabpanel_L1mgNjEKQN-28_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[7]]" class="lang-csharp">[GenerateViewModel]
public partial class ViewModel {
    [GenerateCommand]
    void Login(string parameter) {
        //...
    }
    bool CanLogin(string parameter) {
        //...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-29_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[8]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    DelegateCommand? loginCommand;
    public DelegateCommand LoginCommand {
        get =&gt; loginCommand ??= new DelegateCommand(Login, CanLogin, true);
    }
}
</code></pre></section>

Use attribute properties to specify Command constructor parameters. The code sample below specifies a custom name for the Command and sets the **UseCommandManager** parameter to **false**. If you disable **UseCommandManager**, add the **RaiseCanExecuteChanged** method to the base View Model as follows:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-30_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[3],[10]]" class="lang-csharp">[GenerateViewModel]
public partial class ViewModel {
    [GenerateCommand(UseCommandManager = false, Name = &quot;CustomName&quot;)]
    void Show() {
        //...
    }
    bool CanShow() {
        //...
    }
    public void UpdateShowCommand() =&gt; CustomName.RaiseCanExecuteChanged();
} 
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-31_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[8]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    DelegateCommand? customName;
    public DelegateCommand CustomName {
        get =&gt; customName ??= new DelegateCommand(Show, CanShow, false);
    }
}
</code></pre></section>

### Asynchronous Commands

Declare a method that returns a **Task** to create an [Asynchronous Command](/WPF/17354/mvvm-framework/commands/asynchronous-commands). Apply the **GenerateCommand** attribute.

- Base View Model

<section id="tabpanel_L1mgNjEKQN-32_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
partial class ViewModel {
    [GenerateCommand]
    async Task CalculateAsync() {
        //...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-33_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    AsyncCommand? calculateAsyncCommand;
    public AsyncCommand CalculateAsyncCommand {
        get =&gt; calculateAsyncCommand ??= new AsyncCommand(CalculateAsync, null, false, true);
    }
}
</code></pre></section>

Use attribute properties to specify Command constructor parameters. The code sample below sets the **AllowMultipleExecution** parameter to **true**.

- Base View Model

<section id="tabpanel_L1mgNjEKQN-34_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
partial class ViewModel {
    [GenerateCommand (AllowMultipleExecution = true)]
    async Task CalculateAsync() {
        //...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-35_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[8]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    public event PropertyChangedEventHandler? PropertyChanged;

    protected void RaisePropertyChanged(PropertyChangedEventArgs e) =&gt; PropertyChanged?.Invoke(this, e);

    AsyncCommand? calculateAsyncCommand;
    public AsyncCommand CalculateAsyncCommand {
        get =&gt; calculateAsyncCommand ??= new AsyncCommand(CalculateAsync, null, true, true);
    }
}
</code></pre></section>

## Add XML Comments

You can add XML comments to a field and method. The generated property or command copies these comments. 
The following members are not supported:

- PropertyChanged events
- PropertyChanging events
- RaisePropertyChanged methods
- RaisePropertyChanging methods
- ParentViewModels
- ServiceContainers

If you want to add comments to these members, declare them in a base View Model.

## Add Additional Attributes

You can apply additional attributes to fields and methods. Generated properties and commands copy them. If you want to apply an attribute to a command, do not restrict attribute usage. Alternatively, you can specify your attribute as follows:

```
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property)]
public sealed class AttributeClassName : Attribute {
    // ...
}
```

You can also inherit your attribute class from another class. The child class copies attribute usage from the parent class if [AttributeUsageAttribute.Inherited](https://learn.microsoft.com/dotnet/api/system.attributeusageattribute.inherited#system-attributeusageattribute-inherited) is set to **true**.

## Third-party Library Support

The View Model code generator supports third-party libraries. To use a third-party library, apply attributes defined in the corresponding namespace to a base View Model class. You can refer only to one library within your class. 

### Prism Library

Install the [Prism.Wpf](https://www.nuget.org/packages/Prism.Wpf/) NuGet package to use the [Prism Library](https://prismlibrary.com).

Declare a namespace as follows to access attributes:

 `using DevExpress.Mvvm.CodeGenerators.Prism;`

- GenerateViewModel

    - Applies to a class. Indicates that the source generator should process this class and produce View Model boilerplate code.

| Property | Type | Description |
| --- | --- | --- |
| ImplementINotifyPropertyChanging | bool | Implements [INotifyPropertyChanging](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanging). |
| ImplementIActiveAware | bool | Implements **IActiveAware** that notifies you when the View becomes active or inactive. |

- GenerateProperty

    - Applies to a field. The source generator produces boilerplate code for the property getter and setter based on the field declaration.

| Property | Type | Description |
| --- | --- | --- |
| IsVirtual | bool | Assigns a virtual modifier to the property. |
| OnChangedMethod | string? | Specifies the name of the method invoked after the property value is changed. If the property is not specified, the method’s name should follow the **On[PropertyName]Changed** pattern. |
| OnChangingMethod | string? | Specifies the name of the method invoked when the property value is changing.  If the property is not specified, the method’s name should follow the **On[PropertyName]Changing**  pattern. |
| SetterAccessModifier | AccessModifier | Specifies an access modifier for a set accessor. The default value is the same as a property’s modifier. Available values: *Public*, *Private*, *Protected*, *Internal*, *ProtectedInternal*. |

- GenerateCommand

    - Applies to a method. The source generator produces boilerplate code for a Command based on this method. 

| Property | Type | Description |
| --- | --- | --- |
| ObservesCanExecuteProperty | string? | Specifies the [ObservesCanExecute](https://docs.prismlibrary.com/docs/9.0/) method for the supplied property. This method listens to property changes and uses the property as the **CanExecute** delegate. |
| ObservesProperties | string[]? | Specifies the [ObservesProperty](https://docs.prismlibrary.com/docs/9.0/) methods for all supplied properties. Each method calls the **CanExecute** method when the corresponding property value changes. |
| CanExecuteMethod | string? | Specifies a custom **CanExecute** method name. If the property is not specified, the method’s name should follow the **Can[ActionName]** pattern. |
| Name | string? | Specifies a custom **Command** name. The default value is **[ActionName]Command**. |

#### Asynchronous Commands

Declare a method that returns a **Task** to create an asynchronous command. Apply the **GenerateCommand** attribute.

- Base View Model

<section id="tabpanel_L1mgNjEKQN-36_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
partial class ViewModel {
    [GenerateCommand]
    public Task WithNoArg() =&gt; Task.CompletedTask;

    [GenerateCommand]
    public Task WithArg(int? arg) =&gt; Task.CompletedTask;
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-37_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    DelegateCommand? withNoArgCommand;
    public DelegateCommand WithNoArgCommand =&gt; withNoArgCommand ??= new DelegateCommand(async () =&gt; await WithNoArg());

    DelegateCommand&lt;int?&gt;? withArgCommand;
    public DelegateCommand&lt;int?&gt; WithArgCommand =&gt; withArgCommand ??= new DelegateCommand&lt;int?&gt;(async (arg) =&gt; await WithArg(arg));
}
</code></pre></section>

#### IActiveAware Implementation Notes

You can define the method that is invoked when the **IsActive** property is changed. This method should meet the following requirements:

- The method has the **OnIsActiveChanged** name.
- It returns **void**.
- It has no parameters.

The generator analyzes the implementation and searches **OnIsActiveChanged()** to raise it from the generated View Model:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-38_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel(ImplementIActiveAware = true)]
partial class ViewModel {
    // ...
    void OnIsActiveChanged() {
        // ...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-39_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[8]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged, IActiveAware {
    // ...
    bool isActive;
    public bool IsActive {
        get =&gt; isActive;
        set {
            isActive = value;
            OnIsActiveChanged();
            IsActiveChanged?.Invoke(this, EventArgs.Empty);
        }
    }
    public event EventHandler? IsActiveChanged;
    // ...
}
</code></pre></section>

### MVVM Light Toolkit

Tip

If you work with the [MVVM Toolkit](https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction) (the official replacement for the MVVM Light Toolkit), you can use its built-in source generators that were shipped in v8.0.0: [MVVM Toolkit source generators](https://devblogs.microsoft.com/dotnet/announcing-the-dotnet-community-toolkit-800/).

Install the [MvvmLight](https://www.nuget.org/packages/MvvmLight) NuGet package to use the [MVVM Light Toolkit](https://github.com/lbugnion/mvvmlight).

Declare a namespace as follows to access attributes:

 `using DevExpress.Mvvm.CodeGenerators.MvvmLight;`

- GenerateViewModel

    - Applies to a class. Indicates that the source generator should process this class and produce View Model boilerplate code.

| Property | Type | Description |
| --- | --- | --- |
| ImplementINotifyPropertyChanging | bool | Implements [INotifyPropertyChanging](https://learn.microsoft.com/dotnet/api/system.componentmodel.inotifypropertychanging). |
| ImplementICleanup | bool | Implements the **ICleanup** interface that allows you to clean your View Model (for example, flush its state to persistent storage, close the stream). |

- GenerateProperty

    - Applies to a field. The source generator produces boilerplate code for the property getter and setter based on the field declaration.

| Property | Type | Description |
| --- | --- | --- |
| IsVirtual | bool | Assigns a virtual modifier to the property. |
| OnChangedMethod | string? | Specifies the name of the method invoked after the property value is changed. If the property is not specified, the method’s name should follow the **On[PropertyName]Changed** pattern. |
| OnChangingMethod | string? | Specifies the name of the method invoked when the property value is changing.  If the property is not specified, the method’s name should follow the **On[PropertyName]Changing**  pattern. |
| SetterAccessModifier | AccessModifier | Specifies an access modifier for a set accessor. The default value is the same as a property’s modifier. Available values: *Public*, *Private*, *Protected*, *Internal*, *ProtectedInternal*. |

- GenerateCommand

    - Applies to a method. The source generator produces boilerplate code for a Command based on this method. 

| Property | Type | Description |
| --- | --- | --- |
| CanExecuteMethod | string? | Specifies a custom **CanExecute** method name. If the property is not specified, the method’s name should follow the **Can[ActionName]** pattern. |
| Name | string? | Specifies a custom **Command** name. The default value is **[ActionName]Command**. |

#### Asynchronous Commands

Declare a method that returns a **Task** to create an asynchronous command. Apply the **GenerateCommand** attribute.

- Base View Model

<section id="tabpanel_L1mgNjEKQN-40_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel]
partial class ViewModel {
    [GenerateCommand]
    public Task WithNoArg() =&gt; Task.CompletedTask;

    [GenerateCommand]
    public Task WithArg(int arg) =&gt; Task.CompletedTask;
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-41_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged {
    RelayCommand? withNoArgCommand;
    public RelayCommand WithNoArgCommand =&gt; withNoArgCommand ??= new RelayCommand(async () =&gt; await WithNoArg(), null);

    RelayCommand&lt;int&gt;? withArgCommand;
    public RelayCommand&lt;int&gt; WithArgCommand =&gt; withArgCommand ??= new RelayCommand&lt;int&gt;(async (arg) =&gt; await WithArg(arg), null);
}
</code></pre></section>

#### ICleanup Implementation Notes

You can define the method that is invoked when the View Model is cleaned up. This method should meet the following requirements:

- The method has the **OnCleanup** name.
- It returns **void**.
- It has no parameters.

The generator analyzes the implementation and searches **OnCleanup()** to raise it from the generated View Model:

- Base View Model

<section id="tabpanel_L1mgNjEKQN-42_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" class="lang-csharp">[GenerateViewModel(ImplementICleanup = true)]
partial class ViewModel {
    // ...
    void OnCleanup() {
        // ...
    }
}
</code></pre></section>

- Generated View Model

<section id="tabpanel_L1mgNjEKQN-43_tabid-csharp" role="tabpanel" data-tab="tabid-csharp">
<pre><code data-code-links="{&quot;AttributeUsage&quot;:&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#attributeusage-attribute&quot;}" data-highlight-lines="[[5]]" class="lang-csharp">partial class ViewModel : INotifyPropertyChanged, ICleanup {
    // ...
    public virtual void Cleanup() {
        MessengerInstance.Unregister(this);
        OnCleanup();
    }
    // ...
}
</code></pre></section>