Files
antigravity-skills-reference/skills/avalonia-zafiro-development/avalonia-reactive-rules.md

50 lines
1.9 KiB
Markdown

# Avalonia, Zafiro & Reactive Rules
## Avalonia UI Rules
- **Strict Avalonia**: Never use `System.Drawing`; always use Avalonia types.
- **Pure ViewModels**: ViewModels must **never** reference Avalonia types.
- **Bindings Over Code-Behind**: Logic should be driven by bindings.
- **DataTemplates**: Prefer explicit `DataTemplate`s and typed `DataContext`s.
- **VisualStates**: Avoid using `VisualStates` unless absolutely required.
## Zafiro Guidelines
- **Prefer Abstractions**: Always look for existing Zafiro helpers, extension methods, and abstractions before re-implementing logic.
- **Validation**: Use Zafiro's `ValidationRule` and validation extensions instead of ad-hoc reactive logic.
## DynamicData & Reactive Rules
### The Mandatory Approach
- **Operator Preference**: Always prefer **DynamicData** operators (`Connect`, `Filter`, `Transform`, `Sort`, `Bind`, `DisposeMany`) over plain Rx operators when working with collections.
- **Readable Pipelines**: Build and maintain pipelines as a single, readable chain.
- **Lifecycle**: Use `DisposeWith` for lifecycle management.
- **Minimal Subscriptions**: Subscriptions should be minimal, centralized, and strictly for side-effects.
### Forbidden Anti-Patterns
- **Ad-hoc Sources**: Do NOT create new `SourceList` / `SourceCache` on the fly for local problems.
- **Logic in Subscribe**: Do NOT place business logic inside `Subscribe`.
- **Operator Mismatch**: Do NOT use `System.Reactive` operators if a DynamicData equivalent exists.
### Canonical Patterns
**Validation of Dynamic Collections:**
```csharp
this.ValidationRule(
StagesSource
.Connect()
.FilterOnObservable(stage => stage.IsValid)
.IsEmpty(),
b => !b,
_ => "Stages are not valid")
.DisposeWith(Disposables);
```
**Filtering Nulls:**
Use `WhereNotNull()` in reactive pipelines.
```csharp
this.WhenAnyValue(x => x.DurationPreset).WhereNotNull()
```