Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Importante
Per concetti e termini essenziali che supportano la comprensione di come usare e creare classi di runtime con C++/WinRT, vedi Usare API con C++/WinRT e Creare API con C++/WinRT.
Una delle funzionalità più potenti del SDK per app di Windows è la flessibilità offerta dallo stack dell'interfaccia utente per creare controlli personalizzati in base al tipo di controllo XAML. Il framework dell'interfaccia utente XAML offre funzionalità quali proprietà di dipendenza personalizzate e proprietà associate e modelli di controllo, che semplificano la creazione di controlli avanzati e personalizzabili. Questo argomento illustra i passaggi per la creazione di un controllo personalizzato (basato su modelli) con C++/WinRT.
Creare un'applicazione vuota (BgLabelControlApp)
Per iniziare, crea un nuovo progetto in Microsoft Visual Studio. Creare un'app vuota, in pacchetto (WinUI 3 in Desktop) per il progetto C++, impostarne il nome su BgLabelControlApp e (in modo che la struttura di cartelle corrisponda alla procedura dettagliata) assicurarsi che l'opzione Inserisci soluzione e progetto nella stessa directory sia deselezionata. Scegliere come destinazione la versione più recente disponibile a livello generale (ovvero non di anteprima) di Windows SDK.
In una sezione successiva di questo argomento, ti verrà chiesto di compilare il progetto (ma non compilarlo fino ad allora).
Note
Per informazioni sulla configurazione di Visual Studio per lo sviluppo C++/WinRT, inclusa l'installazione e l'uso dell'estensione Visual Studio C++/WinRT (VSIX) e del pacchetto NuGet (che insieme forniscono il modello di progetto e il supporto per la compilazione), vedi Visual Studio supporto per C++/WinRT.
Verrà creata una nuova classe per rappresentare un controllo personalizzato (basato su modelli). Stiamo definendo e utilizzando la classe all'interno della stessa unità di compilazione. Ma vogliamo essere in grado di creare un'istanza di questa classe dal markup XAML e per questo motivo sarà una classe di runtime. E utilizzeremo C++/WinRT sia per svilupparlo che per utilizzarlo.
Il primo passaggio per la creazione di una nuova classe di runtime consiste nell'aggiungere un nuovo elemento Midl File (con estensione idl) al progetto. Chiamalo BgLabelControl.idl. Eliminare il contenuto predefinito di BgLabelControl.idl e incollare questa dichiarazione della classe di runtime.
// BgLabelControl.idl
namespace BgLabelControlApp
{
runtimeclass BgLabelControl : Microsoft.UI.Xaml.Controls.Control
{
BgLabelControl();
static Microsoft.UI.Xaml.DependencyProperty LabelProperty{ get; };
String Label;
}
}
L'elenco precedente mostra il pattern che segui quando dichiari una proprietà di dipendenza (DP). Esistono due parti per ogni DP. In primo luogo, si dichiara una proprietà statica di sola lettura di tipo DependencyProperty. Ha il nome del tuo DP più Property. Questa proprietà statica verrà usata nell'implementazione. In secondo luogo, si dichiara una proprietà di istanza di lettura e scrittura con il tipo e il nome del DP. Se si vuole creare una proprietà associata (anziché un dp), vedere gli esempi di codice in Proprietà associate personalizzate.
Note
Se si desidera un DP di tipo a virgola mobile, impostalo su double (Double in MIDL 3.0). La dichiarazione e l'implementazione di un dp di tipo float (Single in MIDL) e quindi l'impostazione di un valore per tale dp nel markup XAML genera l'errore Non è stato possibile creare un 'Windows. Foundation.Single' dal testo '<NUMBER>'.
Salva il file. Al momento la compilazione del progetto non può essere completata, ma compilarlo ora è comunque utile perché genera i file di codice sorgente nei quali verrà implementata la classe di runtime BgLabelControl. Quindi procedi pure con la compilazione ora (gli errori di compilazione che puoi aspettarti in questa fase riguardano un "simbolo esterno non risolto").
Durante il processo di compilazione, lo midl.exe strumento viene eseguito per creare un file di metadati Windows Runtime (\BgLabelControlApp\Debug\BgLabelControlApp\Unmerged\BgLabelControl.winmd) che descrive la classe di runtime. Viene quindi eseguito lo strumento cppwinrt.exe per generare i file di codice sorgente che consentono di scrivere e utilizzare la classe di runtime. Questi file includono stub per iniziare a implementare la classe di runtime BgLabelControl dichiarata nel file IDL. Questi stub sono \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\BgLabelControl.h e BgLabelControl.cpp.
Copiare i file BgLabelControl.h stub e BgLabelControl.cpp da \BgLabelControlApp\BgLabelControlApp\Generated Files\sources\ nella cartella del progetto, ovvero \BgLabelControlApp\BgLabelControlApp\. In Esplora soluzioni, assicurarsi che Mostra tutti i file sia attivato. Fare clic con il pulsante destro del mouse sui file stub copiati e scegliere Include In Project.
Vedrai un static_assert in alto in BgLabelControl.h e BgLabelControl.cpp, che dovrai rimuovere. A questo momento il progetto verrà compilato.
Implementare la classe di controllo personalizzato BgLabelControl
Ora, apriamo \BgLabelControlApp\BgLabelControlApp\BgLabelControl.h e BgLabelControl.cpp e implementiamo la nostra classe runtime. In BgLabelControl.hmodificare il costruttore per impostare la chiave di stile predefinita, implementare Label e LabelProperty, aggiungere un gestore eventi statico denominato OnLabelChanged per elaborare le modifiche al valore della proprietà di dipendenza e aggiungere un membro privato per archiviare il campo sottostante per LabelProperty.
Dopo averli aggiunti, il tuo BgLabelControl.h sarà simile a questo. È possibile copiare e incollare questo listato di codice per sostituire il contenuto di 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>
{
};
}
In BgLabelControl.cpp, definisci i membri statici in questo modo. È possibile copiare e incollare questo listato di codice per sostituire il contenuto di 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.
}
}
}
In questa procedura dettagliata non verrà usato OnLabelChanged. Ma è lì per mostrare come registrare una proprietà di dipendenza con un callback di modifica della proprietà. L'implementazione di OnLabelChanged mostra anche come ottenere un tipo proiettato derivato da un tipo proiettato di base (il tipo proiettato di base è DependencyObject, in questo caso). Viene inoltre illustrato come ottenere un puntatore al tipo che implementa il tipo proiettato. Questa seconda operazione sarà naturalmente possibile solo nel progetto che implementa il tipo proiettato , ovvero il progetto che implementa la classe di runtime.
Note
Se non è stato installato Windows SDK versione 10.0.17763.0 (Windows 10, versione 1809) o versioni successive, è necessario chiamare winrt::from_abi nel gestore eventi della proprietà di dipendenza modificato in precedenza, anziché winrt::get_self.
Progettare lo stile predefinito per BgLabelControl
Nel costruttore, BgLabelControl imposta automaticamente una chiave di stile predefinita. Ma che cos'è uno stile predefinito? Un controllo personalizzato (basato su modelli) deve avere uno stile predefinito, contenente un modello di controllo predefinito, che può essere usato per eseguire il rendering con nel caso in cui il consumer del controllo non imposti uno stile e/o un modello. In questa sezione verrà aggiunto un file di markup al progetto contenente lo stile predefinito.
Assicurarsi che Show All Files sia ancora attivato (in Esplora soluzioni). Nel nodo del progetto creare una nuova cartella (non un filtro, ma una cartella) e denominarla "Temi". In Themesaggiungere un nuovo elemento di tipo Visual C++>XAML XAML>View e denominarlo "Generic.xaml". I nomi di cartella e file devono essere simili a questo per consentire al framework XAML di trovare lo stile predefinito per un controllo personalizzato. Eliminare il contenuto predefinito di Generic.xamle incollare il markup seguente.
<!-- \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>
In questo caso, l'unica proprietà impostata dallo stile predefinito è il modello di controllo. Il modello è costituito da un quadrato (il cui sfondo è associato alla proprietà Background di cui dispongono tutte le istanze del tipo di controllo XAML) e da un elemento di testo (il cui testo è associato alla proprietà di dipendenza BgLabelControl::Label ).
Aggiungere un'istanza di BgLabelControl alla pagina principale dell'interfaccia utente
Apri MainPage.xaml, che contiene il markup XAML per la nostra pagina dell'interfaccia utente principale. Immediatamente dopo l'elemento Button, all'interno di StackPanel, aggiungi il markup seguente.
<local:BgLabelControl Background="Red" Label="Hello, World!"/>
Aggiungere anche la direttiva di inclusione seguente a MainPage.h in modo che il tipo MainPage (una combinazione di markup XAML e codice imperativo) sia a conoscenza del tipo di controllo personalizzato BgLabelControl . Se vuoi usare BgLabelControl da un'altra pagina XAML, aggiungi la stessa direttiva di inclusione anche al file di intestazione per quella pagina. In alternativa, è sufficiente inserire una singola direttiva di inclusione nel file di intestazione precompilato.
// MainPage.h
...
#include "BgLabelControl.h"
...
Compilare ed eseguire il progetto. Si noterà che il modello di controllo predefinito è associato al pennello dello sfondo e all'etichetta dell'istanza di BgLabelControl nel markup.
Questa procedura dettagliata ha mostrato un semplice esempio di controllo personalizzato (basato su modelli) in C++/WinRT. È possibile creare controlli personalizzati arbitrariamente ricchi e completi. Ad esempio, un controllo personalizzato può assumere la forma di qualcosa di complicato come una griglia di dati modificabile, un lettore video o un visualizzatore di geometria 3D.
Implementazione di metodi sostituibili , ad esempio MeasureOverride e OnApplyTemplate
Vedi la sezione in Richiamo e sovrascrittura del tipo di base con C++/WinRT.