Übersicht über DatenbindungData binding overview

In diesem Thema erfahren Sie, wie Sie in einer UWP-App (Universelle Windows-Plattform) ein Steuerelement (oder ein anderes Benutzeroberflächenelement) an ein einzelnes Element oder ein Elementsteuerelement an eine Sammlung von Elementen binden.This topic shows you how to bind a control (or other UI element) to a single item or bind an items control to a collection of items in a Universal Windows Platform (UWP) app. Darüber hinaus wird erläutert, wie Sie die Anzeige von Elementen steuern, eine Detailansicht auf Grundlage einer Auswahl implementieren und Daten für die Anzeige umwandeln.In addition, we show how to control the rendering of items, implement a details view based on a selection, and convert data for display. Ausführliche Informationen finden Sie unter Datenbindung im Detail.For more detailed info, see Data binding in depth.

Erforderliche KomponentenPrerequisites

In diesem Thema wird vorausgesetzt, dass Sie mit dem Erstellen von UWP-Apps vertraut sind.This topic assumes that you know how to create a basic UWP app. Eine Anleitung zum Erstellen Ihrer ersten UWP-App finden Sie unter Erste Schritte mit Windows-Apps.For instructions on creating your first UWP app, see Get started with Windows apps.

Erstellen des ProjektsCreate the project

Erstellen Sie ein neues Projekt vom Typ Leere Anwendung (Windows Universal) .Create a new Blank Application (Windows Universal) project. Nennen Sie sie „Schnellstart“.Name it "Quickstart".

Binden an ein einzelnes ElementBinding to a single item

Jede Bindung besteht aus einem Bindungsziel und einer Bindungsquelle.Every binding consists of a binding target and a binding source. In der Regel ist das Ziel eine Eigenschaft eines Steuerelements oder anderen Benutzeroberflächenelements, und die Quelle ist eine Eigenschaft einer Klasseninstanz (ein Datenmodell oder ein Ansichtsmodell).Typically, the target is a property of a control or other UI element, and the source is a property of a class instance (a data model, or a view model). In diesem Beispiel wird veranschaulicht, wie Sie ein Steuerelement an ein einzelnes Element binden.This example shows how to bind a control to a single item. Das Ziel ist die Text-Eigenschaft eines TextBlock.The target is the Text property of a TextBlock. Die Quelle ist eine Instanz einer einfachen Klasse namens Recording, die eine Audioaufnahme darstellt.The source is an instance of a simple class named Recording that represents an audio recording. Befassen wir uns zuerst mit der Klasse.Let's look at the class first.

Wenn Sie oder C++/CX C# verwenden, fügen Sie dem Projekt eine neue Klasse hinzu, und benennen Sie die Klassen Aufzeichnung.If you're using C# or C++/CX, then add a new class to your project, and name the class Recording.

Wenn Sie C++/WinRTverwenden, fügen Sie dem Projekt neue Dateien für die mittlere Datei (. idl) hinzu, wie im C++folgenden Beispiel gezeigt.If you're using C++/WinRT, then add new Midl File (.idl) items to the project, named as shown in the C++/WinRT code example listing below. Ersetzen Sie den Inhalt dieser neuen Dateien durch den in der Auflistung gezeigten Mittelwert 3,0 -Code, erstellen Sie das Projekt, um Recording.h und .cpp und RecordingViewModel.h und .cpp zu generieren, und fügen Sie dann den generierten Dateien Code hinzu, damit dieser der Auflistung entspricht.Replace the contents of those new files with the MIDL 3.0 code shown in the listing, build the project to generate Recording.h and .cpp and RecordingViewModel.h and .cpp, and then add code to the generated files to match the listing. Weitere Informationen zu diesen generierten Dateien und zum Kopieren der Dateien in das Projekt finden Sie unter XAML-Steuerelemente, binden C++an eine/WinRT-Eigenschaft.For more info about those generated files and how to copy them into your project, see XAML controls; bind to a C++/WinRT property.

namespace Quickstart
{
    public class Recording
    {
        public string ArtistName { get; set; }
        public string CompositionName { get; set; }
        public DateTime ReleaseDateTime { get; set; }
        public Recording()
        {
            this.ArtistName = "Wolfgang Amadeus Mozart";
            this.CompositionName = "Andante in C for Piano";
            this.ReleaseDateTime = new DateTime(1761, 1, 1);
        }
        public string OneLineSummary
        {
            get
            {
                return $"{this.CompositionName} by {this.ArtistName}, released: "
                    + this.ReleaseDateTime.ToString("d");
            }
        }
    }
    public class RecordingViewModel
    {
        private Recording defaultRecording = new Recording();
        public Recording DefaultRecording { get { return this.defaultRecording; } }
    }
}
// Recording.idl
namespace Quickstart
{
    runtimeclass Recording
    {
        Recording(String artistName, String compositionName, Windows.Globalization.Calendar releaseDateTime);
        String ArtistName{ get; };
        String CompositionName{ get; };
        Windows.Globalization.Calendar ReleaseDateTime{ get; };
        String OneLineSummary{ get; };
    }
}

