XAML-Steuerelemente: Binden an eine C++/WinRT-EigenschaftXAML controls; bind to a C++/WinRT property

Eine Eigenschaft, die effektiv an ein XAML-Steuerelement gebunden werden kann, wird als Observable-Eigenschaft bezeichnet.A property that can be effectively bound to a XAML control is known as an observable property. Dieses Konzept basiert auf dem Softwareentwurfsmuster, das als Beobachter-Muster bekannt ist.This idea is based on the software design pattern known as the observer pattern. In diesem Thema erfährst du, wie du beobachtbare Eigenschaften in C++/WinRT implementierst und XAML-Steuerelemente an sie bindest (Hintergrundinformationen findest Du unter Datenbindung).This topic shows how to implement observable properties in C++/WinRT, and how to bind XAML controls to them (for background info, see Data binding).

Wichtig

Wichtige Konzepte und Begriffe im Zusammenhang mit der Nutzung und Erstellung von Laufzeitklassen mit C++/WinRT findest du unter Verwenden von APIs mit C++/WinRT sowie unter Erstellen von APIs mit C++/WinRT.For essential concepts and terms that support your understanding of how to consume and author runtime classes with C++/WinRT, see Consume APIs with C++/WinRT and Author APIs with C++/WinRT.

Was bedeutet beobachtbar für eine Eigenschaft?What does observable mean for a property?

Angenommen, eine Laufzeitklasse namens BookSku besitzt eine Eigenschaft namens Title.Let's say that a runtime class named BookSku has a property named Title. Falls BookSku bei jeder Änderung des Werts von Title das Ereignis INotifyPropertyChanged::PropertyChanged auslöst, heißt das, dass Title eine beobachtbare Eigenschaft ist.If BookSku raises the INotifyPropertyChanged::PropertyChanged event whenever the value of Title changes, then that means that Title is an observable property. Das Verhalten von BookSku (Auslösen oder nicht Auslösen des Ereignisses) bestimmt, welche der zugehörigen Eigenschaften beobachtbar sind.It's the behavior of BookSku (raising or not raising the event) that determines which, if any, of its properties are observable.

Ein XAML-Textelement oder Steuerelement kann an diese Ereignisse gebunden werden und sie behandeln.A XAML text element, or control, can bind to, and handle, these events. Ein solches Element oder Steuerelement behandelt das Ereignis, indem es die aktualisierten Werte abruft und sich anschließend selbst mit dem neuen Wert aktualisiert.Such an element or control handles the event by retrieving the updated value(s), and then updating itself to show the new value.

Hinweis

Informationen zum Installieren und Verwenden der C++/WinRT Visual Studio-Erweiterung (VSIX) und des NuGet-Pakets (die zusammen die Projektvorlage und Buildunterstützung bereitstellen) findest du unter Visual Studio-Unterstützung für C++/WinRT.For info about installing and using the C++/WinRT Visual Studio Extension (VSIX) and the NuGet package (which together provide project template and build support), see Visual Studio support for C++/WinRT.

Erstellen einer leeren App (Bookstore)Create a Blank App (Bookstore)

Erstelle zunächst ein neues Projekt in Microsoft Visual Studio.Begin by creating a new project in Microsoft Visual Studio. Erstelle ein Projekt vom Typ Leere App (C++/WinRT) , und nenne es Bookstore.Create a Blank App (C++/WinRT) project, and name it Bookstore. Stelle sicher, dass Platzieren Sie die Projektmappe und das Projekt im selben Verzeichnis deaktiviert ist.Make sure that Place solution and project in the same directory is unchecked. Die neueste allgemein verfügbare Version von Windows SDK (d. h. keine Vorschauversion).Target the latest generally-available (that is, not preview) version of the Windows SDK.

Wir erstellen eine neue Klasse, um ein Buch mit einer beobachtbaren Titeleigenschaft darzustellen.We're going to author a new class to represent a book that has an observable title property. Die Klasse wird innerhalb der gleichen Kompilierungseinheit erstellt und genutzt.We're authoring and consuming the class within the same compilation unit. Da wir jedoch die Möglichkeit haben möchten, über XAML eine Bindung mit dieser Klasse herzustellen, verwenden wir eine Laufzeitklasse.But we want to be able to bind to this class from XAML, and for that reason it's going to be a runtime class. Und wir verwenden C++/WinRT, um sie zu schreiben und zu nutzen.And we're going to use C++/WinRT to both author and consume it.

