Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Een eigenschap die effectief kan worden gebonden aan een XAML-besturingselement, wordt een waarneembare eigenschap genoemd. Dit idee is gebaseerd op het softwareontwerppatroon dat bekend staat als het waarnemerspatroon. In dit onderwerp wordt beschreven hoe u waarneembare eigenschappen implementeert in C++/WinRT en hoe u XAML-besturingselementen aan deze besturingselementen koppelt (zie Gegevensbinding op de achtergrond).
Belangrijk
Zie API's gebruiken met C++/WinRT en Author API's met C++/WinRT voor essentiële concepten en termen die ondersteuning bieden voor uw begrip van het gebruiken en schrijven van runtimeklassen met C++/WinRT.
Wat betekent waarneembaar voor een eigenschap?
Stel dat een runtimeklasse met de naam BookSku een eigenschap Title heeft. Als BookSku de gebeurtenis INotifyPropertyChanged::P ropertyChanged genereert wanneer de waarde van Titel wordt gewijzigd, betekent dit dat Titel een waarneembare eigenschap is. Het is het gedrag van BookSku (het verhogen of niet verhogen van de gebeurtenis) die bepaalt welke, indien van toepassing, van de eigenschappen waarneembaar zijn.
Een XAML-tekstelement of besturingselement kan deze gebeurtenissen binden en afhandelen. Een dergelijk element of besturingselement verwerkt de gebeurtenis door de bijgewerkte waarde(s) op te halen en zichzelf vervolgens bij te werken om de nieuwe waarde weer te geven.
Note
Zie Visual Studio support for C++/WinRT voor informatie over het installeren en gebruiken van de Visual Studio-extensie (VSIX) en het NuGet-pakket voor C++/WinRT, die samen projectsjablonen en ondersteuning voor builds bieden.
Een lege app maken (boekwinkel)
Begin met het maken van een nieuw project in Microsoft Visual Studio. Maak een lege app, verpakt (WinUI 3 in Desktop) voor het C++-project en noem het boekarchief. Zorg ervoor dat Oplossing en project in dezelfde map plaatsen niet is aangevinkt. Richt u op de meest recente algemeen beschikbare (dus niet preview)-versie van de Windows SDK.
We gaan een nieuwe klasse ontwerpen om een boek te vertegenwoordigen dat een waarneembare titeleigenschap heeft. We ontwerpen en gebruiken de klasse binnen dezelfde compilatie-eenheid. Maar we willen verbinding kunnen maken met deze klasse vanuit XAML en daarom wordt het een runtimeklasse. En we gaan C++/WinRT gebruiken om het te schrijven en te gebruiken.
De eerste stap bij het ontwerpen van een nieuwe runtimeklasse is het toevoegen van een nieuw Midl File-item (.idl) aan het project. Geef het nieuwe item BookSku.idleen naam. Verwijder de standaardinhoud van BookSku.idl, en plak vervolgens deze declaratie van de runtimeklasse.
// BookSku.idl
namespace Bookstore
{
runtimeclass BookSku : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
BookSku(String title);
String Title;
}
}
Note
Uw weergavemodelklassen, in feite elke runtimeklasse die u in uw toepassing declareert, hoeft niet te worden afgeleid van een basisklasse. De hierboven opgegeven BookSku-klasse is een voorbeeld hiervan. Er wordt een interface geïmplementeerd, maar deze is niet afgeleid van een basisklasse.
Elke runtimeklasse die u declareert in de toepassing die is afgeleid van een basisklasse, wordt een composeerbare klasse genoemd. En er zijn beperkingen voor composable klassen. Wil een toepassing slagen voor de tests van de Windows-app Certification Kit die door Visual Studio en de Microsoft Store worden gebruikt om inzendingen te valideren (en dus om de toepassing succesvol in de Microsoft Store te kunnen opnemen), dan moet een samenstelbare klasse uiteindelijk afstammen van een Windows-basisklasse. Dit betekent dat de klasse helemaal aan de basis van de overervingshiërarchie een type moet zijn dat afkomstig is uit een Windows.*- of Microsoft.*-naamruimte. Als u een runtimeklasse moet afleiden van een basisklasse, bijvoorbeeld om een BindableBase-klasse te implementeren voor al uw weergavemodellen waaruit moet worden afgeleid, kunt u afleiden van Microsoft. UI. Xaml.DependencyObject.
Een weergavemodel is een abstractie van een weergave en is dus rechtstreeks gebonden aan de weergave (de XAML-markering). Een gegevensmodel is een abstractie van gegevens en wordt alleen gebruikt vanuit uw weergavemodellen en is niet rechtstreeks gebonden aan XAML. U kunt uw gegevensmodellen dus niet als runtimeklassen declareren, maar als C++-structs of -klassen. Ze hoeven niet te worden gedeclareerd in MIDL en u kunt de overnamehiërarchie die u wilt gebruiken.
Sla het bestand op en bouw het project. De build zal nog niet (volledig) slagen, maar er worden wel enkele noodzakelijke dingen voor ons uitgevoerd. Tijdens het buildproces wordt het midl.exe hulpprogramma uitgevoerd om een Windows Runtime metagegevensbestand te maken dat de runtimeklasse beschrijft (het bestand wordt op schijf geplaatst).\Bookstore\Debug\Bookstore\Unmerged\BookSku.winmd Vervolgens wordt het hulpprogramma uitgevoerd om broncodebestanden te genereren die u ondersteunen bij het cppwinrt.exe ontwerpen en gebruiken van uw runtimeklasse. Deze bestanden bevatten stubs om u op weg te helpen met het implementeren van de BookSku-runtimeklasse die u hebt gedeclareerd in uw IDL. We vinden ze over een ogenblik op schijf, maar die stubs zijn \Bookstore\Bookstore\Generated Files\sources\BookSku.h en BookSku.cpp.
Klik nu met de rechtermuisknop op het projectknooppunt in Visual Studio en klik op Map openen in Verkenner. Hiermee opent u de projectmap in Verkenner. U moet nu de inhoud van de \Bookstore\Bookstore\ map bekijken. Ga van daaruit naar de \Generated Files\sources\ map en kopieer de stub-bestanden BookSku.h en BookSku.cpp naar het klembord. Ga terug naar de projectmap (\Bookstore\Bookstore\) en plak de twee bestanden die u zojuist hebt gekopieerd. Controleer ten slotte in Solution Explorer met het projectknooppunt geselecteerd dat Alle bestanden weergeven is ingeschakeld. Klik met de rechtermuisknop op de stub-bestanden die u hebt gekopieerd en klik op Include In Project.
BookSku implementeren
Nu gaan we onze runtimeklasse openen \Bookstore\Bookstore\BookSku.h en BookSku.cpp implementeren. Eerst ziet u bovenaan BookSku.h en BookSku.cpp een static_assert, dat u moet verwijderen.
Breng vervolgens in BookSku.h deze wijzigingen aan.
- Wijzig in de standaardconstructor
= defaultin= delete. Dat komt omdat we geen standaardconstructor willen. - Voeg een privélid toe om de titeltekenreeks op te slaan. Houd er rekening mee dat we een constructor hebben die een winrt::hstring-waarde gebruikt. Deze waarde is de titeltekenreeks.
- Voeg nog een extra private member toe voor het event dat we activeren wanneer de titel wordt gewijzigd.
Nadat u deze wijzigingen hebt aangebracht, ziet u BookSku.h er als volgt uit.
// 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>
{
};
}
Implementeer in BookSku.cpp de functies als volgt.
// 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);
}
}
In de functie Titelmutator controleren we of een waarde wordt ingesteld die verschilt van de huidige waarde. Als dat het geval is, werken we de titel bij en verhogen we ook de gebeurtenis INotifyPropertyChanged::P ropertyChanged met een argument dat gelijk is aan de naam van de eigenschap die is gewijzigd. Dit is zo dat de gebruikersinterface (UI) weet welke waarde van de eigenschap opnieuw moet worden opgeslagen.
Het project zal nu opnieuw worden gebouwd, als u dat wilt nagaan.
BookstoreViewModel declareren en implementeren
Onze primaire XAML-pagina wordt gekoppeld aan een hoofdweergavemodel. En dat weergavemodel heeft verschillende eigenschappen, waaronder een van het type BookSku. In deze stap declareren en implementeren we de runtimeklasse van het hoofdweergavemodel.
Voeg een nieuw Midl-bestand (.idl)- item toe met de naam BookstoreViewModel.idl. Maar zie ook Runtimeklassen onderbrengen in MIDL-bestanden (.idl).
// BookstoreViewModel.idl
import "BookSku.idl";
namespace Bookstore
{
runtimeclass BookstoreViewModel
{
BookstoreViewModel();
BookSku BookSku{ get; };
}
}
Opslaan en bouwen (de build lukt nog niet helemaal, maar de reden waarom we bouwen is om stub-bestanden opnieuw te genereren).
Kopieer BookstoreViewModel.h en BookstoreViewModel.cpp van de Generated Files\sources map naar de projectmap en neem deze op in het project. Open deze bestanden (waarbij je static_assert opnieuw verwijdert) en implementeer de runtime-klasse zoals hieronder weergegeven. Merk op dat we in BookstoreViewModel.hBookSku.h opnemen, waarin het implementatietype voor BookSku wordt gedeclareerd (namelijk winrt::Bookstore::implementation::BookSku). En we verwijderen = default uit de standaardconstructor.
Note
In de onderstaande vermeldingen voor BookstoreViewModel.h en BookstoreViewModel.cpp, de code illustreert de standaard manier om het m_bookSku gegevenslid samen te stellen. Dat is de methode die dateert uit de eerste release van C++/WinRT en het is een goed idee om ten minste bekend te zijn met het patroon. Met C++/WinRT versie 2.0 en hoger is er een geoptimaliseerde vorm van constructie beschikbaar voor u, bekend als uniforme constructie (zie Nieuws en wijzigingen, in C++/WinRT 2.0). Verderop in dit onderwerp laten we een voorbeeld van uniforme constructie zien.
// 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
Het type m_bookSku is het verwachte type (winrt::Bookstore::BookSku) en de sjabloonparameter die u gebruikt met winrt::make is het implementatietype (winrt::Bookstore::implementation:BookSku). Toch retourneert make een exemplaar van het geprojecteerde type.
Het project wordt nu opnieuw gebouwd.
Een eigenschap van het type BookstoreViewModel toevoegen aan MainPage
Openen MainPage.idl, waarmee de runtimeklasse wordt aangegeven die de hoofdpagina van de gebruikersinterface vertegenwoordigt.
- Voeg een
importinstructie toe om te importerenBookstoreViewModel.idl. - Voeg een alleen-lezen eigenschap toe met de naam MainViewModel, van het type BookstoreViewModel.
- Verwijder de eigenschap MyProperty .
// MainPage.idl
import "BookstoreViewModel.idl";
namespace Bookstore
{
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
BookstoreViewModel MainViewModel{ get; };
}
}
Sla het bestand op. Het project kan nog niet helemaal worden gebouwd, maar het bouwen is nu handig omdat hiermee de broncodebestanden worden gegenereerd waarin de MainPage-runtimeklasse is geïmplementeerd (\Bookstore\Bookstore\Generated Files\sources\MainPage.h en MainPage.cpp). Dus ga verder en bouw nu. De buildfout die u in deze fase kunt verwachten, is MainViewModel: is geen lid van 'winrt::Bookstore::implementation::MainPage'.
Als u de include van BookstoreViewModel.idl weglaat (zie de bovenstaande lijst van MainPage.idl), dan ziet u de fout verwacht < in de buurt van "MainViewModel". Een andere tip is om ervoor te zorgen dat u alle typen in dezelfde naamruimte laat staan: de naamruimte die wordt weergegeven in de codevermeldingen.
Om de fout op te lossen die we naar verwachting zullen zien, moet u nu de accessorstubs voor de eigenschap MainViewModel uit de gegenereerde bestanden (\Bookstore\Bookstore\Generated Files\sources\MainPage.h en MainPage.cpp) kopiëren en in \Bookstore\Bookstore\MainPage.h en MainPage.cpp plaatsen. De stappen die u moet uitvoeren, worden hierna beschreven.
Voer in \Bookstore\Bookstore\MainPage.h deze stappen uit.
- Neem
BookstoreViewModel.hop, waarmee het implementatietype voor BookstoreViewModel wordt gedeclareerd (dit is winrt::Bookstore::implementation::BookstoreViewModel). - Voeg een privélid toe om het weergavemodel op te slaan. Houd er rekening mee dat de eigenschapstoegangsfunctie (en het lid m_mainViewModel) is geïmplementeerd in termen van het verwachte type voor BookstoreViewModel (dit is Bookstore::BookstoreViewModel).
- Het implementatietype bevindt zich in hetzelfde project (compilatie-eenheid) als de applicatie, dus construeren we m_mainViewModel via de overbelaste constructor die std::nullptr_t accepteert.
- Verwijder de eigenschap MyProperty .
Note
In het onderstaande paar vermeldingen voor MainPage.h en MainPage.cppillustreert de code de standaard manier om het m_mainViewModel gegevenslid samen te stellen. In de volgende sectie wordt een versie weergegeven die gebruikmaakt van uniforme constructie.
// 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 };
};
}
...
Breng in \Bookstore\Bookstore\MainPage.cpp, zoals weergegeven in het onderstaande codefragment, de volgende wijzigingen aan.
- Roep winrt::make (met het implementatietype BookstoreViewModel ) aan om een nieuw exemplaar van het projected BookstoreViewModel-type toe te wijzen aan m_mainViewModel. Zoals we hierboven zagen, maakt de constructor van BookstoreViewModel een nieuw BookSku-object aan als privégegevenslid, waarbij de titel in eerste instantie op
L"Atticus"wordt ingesteld. - Werk in de gebeurtenis-handler van de knop (ClickHandler) de titel van het boek bij naar de gepubliceerde titel.
- Implementeer de accessor voor de eigenschap MainViewModel .
- Verwijder de eigenschap 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;
}
}
Uniforme constructie
Als u uniforme constructie wilt gebruiken in plaats van winrt::make, MainPage.h declareert en initialiseert u m_mainViewModel in slechts één stap, zoals hieronder wordt weergegeven.
// MainPage.h
...
#include "BookstoreViewModel.h"
...
struct MainPage : MainPageT<MainPage>
{
...
private:
Bookstore::BookstoreViewModel m_mainViewModel;
};
...
En in de MainPage-constructor in MainPage.cppis de code m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();niet nodig.
Zie Aanmelden voor uniforme constructie en directe implementatietoegang voor meer informatie over uniforme constructie en codevoorbeelden.
De knop verbinden met de eigenschap Titel
Open MainPage.xaml, die de XAML-opmaak voor onze hoofdgebruikersinterfacepagina bevat. Zoals wordt weergegeven in de onderstaande vermelding, verwijdert u de naam van de knop en wijzigt u de waarde van de eigenschap Inhoud van een letterlijke waarde in een bindingsexpressie. Let op de eigenschap Mode=OneWay van de bindingsexpressie (eenrichting, van het viewmodel naar de UI). Zonder deze eigenschap reageert de gebruikersinterface niet op gewijzigde gebeurtenissen van de eigenschap.
<Button Click="ClickHandler" Content="{x:Bind MainViewModel.BookSku.Title, Mode=OneWay}"/>
Bouw nu het project en voer het uit. Klik op de knop om de gebeurtenisafhandelaar voor Klik uit te voeren. Die handler roept de titelmutatorfunctie van het boek aan; die mutator een gebeurtenis genereert om de gebruikersinterface te laten weten dat de eigenschap Titel is gewijzigd; en de knop voert een query uit op de waarde van die eigenschap om de eigen inhoudswaarde bij te werken.
De markeringsextensie {Binding} gebruiken met C++/WinRT
Voor de momenteel uitgebrachte versie van C++/WinRT moet u de interfaces ICustomPropertyProvider en ICustomProperty implementeren om de markeringsextensie {Binding} te kunnen gebruiken.
Element-naar-element-binding
U kunt de eigenschap van één XAML-element binden aan de eigenschap van een ander XAML-element. Hier volgt een voorbeeld van hoe dit eruitziet in markeringen.
<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />
U moet de benoemde XAML-entiteit myTextBox declareren als een alleen-lezen eigenschap in uw Midl-bestand (.idl).
// MainPage.idl
runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
{
MainPage();
Microsoft.UI.Xaml.Controls.TextBox myTextBox{ get; };
}
Dit is de reden voor deze noodzaak. Alle typen die de XAML-compiler nodig heeft om te valideren (inclusief de typen die worden gebruikt in {x:Bind}), worden gelezen uit Windows Metagegevens (WinMD). U hoeft alleen de eigenschap Alleen-lezen toe te voegen aan uw Midl-bestand. Implementeer deze niet, omdat de automatisch gegenereerde XAML-code-behind de implementatie voor u biedt.
Objecten uit XAML-opmaak gebruiken
Alle entiteiten die worden gebruikt met behulp van de XAML -markeringsextensie {x:Bind} , moeten openbaar worden weergegeven in IDL. Als XAML-markeringen bovendien een verwijzing bevatten naar een ander element dat ook in markeringen staat, moet de getter voor die markering aanwezig zijn in 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>
Het element ChangeColorButton verwijst naar het element UseCustomColorCheckBox via binding. De IDL voor deze pagina moet dus een alleen-lezen eigenschap met de naam UseCustomColorCheckBox declareren om deze toegankelijk te maken voor binding.
De delegate voor de klikgebeurtenis-handler van UseCustomColorCheckBox gebruikt de klassieke XAML-delegatesyntaxis, dus daarvoor is geen invoer in de IDL nodig; deze hoeft alleen openbaar te zijn in uw implementatieklasse. Aan de andere kant heeft ChangeColorButton ook een {x:Bind} klikgebeurtenis-handler, die ook in de IDL moet worden opgenomen.
runtimeclass MyPage : Microsoft.UI.Xaml.Controls.Page
{
MyPage();
// These members are consumed by binding.
void ChangeColorButton_OnClick();
Microsoft.UI.Xaml.Controls.CheckBox UseCustomColorCheckBox{ get; };
}
U hoeft geen implementatie op te geven voor de eigenschap UseCustomColorCheckBox . De XAML-codegenerator doet dat voor u.
Binding met Booleaanse waarde
U kunt dit doen in een diagnostische modus:
<TextBlock Text="{Binding CanPair}"/>
Dit wordt in C++/CX weergegeven als true of false; maar in C++/WinRT wordt Windows.Foundation.IReference`1<Boolean> weergegeven.
Gebruik in plaats daarvan x:Bind bij het binden aan een Booleaanse waarde.
<TextBlock Text="{x:Bind CanPair}"/>
De Windows Implementation Libraries (WIL) gebruiken
De Windows Implementation Libraries (WIL) biedt helpers om het schrijven van bindbare eigenschappen te vereenvoudigen. Zie Eigenschappen melden in de WIL-documentatie.
Belangrijke API's
Verwante onderwerpen
Windows developer