// RecordingViewModel.idl
import "Recording.idl";

namespace Quickstart
{
    runtimeclass RecordingViewModel
    {
        RecordingViewModel();
        Quickstart.Recording DefaultRecording{ get; };
    }
}

// Recording.h
// Add these fields:
...
#include <sstream>
...
private:
    std::wstring m_artistName;
    std::wstring m_compositionName;
    Windows::Globalization::Calendar m_releaseDateTime;
...

// Recording.cpp
// Implement like this:
...
Recording::Recording(hstring const& artistName, hstring const& compositionName, Windows::Globalization::Calendar const& releaseDateTime) :
    m_artistName{ artistName.c_str() },
    m_compositionName{ compositionName.c_str() },
    m_releaseDateTime{ releaseDateTime } {}

hstring Recording::ArtistName(){ return hstring{ m_artistName }; }
hstring Recording::CompositionName(){ return hstring{ m_compositionName }; }
Windows::Globalization::Calendar Recording::ReleaseDateTime(){ return m_releaseDateTime; }

hstring Recording::OneLineSummary()
{
    std::wstringstream wstringstream;
    wstringstream << m_compositionName.c_str();
    wstringstream << L" by " << m_artistName.c_str();
    wstringstream << L", released: " << m_releaseDateTime.MonthAsNumericString().c_str();
    wstringstream << L"/" << m_releaseDateTime.DayAsString().c_str();
    wstringstream << L"/" << m_releaseDateTime.YearAsString().c_str();
    return hstring{ wstringstream.str().c_str() };
}
...

// RecordingViewModel.h
// Add this field:
...
#include "Recording.h"
...
private:
    Quickstart::Recording m_defaultRecording{ nullptr };
...

// RecordingViewModel.cpp
// Implement like this:
...
Quickstart::Recording RecordingViewModel::DefaultRecording()
{
    Windows::Globalization::Calendar releaseDateTime;
    releaseDateTime.Year(1761);
    releaseDateTime.Month(1);
    releaseDateTime.Day(1);
    m_defaultRecording = winrt::make<Recording>(L"Wolfgang Amadeus Mozart", L"Andante in C for Piano", releaseDateTime);
    return m_defaultRecording;
}
...
// Recording.h
#include <sstream>
namespace Quickstart
{
    public ref class Recording sealed
    {
    private:
        Platform::String^ artistName;
        Platform::String^ compositionName;
        Windows::Globalization::Calendar^ releaseDateTime;
    public:
        Recording(Platform::String^ artistName, Platform::String^ compositionName,
            Windows::Globalization::Calendar^ releaseDateTime) :
            artistName{ artistName },
            compositionName{ compositionName },
            releaseDateTime{ releaseDateTime } {}
        property Platform::String^ ArtistName
        {
            Platform::String^ get() { return this->artistName; }
        }
        property Platform::String^ CompositionName
        {
            Platform::String^ get() { return this->compositionName; }
        }
        property Windows::Globalization::Calendar^ ReleaseDateTime
        {
            Windows::Globalization::Calendar^ get() { return this->releaseDateTime; }
        }
        property Platform::String^ OneLineSummary
        {
            Platform::String^ get()
            {
                std::wstringstream wstringstream;
                wstringstream << this->CompositionName->Data();
                wstringstream << L" by " << this->ArtistName->Data();
                wstringstream << L", released: " << this->ReleaseDateTime->MonthAsNumericString()->Data();
                wstringstream << L"/" << this->ReleaseDateTime->DayAsString()->Data();
                wstringstream << L"/" << this->ReleaseDateTime->YearAsString()->Data();
                return ref new Platform::String(wstringstream.str().c_str());
            }
        }
    };
    public ref class RecordingViewModel sealed
    {
    private:
        Recording ^ defaultRecording;
    public:
        RecordingViewModel()
        {
            Windows::Globalization::Calendar^ releaseDateTime = ref new Windows::Globalization::Calendar();
            releaseDateTime->Year = 1761;
            releaseDateTime->Month = 1;
            releaseDateTime->Day = 1;
            this->defaultRecording = ref new Recording{ L"Wolfgang Amadeus Mozart", L"Andante in C for Piano", releaseDateTime };
        }
        property Recording^ DefaultRecording
        {
            Recording^ get() { return this->defaultRecording; };
        }
    };
}

// Recording.cpp
#include "pch.h"
#include "Recording.h"