Um eine neue Laufzeitklasse zu erstellen, müssen wir dem Projekt zunächst ein neues Element vom Typ Midl-Datei (.idl) hinzufügen.The first step in authoring a new runtime class is to add a new Midl File (.idl) item to the project. Benennen Sie das neue Element BookSku.idl.Name the new item BookSku.idl. Lösche den Standardinhalt von BookSku.idl, und füge die folgende Laufzeitklassendeklaration ein:Delete the default contents of BookSku.idl, and paste in this runtime class declaration.

// BookSku.idl
namespace Bookstore
{
    runtimeclass BookSku : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        BookSku(String title);
        String Title;
    }
}

Hinweis

Deine ViewModel-Klassen müssen nicht von einer Basisklasse abgeleitet werden. (Das gilt eigentlich für alle Laufzeitklassen, die du in deiner Anwendung deklarierst.)Your view model classes—in fact, any runtime class that you declare in your application—need not derive from a base class. Die oben deklarierte Klasse BookSku ist ein Beispiel hierfür.The BookSku class declared above is an example of that. Sie implementiert eine Schnittstelle, ist aber von keiner Basisklasse abgeleitet.It implements an interface, but it doesn't derive from any base class.

In der Anwendung deklarierte Laufzeitklassen, die von einer Basisklasse abgeleitet sind, werden als zusammensetzbare Klassen bezeichnet.Any runtime class that you declare in the application that does derive from a base class is known as a composable class. Für zusammensetzbare Klassen gelten bestimmte Einschränkungen.And there are constraints around composable classes. Damit eine Anwendung die Tests des Zertifizierungskits für Windows-Apps besteht, das von Visual Studio sowie vom Microsoft Store zur Überprüfung von Übermittlungen verwendet wird, und erfolgreich in den Microsoft Store aufgenommen werden kann, muss eine zusammensetzbare Klasse letztendlich von einer Windows-Basisklasse abgeleitet sein.For an application to pass the Windows App Certification Kit tests used by Visual Studio and by the Microsoft Store to validate submissions (and therefore for the application to be successfully ingested into the Microsoft Store), a composable class must ultimately derive from a Windows base class. Das bedeutet, dass es sich am Stamm der Vererbungshierarchie um einen Klassentyp aus einem Windows.*-Namespace handeln muss.Meaning that the class at the very root of the inheritance hierarchy must be a type originating in a Windows.* namespace. Wenn du eine Laufzeitklasse von einer Basisklasse ableiten musst, um beispielsweise eine Klasse vom Typ BindableBase zur Ableitung deiner Ansichtsmodelle zu implementieren, kannst du Windows.UI.Xaml.DependencyObject als Grundlage für die Ableitung verwenden.If you do need to derive a runtime class from a base class—for example, to implement a BindableBase class for all of your view models to derive from—then you can derive from Windows.UI.Xaml.DependencyObject.

Ein Ansichtsmodell ist eine Abstraktion einer Ansicht und somit direkt an die Ansicht (XAML-Markup) gebunden.A view model is an abstraction of a view, and so it's bound directly to the view (the XAML markup). Ein Datenmodell ist eine Abstraktion von Daten. Es wird nur über deine Ansichtsmodelle genutzt und nicht direkt an XAML gebunden.A data model is an abstraction of data, and it's consumed only from your view models, and not bound directly to XAML. Sie können Ihre Datenmodelle also als C++-Strukturen oder -Klassen deklarieren und nicht als Laufzeitklassen.So you can declare your data models not as runtime classes, but as C++ structs or classes. Sie müssen nicht in MIDL deklariert werden, und du kannst eine beliebige Vererbungshierarchie verwenden.They don't need to be declared in MIDL, and you're free to use whatever inheritance hierarchy you like.

