Creare un'app "Hello, World!" App UWP con C++/WinRT

Questo argomento illustra la creazione di un'app Universal Windows Platform UWP per Windows "Hello, World!" usando C++/WinRT. L'interfaccia utente dell'app è definita tramite Extensible Application Markup Language (XAML).

C++/WinRT è una proiezione di linguaggio, interamente standard, moderna di C++ 17 per le API di Windows Runtime (WinRT). Per altre informazioni e per altre procedure dettagliate ed esempi di codice, vedere la documentazione di C++/WinRT. Un argomento valido per iniziare è Introduzione a C++/WinRT.

Configurare Visual Studio per C++/WinRT

Per informazioni sulla configurazione di Visual Studio per lo sviluppo in C++/WinRT, compresi l'installazione e l'uso dell'estensione C++/WinRT per Visual Studio (VSIX) e del pacchetto NuGet, che insieme forniscono il modello di progetto e il supporto della compilazione, vedi Supporto di Visual Studio per C++/WinRT.

Per scaricare Visual Studio, vedere Download.

Per un'introduzione a XAML, vedere Panoramica di XAML

Creare un'app vuota (HelloWorldCppWinRT)

La nostra prima app è "Hello, World!" che mostra alcune funzionalità di base per interattività, layout e stili.

Per iniziare, crea un nuovo progetto in Microsoft Visual Studio. Creare un progetto di app vuota (C++/WinRT) con il nome HelloWorldCppWinRT. Assicurarsi che l'opzione Inserisci soluzione e progetto nella stessa directory sia deselezionata. Specificare come destinazione la versione più recente disponibile a livello generale, ovvero non l'anteprima, di Windows SDK.

In una sezione successiva di questo argomento sono riportate le istruzioni per compilare il progetto: evita però di eseguire la compilazione fino a quel momento.

Informazioni sui file di progetto

In genere, nella cartella del progetto, ogni file .xaml (markup XAML) ha un file .idl, .h e .cpp corrispondente. Insieme, questi file vengono compilati in un tipo di pagina XAML.

È possibile modificare un file di markup XAML per creare elementi dell'interfaccia utente ed è possibile associare tali elementi alle origini dati (attività nota come data binding). Modificare i file .h e .cpp (e talvolta il file .idl) per aggiungere la logica personalizzata per la pagina XAML dei gestori eventi, ad esempio.

Ecco alcuni file di progetto.

  • App.idl, App.xaml, App.h e App.cpp. Questi file rappresentano la specializzazione dell'app della classe Windows:: UI:: XAML:: Application, che include il punto d'ingresso dell'app. App.xaml non contiene alcun markup specifico della pagina, ma è possibile aggiungere gli stili degli elementi dell'interfaccia utente in tale posizione, nonché qualsiasi altro elemento a cui è utile accedere da tutte le pagine. I file .h e .cpp contengono gestori per diversi eventi del ciclo di vita dell'applicazione. In genere, è possibile aggiungere codice personalizzato in questa posizione per inizializzare l'app all'avvio ed eseguire le operazioni di pulizia quando viene sospesa o terminata.
  • MainPage.idl, MainPage.xaml, MainPage.h e MainPage.cpp. Includere il markup XAML e l'implementazione per il tipo di pagina principale (avvio) predefinito in un'app, ovvero la classe di runtime MainPage. MainPage non dispone di supporto per la navigazione, ma fornisce un'interfaccia utente predefinita e un gestore eventi per iniziare.
  • pch.h e pch.cpp. Questi file rappresentano il file di intestazione precompilato del progetto. In pch.h includere tutti i file di intestazione che non cambiano spesso e quindi includere pch.h in altri file del progetto.

Una prima occhiata al codice

Classi di runtime

Come si può notare, tutte le classi in un'app della piattaforma UWP scritta in C# sono tipi di Windows Runtime. Quando tuttavia crei un tipo in un'applicazione C++/WinRT, puoi scegliere se deve essere un tipo di Windows Runtime o una normale classe/struct/enumerazione C++.

Qualsiasi tipo di pagina XAML nel progetto deve essere un tipo di Windows Runtime. MainPage è quindi un tipo di Windows Runtime. Si tratta in particolare di una classe di runtime. Un tipo utilizzato da una pagina XAML deve essere anche un tipo di Windows Runtime. Quando si scrive un componente di Windows Runtime e si vuole creare un tipo che possa essere utilizzato da un'altra app, verrà creato un tipo di Windows Runtime. In altri casi, il tipo può essere un tipo C++ normale. In generale, un tipo di Windows Runtime può essere utilizzato usando qualsiasi linguaggio Windows Runtime.