Machen Sie als Nächstes die Bindungsquellklasse aus der Klasse verfügbar, die die Markupseite darstellt.Next, expose the binding source class from the class that represents your page of markup. Zu diesem Zweck fügen Sie eine Eigenschaft vom Typ RecordingViewModel zu MainPage hinzu.We do that by adding a property of type RecordingViewModel to MainPage.

Wenn Sie C++/WinRTverwenden, aktualisieren Sie zuerst MainPage.idl.If you're using C++/WinRT, then first update MainPage.idl. Erstellen Sie das Projekt, um MainPage.h und .cpp neu zu generieren, und führen Sie die Änderungen in diesen generierten Dateien in den in Ihrem Projekt erstellten Dateien zusammen.Build the project to regenerate MainPage.h and .cpp, and merge the changes in those generated files into the ones in your project.

namespace Quickstart
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.ViewModel = new RecordingViewModel();
        }
        public RecordingViewModel ViewModel{ get; set; }
    }
}
// MainPage.idl
// Add this property:
import "RecordingViewModel.idl";
...
RecordingViewModel ViewModel{ get; };
...

// MainPage.h
// Add this property and this field:
...
#include "RecordingViewModel.h"
...
    Quickstart::RecordingViewModel ViewModel();

private:
    Quickstart::RecordingViewModel m_viewModel{ nullptr };
...

// MainPage.cpp
// Implement like this:
...
MainPage::MainPage()
{
    InitializeComponent();
    m_viewModel = winrt::make<RecordingViewModel>();
}
Quickstart::RecordingViewModel MainPage::ViewModel()
{
    return m_viewModel;
}
...
// MainPage.h
...
#include "Recording.h"

namespace Quickstart
{
    public ref class MainPage sealed
    {
    private:
        RecordingViewModel ^ viewModel;
    public:
        MainPage();

        property RecordingViewModel^ ViewModel
        {
            RecordingViewModel^ get() { return this->viewModel; };
        }
    };
}

// MainPage.cpp
...
MainPage::MainPage()
{
    InitializeComponent();
    this->viewModel = ref new RecordingViewModel();
}

Der letzte Codeteil ist das Binden eines TextBlock an die ViewModel.DefaultRecording.OneLiner-Eigenschaft.The last piece is to bind a TextBlock to the ViewModel.DefaultRecording.OneLiner property.

<Page x:Class="Quickstart.MainPage" ... >
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
    HorizontalAlignment="Center"
    VerticalAlignment="Center"/>
    </Grid>
</Page>

Wenn Sie C++/WinRTverwenden, müssen Sie die MainPage:: ClickHandler -Funktion entfernen, damit das Projekt erstellt werden kann.If you're using C++/WinRT, then you'll need to remove the MainPage::ClickHandler function in order for the project to build.

Dies ist das Ergebnis.Here's the result.

Binden eines Textblocks

Binden an eine Sammlung von ElementenBinding to a collection of items

Ein häufiges Szenario ist das Binden an eine Sammlung von Geschäftsobjekten.A common scenario is to bind to a collection of business objects. In C# und Visual Basic stellt die generische ObservableCollection<T> -Klasse eine gute Wahl für die Datenbindung bei Sammlungen dar, da sie die INotifyPropertyChanged-Schnittstelle und die INotifyCollectionChanged-Schnittstelle implementiert.In C# and Visual Basic, the generic ObservableCollection<T> class is a good collection choice for data binding, because it implements the INotifyPropertyChanged and INotifyCollectionChanged interfaces. Diese Schnittstellen bieten eine Änderungsbenachrichtigung für Bindungen, wenn Elemente hinzugefügt oder entfernt werden oder eine Eigenschaft der Liste selbst geändert wird.These interfaces provide change notification to bindings when items are added or removed or a property of the list itself changes. Wenn Ihre gebundenen Steuerelemente bei Änderungen an Eigenschaften von Objekten in der Sammlung aktualisiert werden sollen, muss das Geschäftsobjekt auch INotifyPropertyChanged implementieren.If you want your bound controls to update with changes to properties of objects in the collection, the business object should also implement INotifyPropertyChanged. Weitere Informationen finden Sie unter Datenbindung im Detail.For more info, see Data binding in depth.

Wenn Sie C++/WinRTverwenden, können Sie weitere Informationen zum Binden an eine Observable-Auflistung in XAML-Element Steuerelementen und zum Binden C++an eine/WinRT-Auflistung erhalten.If you're using C++/WinRT, then you can learn more about binding to an observable collection in XAML items controls; bind to a C++/WinRT collection. Wenn Sie dieses Thema zuerst lesen, ist der Zweck der unten C++gezeigten/WinRT-Code Auflistung klarer.If you read that topic first, then the intent of the C++/WinRT code listing shown below will be clearer.