Speichern Sie die Datei, und erstellen Sie das Projekt.Save the file, and build the project. Der Build ist noch nicht vollständig erfolgreich, aber es werden einige erforderliche Dinge für uns durchgeführt.The build won't entirely succeed yet, but it will do some necessary things for us. Insbesondere wird während des Buildprozesses das Tool midl.exe ausgeführt, um eine Windows-Runtime-Metadatendatei (\Bookstore\Debug\Bookstore\Unmerged\BookSku.winmd) zu erstellen, die die Laufzeitklasse beschreibt.Specifically, during the build process the midl.exe tool is run to create a Windows Runtime metadata file (\Bookstore\Debug\Bookstore\Unmerged\BookSku.winmd) describing the runtime class. Danach wird das Tool cppwinrt.exe ausgeführt, um Quellcodedateien zu generieren, die dich bei der Erstellung und Nutzung deiner Laufzeitklasse unterstützen.Then, the cppwinrt.exe tool is run to generate source code files to support you in authoring and consuming your runtime class. Diese Dateien enthalten Stubs zur Implementierung der Laufzeitklasse BookSku, die du in deiner IDL deklariert hast.These files include stubs to get you started implementing the BookSku runtime class that you declared in your IDL. Diese Stubs sind \Bookstore\Bookstore\Generated Files\sources\BookSku.h und BookSku.cpp.Those stubs are \Bookstore\Bookstore\Generated Files\sources\BookSku.h and BookSku.cpp.

Klicke mit der rechten Maustaste auf den Projektknoten, und klicke auf Ordner in Datei-Explorer öffnen.Right-click the project node and click Open Folder in File Explorer. Dadurch wird der Projektordner im Datei-Explorer geöffnet.This opens the project folder in File Explorer. Kopiere dort die Stub-Dateien BookSku.h und BookSku.cpp aus dem Ordner \Bookstore\Bookstore\Generated Files\sources\ in den Projektordner \Bookstore\Bookstore\.There, copy the stub files BookSku.h and BookSku.cpp from the \Bookstore\Bookstore\Generated Files\sources\ folder and into the project folder, which is \Bookstore\Bookstore\. Vergewissere dich im Projektmappen-Explorer, dass Alle Dateien anzeigen aktiviert ist.In Solution Explorer, with the project node selected, make sure Show All Files is toggled on. Klicke mit der rechten Maustaste auf die kopierten Stub-Dateien, und klicke auf Zu Projekt hinzufügen.Right-click the stub files that you copied, and click Include In Project.

Implementieren von BookSkuImplement BookSku

Als Nächstes öffnen wir \Bookstore\Bookstore\BookSku.h und BookSku.cpp und implementieren unsere Laufzeitklasse.Now let's open \Bookstore\Bookstore\BookSku.h and BookSku.cpp and implement our runtime class. Zuerst wird eine static_assert-Deklaration am Anfang von BookSku.h und BookSku.cpp angezeigt, die Sie entfernen müssen.First, you'll see a static_assert at the top of BookSku.h and BookSku.cpp, which you'll need to remove.

Anschließend nehmen Sie diese Änderungen in BookSku.h vor.Next, in BookSku.h, make these changes.

  • Ändern Sie in Standardkonstruktor = default in = delete.On the default constructor, change = default to = delete. Das ist erforderlich, da wir keinen Standardkonstruktor wünschen.That's because we don't want a default constructor.
  • Fügen Sie einen privaten Member zum Speichern der Titelzeichenfolge hinzu.Add a private member to store the title string. Beachten Sie, dass wir über einen Konstruktor verfügen, der den Wert winrt::hstring annimmt.Note that we have a constructor that takes a winrt::hstring value. Dieser Wert ist die Titelzeichenfolge.That value is the title string.
  • Fügen Sie einen weiteren privaten Member für das Ereignis hinzu, das bei einer Änderung des Titels ausgelöst wird.Add another private member for the event that we'll raise when the title changes.

Nach diesen Änderungen sieht BookSku.h wie folgt aus:After making these changes, your BookSku.h will look like this.

// 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(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& value);
        void PropertyChanged(winrt::event_token const& token);
    
    private:
        winrt::hstring m_title;
        winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;
    };
}
namespace winrt::Bookstore::factory_implementation
{
    struct BookSku : BookSkuT<BookSku, implementation::BookSku>
    {
    };
}

