Sdílet prostřednictvím


Atribut ObservableProperty

Typ ObservableProperty je atribut, který umožňuje generovat pozorovatelné vlastnosti z anotovaných polí. Jejím účelem je výrazně snížit množství často používaných vlastností, které je potřeba k definování pozorovatelných vlastností.

Poznámka:

Aby bylo možné pracovat, musí být pole s poznámkami v částečné třídě s potřebnou INotifyPropertyChanged infrastrukturou. Pokud je typ vnořený, musí být všechny typy ve stromu syntaxe deklarace také opatřeny poznámkami jako částečné. Pokud to neuděláte, dojde k chybám kompilace, protože generátor nebude moci vygenerovat jinou částečnou deklaraci tohoto typu s požadovanou pozorovatelnou vlastností.

Rozhraní API platformy:ObservableProperty, NotifyPropertyChangedFor, NotifyPropertyChangedRecipientsNotifyDataErrorInfoICommandNotifyCanExecuteChangedFor, IRelayCommandObservableValidator, , PropertyChangedMessage<T>IMessenger

Jak to funguje

Atribut ObservableProperty lze použít k anotaci pole v částečném typu, například takto:

[ObservableProperty]
private string? name;

A vygeneruje pozorovatelnou vlastnost, jako je tato:

public string? Name
{
    get => name;
    set => SetProperty(ref name, value);
}

Provede to také s optimalizovanou implementací, takže konečný výsledek bude ještě rychlejší.

Poznámka:

Název vygenerované vlastnosti se vytvoří na základě názvu pole. Generátor předpokládá, že pole má název lowerCamel, _lowerCamel nebo m_lowerCamela transformuje ho tak, aby UpperCamel postupoval podle správných konvencí pojmenování .NET. Výsledná vlastnost bude mít vždy veřejné přístupové objekty, ale pole lze deklarovat s libovolnou viditelností (private doporučuje se).

Spuštění kódu při změnách

Vygenerovaný kód je ve skutečnosti o něco složitější, a důvodem je to, že také zveřejňuje některé metody, které můžete implementovat pro připojení k logice oznámení, a spuštění další logiky, když se vlastnost chystá aktualizovat a hned po její aktualizaci, v případě potřeby. To znamená, že vygenerovaný kód je ve skutečnosti podobný tomuto:

public string? Name
{
    get => name;
    set
    {
        if (!EqualityComparer<string?>.Default.Equals(name, value))
        {
            string? oldValue = name;
            OnNameChanging(value);
            OnNameChanging(oldValue, value);
            OnPropertyChanging();
            name = value;
            OnNameChanged(value);
            OnNameChanged(oldValue, value);
            OnPropertyChanged();
        }
    }
}

partial void OnNameChanging(string? value);
partial void OnNameChanged(string? value);

partial void OnNameChanging(string? oldValue, string? newValue);
partial void OnNameChanged(string? oldValue, string? newValue);

To vám umožní implementovat jakoukoli z těchto metod pro vložení dalšího kódu. První dva jsou užitečné vždy, když chcete spustit nějakou logiku, která musí odkazovat pouze na novou hodnotu, na kterou byla vlastnost nastavena. Další dvě jsou užitečné, kdykoli máte složitější logiku, která také musí aktualizovat nějaký stav na staré i nové hodnotě, která je nastavena.

Tady je příklad použití prvních dvou přetížení:

[ObservableProperty]
private string? name;

partial void OnNameChanging(string? value)
{
    Console.WriteLine($"Name is about to change to {value}");
}

partial void OnNameChanged(string? value)
{
    Console.WriteLine($"Name has changed to {value}");
}

Tady je příklad, jak se dají použít další dvě přetížení:

[ObservableProperty]
private ChildViewModel? selectedItem;

partial void OnSelectedItemChanging(ChildViewModel? oldValue, ChildViewModel? newValue)
{
    if (oldValue is not null)
    {
        oldValue.IsSelected = true;
    }

    if (newValue is not null)
    {
        newValue.IsSelected = true;
    }
}

Můžete implementovat pouze libovolný počet metod mezi dostupnými nebo žádnými z nich. Pokud nejsou implementované (nebo pokud je pouze jedno), kompilátor pouze odebere celá volání, takže v případech, kdy se tato další funkce nevyžaduje, nebude vůbec dosaženo výkonu.

Poznámka:

Vygenerované metody jsou částečné metody bez implementace, což znamená, že pokud se rozhodnete je implementovat, nemůžete pro ně určit explicitní přístupnost. To znamená, že implementace těchto metod by také měly být deklarovány jako pouze partial metody a budou mít vždy implicitně privátní přístupnost. Při pokusu o přidání explicitní přístupnosti (např. přidání public nebo private) dojde k chybě, protože v jazyce C# to není povolené.

