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
,NotifyPropertyChangedRecipients
NotifyDataErrorInfo
ICommand
NotifyCanExecuteChangedFor
,IRelayCommand
ObservableValidator, ,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_lowerCamel
a 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.