Implementiere die Funktionen in BookSku.cpp:In BookSku.cpp, implement the functions like this.

// 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, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"Title" });
        }
    }

    winrt::event_token BookSku::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
    {
        return m_propertyChanged.add(handler);
    }

    void BookSku::PropertyChanged(winrt::event_token const& token)
    {
        m_propertyChanged.remove(token);
    }
}

In der Mutatorfunktion Title wird überprüft, ob ein Wert festgelegt wird, der sich vom aktuellen Wert unterscheidet.In the Title mutator function, we check whether a value is being set that's different from the current value. Falls ja, aktualisieren wir anschließend den Titel und lösen außerdem das Ereignis INotifyPropertyChanged::PropertyChanged mit einem Argument aus, das dem Namen der geänderten Eigenschaft entspricht.And, if so, then we update the title and also raise the INotifyPropertyChanged::PropertyChanged event with an argument equal to the name of the property that has changed. Dadurch weiß die Benutzeroberfläche (User Interface, UI), welcher Eigenschaftswert erneut abgefragt werden muss.This is so that the user-interface (UI) will know which property's value to re-query.

Nun wird ein neuer Build des Projekts erstellt, wenn Sie dies überprüfen wollen.The project will build again now, if you want to check that.

Deklarieren und Implementieren von BookstoreViewModelDeclare and implement BookstoreViewModel

Unsere XAML-Hauptseite wird an ein Hauptansichtsmodell gebunden.Our main XAML page is going to bind to a main view model. Dieses Ansichtsmodell erhält mehrere Eigenschaften –unter anderem eine vom Typ BookSku.And that view model is going to have several properties, including one of type BookSku. In diesem Schritt deklarieren und implementieren wir unsere Laufzeitklasse für das Hauptansichtsmodell.In this step, we'll declare and implement our main view model runtime class.

Füge ein neues Element vom Typ Midl-Datei (.idl) namens BookstoreViewModel.idl hinzu.Add a new Midl File (.idl) item named BookstoreViewModel.idl. Siehe auch Einbeziehen von Laufzeitklassen in Midl-Dateien (.idl).But also see Factoring runtime classes into Midl files (.idl).

// BookstoreViewModel.idl
import "BookSku.idl";

namespace Bookstore
{
    runtimeclass BookstoreViewModel
    {
        BookstoreViewModel();
        BookSku BookSku{ get; };
    }
}

Speichern und Erstellen (der Build wird noch nicht vollständig erfolgreich sein, aber der Grund für die Erstellung des Builds ist die erneute Generierung von Stubdateien).Save and build (the build won't entirely succeed yet, but the reason we're building is to generate stub files again).

Kopiere BookstoreViewModel.h und BookstoreViewModel.cpp aus dem Ordner Generated Files\sources in den Projektordner, und füge sie dem Projekt hinzu.Copy BookstoreViewModel.h and BookstoreViewModel.cpp from the Generated Files\sources folder into the project folder, and include them in the project. Öffnen Sie die Dateien (entfernen Sie static_assert wieder), und implementieren Sie die Laufzeitklasse, wie im Anschluss gezeigt.Open those files (removing the static_assert again), and implement the runtime class as shown below. Beachte, dass wir BookSku.h zu BookstoreViewModel.h hinzufügen, um den Implementierungstyp winrt::Bookstore::implementation::BookSku für BookSku zu deklarieren.Note how, in BookstoreViewModel.h, we're including BookSku.h, which declares the implementation type for BookSku (which is winrt::Bookstore::implementation::BookSku). Außerdem entfernen wir = default aus dem Standardkonstruktor.And we're removing = default from the default constructor.

Hinweis