In diesem nächsten Beispiel wird eine ListView an eine Sammlung von Recording-Objekten gebunden.This next example binds a ListView to a collection of Recording objects. Beginnen wir, indem wir die Sammlung zum Ansichtsmodell hinzufügen.Let's start by adding the collection to our view model. Fügen Sie einfach diese neuen Member zur RecordingViewModel-Klasse hinzu.Just add these new members to the RecordingViewModel class.

public class RecordingViewModel
{
    ...
    private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
    public ObservableCollection<Recording> Recordings{ get{ return this.recordings; } }
    public RecordingViewModel()
    {
        this.recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
            CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
        this.recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
            CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
        this.recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
            CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
    }
}
// RecordingViewModel.idl
// Add this property:
...
#include <winrt/Windows.Foundation.Collections.h>
...
Windows.Foundation.Collections.IVector<IInspectable> Recordings{ get; };
...

// RecordingViewModel.h
// Change the constructor declaration, and add this property and this field:
...
    RecordingViewModel();
    Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> Recordings();

private:
    Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> m_recordings;
...

// RecordingViewModel.cpp
// Update/add implementations like this:
...
RecordingViewModel::RecordingViewModel()
{
    std::vector<Windows::Foundation::IInspectable> recordings;

    Windows::Globalization::Calendar releaseDateTime;
    releaseDateTime.Month(7); releaseDateTime.Day(8); releaseDateTime.Year(1748);
    recordings.push_back(winrt::make<Recording>(L"Johann Sebastian Bach", L"Mass in B minor", releaseDateTime));

    releaseDateTime = Windows::Globalization::Calendar{};
    releaseDateTime.Month(11); releaseDateTime.Day(2); releaseDateTime.Year(1805);
    recordings.push_back(winrt::make<Recording>(L"Ludwig van Beethoven", L"Third Symphony", releaseDateTime));

    releaseDateTime = Windows::Globalization::Calendar{};
    releaseDateTime.Month(3); releaseDateTime.Day(12); releaseDateTime.Year(1737);
    recordings.push_back(winrt::make<Recording>(L"George Frideric Handel", L"Serse", releaseDateTime));

    m_recordings = winrt::single_threaded_observable_vector<Windows::Foundation::IInspectable>(std::move(recordings));
}

Windows::Foundation::Collections::IVector<Windows::Foundation::IInspectable> RecordingViewModel::Recordings() { return m_recordings; }
...
// Recording.h
...
public ref class RecordingViewModel sealed
{
private:
    ...
    Windows::Foundation::Collections::IVector<Recording^>^ recordings;
public:
    RecordingViewModel()
    {
        ...
        releaseDateTime = ref new Windows::Globalization::Calendar();
        releaseDateTime->Year = 1748;
        releaseDateTime->Month = 7;
        releaseDateTime->Day = 8;
        Recording^ recording = ref new Recording{ L"Johann Sebastian Bach", L"Mass in B minor", releaseDateTime };
        this->Recordings->Append(recording);
        releaseDateTime = ref new Windows::Globalization::Calendar();
        releaseDateTime->Year = 1805;
        releaseDateTime->Month = 2;
        releaseDateTime->Day = 11;
        recording = ref new Recording{ L"Ludwig van Beethoven", L"Third Symphony", releaseDateTime };
        this->Recordings->Append(recording);
        releaseDateTime = ref new Windows::Globalization::Calendar();
        releaseDateTime->Year = 1737;
        releaseDateTime->Month = 12;
        releaseDateTime->Day = 3;
        recording = ref new Recording{ L"George Frideric Handel", L"Serse", releaseDateTime };
        this->Recordings->Append(recording);
    }
    ...
    property Windows::Foundation::Collections::IVector<Recording^>^ Recordings
    {
        Windows::Foundation::Collections::IVector<Recording^>^ get()
        {
            if (this->recordings == nullptr)
            {
                this->recordings = ref new Platform::Collections::Vector<Recording^>();
            }
            return this->recordings;
        };
    }
};

Binden Sie dann eine ListView an die ViewModel.Recordings-Eigenschaft.And then bind a ListView to the ViewModel.Recordings property.

<Page x:Class="Quickstart.MainPage" ... >
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView ItemsSource="{x:Bind ViewModel.Recordings}"
        HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Page>

Wir haben noch keine Datenvorlage für die Recording-Klasse bereitgestellt. Daher kann das Benutzeroberflächenframework nur ToString für jedes Element in der ListView aufrufen.We haven't yet provided a data template for the Recording class, so the best the UI framework can do is to call ToString for each item in the ListView. Die Standardimplementierung von ToString ist die Rückgabe des Typnamens.The default implementation of ToString is to return the type name.

Binden einer Listenansicht

