Remarque
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.
Important
Pour connaître les concepts et termes essentiels qui prennent en charge votre compréhension de l’utilisation et de la création de classes runtime avec C++/WinRT, consultez Consommer des API avec C++/WinRT et créer des API avec C++/WinRT.
L’une des fonctionnalités les plus puissantes de l’SDK d'application Windows est la flexibilité que la pile d’interface utilisateur fournit pour créer des contrôles personnalisés en fonction du type de contrôle XAML. L’infrastructure d’interface utilisateur XAML fournit des fonctionnalités telles que des propriétés de dépendance personnalisées et des propriétés jointes et des modèles de contrôle, ce qui facilite la création de contrôles riches en fonctionnalités et personnalisables. Cette rubrique vous guide tout au long des étapes de création d’un contrôle personnalisé (modèle) avec C++/WinRT.
Créer une application vide (BgLabelControlApp)
Commencez par créer un projet dans Microsoft Visual Studio. Créez une application vide empaquetée (WinUI 3 dans Desktop) pour un projet C++, définissez-lui le nom BgLabelControlApp et, afin que votre structure de dossiers corresponde à celle du guide pas à pas, assurez-vous que l’option Placer la solution et le projet dans le même répertoire est décochée. Ciblez la dernière version en disponibilité générale (c’est-à-dire non en préversion) du KIT DE développement logiciel (SDK) Windows.
Dans une section ultérieure de cette rubrique, vous serez dirigé vers la génération de votre projet (mais ne générez pas avant).
Note
Pour plus d’informations sur la configuration de Visual Studio pour le développement C++/WinRT, notamment l’installation et l’utilisation de l’extension de Visual Studio C++/WinRT (VSIX) et du package NuGet (qui fournissent ensemble un modèle de projet et une prise en charge de build), consultez Visual Studio prise en charge de C++/WinRT.
Nous allons créer une nouvelle classe pour représenter un contrôle personnalisé (modèle). Nous créons et consommons la classe dans la même unité de compilation. Mais nous voulons pouvoir instancier cette classe à partir du balisage XAML et, pour cette raison, il s’agit d’une classe runtime. Et nous allons utiliser C++/WinRT pour le créer et l’utiliser.
La première étape de la création d’une nouvelle classe runtime consiste à ajouter un nouvel élément Midl File (.idl) au projet. Nommez-le BgLabelControl.idl. Supprimez le contenu par défaut de BgLabelControl.idl, puis collez-le dans cette déclaration de classe runtime.
// BgLabelControl.idl
namespace BgLabelControlApp
{
runtimeclass BgLabelControl : Microsoft.UI.Xaml.Controls.Control
{
BgLabelControl();
static Microsoft.UI.Xaml.DependencyProperty LabelProperty{ get; };
String Label;
}
}
La liste ci-dessus montre le modèle que vous suivez lors de la déclaration d’une propriété de dépendance (DP). Il y a deux pièces pour chaque DP. Tout d’abord, vous déclarez une propriété statique en lecture seule de type DependencyProperty. Il porte le nom de votre DP, suivi de Property. Vous allez utiliser cette propriété statique dans votre implémentation. Ensuite, vous déclarez une propriété d’instance en lecture-écriture avec le type et le nom de votre DP. Si vous souhaitez créer une propriété jointe (plutôt qu’une dp), consultez les exemples de code dans les propriétés jointes personnalisées.
Note
Si vous souhaitez un DP avec un type à virgule flottante, faites-le double (Double dans MIDL 3.0). La déclaration et l'implémentation d'un DP de type float (Singledans MIDL), puis la définition d'une valeur pour ce DP dans le balisage XAML entraîne l'échec de la création d'un « Windows ». Foundation.Single » à partir du texte '<NUMBER>'.
Enregistrez le fichier. Le projet ne peut pas être généré jusqu’au bout pour le moment, mais le générer maintenant est utile, car cela crée les fichiers de code source dans lesquels vous implémenterez la classe d’exécution BgLabelControl. Allez-y et lancez maintenant la compilation (les erreurs de compilation auxquelles vous pouvez vous attendre à ce stade sont liées à un « symbole externe non résolu »).
Pendant le processus de génération, l’outil midl.exe est exécuté pour créer un fichier de métadonnées Windows Runtime (\BgLabelControlApp\Debug\BgLabelControlApp\Unmerged\BgLabelControl.winmd) décrivant la classe runtime. Ensuite, l’outil cppwinrt.exe est exécuté pour générer des fichiers de code source pour vous aider à créer et à consommer votre classe runtime. Ces fichiers incluent des stubs pour commencer à implémenter la classe runtime BgLabelControl que vous avez déclarée dans votre IDL. Ces stubs sont \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\BgLabelControl.h et BgLabelControl.cpp.
Copiez les fichiers stub BgLabelControl.h et BgLabelControl.cpp depuis \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\ dans le dossier du projet, à savoir \BgLabelControlApp\BgLabelControlApp\. Dans Explorateur de solutions, vérifiez que l’option Afficher tous les fichiers est activée. Cliquez avec le bouton droit sur les fichiers stub que vous avez copiés, puis cliquez sur Include Dans Project.
Vous verrez l’élément static_assert en haut de BgLabelControl.h et de BgLabelControl.cpp, que vous devrez supprimer. Maintenant, le projet va se compiler.
Implémenter la classe de contrôle personnalisé BgLabelControl
Maintenant, nous allons ouvrir \BgLabelControlApp\BgLabelControlApp\BgLabelControl.h et BgLabelControl.cpp implémenter notre classe runtime. Dans BgLabelControl.h, modifiez le constructeur pour définir la clé de style par défaut, implémentez Label etLabelProperty, ajoutez un gestionnaire d’événements statique nommé OnLabelChanged pour traiter les modifications apportées à la valeur de la propriété de dépendance et ajoutez un membre privé pour stocker le champ de stockage pour LabelProperty.
Après avoir ajouté ces éléments, votre BgLabelControl.h ressemble à ceci. Vous pouvez copier et coller cette liste de codes pour remplacer le contenu de BgLabelControl.h.
// BgLabelControl.h
#pragma once
#include "BgLabelControl.g.h"
namespace winrt::BgLabelControlApp::implementation
{
struct BgLabelControl : BgLabelControlT<BgLabelControl>
{
BgLabelControl() { DefaultStyleKey(winrt::box_value(L"BgLabelControlApp.BgLabelControl")); }
winrt::hstring Label()
{
return winrt::unbox_value<winrt::hstring>(GetValue(m_labelProperty));
}
void Label(winrt::hstring const& value)
{
SetValue(m_labelProperty, winrt::box_value(value));
}
static Microsoft::UI::Xaml::DependencyProperty LabelProperty() { return m_labelProperty; }
static void OnLabelChanged(Microsoft::UI::Xaml::DependencyObject const&, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const&);
private:
static Microsoft::UI::Xaml::DependencyProperty m_labelProperty;
};
}
namespace winrt::BgLabelControlApp::factory_implementation
{
struct BgLabelControl : BgLabelControlT<BgLabelControl, implementation::BgLabelControl>
{
};
}
Dans BgLabelControl.cpp, définissez les membres statiques comme ceci. Vous pouvez copier et coller cette liste de codes pour remplacer le contenu de BgLabelControl.cpp.
// BgLabelControl.cpp
#include "pch.h"
#include "BgLabelControl.h"
#include "BgLabelControl.g.cpp"
namespace winrt::BgLabelControlApp::implementation
{
Microsoft::UI::Xaml::DependencyProperty BgLabelControl::m_labelProperty =
Microsoft::UI::Xaml::DependencyProperty::Register(
L"Label",
winrt::xaml_typename<winrt::hstring>(),
winrt::xaml_typename<BgLabelControlApp::BgLabelControl>(),
Microsoft::UI::Xaml::PropertyMetadata{ winrt::box_value(L"default label"), Microsoft::UI::Xaml::PropertyChangedCallback{ &BgLabelControl::OnLabelChanged } }
);
void BgLabelControl::OnLabelChanged(Microsoft::UI::Xaml::DependencyObject const& d, Microsoft::UI::Xaml::DependencyPropertyChangedEventArgs const& /* e */)
{
if (BgLabelControlApp::BgLabelControl theControl{ d.try_as<BgLabelControlApp::BgLabelControl>() })
{
// Call members of the projected type via theControl.
BgLabelControlApp::implementation::BgLabelControl* ptr{ winrt::get_self<BgLabelControlApp::implementation::BgLabelControl>(theControl) };
// Call members of the implementation type via ptr.
}
}
}
Dans cette procédure pas à pas, nous n’utiliserons pas OnLabelChanged. Mais c’est là pour vous montrer comment enregistrer une propriété de dépendance avec un rappel appelé lors d’un changement de propriété. L’implémentation d’OnLabelChanged montre également comment obtenir un type projeté dérivé à partir d’un type projeté de base (le type projeté de base est DependencyObject, dans ce cas). Il montre comment obtenir ensuite un pointeur vers le type qui implémente le type projeté. Cette deuxième opération sera naturellement possible uniquement dans le projet qui implémente le type projeté (autrement dit, le projet qui implémente la classe runtime).
Note
Si vous n'avez pas installé le sdk Windows version 10.0.17763.0 (Windows 10, version 1809) ou ultérieure, vous devez appeler winrt ::from_abi dans le gestionnaire d'événements modifié de la propriété de dépendance ci-dessus, au lieu de winrt ::get_self.
Concevoir le style par défaut pour BgLabelControl
Dans son constructeur, BgLabelControl définit une clé de style par défaut pour elle-même. Mais qu’est-ce qu’un style par défaut ? Un contrôle personnalisé (modèle) doit avoir un style par défaut contenant un modèle de contrôle par défaut, qu’il peut utiliser pour s’afficher lui-même si le consommateur du contrôle ne définit pas de style et/ou de modèle. Dans cette section, nous allons ajouter un fichier de balisage au projet contenant notre style par défaut.
Vérifiez que Show All Files est toujours activé (dans Explorateur de solutions). Sous votre nœud de projet, créez un dossier (pas un filtre, mais un dossier) et nommez-le « Thèmes ». Sous Themes, ajoutez un nouvel élément de type Visual C++>XAML XAML>View, puis nommez-le « Generic.xaml ». Les noms de dossiers et de fichiers doivent être similaires pour que l’infrastructure XAML recherche le style par défaut d’un contrôle personnalisé. Supprimez le contenu par défaut de Generic.xaml, puis collez le balisage ci-dessous.
<!-- \Themes\Generic.xaml -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BgLabelControlApp">
<Style TargetType="local:BgLabelControl" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:BgLabelControl">
<Grid Width="100" Height="100" Background="{TemplateBinding Background}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Label}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Dans ce cas, la seule propriété que le style par défaut définit est le modèle de contrôle. Le modèle se compose d’un carré (dont l’arrière-plan est lié à la propriété Background que toutes les instances du type de contrôle XAML ont) et d’un élément de texte (dont le texte est lié à la propriété de dépendance BgLabelControl ::Label ).
Ajouter une instance de BgLabelControl à la page d’interface utilisateur principale
Ouvrez MainPage.xaml, qui contient le balisage XAML de notre page d’interface utilisateur principale. Immédiatement après l’élément Button (dans StackPanel), ajoutez le balisage suivant.
<local:BgLabelControl Background="Red" Label="Hello, World!"/>
Ajoutez également la directive include suivante à MainPage.h afin que le type MainPage (une combinaison de balisage XAML compilé et de code impératif) connaisse le type de contrôle personnalisé BgLabelControl. Si vous souhaitez utiliser BgLabelControl à partir d’une autre page XAML, ajoutez également cette même directive include au fichier d’en-tête de cette page. Sinon, placez simplement une directive include unique dans votre fichier d’en-tête précompilé.
// MainPage.h
...
#include "BgLabelControl.h"
...
Maintenant, compilez et exécutez le projet. Vous verrez que le modèle de contrôle par défaut est lié au pinceau d’arrière-plan, et à l’étiquette, de l’instance BgLabelControl dans le balisage.
Cette procédure pas à pas a montré un exemple simple de contrôle personnalisé (modèle) dans C++/WinRT. Vous pouvez créer vos propres contrôles personnalisés arbitrairement riches et complets. Par exemple, un contrôle personnalisé peut prendre la forme d’un élément aussi compliqué qu’une grille de données modifiable, un lecteur vidéo ou un visualiseur de géométrie 3D.
Implémentation de méthodes substituables , telles que MeasureOverride et OnApplyTemplate
Consultez la section Appel et substitution de votre type de base avec C++/WinRT.
API importantes
Rubriques connexes
Windows developer