In den folgenden Auflistungen für BookstoreViewModel.h und BookstoreViewModel.cpp veranschaulicht der Code die Standardmethode zur Konstruktion des m_bookSku-Datenelements.In the listings below for BookstoreViewModel.h and BookstoreViewModel.cpp, the code illustrates the default way of constructing the m_bookSku data member. Das ist die Methode, die auf das erste Release von C++/WinRT zurückgeht, und es ist sinnvoll, zumindest mit dem Muster vertraut zu sein.That's the method that dates back to the first release of C++/WinRT, and it's a good idea to be at least familiar with the pattern. Mit C++/WinRT Version 2.0 und höher steht Ihnen eine optimierte Form der Konstruktion zur Verfügung, die als einheitliche Konstruktion bezeichnet wird (siehe Neuerungen und Änderungen in C++/WinRT 2.0).With C++/WinRT version 2.0 and later, there's an optimized form of construction available to you known as uniform construction (see News, and changes, in C++/WinRT 2.0). Später in diesem Thema zeigen wir ein Beispiel für eine einheitliche Konstruktion.Later in this topic, we'll show an example of uniform construction.

// 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;
    }
}

Hinweis

Der Typ von m_bookSku ist der projizierte Typ (winrt::Bookstore::BookSku), und der mit winrt::make verwendete Vorlagenparameter ist der Implementierungstyp (winrt::Bookstore::implementation::BookSku).The type of m_bookSku is the projected type (winrt::Bookstore::BookSku), and the template parameter that you use with winrt::make is the implementation type (winrt::Bookstore::implementation::BookSku). Dennoch gibt make eine Instanz des projizierten Typs zurück.Even so, make returns an instance of the projected type.

Jetzt wird das Projekt erneut erstellt.The project will build again now.

Hinzufügen einer Eigenschaft vom Typ BookstoreViewModel zu MainPageAdd a property of type BookstoreViewModel to MainPage

Öffne MainPage.idl. Darin wird die Laufzeitklasse deklariert, die unsere UI-Hauptseite darstellt.Open MainPage.idl, which declares the runtime class that represents our main UI page.

  • Fügen Sie eine import-Direktive zum Importieren von BookstoreViewModel.idl hinzu.Add an import directive to import BookstoreViewModel.idl.
  • Fügen Sie eine schreibgeschützte Eigenschaft namens MainViewModel vom Typ BookstoreViewModel hinzu.Add a read-only property named MainViewModel, of type BookstoreViewModel.
  • Entfernen Sie die Eigenschaft MyProperty.Remove the MyProperty property.
// MainPage.idl
import "BookstoreViewModel.idl";

namespace Bookstore
{
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        BookstoreViewModel MainViewModel{ get; };
    }
}

Speichern Sie die Datei.Save the file. Das Projekt wird zwar noch nicht vollständig erfolgreich erstellt, die Erstellung ist jedoch hilfreich, da dadurch die Quellcodedateien neu generiert werden, in denen die Laufzeitklasse MainPage implementiert ist (\Bookstore\Bookstore\Generated Files\sources\MainPage.h und MainPage.cpp).The project won't entirely succeed in building yet, but building now is a useful thing to do because it regenerates the source code files in which the MainPage runtime class is implemented (\Bookstore\Bookstore\Generated Files\sources\MainPage.h and MainPage.cpp). Erstelle daher als Nächstes das Projekt.So go ahead and build now. In dieser Phase ist mit folgendem Buildfehler zu rechnen: 'MainViewModel' ist kein Member von 'winrt::Bookstore::implementation::MainPage' .The build error you can expect to see at this stage is 'MainViewModel': is not a member of 'winrt::Bookstore::implementation::MainPage'.

Wenn du BookstoreViewModel.idl nicht hinzufügst (siehe Listing von MainPage.idl weiter oben), tritt der Fehler expecting < near "MainViewModel" (In der Nähe von „MainViewModel“ wird < erwartet.) auf.If you omit the include of BookstoreViewModel.idl (see the listing of MainPage.idl above), then you'll see the error expecting < near "MainViewModel". Ein weiterer Tipp: Achten Sie darauf, dass sich alle Typen im gleichen Namespace befinden (und zwar in dem Namespace, der in den Codeauflistungen zu sehen ist).Another tip is to make sure that you leave all types in the same namespace—the namespace that's shown in the code listings.

