Sdílet prostřednictvím


ObservableObject

Je ObservableObject základní třídou pro objekty, které jsou pozorovatelné implementací INotifyPropertyChanged a INotifyPropertyChanging rozhraní. Dá se použít jako výchozí bod pro všechny druhy objektů, které potřebují podporovat oznámení o změnách vlastností.

Rozhraní API platformy: ObservableObject, TaskNotifierTaskNotifier<T>

Jak to funguje

ObservableObject má následující hlavní funkce:

  • Poskytuje základní implementaci pro INotifyPropertyChanged a INotifyPropertyChangingzveřejnění PropertyChanged událostí a PropertyChanging událostí.
  • Poskytuje řadu SetProperty metod, které lze použít k snadnému nastavení hodnot vlastností z typů dědění z ObservableObjecta k automatickému vyvolání příslušných událostí.
  • Poskytuje metodu SetPropertyAndNotifyOnCompletion , která je analogická SetProperty , ale s možností nastavit Task vlastnosti a vyvolat události oznámení automaticky při dokončení přiřazených úkolů.
  • Zveřejňuje OnPropertyChanged metody a OnPropertyChanging metody, které je možné přepsat v odvozených typech a přizpůsobit způsob vyvolání událostí oznámení.

Jednoduchá vlastnost

Tady je příklad implementace podpory oznámení pro vlastní vlastnost:

public class User : ObservableObject
{
    private string name;

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

Zadaná SetProperty<T>(ref T, T, string) metoda zkontroluje aktuální hodnotu vlastnosti a aktualizuje ji, pokud se liší, a pak také vyvolá příslušné události automaticky. Název vlastnosti se automaticky zaznamenává pomocí atributu [CallerMemberName] , takže není nutné ručně určit, která vlastnost se aktualizuje.

Zabalení nepozorovatelného modelu

Běžným scénářem, například při práci s databázovými položkami, je vytvoření obtékání "bindable" modelu, který předává vlastnosti databázového modelu a v případě potřeby vyvolá oznámení o změně vlastnosti. To je potřeba také v případě, že chcete do modelů vložit podporu oznámení, která rozhraní neimplementují INotifyPropertyChanged . ObservableObject poskytuje vyhrazenou metodu, která usnadňuje tento proces. V následujícím příkladu User je model přímo mapující databázovou tabulku bez dědění z ObservableObject:

public class ObservableUser : ObservableObject
{
    private readonly User user;

    public ObservableUser(User user) => this.user = user;

    public string Name
    {
        get => user.Name;
        set => SetProperty(user.Name, value, user, (u, n) => u.Name = n);
    }
}

V tomto případě používáme SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) přetížení. Podpis je o něco složitější než předchozí – to je nezbytné k tomu, aby byl kód stále velmi efektivní, i když nemáme přístup k záložnímu poli, jako je v předchozím scénáři. Jednotlivé části tohoto podpisu metody můžeme podrobně projít, abychom porozuměli roli různých komponent:

  • TModel je argument typu označující typ modelu, který zabalíme. V tomto případě to bude naše User třída. Všimněte si, že toto explicitní zadání nepotřebujeme – kompilátor jazyka C# to automaticky odvodí tím, jak metodu SetProperty vyvoláváme.
  • T je typ vlastnosti, kterou chceme nastavit. TModelPodobně jako , to je odvozeno automaticky.
  • T oldValue je první parametr a v tomto případě používáme user.Name k předání aktuální hodnoty této vlastnosti, kterou zabalíme.
  • T newValue je nová hodnota nastavená na vlastnost a zde předáváme value, což je vstupní hodnota v rámci setter vlastnosti.
  • TModel model je cílový model, který zabalíme, v tomto případě předáváme instanci uloženou user v poli.
  • Action<TModel, T> callback je funkce, která se vyvolá, pokud se nová hodnota vlastnosti liší od aktuální hodnoty a vlastnost musí být nastavena. To provede tato funkce zpětného volání, která přijímá jako vstup cílový model a novou hodnotu vlastnosti, která se má nastavit. V tomto případě pouze přiřazujeme vstupní hodnotu (kterou jsme volalin) vlastnosti Name (tím).u.Name = n Je důležité se zde vyhnout zachycení hodnot z aktuálního oboru a pracovat pouze s hodnotami zadanými jako vstup pro zpětné volání, protože to umožňuje kompilátoru jazyka C# ukládat funkci zpětného volání do mezipaměti a provádět řadu vylepšení výkonu. Důvodem je to, že k poli tady value nebo parametru v setteru nemáme jen přímý přístupuser, ale místo toho používáme jenom vstupní parametry pro výraz lambda.

Metoda SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) vytváří tyto vlastnosti obtékání velmi jednoduché, protože se postará o načtení a nastavení cílových vlastností při poskytování extrémně kompaktního rozhraní API.

Poznámka:

Ve srovnání s implementací této metody pomocí výrazů LINQ, konkrétně prostřednictvím parametru typu Expression<Func<T>> místo parametrů stavu a zpětného volání, zlepšení výkonu, které lze dosáhnout tímto způsobem, jsou opravdu významné. Konkrétně je tato verze ~200x rychlejší než ta, která používá výrazy LINQ, a neuvádí vůbec žádné přidělení paměti.

Zpracování Task<T> vlastností

Je-li vlastnost Task také nutné vyvolat událost oznámení po dokončení úkolu, aby byly vazby aktualizovány ve správný čas. Např. zobrazení indikátoru načítání nebo jiné informace o stavu operace reprezentované úkolem. ObservableObject má rozhraní API pro tento scénář:

public class MyModel : ObservableObject
{
    private TaskNotifier<int>? requestTask;

    public Task<int>? RequestTask
    {
        get => requestTask;
        set => SetPropertyAndNotifyOnCompletion(ref requestTask, value);
    }

    public void RequestValue()
    {
        RequestTask = WebService.LoadMyValueAsync();
    }
}

SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>, Task<T>, string) Zde se metoda postará o aktualizaci cílového pole, monitorování nového úkolu, pokud je k dispozici, a vyvolání události oznámení po dokončení úkolu. Tímto způsobem je možné vytvořit vazbu na vlastnost úkolu a upozornit na změny stavu. Jedná se TaskNotifier<T> o speciální typ vystavený ObservableObject tím, že zabalí cílovou Task<T> instanci a povolí potřebnou logiku oznámení pro tuto metodu. Typ TaskNotifier je také k dispozici přímo, pokud máte pouze obecný Task .

Poznámka:

Metoda SetPropertyAndNotifyOnCompletion je určena k nahrazení použití NotifyTaskCompletion<T> typu z Microsoft.Toolkit balíčku. Pokud byl tento typ použit, může být nahrazen pouze vnitřní Task (nebo Task<TResult>) vlastnost, a pak lze metodu SetPropertyAndNotifyOnCompletion použít k nastavení jeho hodnoty a vyvolat změny oznámení. Všechny vlastnosti vystavené typem NotifyTaskCompletion<T> jsou k dispozici přímo na Task instancích.

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.