Um dieses Problem zu beheben, können Sie entweder "$ String " außer Kraft setzen, um den Wert von " onelinesenummary" zurückzugeben, oder Sie können eine Daten Vorlage angeben.To remedy this, we can either override ToString to return the value of OneLineSummary, or we can provide a data template. Die Option Daten Vorlage ist eine übliche Lösung und eine flexiblere Lösung.The data template option is a more usual solution, and a more flexible one. Sie legen eine Datenvorlage mithilfe der ContentTemplate-Eigenschaft eines Inhaltssteuerelements oder mit der ItemTemplate-Eigenschaft eines Elementsteuerelements fest.You specify a data template by using the ContentTemplate property of a content control or the ItemTemplate property of an items control. Nachfolgend sind zwei Möglichkeiten zum Entwerfen einer Datenvorlage für Recording dargestellt, zusammen mit einer Abbildung des Ergebnisses.Here are two ways we could design a data template for Recording together with an illustration of the result.

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <TextBlock Text="{x:Bind OneLineSummary}"/>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Binden einer Listenansicht

<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="local:Recording">
            <StackPanel Orientation="Horizontal" Margin="6">
                <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                <StackPanel>
                    <TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
                    <TextBlock Text="{x:Bind CompositionName}"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Binden einer Listenansicht

Weitere Informationen zur XAML-Syntax finden Sie unter Erstellen einer Benutzeroberfläche mit XAML.For more information about XAML syntax, see Create a UI with XAML. Weitere Informationen zum Steuerelementlayout finden Sie unter Definieren von Layouts mit XAML.For more information about control layout, see Define layouts with XAML.

Hinzufügen einer DetailansichtAdding a details view

Sie können auch alle Details der Recording-Objekte in ListView-Elementen anzeigen.You can choose to display all the details of Recording objects in ListView items. Dies nimmt jedoch sehr viel Platz in Anspruch.But that takes up a lot of space. Stattdessen können Sie gerade so viele Daten im Element anzeigen, um es zu identifizieren, und wenn der Benutzer dann eine Auswahl vornimmt, können Sie alle Details des ausgewählten Elements in einem separaten Teil der Benutzeroberfläche anzeigen, der als „Detailansicht“ bezeichnet wird.Instead, you can show just enough data in the item to identify it and then, when the user makes a selection, you can display all the details of the selected item in a separate piece of UI known as the details view. Diese Anordnung wird auch als „Haupt-/Detailansicht“ oder „Listen-/Detailansicht“ bezeichnet.This arrangement is also known as a master/details view, or a list/details view.

Sie haben zwei Möglichkeiten, dieses Verhalten zu implementieren.There are two ways to go about this. Sie können die Detailansicht an die SelectedItem-Eigenschaft der ListView binden.You can bind the details view to the SelectedItem property of the ListView. Oder Sie können eine CollectionViewSourceverwenden. in diesem Fall binden Sie sowohl die ListView -als auch die Detailansicht an die CollectionViewSource (dabei wird das aktuell ausgewählte Element für Sie übernommen).Or you can use a CollectionViewSource, in which case you bind both the ListView and the details view to the CollectionViewSource (doing so takes care of the currently-selected item for you). Beide Verfahren sind unten dargestellt, und beide weisen die gleichen Ergebnisse auf (in der Abbildung dargestellt).Both techniques are shown below, and they both give the same results (shown in the illustration).

Hinweis

Bisher haben wir in diesem Thema nur die {x:Bind}-Markuperweiterung verwendet. Die beiden weiter unten aufgeführten Methoden benötigen jedoch die flexiblere (aber weniger leistungsfähige) {Binding}-Markuperweiterung.So far in this topic we've only used the {x:Bind} markup extension, but both of the techniques we'll show below require the more flexible (but less performant) {Binding} markup extension.

Wenn Sie C++/WinRT oder Visual C++ Component Extensions (C++/CX) verwenden und dann die {Binding} -Markup Erweiterung verwenden, müssen Sie der Lauf Zeit Klasse, an die Sie binden möchten, das BindableAttribute -Attribut hinzufügen.If you're using C++/WinRT or Visual C++ component extensions (C++/CX) then, to use the {Binding} markup extension, you'll need to add the BindableAttribute attribute to any runtime class that you want to bind to. Um {x:Bind}verwenden zu können, benötigen Sie dieses Attribut nicht.To use {x:Bind}, you don't need that attribute.

Wichtig