Zur Behebung des erwarteten Fehlers musst du die Accessor-Stubs für die Eigenschaft MainViewModel aus den generierten Dateien (\Bookstore\Bookstore\Generated Files\sources\MainPage.h und MainPage.cpp) kopieren und in \Bookstore\Bookstore\MainPage.h und MainPage.cpp einfügen.To resolve the error that we expect to see, you'll now need to copy the accessor stubs for the MainViewModel property out of the generated files (\Bookstore\Bookstore\Generated Files\sources\MainPage.h and MainPage.cpp) and into \Bookstore\Bookstore\MainPage.h and MainPage.cpp. Dies wird als Nächstes beschrieben.The steps to do that are described next.

Führen Sie in \Bookstore\Bookstore\MainPage.h diese Schritte aus.In \Bookstore\Bookstore\MainPage.h, perform these steps.

  • Fügen Sie BookstoreViewModel.h hinzu, um den Implementierungstyp winrt::Bookstore::implementation::BookstoreViewModel für BookstoreViewModel zu deklarieren.Include BookstoreViewModel.h, which declares the implementation type for BookstoreViewModel (which is winrt::Bookstore::implementation::BookstoreViewModel).
  • Füge einen privaten Member zum Speichern des Ansichtsmodells hinzu.Add a private member to store the view model. Beachten Sie, dass die Accessorfunktion für die Eigenschaft (und der Member m_mainViewModel) als projizierter Typ für BookstoreViewModel (Bookstore::BookstoreViewModel) implementiert wird.Note that the property accessor function (and the member m_mainViewModel) is implemented in terms of the projected type for BookstoreViewModel (which is Bookstore::BookstoreViewModel).
  • Da sich der Implementierungstyp im gleichen Projekt (Kompilierungseinheit) befindet wie die Anwendung, konstruieren wir m_mainViewModel über die Konstruktorüberladung mit std::nullptr_t.The implementation type is in the same project (compilation unit) as the application, so we construct m_mainViewModel via the constructor overload that takes std::nullptr_t.
  • Entfernen Sie die Eigenschaft MyProperty.Remove the MyProperty property.

Hinweis

Im folgenden Auflistungspaar für MainPage.h und MainPage.cpp veranschaulicht der Code die Standardmethode zur Konstruktion des m_mainViewModel-Datenelements.In the pair of listings below for MainPage.h and MainPage.cpp, the code illustrates the default way of constructing the m_mainViewModel data member. Im folgenden Abschnitt wird eine Version gezeigt, die stattdessen eine einheitliche Konstruktion verwendet.In the section that follows, we'll show a version that uses uniform construction instead.

// MainPage.h
...
#include "BookstoreViewModel.h"
...
namespace winrt::Bookstore::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        Bookstore::BookstoreViewModel MainViewModel();

        void ClickHandler(Windows::Foundation::IInspectable const&, Windows::UI::Xaml::RoutedEventArgs const&);

    private:
        Bookstore::BookstoreViewModel m_mainViewModel{ nullptr };
    };
}
...

Nimm in \Bookstore\Bookstore\MainPage.cpp, wie in dem folgenden Listing gezeigt, die folgenden Änderungen vor.In \Bookstore\Bookstore\MainPage.cpp, as shown in the listing below, make the following changes.

  • Rufe winrt::make (mit dem ImplementierungstypBookstoreViewModel) auf, um m_mainViewModel eine neue Instanz des projizierten Typs BookstoreViewModel zuzuweisen.Call winrt::make (with the BookstoreViewModel implementation type) to assign a new instance of the projected BookstoreViewModel type to m_mainViewModel. Wie zuvor gesehen, erstellt der BookstoreViewModel-Konstruktor ein neues BookSku-Objekt als privaten Datenmember, wobei dessen Titel anfänglich auf L"Atticus" festgelegt wird.As we saw above, the BookstoreViewModel constructor creates a new BookSku object as a private data member, setting its title initially to L"Atticus".
  • Aktualisiere den Buchtitel im Ereignishandler (ClickHandler) auf den veröffentlichten Titel.In the button's event handler (ClickHandler), update the book's title to its published title.
  • Implementieren Sie den Accessor für die MainViewModel-Eigenschaft.Implement the accessor for the MainViewModel property.
  • Entfernen Sie die Eigenschaft MyProperty.Remove the MyProperty property.
