69 lines
1.7 KiB
Markdown
69 lines
1.7 KiB
Markdown
# ViewModels & Commands
|
|
|
|
In a Zafiro-based application, ViewModels should be functional, reactive, and resilient.
|
|
|
|
## Reactive ViewModels
|
|
|
|
Use `ReactiveObject` as the base class. Properties should be defined using the `[Reactive]` attribute (from ReactiveUI.SourceGenerators) for brevity.
|
|
|
|
```csharp
|
|
public partial class MyViewModel : ReactiveObject
|
|
{
|
|
[Reactive] private string name;
|
|
[Reactive] private bool isBusy;
|
|
}
|
|
```
|
|
|
|
### Observation and Transformation
|
|
|
|
Use `WhenAnyValue` to react to property changes:
|
|
|
|
```csharp
|
|
this.WhenAnyValue(x => x.Name)
|
|
.Select(name => !string.IsNullOrEmpty(name))
|
|
.ToPropertyEx(this, x => x.CanSubmit);
|
|
```
|
|
|
|
## Enhanced Commands
|
|
|
|
Zafiro uses `IEnhancedCommand`, which extends `ICommand` and `IReactiveCommand` with additional metadata like `Name` and `Text`.
|
|
|
|
### Creating a Command
|
|
|
|
Use `ReactiveCommand.Create` or `ReactiveCommand.CreateFromTask` and then `Enhance()` it.
|
|
|
|
```csharp
|
|
public IEnhancedCommand Submit { get; }
|
|
|
|
public MyViewModel()
|
|
{
|
|
Submit = ReactiveCommand.CreateFromTask(OnSubmit, canSubmit)
|
|
.Enhance(text: "Submit Data", name: "SubmitCommand");
|
|
}
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
Use `HandleErrorsWith` to automatically channel command errors to the `NotificationService`.
|
|
|
|
```csharp
|
|
Submit.HandleErrorsWith(uiServices.NotificationService, "Submission Failed")
|
|
.DisposeWith(disposable);
|
|
```
|
|
|
|
## Disposables
|
|
|
|
Always use a `CompositeDisposable` to manage subscriptions and command lifetimes.
|
|
|
|
```csharp
|
|
public class MyViewModel : ReactiveObject, IDisposable
|
|
{
|
|
private readonly CompositeDisposable disposables = new();
|
|
|
|
public void Dispose() => disposables.Dispose();
|
|
}
|
|
```
|
|
|
|
> [!TIP]
|
|
> Use `.DisposeWith(disposables)` on any observable subscription or command to ensure proper cleanup.
|