Wenn Sie C++/WinRTverwenden, ist das BindableAttribute -Attribut verfügbar, wenn Sie die Windows SDK Version 10.0.17763.0 (Windows 10, Version 1809) oder höher installiert haben.If you're using C++/WinRT, then the BindableAttribute attribute is available if you've installed the Windows SDK version 10.0.17763.0 (Windows 10, version 1809), or later. Ohne dieses Attribut müssen Sie die icustompropertyprovider -Schnittstelle und die icustomproperty -Schnittstelle implementieren, um die {Binding} -Markup Erweiterung verwenden zu können.Without that attribute, you'll need to implement the ICustomPropertyProvider and ICustomProperty interfaces in order to be able to use the {Binding} markup extension.

Sehen wir uns zuerst die SelectedItem-Methode an.First, here's the SelectedItem technique.

// No code changes necessary for C#.
// Recording.idl
// Add this attribute:
...
[Windows.UI.Xaml.Data.Bindable]
runtimeclass Recording
...
[Windows::UI::Xaml::Data::Bindable]
public ref class Recording sealed
{
    ...
};

Darüber hinaus muss nur noch eine Änderung am Markup vorgenommen werden.The only other change necessary is to the markup.

<Page x:Class="Quickstart.MainPage" ... >
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="local:Recording">
                        <StackPanel Orientation="Horizontal" Margin="6">
                            <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                            <StackPanel>
                                <TextBlock Text="{x:Bind CompositionName}"/>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
            Margin="0,24,0,0">
                <TextBlock Text="{Binding ArtistName}"/>
                <TextBlock Text="{Binding CompositionName}"/>
                <TextBlock Text="{Binding ReleaseDateTime}"/>
            </StackPanel>
        </StackPanel>
    </Grid>
</Page>

Fügen Sie für die CollectionViewSource-Methode zuerst eine CollectionViewSource als Seitenressource hinzu.For the CollectionViewSource technique, first add a CollectionViewSource as a page resource.

<Page.Resources>
    <CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Page.Resources>

Passen Sie dann die Bindungen in der ListView (die nicht mehr benannt werden muss) und in der Detailansicht so an, dass die CollectionViewSource verwendet wird.And then adjust the bindings on the ListView (which no longer needs to be named) and on the details view to use the CollectionViewSource. Beachten Sie, dass Sie durch die direkte Bindung der Detailansicht an die CollectionViewSource implizieren, dass Sie in Bindungen, in denen der Pfad in der Sammlung selbst nicht gefunden werden kann, an das aktuelle Element binden möchten.Note that by binding the details view directly to the CollectionViewSource, you're implying that you want to bind to the current item in bindings where the path cannot be found on the collection itself. Die CurrentItem-Eigenschaft muss nicht als Pfad für die Bindung angegeben werden, obwohl dies im Zweifelsfall möglich ist.There's no need to specify the CurrentItem property as the path for the binding, although you can do that if there's any ambiguity).

...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...

Nachfolgend ist das identische Ergebnis für die beiden Methoden dargestellt.And here's the identical result in each case.

Hinweis

Wenn Sie verwenden C++, sieht die Benutzeroberfläche nicht genau wie in der folgenden Abbildung aus: das Rendering der releasedatetime -Eigenschaft ist unterschiedlich.If you're using C++, then your UI won't look exactly like the illustration below: the rendering of the ReleaseDateTime property is different. Weitere Informationen hierzu finden Sie im folgenden Abschnitt.See the following section for more discussion of this.

Binden einer Listenansicht

Formatieren oder Konvertieren von Datenwerten für die AnzeigeFormatting or converting data values for display

Es liegt ein Problem mit dem obigen Rendering vor.There is an issue with the rendering above. Die releasedatetime -Eigenschaft ist nicht nur ein Datum, sondern ein DateTime -Wert (wenn Sie C++verwenden, ist es ein Kalender).The ReleaseDateTime property is not just a date, it's a DateTime (if you're using C++, then it's a Calendar). In C#wird Sie also mit mehr Genauigkeit angezeigt, als wir benötigen.So, in C#, it's being displayed with more precision than we need. C++ Und darin wird als Typname gerendert.And in C++ it's being rendered as a type name. Eine Lösung besteht darin, der Aufzeichnungs Klasse eine Zeichen folgen Eigenschaft hinzuzufügen, die das Äquivalent von this.ReleaseDateTime.ToString("d") zurückgibt.One solution is to add a string property to the Recording class that returns the equivalent of this.ReleaseDateTime.ToString("d"). Wenn Sie die Eigenschaft ReleaseDate benennen, geben Sie an, dass ein Datum und kein Datum und keine Uhrzeit zurückgegeben werden.Naming that property ReleaseDate would indicate that it returns a date, and not a date-and-time. Die Benennung als ReleaseDateAsString gibt dann auch noch an, dass sie eine Zeichenfolge zurückgibt.Naming it ReleaseDateAsString would further indicate that it returns a string.