Upozorňování závislých vlastností

Představte si, že jste měli FullName vlastnost, kterou jste chtěli při každé Name změně upozornit. Můžete to udělat pomocí atributu NotifyPropertyChangedFor , například takto:

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string? name;

Výsledkem bude vygenerovaná vlastnost ekvivalentní tomuto:

public string? Name
{
    get => name;
    set
    {
        if (SetProperty(ref name, value))
        {
            OnPropertyChanged("FullName");
        }
    }
}

Upozorňování závislých příkazů

Představte si, že jste měli příkaz, jehož stav provádění závisí na hodnotě této vlastnosti. To znamená, že kdykoli se vlastnost změnila, stav spuštění příkazu by se měl zneplatnit a znovu vypočítat. Jinými slovy, ICommand.CanExecuteChanged měla by být znovu vyvolána. Toho dosáhnete pomocí atributu NotifyCanExecuteChangedFor :

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(MyCommand))]
private string? name;

Výsledkem bude vygenerovaná vlastnost ekvivalentní tomuto:

public string? Name
{
    get => name;
    set
    {
        if (SetProperty(ref name, value))
        {
            MyCommand.NotifyCanExecuteChanged();
        }
    }
}

Aby to fungovalo, musí být cílový příkaz nějakou IRelayCommand vlastností.

Vyžádání ověření vlastnosti

Pokud je vlastnost deklarována v typu, který dědí z ObservableValidator, je také možné ji opatřit poznámkami s libovolnými ověřovacími atributy a potom požádat vygenerovaný setter o aktivaci ověření této vlastnosti. Toho lze dosáhnout pomocí atributu NotifyDataErrorInfo :

[ObservableProperty]
[NotifyDataErrorInfo]
[Required]
[MinLength(2)] // Any other validation attributes too...
private string? name;

Výsledkem bude vygenerování následující vlastnosti:

public string? Name
{
    get => name;
    set
    {
        if (SetProperty(ref name, value))
        {
            ValidateProperty(value, "Value2");
        }
    }
}

Toto vygenerované ValidateProperty volání pak ověří vlastnost a aktualizuje stav objektu ObservableValidator , aby na ni komponenty uživatelského rozhraní mohly reagovat a odpovídajícím způsobem zobrazit všechny chyby ověření.

Poznámka:

Záměrně se předávají do vygenerované vlastnosti pouze atributy pole, které dědí z ValidationAttribute . To se provádí speciálně pro podporu scénářů ověřování dat. Všechny ostatní atributy pole budou ignorovány, takže v současné době není možné přidat do pole další vlastní atributy a použít je také na vygenerovanou vlastnost. Pokud je to požadováno (např. k řízení serializace), zvažte místo toho použití tradiční ruční vlastnosti.

Odesílání zpráv s oznámením

Pokud je vlastnost deklarována v typu, který dědí z ObservableRecipient, můžete pomocí NotifyPropertyChangedRecipients atributu dát generátoru pokyn, aby také vložil kód pro odeslání zprávy změněné vlastnosti pro změnu vlastnosti. To umožní registrovaným příjemcům dynamicky reagovat na změnu. To znamená, že zvažte tento kód:

[ObservableProperty]
[NotifyPropertyChangedRecipients]
private string? name;

Výsledkem bude vygenerování následující vlastnosti:

public string? Name
{
    get => name;
    set
    {
        string? oldValue = name;

        if (SetProperty(ref name, value))
        {
            Broadcast(oldValue, value);
        }
    }
}

Tento vygenerovaný Broadcast hovor pak odešle novou PropertyChangedMessage<T> instanci, IMessenger která se používá v aktuálním modelu viewmodel, všem registrovaným odběratelům.

Přidání vlastních atributů

V některýchpřípadechch Abyste toho dosáhli, můžete jednoduše použít [property: ] cíl v seznamech atributů nad anotovanými poli a sada MVVM Toolkit tyto atributy automaticky předá vygenerovaným vlastnostem.

Představte si například pole podobné tomuto:

[ObservableProperty]
[property: JsonRequired]
[property: JsonPropertyName("name")]
private string? username;

Tím se Username vygeneruje vlastnost s těmito dvěma [JsonRequired] atributy.[JsonPropertyName("name")] Můžete použít libovolný počet seznamů atributů, které cílí na vlastnost, a všechny z nich budou předány do vygenerovaných vlastností.

Příklady

  • Podívejte se na ukázkovou aplikaci (pro více architektur uživatelského rozhraní) a podívejte se na sadu nástrojů MVVM v akci.
  • Další příklady najdete také v testech jednotek.