// MainPage.cpp
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::Bookstore::implementation
{
    MainPage::MainPage()
    {
        m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();
        InitializeComponent();
    }

    void MainPage::ClickHandler(Windows::Foundation::IInspectable const& /* sender */, Windows::UI::Xaml::RoutedEventArgs const& /* args */)
    {
        MainViewModel().BookSku().Title(L"To Kill a Mockingbird");
    }

    Bookstore::BookstoreViewModel MainPage::MainViewModel()
    {
        return m_mainViewModel;
    }
}

Einheitliche KonstruktionUniform construction

Um eine einheitliche Konstruktion anstelle von winrt::make zu verwenden, deklarieren und initialisieren Sie m_mainViewModel in MainPage.h in nur einem Schritt, wie unten gezeigt.To use uniform construction instead of winrt::make, in MainPage.h declare and initialize m_mainViewModel in just one step, as shown below.

// MainPage.h
...
#include "BookstoreViewModel.h"
...
struct MainPage : MainPageT<MainPage>
{
    ...
private:
    Bookstore::BookstoreViewModel m_mainViewModel;
};
...

Im MainPage-Konstruktor in MainPage.cpp ist der Code m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>(); dann nicht erforderlich.And then, in the MainPage constructor in MainPage.cpp, there's no need for the code m_mainViewModel = winrt::make<Bookstore::implementation::BookstoreViewModel>();.

Weitere Informationen zur einheitlichen Konstruktion und Codebeispiele finden Sie unter Aktivieren von einheitlicher Konstruktion und direktem Implementierungszugriff.For more info about uniform construction, and code examples, see Opt in to uniform construction, and direct implementation access.

Binden der Schaltfläche an die Eigenschaft TitleBind the button to the Title property

Öffne MainPage.xaml. Darin befindet sich das XAML-Markup für unsere UI-Hauptseite.Open MainPage.xaml, which contains the XAML markup for our main UI page. Entferne wie im folgenden Listing zu sehen den Namen aus der Schaltfläche, und ändere den Wert der Eigenschaft Content von einem literalen Ausdruck in einen Bindungsausdruck.As shown in the listing below, remove the name from the button, and change its Content property value from a literal to a binding expression. Beachte die Eigenschaft Mode=OneWay für den Bindungsausdruck (unidirektional vom Ansichtsmodell zur UI).Note the Mode=OneWay property on the binding expression (one-way from the view model to the UI). Ohne diese Eigenschaft reagiert die Benutzeroberfläche nicht auf Eigenschaftsänderungsereignisse.Without that property, the UI will not respond to property changed events.

<Button Click="ClickHandler" Content="{x:Bind MainViewModel.BookSku.Title, Mode=OneWay}"/>

Erstelle nun das Projekt, und führe es aus.Now build and run the project. Klicke auf die Schaltfläche, um den Ereignishandler für Click auszuführen.Click the button to execute the Click event handler. Der Handler ruft die Titelmutatorfunktion des Buchs auf. Dieser Mutator löst ein Ereignis aus, um die Benutzeroberfläche darauf hinzuweisen, dass sich die Eigenschaft Title geändert hat, und die Schaltfläche fragt den Wert dieser Eigenschaft erneut ab, um den eigenen Wert für Content zu aktualisieren.That handler calls the book's title mutator function; that mutator raises an event to let the UI know that the Title property has changed; and the button re-queries that property's value to update its own Content value.

Verwenden der {Binding}-Markuperweiterung mit C++/WinRTUsing the {Binding} markup extension with C++/WinRT

Um in der aktuellen Version von C++/WinRT die {Binding}-Markuperweiterung verwenden zu können, müssen die Schnittstellen ICustomPropertyProvider und ICustomProperty implementiert werden.For the currently released version of C++/WinRT, in order to be able to use the {Binding} markup extension you'll need to implement the ICustomPropertyProvider and ICustomProperty interfaces.

Element-an-Element-BindungElement-to-element binding

Sie können die Eigenschaft eines XAML-Elements an die Eigenschaft eines anderen XAML-Elements binden.You can bind the property of one XAML element to the property of another XAML element. Dies ist ein Beispiel hierfür im Markup.Here's an example of how that looks in markup.