Un indicatore del fatto che un tipo sia un tipo di Windows Runtime è che viene definito in Microsoft Interface Definition Language (Midl) all'interno di un file del linguaggio di definizione dell'interfaccia (.idl). Si prenda MainPage come esempio.

// MainPage.idl
namespace HelloWorldCppWinRT
{
    [default_interface]
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        Int32 MyProperty;
    }
}

Di seguito è illustrata la struttura di base dell'implementazione della classe di runtime MainPage e della relativa factory di attivazione, come illustrato in MainPage.h.

// MainPage.h
...
namespace winrt::HelloWorldCppWinRT::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        int32_t MyProperty();
        void MyProperty(int32_t value);
        ...
    };
}

namespace winrt::HelloWorldCppWinRT::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}

Per informazioni più dettagliate sull'opportunità di creare o meno una classe di runtime per un determinato tipo, vedi l'argomento Creare API con C++/WinRT. Per altre informazioni sulla connessione tra classi di runtime e IDL (file .idl), è possibile leggere e seguire l'argomento Controlli XAML, binding a una proprietà C++/WinRT, che illustra il processo di creazione di una nuova classe di runtime, in cui il primo passaggio consiste nell'aggiungere un nuovo elemento File Midl (.idl) al progetto.

A questo punto, è possibile aggiungere alcune funzionalità al progetto HelloWorldCppWinRT.

Passaggio 1. Modificare la pagina di avvio

In Esplora soluzioni aprire MainPage.xaml per creare i controlli che formano l'interfaccia utente.

Eliminare l'elemento StackPanel, che è già presente, e il relativo contenuto. In questa area, incollare il codice XAML seguente.

<StackPanel x:Name="contentPanel" Margin="120,30,0,0">
    <TextBlock HorizontalAlignment="Left" Text="Hello, World!" FontSize="36"/>
    <TextBlock Text="What's your name?"/>
    <StackPanel x:Name="inputPanel" Orientation="Horizontal" Margin="0,20,0,20">
        <TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/>
        <Button x:Name="inputButton" Content="Say &quot;Hello&quot;"/>
    </StackPanel>
    <TextBlock x:Name="greetingOutput"/>
</StackPanel>

Il nuovo elemento StackPanel contiene un elemento TextBlock per richiedere il nome dell'utente, un elemento TextBox che accetta il nome dell'utente, un elemento Button e un altro elemento TextBlock.

Poiché è stato eliminato l'elemento Button denominato myButton, sarà necessario rimuovere il riferimento dal codice. In MainPage.cpp, quindi, eliminare la riga di codice all'interno della funzione MainPage::ClickHandler.

È stata quindi creata un'app di Windows universale molto semplice. Per visualizzare l'aspetto dell'app UWP, compilare ed eseguire l'app.

UWP app screen, with controls

Nell'app è possibile digitare nella casella di testo. Tuttavia, facendo clic sul pulsante non viene ancora eseguita alcuna operazione.

Passaggio 2. Aggiungere un gestore eventi

In MainPage.xaml trovare l'elemento Button denominato inputButton e dichiarare un gestore eventi per il relativo evento ButtonBase::Click. Il markup per l'elemento Button dovrebbe essere visualizzato come segue.

<Button x:Name="inputButton" Content="Say &quot;Hello&quot;" Click="inputButton_Click"/>

Implementare il gestore eventi nel modo seguente.

