Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Vlastnost, která může být účinně vázána na ovládací prvek XAML je známá jako pozorovatelná vlastnost. Tato myšlenka je založená na vzoru návrhu softwaru známém jako vzor pozorovatele. Toto téma ukazuje, jak implementovat pozorovatelné vlastnosti v jazyce C++/WinRT a jak s nimi svázat ovládací prvky XAML (informace o pozadí najdete v tématu Datová vazba).
Důležité
Základní koncepty a termíny, které podporují pochopení toho, jak využívat a vytvářet třídy modulu runtime pomocí C++/WinRT, najdete v tématu Využívání rozhraní API s rozhraními C++/WinRT a Author API s C++/WinRT.
Co pozorovatelné znamená pro vlastnost?
Řekněme, že třída modulu runtime s názvem BookSku má vlastnost s názvem Title. Pokud BookSku vyvolá INotifyPropertyChanged::P ropertyChanged událost při každé změně hodnoty Title , znamená to, že Title je pozorovatelná vlastnost. Jedná se o chování BookSku (vyvolání nebo nezvyšování události), které určuje, která z vlastností, pokud existuje, jsou pozorovatelné.
Textový prvek XAML nebo ovládací prvek může tyto události svázat a zpracovat. Takový prvek nebo ovládací prvek zpracovává událost načtením aktualizovaných hodnot a následnou aktualizací, aby se zobrazila nová hodnota.
Note
Informace o instalaci a použití rozšíření C++/WinRT Visual Studio (VSIX) a balíčku NuGet (které společně poskytují podporu šablony projektu a sestavení) najdete v tématu Visual Studio podpora pro C++/WinRT.
Vytvořit prázdnou aplikaci (Knihkupectví)
Začněte vytvořením nového project v Microsoft Visual Studio. Vytvořte prázdnou aplikaci, zabalenou (WinUI 3 v desktopové verzi) pro projekt C++ a pojmenujte ji Bookstore. Ujistěte se, že je zaškrtnuto políčko Umístit řešení a projekt do stejného adresáře . Cilte na nejnovější běžně dostupnou verzi sady Windows SDK (tedy ne ve verzi Preview).
Vytvoříme novou třídu, která bude představovat knihu, která má pozorovatelnou vlastnost názvu. Třídu vytvoříme a spotřebováváme ve stejné kompilační jednotce. Chceme ale mít možnost vytvořit vazbu s touto třídou z XAML a z tohoto důvodu to bude třída modulu runtime. A k jeho vytvoření a využití použijeme C++/WinRT.
Prvním krokem při vytváření nové třídy modulu runtime je přidání nové položky souboru Midl (.idl) do projektu. Pojmenujte novou položku BookSku.idl. Odstraňte výchozí obsah BookSku.idl a vložte tuto deklaraci runtime třídy.
// BookSku.idl
namespace Bookstore
{
runtimeclass BookSku : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
BookSku(String title);
String Title;
}
}
Note
Třídy modelu zobrazení – ve skutečnosti všechny třídy modulu runtime, které deklarujete v aplikaci – nemusí odvozovat ze základní třídy. Třída BookSku deklarovaná výše je příkladem toho. Implementuje rozhraní, ale neodvozuje z žádné základní třídy.
Každá třída modulu runtime, kterou deklarujete v aplikaci, která je odvozena ze základní třídy, se označuje jako kompozovatelná třída. A kolem tříd, které lze skládat, existují omezení. Aby aplikace prošla testy aplikace pro Windows Certification Kit, které Visual Studio a Microsoft Store používají k ověřování odesílaných aplikací (a tedy aby ji bylo možné úspěšně přijmout do Microsoft Storu), musí kompozitní třída v konečném důsledku dědit ze základní třídy systému Windows. To znamená, že třída na samém kořeni hierarchie dědičnosti musí být typem pocházejícím z oborů názvů Windows.* nebo Microsoft.*. Pokud skutečně potřebujete odvodit třídu za běhu ze základní třídy – například k implementaci třídy BindableBase, od které budou odvozeny všechny vaše modely zobrazení – můžete ji odvodit z Microsoft.UI.Xaml.DependencyObject.
Model zobrazení je abstrakcí zobrazení, takže je vázán přímo k zobrazení (kód XAML). Datový model je abstrakce dat a využívá se pouze z vašich modelů zobrazení a není vázán přímo na XAML. Datové modely tedy můžete deklarovat ne jako třídy modulu runtime, ale jako struktury nebo třídy jazyka C++. Nemusí být deklarovány v MIDL a můžete použít libovolnou hierarchii dědičnosti, kterou chcete.
Uložte soubor a sestavte projekt. Sestavení se zatím nepodaří (zcela) dokončit, ale provede pro nás několik nezbytných kroků. Konkrétně se během procesu midl.exe sestavení nástroj spustí a vytvoří soubor metadat prostředí Windows Runtime, který popisuje třídu runtime (soubor je umístěn na disku na \Bookstore\Debug\Bookstore\Unmerged\BookSku.winmdadrese ). Pak se cppwinrt.exe nástroj spustí a vygeneruje soubory zdrojového kódu, které vám pomůžou s vytvářením a využíváním třídy runtime. Tyto soubory zahrnují zástupné procedury, které vám pomůžou začít s implementací třídy runtime BookSku , kterou jste deklarovali ve svém IDL. Za chvíli je najdeme na disku, ale ty stuby jsou \Bookstore\Bookstore\Generated Files\sources\BookSku.h a BookSku.cpp.
Teď tedy klikněte pravým tlačítkem myši na uzel projektu v Visual Studio a v Průzkumníku souborů klikněte na Otevřít složku. Tím se otevře složka projektu v Průzkumníku souborů. Teď byste se měli podívat na obsah \Bookstore\Bookstore\ složky. Odtud přejděte do složky \Generated Files\sources\ a do schránky zkopírujte soubory stub BookSku.h a BookSku.cpp. Přejděte zpět do složky projektu (\Bookstore\Bookstore\) a vložte dva soubory, které jste právě zkopírovali. Nakonec v Průzkumník řešení s vybraným uzlem projektu zkontrolujte, jestli je zapnutá možnost Show All Files. Klikněte pravým tlačítkem myši na zástupné soubory, které jste zkopírovali, a vyberte Zahrnout do projektu.
Implementujte BookSku
Teď otevřeme \Bookstore\Bookstore\BookSku.h a BookSku.cpp a implementujeme naši běhovou třídu. Nejprve uvidíte static_assert v horní části BookSku.h a BookSku.cpp, kterou budete muset odebrat.
V dalším kroku BookSku.hproveďte tyto změny.
- Ve výchozím konstruktoru změňte
= defaultna= delete. Je to proto, že nechceme výchozí konstruktor. - Přidejte soukromého člena pro uložení řetězce nadpisu. Všimněte si, že máme konstruktor, který přebírá hodnotu typu winrt::hstring. Tato hodnota je text titulku.
- Přidejte dalšího soukromého člena pro událost, kterou vyvoláme při změně názvu.
Po provedení těchto změn BookSku.h bude vypadat takto.
// BookSku.h
#pragma once
#include "BookSku.g.h"
namespace winrt::Bookstore::implementation
{
struct BookSku : BookSkuT<BookSku>
{
BookSku() = delete;
BookSku(winrt::hstring const& title);
winrt::hstring Title();
void Title(winrt::hstring const& value);
winrt::event_token PropertyChanged(Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& value);
void PropertyChanged(winrt::event_token const& token);
private:
winrt::hstring m_title;
winrt::event<Microsoft::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
};
}
namespace winrt::Bookstore::factory_implementation
{
struct BookSku : BookSkuT<BookSku, implementation::BookSku>
{
};
}
V BookSku.cpp implementujte tyto funkce takto.
// BookSku.cpp
#include "pch.h"
#include "BookSku.h"
#include "BookSku.g.cpp"
namespace winrt::Bookstore::implementation
{
BookSku::BookSku(winrt::hstring const& title) : m_title{ title }
{
}
winrt::hstring BookSku::Title()
{
return m_title;
}
void BookSku::Title(winrt::hstring const& value)
{
if (m_title != value)
{
m_title = value;
m_propertyChanged(*this, Microsoft::UI::Xaml::Data::PropertyChangedEventArgs{ L"Title" });
}
}
winrt::event_token BookSku::PropertyChanged(Microsoft::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
{
return m_propertyChanged.add(handler);
}
void BookSku::PropertyChanged(winrt::event_token const& token)
{
m_propertyChanged.remove(token);
}
}
Ve funkci Mutator Title zkontrolujeme, jestli je nastavená hodnota, která se liší od aktuální hodnoty. A pokud ano, pak aktualizujeme název a také vyvoláme INotifyPropertyChanged::P ropertyChanged událost s argumentem, který se rovná názvu vlastnosti, která se změnila. To znamená, že uživatelské rozhraní (UI) bude vědět, která hodnota vlastnosti se má znovu dotazovat.
Projekt se teď znovu sestaví, pokud si to chcete ověřit.
Deklarace a implementace BookstoreViewModel
Naše hlavní stránka XAML bude navázána na hlavní model zobrazení. Model zobrazení bude mít několik vlastností, včetně jednoho typu BookSku. V tomto kroku deklarujeme a implementujeme naši třídu modulu runtime modelu hlavního zobrazení.
Přidejte novou položku midl File (.idl) s názvem BookstoreViewModel.idl. Viz také Vyčlenění tříd modulu runtime do souborů MIDL (.idl).
// BookstoreViewModel.idl
import "BookSku.idl";
namespace Bookstore
{
runtimeclass BookstoreViewModel
{
BookstoreViewModel();
BookSku BookSku{ get; };
}
}
Uložte a sestavte (sestavení ještě nebude úplně úspěšné, ale sestavujeme to proto, abychom znovu vygenerovali soubory stub).
Zkopírujte BookstoreViewModel.h a BookstoreViewModel.cpp z Generated Files\sources této složky do složky projektu a zahrňte je do projektu. Otevřete tyto soubory (znovu odeberte static_assert ) a implementujte třídu modulu runtime, jak je znázorněno níže. Všimněte si, jak v BookstoreViewModel.h zahrnujeme BookSku.h, který deklaruje typ implementace pro BookSku (což je winrt::Bookstore::implementation::BookSku). A odstraňujeme = default z implicitního konstruktoru.
Note
V níže uvedených ukázkách kódu pro BookstoreViewModel.h a BookstoreViewModel.cpp kód znázorňuje výchozí způsob inicializace datového členu m_bookSku. Jedná se o metodu, která se vrací k prvnímu vydání C++/WinRT a je vhodné, abyste se s tímto vzorem seznámili aspoň dobře. S C++/WinRT verze 2.0 a novější je k dispozici optimalizovaná forma konstrukce, která se označuje jako jednotná konstrukce (viz Novinky a změny v C++/WinRT 2.0). Dále v tomto tématu si ukážeme příklad jednotné konstrukce.
// BookstoreViewModel.h
#pragma once
#include "BookstoreViewModel.g.h"
#include "BookSku.h"
namespace winrt::Bookstore::implementation
{
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel>
{
BookstoreViewModel();
Bookstore::BookSku BookSku();
private:
Bookstore::BookSku m_bookSku{ nullptr };
};
}
namespace winrt::Bookstore::factory_implementation
{
struct BookstoreViewModel : BookstoreViewModelT<BookstoreViewModel, implementation::BookstoreViewModel>
{
};
}
// BookstoreViewModel.cpp
#include "pch.h"
#include "BookstoreViewModel.h"
#include "BookstoreViewModel.g.cpp"
namespace winrt::Bookstore::implementation
{
BookstoreViewModel::BookstoreViewModel()
{
m_bookSku = winrt::make<Bookstore::implementation::BookSku>(L"Atticus");
}
Bookstore::BookSku BookstoreViewModel::BookSku()
{
return m_bookSku;
}
}
Note
Typ m_bookSku je projektovaný typ (winrt::Bookstore::BookSku) a parametr šablony, který používáte s winrt::make , je typ implementace (winrt::Bookstore::implementation::BookSku). I tak make vrací instanci projektovaného typu.
Projekt bude nyní znovu sestaven.
Přidání vlastnosti typu BookstoreViewModel do MainPage
Open MainPage.idl, který deklaruje třídu runtime, která představuje naši hlavní stránku uživatelského rozhraní.
- Přidání direktivy
importpro importBookstoreViewModel.idl. - Přidejte vlastnost jen pro čtení s názvem MainViewModel typu BookstoreViewModel.
- Odeberte vlastnost MyProperty.
// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
BookstoreViewModel MainViewModel{ get; };
}
}
Uložte soubor. Projekt zatím nebude zcela úspěšný při sestavování, ale sestavení je teď užitečnou věcí, protože znovu vygeneruje soubory zdrojového kódu, ve kterých je implementovaná třída modulu runtime MainPage (\Bookstore\Bookstore\Generated Files\sources\MainPage.h a MainPage.cpp). Tak do toho, začněte hned vytvářet. Chyba sestavení, kterou můžete očekávat v této fázi , je MainViewModel: není členem winrt::Bookstore::implementation::MainPage.
Pokud vynecháte direktivu include BookstoreViewModel.idl (viz výpis pro MainPage.idl výše), zobrazí se chyba očekává se < poblíž „MainViewModel“. Dalším tipem je zajistit, abyste ponechali všechny typy ve stejném jmenném prostoru – v tom, který je zobrazený ve výpisech kódu.
Chcete-li vyřešit chybu, jejíž výskyt očekáváme, budete nyní muset zkopírovat stuby přístupových metod pro vlastnost MainViewModel z vygenerovaných souborů (\Bookstore\Bookstore\Generated Files\sources\MainPage.h a MainPage.cpp) do \Bookstore\Bookstore\MainPage.h a MainPage.cpp. Kroky, které je potřeba provést, jsou popsány dále.
V \Bookstore\Bookstore\MainPage.haplikaci proveďte tyto kroky.
- Zahrnout
BookstoreViewModel.h, který deklaruje typ implementace pro BookstoreViewModel (což je winrt::Bookstore::implementation:BookstoreViewModel). - Přidejte soukromého člena pro uložení modelu zobrazení. Všimněte si, že funkce přístupového objektu vlastnosti (a člen m_mainViewModel) je implementována z hlediska projektu typu BookstoreViewModel (což je Bookstore::BookstoreViewModel).
- Typ implementace je ve stejném projektu (kompilační jednotka) jako aplikace, takže vytvoříme m_mainViewModel prostřednictvím přetížení konstruktoru, který přebírá std::nullptr_t.
- Odeberte vlastnost MyProperty.
Note
V dvojici níže uvedených ukázek kódu pro MainPage.h a MainPage.cpp kód ilustruje výchozí způsob inicializace datového členu m_mainViewModel. V následující části si ukážeme verzi, která místo toho používá jednotnou konstrukci.
// MainPage.h
...
#include "BookstoreViewModel.h"
...
namespace winrt::Bookstore::implementation
{
struct MainPage : MainPageT<MainPage>
{
MainPage();
Bookstore::BookstoreViewModel MainViewModel();
void ClickHandler(Windows::Foundation::IInspectable const&, Microsoft::UI::Xaml::RoutedEventArgs const&);
private:
Bookstore::BookstoreViewModel m_mainViewModel{ nullptr };
};
}
...
V \Bookstore\Bookstore\MainPage.cpp, jak je znázorněno v následujícím výpisu, proveďte následující změny.
- Zavolejte winrt::make (se typem implementace BookstoreViewModel) a přiřaďte novou instanci projektovaného typu BookstoreViewModel do m_mainViewModel. Jak jsme viděli výše, konstruktor BookstoreViewModel vytváří nový objekt BookSku jako privátní datový člen, přičemž jeho název zpočátku nastaví na
L"Atticus". - V obslužné rutině události tlačítka (ClickHandler) aktualizujte název knihy na jeho publikovaný název.
- Implementujte přístup pro MainViewModel vlastnost.
- Odeberte vlastnost MyProperty.
// MainPage.cpp
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"
using namespace winrt;
using namespace Microsoft::UI::Xaml;
namespace winrt::Bookstore::implementation
{
MainPage::MainPage()
{
m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();
InitializeComponent();
}
void MainPage::ClickHandler(Windows::Foundation::IInspectable const& /* sender */, Microsoft::UI::Xaml::RoutedEventArgs const& /* args */)
{
MainViewModel().BookSku().Title(L"To Kill a Mockingbird");
}
Bookstore::BookstoreViewModel MainPage::MainViewModel()
{
return m_mainViewModel;
}
}
Jednotná konstrukce
Pokud chcete místo winrt::make použít jednotnou konstrukci, deklarujte MainPage.h a inicializujete m_mainViewModel v jediném kroku, jak je znázorněno níže.
// MainPage.h
...
#include "BookstoreViewModel.h"
...
struct MainPage : MainPageT<MainPage>
{
...
private:
Bookstore::BookstoreViewModel m_mainViewModel;
};
...
A pak v konstruktoru MainPage v MainPage.cpp není potřeba kód m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.
Další informace o uniformní konstrukci a ukázky kódu najdete v tématu Volba uniformní konstrukce a přímého přístupu k implementaci.
Přivažte tlačítko k vlastnosti Název
Otevřete MainPage.xaml, který obsahuje kód XAML pro naši hlavní stránku uživatelského rozhraní. Jak je znázorněno v následujícím výpisu, odeberte název z tlačítka a změňte jeho hodnotu vlastnosti Content z literálu na výraz vazby. Všimněte si vlastnosti Mode=OneWay u výrazu vazby (jednosměrně z modelu zobrazení do uživatelského rozhraní). Bez této vlastnosti uživatelské rozhraní nereaguje na změněné události vlastností.
<Button Click="ClickHandler" Content="{x:Bind MainViewModel.BookSku.Title, Mode=OneWay}"/>
Nyní sestavte a spusťte projekt. Kliknutím na tlačítko spusťte obslužnou rutinu události Click . Tato obslužná rutina volá funkci mutátoru názvu knihy; tento mutátor vyvolá událost, aby uživatelské rozhraní vědělo, že se vlastnost Title změnila; a tlačítko znovu dotazuje hodnotu této vlastnosti, aby se aktualizovala její vlastní hodnota obsahu .
Použití rozšíření značek {Binding} v C++/WinRT
V aktuálně vydané verzi C++/WinRT budete muset k tomu, abyste mohli používat značkovací rozšíření {Binding}, implementovat rozhraní ICustomPropertyProvider a ICustomProperty.
Vazba elementu k elementu
Vlastnost jednoho elementu XAML lze svázat s vlastností jiného elementu XAML. Zde je příklad, jak to vypadá ve značkování.
<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />
Pojmenovanou entitu myTextBox XAML budete muset deklarovat jako vlastnost jen pro čtení v souboru Midl (.idl).
// MainPage.idl
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
Microsoft.UI.Xaml.Controls.TextBox myTextBox{ get; };
}
Tady je důvod této nutnosti. Všechny typy, které kompilátor XAML potřebuje ověřit (včetně těch, které se používají v aplikaci {x:Bind}), se čtou z Windows metadat (WinMD). Stačí jen přidat vlastnost jen pro čtení do souboru Midl. Neimplementujte ji, protože automaticky vygenerovaný kód XAML poskytuje implementaci za vás.
Využívání objektů z revizí XAML
Všechny entity spotřebované pomocí rozšíření značek XAML {x:Bind} musí být veřejně zpřístupněny v IDL. Kromě toho, pokud kód XAML obsahuje odkaz na jiný prvek, který je také v revizích, musí být getter pro tento kód přítomn v IDL.
<Page x:Name="MyPage">
<StackPanel>
<CheckBox x:Name="UseCustomColorCheckBox" Content="Use custom color"
Click="UseCustomColorCheckBox_Click" />
<Button x:Name="ChangeColorButton" Content="Change color"
Click="{x:Bind ChangeColorButton_OnClick}"
IsEnabled="{x:Bind UseCustomColorCheckBox.IsChecked.Value, Mode=OneWay}"/>
</StackPanel>
</Page>
ChangeColorButton element odkazuje na UseCustomColorCheckBox element prostřednictvím vazby. Proto IDL pro tuto stránku musí deklarovat vlastnost jen pro čtení s názvem UseCustomColorCheckBox , aby byla přístupná pro vazbu.
Delegát obslužné rutiny události Click pro UseCustomColorCheckBox používá klasickou syntaxi delegáta XAML, takže nepotřebuje položku v IDL; stačí, když je ve vaší implementační třídě veřejný. Na druhou stranu, ChangeColorButton má také obslužnou rutinu pro událost {x:Bind} click, která také musí být uvedena v IDL.
runtimeclass MyPage : Microsoft.UI.Xaml.Controls.Page
{
MyPage();
// These members are consumed by binding.
void ChangeColorButton_OnClick();
Microsoft.UI.Xaml.Controls.CheckBox UseCustomColorCheckBox{ get; };
}
Pro UseCustomColorCheckBox vlastnost nemusíte zadávat implementaci. Generátor kódu XAML to udělá za vás.
Vázání na logickou hodnotu
Můžete to udělat v diagnostickém režimu:
<TextBlock Text="{Binding CanPair}"/>
To v jazyce C++/CX zobrazí true nebo false, ale v jazyce C++/WinRT se zobrazí Windows.Foundation.IReference`1<Boolean>.
Místo toho použijte x:Bind při vytvoření vazby na booleovskou hodnotu.
<TextBlock Text="{x:Bind CanPair}"/>
Použití knihoven implementace Windows (WIL)
Knihovny Implementation Libraries pro Windows (WIL) poskytují pomocné funkce, které usnadňují vytváření vlastností podporujících datovou vazbu. Viz oznámení vlastností v dokumentaci WIL.
Důležitá rozhraní API
Příbuzná témata
Windows developer