<TextBox x:Name="myTextBox" />
<TextBlock Text="{x:Bind myTextBox.Text, Mode=OneWay}" />

Sie müssen in der Midl-Datei (.idl) die benannte XAML-Entität myTextBox als schreibgeschützte Eigenschaft deklarieren.You'll need to declare the named XAML entity myTextBox as a read-only property in your Midl file (.idl).

// MainPage.idl
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
{
    MainPage();
    Windows.UI.Xaml.Controls.TextBox myTextBox{ get; };
}

Dies hat den folgenden Grund.Here's the reason for this necessity. Alle Typen, die der XAML-Compiler überprüfen muss (einschließlich der in {X:Bind} verwendeten), werden aus Windows-Metadaten (WinMD) gelesen.All types that the XAML compiler needs to validate (including those used in {x:Bind}) are read from Windows Metadata (WinMD). Sie müssen lediglich der Midl-Datei die schreibgeschützte Eigenschaft hinzufügen.All you need to do is to add the read-only property to your Midl file. Implementieren Sie dies nicht, denn die Implementierung erfolgt durch den automatisch generierten XAML-CodeBehind.Don't implement it, because the autogenerated XAML code-behind provides the implementation for you.

Verwenden von Objekten aus XAML-MarkupConsuming objects from XAML markup

Alle Entitäten, die über die XAML- {x:Bind}-Markuperweiterung genutzt werden, müssen in IDL öffentlich verfügbar gemacht werden.All entities consumed by using the XAML {x:Bind} markup extension must be exposed publicly in IDL. Wenn das XAML-Markup einen Verweis auf ein anderes Element enthält, das sich ebenfalls im Markup befindet, muss darüber hinaus der Getter für dieses Markup in IDL vorhanden sein.Furthermore, if XAML markup contains a reference to another element that's also in markup, then the getter for that markup must be present 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>

Das ChangeColorButton-Element verweist über eine Bindung auf das UseCustomColorCheckBox-Element.The ChangeColorButton element refers to the UseCustomColorCheckBox element via binding. Daher muss die IDL für diese Seite eine schreibgeschützte Eigenschaft namens UseCustomColorCheckBox deklarieren, um für die Bindung zugänglich zu sein.So the IDL for this page must declare a read-only property named UseCustomColorCheckBox in order for it to be accessible to binding.

Der Delegat für den Click-Ereignishandler für UseCustomColorCheckBox verwendet die klassische XAML-Delegatsyntax, benötigt daher keinen Eintrag in der IDL, sondern muss nur in deiner Implementierungsklasse öffentlich sein.The click event handler delegate for UseCustomColorCheckBox uses classic XAML delegate syntax, so that doesn't need an entry in the IDL; it just needs to be public in your implementation class. Auf der anderen Seite verfügt ChangeColorButton auch über einen {x:Bind}-Click-Ereignishandler, der in die IDL eingefügt werden muss.On the other hand, ChangeColorButton also has an {x:Bind} click event handler, which must also go into the IDL.

runtimeclass MyPage : Windows.UI.Xaml.Controls.Page
{
    MyPage();

    // These members are consumed by binding.
    void ChangeColorButton_OnClick();
    Windows.UI.Xaml.Controls.CheckBox UseCustomColorCheckBox{ get; };
}

Du musst keine Implementierung für die UseCustomColorCheckBox-Eigenschaft bereitstellen.You don't need to provide an implementation for the UseCustomColorCheckBox property. Das übernimmt der XAML-Codegenerator.The XAML code generator does that for you.

Binden an einen booleschen TypBinding to Boolean

Hierfür kannst du den Diagnosemodus verwenden.You might do this in a diagnostic mode.

Dieses Beispiel zeigt true oder false in C++/CX, aber Windows.Foundation.IReference`1 in C++/WinRT an.This shows true or false in C++/CX, but shows Windows.Foundation.IReference`1 in C++/WinRT.

Verwende x:Bind beim Binden an einen booleschen Typ.Use x:Bind when binding to a Boolean.

<TextBlock Text="{x:Bind CanPair}"/>

Wichtige APIsImportant APIs