// MainPage.h
struct MainPage : MainPageT<MainPage>
{
    ...
    void inputButton_Click(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
};

// MainPage.cpp
namespace winrt::HelloWorldCppWinRT::implementation
{
    ...
    void MainPage::inputButton_Click(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
    {
        greetingOutput().Text(L"Hello, " + nameInput().Text() + L"!");
    }
}

Per altre informazioni, vedere Gestire eventi mediante i delegati.

L'implementazione recupera il nome dell'utente dalla casella di testo, lo usa per creare un messaggio di saluto e lo visualizza nel blocco di testo greetingOutput.

Compilare ed eseguire l'app. Digitare il nome nella casella di testo e fare clic sul pulsante. L'app visualizza un messaggio di saluto personalizzato.

App screen with message display

Passaggio 3. Scegliere uno stile per la pagina di avvio

Scegliere un tema

È possibile personalizzare facilmente l'aspetto dell'app. Per impostazione predefinita, l'app usa risorse con un tema di colore chiaro. Nelle risorse del sistema è incluso anche un tema scuro.

Per provare il tema scuro, modificare App.xaml e aggiungere un valore per Application::RequestedTheme.

<Application
    ...
    RequestedTheme="Dark">

</Application>

Per le app che visualizzano principalmente immagini o video, è consigliabile usare il tema scuro, riservando invece il tema chiaro alle app che contengono molto testo. Se usi una combinazione di colori personalizzata, scegliere il tema che meglio si addice all'aspetto dell'app.

Nota

All'avvio dell'app, viene applicato un tema. Non può essere modificato mentre l'app è in esecuzione.

Usare gli stili di sistema

In questa sezione si modificherà l'aspetto del testo (ad esempio, si aumenteranno le dimensioni del carattere).

In MainPage.xaml trovare il blocco di testo "What's your name?". Impostare la relativa proprietà Style su un riferimento alla chiave di risorsa di sistema BaseTextBlockStyle.

<TextBlock Text="What's your name?" Style="{ThemeResource BaseTextBlockStyle}"/>

BaseTextBlockStyle è la chiave di una risorsa definita in ResourceDictionary in \Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<version>\Generic\generic.xaml. Di seguito sono riportati i valori delle proprietà impostati con lo stile.

<Style x:Key="BaseTextBlockStyle" TargetType="TextBlock">
    <Setter Property="FontFamily" Value="XamlAutoFontFamily" />
    <Setter Property="FontWeight" Value="SemiBold" />
    <Setter Property="FontSize" Value="14" />
    <Setter Property="TextTrimming" Value="None" />
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="LineStackingStrategy" Value="MaxHeight" />
    <Setter Property="TextLineBounds" Value="Full" />
</Style>

In MainPage.xaml, inoltre, trovare l'elemento TextBlock denominato greetingOutput. Impostare anche la relativa proprietà Style su BaseTextBlockStyle. Se l'app viene compilata ed eseguita adesso, si noterà che l'aspetto di entrambi i blocchi di testo è stato modificato (ad esempio, le dimensioni del carattere sono ora maggiori).

Passaggio 4. Adattare l'interfaccia utente a diverse dimensioni della finestra

A questo punto, l'interfaccia utente verrà adattata dinamicamente a una dimensione della finestra mutevole, in modo che abbia un aspetto ottimale nei dispositivi con schermi di piccole dimensioni. A tale scopo, aggiungere una sezione VisualStateManager in MainPage.xaml. Verranno definiti diversi stati di visualizzazione per le diverse dimensioni della finestra e quindi verranno impostate le proprietà da applicare per ognuno di questi stati di visualizzazione.

Regolare il layout dell'interfaccia utente

Aggiungere questo blocco di XAML come primo elemento figlio dell'elemento StackPanel radice.

<StackPanel ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="wideState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="641" />
                </VisualState.StateTriggers>
            </VisualState>
            <VisualState x:Name="narrowState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="contentPanel.Margin" Value="20,30,0,0"/>
                    <Setter Target="inputPanel.Orientation" Value="Vertical"/>
                    <Setter Target="inputButton.Margin" Value="0,4,0,0"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    ...
</StackPanel>

Compilare ed eseguire l'app. Tenere presente che l'interfaccia utente è identica a prima, a meno che la dimensione della finestra non sia più stretta di 641 DIP (Device-Independent Pixel). A questo punto, viene applicato lo stato di visualizzazione narrowState e, insieme, tutti i setter di proprietà definiti per tale stato.

L'oggetto VisualState denominato wideState ha AdaptiveTrigger con la proprietà MinWindowWidth impostata su 641. Ciò significa che lo stato deve essere applicato solo quando la larghezza della finestra non è inferiore a quella minima di 641 DIP. Non viene definito alcun oggetto Setter per questo stato, vengono quindi usate le proprietà di layout definite nel codice XAML per il contenuto della pagina.

Il secondo oggetto VisualState, narrowState, ha AdaptiveTrigger con la proprietà MinWindowWidth impostata su 0. Questo stato viene applicato quando la larghezza della finestra è maggiore di 0, ma minore di 641 DIP. wideState è attivo esattamente a 641 DIP. In narrowState definire gli oggetti Setter per modificare le proprietà di layout dei controlli dell'interfaccia utente.

  • Ridurre il margine sinistro dell'elemento contentPanel da 120 a 20.
  • Cambiare la proprietà Orientation dell'elemento inputPanel da Horizontal a Vertical.
  • Aggiungere un margine superiore di 4 DIP all'elemento inputButton.

Riepilogo

Questa procedura dettagliata ha illustrato come aggiungere contenuto a un'app universale di Windows, come aggiungere interattività e come modificare l'aspetto dell'interfaccia utente.