Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Cette rubrique vous montre comment lier un contrôle (ou un autre élément d’interface utilisateur) à un seul élément ou lier un contrôle d’éléments à une collection d’éléments dans une application de plateforme Windows universelle (UWP). En outre, nous montrons comment contrôler le rendu des éléments, implémenter une vue de détails basée sur une sélection et convertir des données pour l’affichage. Pour plus d’informations, consultez liaison de données approfondie.
Conditions préalables
Cette rubrique part du principe que vous savez comment créer une application UWP de base. Pour obtenir des instructions sur la création de votre première application UWP, consultez Prise en main des applications Windows.
Créer le projet
Créez un nouveau projet Application Vide (Windows Universal). Nommez-le « Démarrage rapide ».
Liaison à un seul élément
Chaque liaison se compose d’une cible de liaison et d’une source de liaison. En règle générale, la cible est une propriété d’un contrôle ou d’un autre élément d’interface utilisateur, et la source est une propriété d’une instance de classe (un modèle de données ou un modèle de vue). Cet exemple montre comment lier un contrôle à un seul élément. La cible est la propriété Texte d'un BlocTexte. La source est une instance d’une classe simple nommée Recording qui représente un enregistrement audio. Examinons d’abord la classe.
Si vous utilisez C# ou C++/CX, ajoutez une nouvelle classe à votre projet et nommez la classe Recording.
Si vous utilisez C++/WinRT, ajoutez de nouveaux fichier Midl (.idl) éléments au projet, nommés comme indiqué dans l’exemple de code C++/WinRT ci-dessous. Remplacez le contenu de ces nouveaux fichiers par le code MIDL 3.0 affiché dans la liste, générez le projet pour générer Recording.h
et .cpp
et RecordingViewModel.h
et .cpp
, puis ajoutez du code aux fichiers générés pour qu’ils correspondent à la liste. Pour plus d’informations sur ces fichiers générés et sur la façon de les copier dans votre projet, consultez contrôles XAML ; liez à une propriété C++/WinRT.
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"
Ensuite, exposez la classe source de liaison depuis la classe qui représente votre page de balisage. Pour cela, nous ajoutons une propriété de type RecordingViewModel à MainPage .
Si vous utilisez C++/WinRT, commencez par mettre à jour MainPage.idl
. Générez le projet pour régénérer MainPage.h
et .cpp
, puis fusionnez les modifications apportées aux fichiers générés dans ceux de votre projet.
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();
}
Le dernier élément consiste à lier un TextBlock
<Page x:Class="Quickstart.MainPage" ... >
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Page>
Si vous utilisez C++/WinRT, vous devez supprimer la fonction MainPage::ClickHandler pour que le projet soit généré.
Voici le résultat.
Liaison à une collection d’éléments
Un scénario courant consiste à établir une liaison à une collection d’objets métier. En C# et Visual Basic, la classe générique ObservableCollection<T> est un excellent choix de collection de données pour la liaison de données, car elle implémente les interfaces INotifyPropertyChanged et INotifyCollectionChanged. Ces interfaces fournissent une notification de modification aux liaisons lorsque des éléments sont ajoutés ou supprimés ou qu’une propriété de la liste elle-même change. Si vous souhaitez que vos contrôles liés soient mis à jour avec des modifications apportées aux propriétés des objets de la collection, l’objet métier doit également implémenter INotifyPropertyChanged. Pour plus d’informations, consultez liaison de données en profondeur.
Si vous utilisez C++/WinRT, vous pouvez en savoir plus sur la liaison à une collection observable dans contrôles d’éléments XAML ; liez à une collection C++/WinRT. Si vous lisez d’abord cette rubrique, l’intention de la liste de code C++/WinRT indiquée ci-dessous sera plus claire.
Cet exemple suivant lie une ListView à une collection d’objets Recording
. Commençons par ajouter la collection à notre modèle d’affichage. Ajoutez simplement ces nouveaux membres à la classe RecordingViewModel.
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;
};
}
};
Ensuite, liez une ListView à la propriété ViewModel.Recordings.
<Page x:Class="Quickstart.MainPage" ... >
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Page>
Nous n'avons pas encore fourni de modèle de données pour la classe Recording, donc le meilleur que le cadre de l'interface utilisateur puisse faire est d'appeler ToString pour chaque élément du ListView . L’implémentation par défaut de ToString consiste à retourner le nom du type.
Pour résoudre ce problème, nous pouvons remplacer ToString pour retourner la valeur de OneLineSummary, ou nous pouvons fournir un modèle de données. L’option de modèle de données est une solution plus habituelle et une solution plus flexible. Vous spécifiez un modèle de données à l’aide de la propriété ContentTemplate d’un contrôle de contenu ou de la propriété ItemTemplate d’un contrôle d’éléments. Voici deux façons de concevoir un modèle de données pour Enregistrement avec une illustration du résultat.
<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>
<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>
Pour plus d’informations sur la syntaxe XAML, consultez Créer une interface utilisateur avec xaml. Pour plus d’informations sur la mise en page des contrôles, consultez Définir les mises en page avec XAML.
Ajout d’une vue de détails
Vous pouvez choisir d’afficher tous les détails des objets Recording dans les éléments de la vue Liste . Mais cela occupe beaucoup d’espace. Au lieu de cela, vous pouvez afficher suffisamment de données dans l’élément pour l’identifier, puis, lorsque l’utilisateur effectue une sélection, vous pouvez afficher tous les détails de l’élément sélectionné dans un élément distinct de l’interface utilisateur appelée vue détails. Cette disposition est également appelée vue maître/détails, ou vue liste/détails.
Il y a deux façons de procéder. Vous pouvez lier l'affichage des détails à la propriété SelectedItem de la ListView . Vous pouvez également utiliser un CollectionViewSource, auquel cas vous liez à la fois les ListView et l’affichage des détails à l'CollectionViewSource (cela prend en charge l’élément actuellement sélectionné pour vous). Les deux techniques sont présentées ci-dessous, et elles donnent tous les deux les mêmes résultats (illustrés dans l’illustration).
Remarque
Jusqu’à présent dans cette rubrique, nous n’avons utilisé que l’extension de balisage {x :Bind}, mais les deux techniques que nous allons montrer ci-dessous nécessitent l’extension de balisage plus flexible (mais moins performante) l’extension de balisage {Binding}.
Si vous utilisez des extensions de composant C++/WinRT ou Visual C++ (C++/CX), pour utiliser l’extension de balisage {Binding}, vous devez ajouter l’attribut BindableAttribute à n’importe quelle classe runtime à laquelle vous souhaitez établir une liaison. Pour utiliser {x :Bind}, vous n’avez pas besoin de cet attribut.
Important
Si vous utilisez C++/WinRT, l’attribut BindableAttribute est disponible si vous avez installé le Kit de développement logiciel (SDK) Windows version 10.0.17763.0 (Windows 10, version 1809) ou version ultérieure. Sans cet attribut, vous devrez implémenter les interfaces ICustomPropertyProvider et ICustomProperty pour pouvoir utiliser l'extension de balisage {Binding}.
Tout d’abord, voici la technique ÉlémentSélectionné.
// 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
{
...
};
La seule autre modification nécessaire est celle du balisage.
<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>
Pour la technique CollectionViewSource, commencez par ajouter un CollectionViewSource en tant que ressource de page.
<Page.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Page.Resources>
Ensuite, ajustez les liaisons sur la ListView (qui n’a plus besoin d’être nommée) et sur la vue des détails pour utiliser la CollectionViewSource . Notez que, en liant la vue détails directement à la CollectionViewSource, vous impliquez que vous souhaitez lier à l'élément actuel dans les liens où le chemin d'accès à cet élément est introuvable dans la collection elle-même. Il n’est pas nécessaire de spécifier la propriété CurrentItem comme chemin d’accès de la liaison, bien que vous puissiez le faire en cas d’ambiguïté).
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
Et voici le résultat identique dans chaque cas.
Remarque
Si vous utilisez C++, votre interface utilisateur ne ressemble pas exactement à l’illustration ci-dessous : le rendu de la propriété ReleaseDateTime est différent. Pour plus d’informations sur ce sujet, consultez la section suivante.
Mise en forme ou conversion de valeurs de données pour l’affichage
Il existe un problème avec le rendu ci-dessus. La propriété ReleaseDateTime n’est pas simplement une date, c’est un DateTime (si vous utilisez C++, c’est un Calendar ). Donc, en C#, il est affiché avec plus de précision que nous n’en avons besoin. En C++, il est rendu sous la forme d’un nom de type. Une solution consiste à ajouter une propriété de chaîne à la classe Recording qui retourne l’équivalent de this.ReleaseDateTime.ToString("d")
. Le nommage de cette propriété ReleaseDate indiquerait qu’elle retourne une date et non une date et une heure. Nommer cela ReleaseDateAsString indiquerait davantage qu'il retourne une chaîne.
Une solution plus flexible consiste à utiliser quelque chose appelé convertisseur de valeur. Voici un exemple de création de votre propre convertisseur de valeur. Si vous utilisez C#, ajoutez le code ci-dessous à votre fichier de code source Recording.cs
. Si vous utilisez C++/WinRT, ajoutez un nouvel élément Fichier Midl (.idl) au projet, nommé comme dans l'exemple de code indiqué ci-dessous pour le C++/WinRT, générez le projet pour produire StringFormatter.h
et .cpp
, ajoutez ces fichiers à votre projet, puis collez-y les extraits de code. Ajoutez également #include "StringFormatter.h"
à 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();
}
}
// pch.h
...
#include <winrt/Windows.Globalization.h>
// 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();
}
};
...
Remarque
Pour la liste de codes C++/WinRT ci-dessus, dans StringFormatter.idl
, nous utilisons l’attribut par défaut pour déclarer IValueConverter comme interface par défaut. Dans la liste, StringFormatter n’a qu’un constructeur et aucune méthode, donc aucune interface par défaut n’est générée pour elle. L’attribut default
est optimal si vous n’ajoutez pas de membres d’instance à StringFormatter, car aucune queryInterface n’est requise pour appeler les méthodes IValueConverter. Vous pouvez également inviter une interface IStringFormatter par défaut à générer, et cela en annotant la classe runtime elle-même avec l’attribut default_interface. Cette option est optimale si vous ajoutez des membres d’instance à StringFormatter qui sont appelés plus souvent que les méthodes de IValueConverter, car aucune QueryInterface ne sera nécessaire pour appeler les membres d’instance.
Maintenant, nous pouvons ajouter une instance de StringFormatter en tant que ressource de page et l’utiliser dans la liaison du TextBlock qui affiche la propriété ReleaseDateTime.
<Page.Resources>
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Page.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
Comme vous pouvez le voir ci-dessus, pour la flexibilité de mise en forme, nous utilisons le balisage pour passer une chaîne de format dans le convertisseur à l’aide du paramètre de convertisseur. Dans les exemples de code présentés dans cette rubrique, seul le convertisseur de valeurs C# utilise ce paramètre. Toutefois, vous pouvez facilement passer une chaîne de format C++en tant que paramètre de convertisseur et l’utiliser dans votre convertisseur de valeurs avec une fonction de mise en forme telle que wprintf ou swprintf.
Voici le résultat.
Remarque
À compter de Windows 10, version 1607, l’infrastructure XAML fournit un convertisseur booléen-à-visibilité intégré. Le convertisseur mappe true à la valeur d'énumération Visibility.Visible et false à Visibility.Collapsed pour que vous puissiez lier une propriété Visibility à un booléen sans créer de convertisseur. Pour utiliser le convertisseur intégré, la version minimale du SDK cible de votre application doit être 14393 ou ultérieure. Vous ne pouvez pas l’utiliser lorsque votre application cible des versions antérieures de Windows 10. Pour plus d’informations sur les versions cibles, consultez code adaptatif version.