Eine flexiblere Lösung ist die Verwendung eines so genannten „Wertkonverters“.A more flexible solution is to use something known as a value converter. Nachfolgend ist ein Beispiel zum Erstellen Ihres eigenen Wertkonverter aufgeführt.Here's an example of how to author your own value converter. Wenn Sie verwenden C#, fügen Sie den folgenden Code zu ihrer Recording.cs-Quell Code Datei hinzu.If you're using C#, then add the code below to your Recording.cs source code file. Wenn Sie/WinRT verwenden C++, fügen Sie dem Projekt ein neues (. idl-) Element (. idl) hinzu, das wie im C++folgenden Beispiel gezeigt wird. Erstellen Sie das Projekt, um StringFormatter.h zu generieren, und .cpp, fügen Sie die Dateien dem Projekt hinzu, und fügen Sie dann das Code Auflistungen.If you're using C++/WinRT, then add a new Midl File (.idl) item to the project, named as shown in the C++/WinRT code example listing below, build the project to generate StringFormatter.h and .cpp, add those files to your project, and then paste the code listings into them. Fügen Sie auch #include "StringFormatter.h" zu MainPage.h hinzu.Also add #include "StringFormatter.h" to MainPage.h.

public class StringFormatter : Windows.UI.Xaml.Data.IValueConverter
{
    // This converts the value object to the string to display.
    // This will work with most simple types.
    public object Convert(object value, Type targetType,
        object parameter, string language)
    {
        // Retrieve the format string and use it to format the value.
        string formatString = parameter as string;
        if (!string.IsNullOrEmpty(formatString))
        {
            return string.Format(formatString, value);
        }

        // If the format string is null or empty, simply
        // call ToString() on the value.
        return value.ToString();
    }

    // No need to implement converting back on a one-way binding
    public object ConvertBack(object value, Type targetType,
        object parameter, string language)
    {
        throw new NotImplementedException();
    }
}
// StringFormatter.idl
namespace Quickstart
{
    runtimeclass StringFormatter : [default] Windows.UI.Xaml.Data.IValueConverter
    {
        StringFormatter();
    }
}

// StringFormatter.h
#pragma once

#include "StringFormatter.g.h"
#include <sstream>

namespace winrt::Quickstart::implementation
{
    struct StringFormatter : StringFormatterT<StringFormatter>
    {
        StringFormatter() = default;

        Windows::Foundation::IInspectable Convert(Windows::Foundation::IInspectable const& value, Windows::UI::Xaml::Interop::TypeName const& targetType, Windows::Foundation::IInspectable const& parameter, hstring const& language);
        Windows::Foundation::IInspectable ConvertBack(Windows::Foundation::IInspectable const& value, Windows::UI::Xaml::Interop::TypeName const& targetType, Windows::Foundation::IInspectable const& parameter, hstring const& language);
    };
}

namespace winrt::Quickstart::factory_implementation
{
    struct StringFormatter : StringFormatterT<StringFormatter, implementation::StringFormatter>
    {
    };
}

// StringFormatter.cpp
#include "pch.h"
#include "StringFormatter.h"
#include "StringFormatter.g.cpp"

namespace winrt::Quickstart::implementation
{
    Windows::Foundation::IInspectable StringFormatter::Convert(Windows::Foundation::IInspectable const& value, Windows::UI::Xaml::Interop::TypeName const& /* targetType */, Windows::Foundation::IInspectable const& /* parameter */, hstring const& /* language */)
    {
        // Retrieve the value as a Calendar.
        Windows::Globalization::Calendar valueAsCalendar{ value.as<Windows::Globalization::Calendar>() };

        std::wstringstream wstringstream;
        wstringstream << L"Released: ";
        wstringstream << valueAsCalendar.MonthAsNumericString().c_str();
        wstringstream << L"/" << valueAsCalendar.DayAsString().c_str();
        wstringstream << L"/" << valueAsCalendar.YearAsString().c_str();
        return winrt::box_value(hstring{ wstringstream.str().c_str() });
    }

    Windows::Foundation::IInspectable StringFormatter::ConvertBack(Windows::Foundation::IInspectable const& /* value */, Windows::UI::Xaml::Interop::TypeName const& /* targetType */, Windows::Foundation::IInspectable const& /* parameter */, hstring const& /* language */)
    {
        throw hresult_not_implemented();
    }
}
...
public ref class StringFormatter sealed : Windows::UI::Xaml::Data::IValueConverter
{
public:
    virtual Platform::Object^ Convert(Platform::Object^ value, TypeName targetType, Platform::Object^ parameter, Platform::String^ language)
    {
        // Retrieve the value as a Calendar.
        Windows::Globalization::Calendar^ valueAsCalendar = dynamic_cast<Windows::Globalization::Calendar^>(value);

        std::wstringstream wstringstream;
        wstringstream << L"Released: ";
        wstringstream << valueAsCalendar->MonthAsNumericString()->Data();
        wstringstream << L"/" << valueAsCalendar->DayAsString()->Data();
        wstringstream << L"/" << valueAsCalendar->YearAsString()->Data();
        return ref new Platform::String(wstringstream.str().c_str());
    }

    // No need to implement converting back on a one-way binding
    virtual Platform::Object^ ConvertBack(Platform::Object^ value, TypeName targetType, Platform::Object^ parameter, Platform::String^ language)
    {
        throw ref new Platform::NotImplementedException();
    }
};
...

