Skip to content
NLNuvyntra Labs

Documentation

Forms

FormViewModel, FormField, dirty navigation guard, and undo / redo — Core types, no MAUI.

Forms, dirty guard, undo

FormViewModel lives in Core and does not reference MAUI. Field(name, value) creates a FormField<T>. Bind(field, propertyName, notifyCanExecute) wires the public property and CanExecute — do not write a manual PropertyChanged wrapper. Bind FormField.Error / HasError. When IDialogs is registered, leaving a dirty form confirms “Discard changes?”. Tests set DirtyNavigation = DirtyNavigationMode.SilentBlock. SubmitAsync(work) calls MarkClean() on success. Use [MustMatch(nameof(Password))] or MustMatch(password, confirm).

public sealed class ProductEditViewModel : FormViewModel
{
    private readonly FormField<string> _name;

    public ProductEditViewModel()
    {
        _name = Field("Name", "");
        Bind(_name, nameof(Name), () => SaveCommand.NotifyCanExecuteChanged());
    }

    public string Name
    {
        get => _name.Value ?? "";
        set => _name.Value = value;
    }

    private Task<Outcome> SaveAsync(CancellationToken ct) =>
        SubmitAsync(token => _catalog.SaveAsync(Name, token), cancellationToken: ct);
}