Hinweis

Für das C++obige/WinRT-Codelisting in StringFormatter.idl verwenden wir das default-Attribut , um IValueConverter als Standardschnittstelle zu deklarieren.For the C++/WinRT code listing above, in StringFormatter.idl, we use the default attribute to declare IValueConverter as the default interface. In der Auflistung hat stringformatter nur einen Konstruktor und keine Methoden, sodass keine Standardschnittstelle für Sie generiert wird.In the listing, StringFormatter has only a constructor, and no methods, so no default interface is generated for it. Das default-Attribut ist optimal, wenn Sie stringformatterkeine Instanzmember hinzufügen, da keine QueryInterface erforderlich ist, um die IValueConverter -Methoden aufzurufen.The default attribute is optimal if you won't be adding instance members to StringFormatter, because no QueryInterface will be required to call the IValueConverter methods. Alternativ dazu können Sie eine standardmäßige istringformatter -Schnittstelle zur Generierung auffordern. dazu können Sie die Lauf Zeit Klasse selbst mit dem default_interface- Attributversehen.Alternatively, you can prompt a default IStringFormatter interface to be generated, and you do that by annotating the runtime class itself with the default_interface attribute. Diese Option ist optimal, wenn Sie stringformatter Instanzmember hinzufügen, die häufiger als die Methoden von IValueConverter aufgerufen werden, da keine QueryInterface erforderlich ist, um die Instanzmember aufzurufen.That option is optimal if you add instance members to StringFormatter that are called more often than the methods of IValueConverter are, because then no QueryInterface will be required to call the instance members.

Nun können wir eine Instanz von stringformatter als Seiten Ressource hinzufügen und Sie in der Bindung des TextBlock -Objekts verwenden, das die releasedatetime -Eigenschaft anzeigt.Now we can add an instance of StringFormatter as a page resource and use it in the binding of the TextBlock that displays the ReleaseDateTime property.

<Page.Resources>
    <local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Page.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
    Converter={StaticResource StringFormatterValueConverter},
    ConverterParameter=Released: \{0:d\}}"/>
...

Wie Sie oben sehen können, verwenden wir für die Formatierungs Flexibilität das Markup, um eine Format Zeichenfolge mithilfe des konverterparameters in den Konverter zu übergeben.As you can see above, for formatting flexibility we use the markup to pass a format string into the converter by way of the converter parameter. In den in diesem Thema gezeigten Codebeispielen verwendet nur der C# Wert Konverter diesen Parameter.In the code examples shown in this topic, only the C# value converter makes use of that parameter. Sie könnten jedoch problemlos eine C++Format Zeichenfolge im Format als Konverterparameter übergeben und diese in ihrem Wert Konverter mit einer Formatierungsfunktion wie wprintf oder tauprintfverwenden.But you could easily pass a C++-style format string as the converter parameter, and use that in your value converter with a formatting function such as wprintf or swprintf.

Dies ist das Ergebnis.Here's the result.

Anzeigen eines Datums mit benutzerdefinierter Formatierung

Hinweis

Ab Windows 10, Version 1607, bietet das XAML-Framework einen integrierten booleschen-to-Visibility-Konverter.Starting in Windows 10, version 1607, the XAML framework provides a built-in Boolean-to-Visibility converter. Der Konverter ordnet dem Visibility. Visible -Enumerationswert den Wert true zu, und die Sichtbarkeit ist auf " false ". reduziert, sodass Sie eine Sichtbarkeit an einen booleschen Wert binden können, ohne einen KonverterThe converter maps true to the Visibility.Visible enumeration value and false to Visibility.Collapsed so you can bind a Visibility property to a Boolean without creating a converter. Für die Verwendung des integrierten Konverters muss die SDK-Zielversion der App mindestens 14393 lauten.To use the built in converter, your app's minimum target SDK version must be 14393 or later. Die Verwendung ist nicht möglich, wenn Ihre App für frühere Versionen von Windows 10 bestimmt ist.You can't use it when your app targets earlier versions of Windows 10. Weitere Informationen zu Ziel Versionen finden Sie unter Version-Adaptive Code.For more info about target versions, see Version-adaptive code.

Siehe auchSee also