使用 C++/CX 建立 "Hello, World!"C++/CX 中的 UWP 應用程式

重要

本教學課程使用 C++/CX。 Microsoft 已發生 C++/WinRT:Windows 執行階段 (WinRT) API 的完全標準現代 C++17 語言投影。 如需有關此語言的詳細資訊,請參閱 C++/WinRT

在 Microsoft Visual Studio 2017,您可以使用 C++/CX 開發在 Windows 上執行且具有使用 Extensible Application Markup Language (XAML) 定義之 UI 的應用程式。

注意

本教學課程使用 Visual Studio Community 2019。 如果您使用不同版本的 Visual Studio,它的外觀可能會略有不同。

在您開始使用 Intune 之前

  • 若要完成此教學課程,您必須在執行 Windows 的電腦上,使用 Visual Studio Community,或是某一個非 Community 版本的 Visual Studio。 若要下載,請參閱取得工具
  • 若要跟著做,您應該對 C++/CX、XAML 及 XAML 概觀中的概念有基本的瞭解。
  • 若要跟著做,您應該使用 Visual Studio 中的預設視窗配置。 若要重設為預設配置,在功能表列上選擇 [視窗]> [重設視窗配置]

比較 C++ 電腦應用程式與 UWP 應用程式

如果您的基礎知識是使用 C++ 來設計 Windows 電腦應用程式,則或許會發現撰寫 UWP 應用程式有某些類似的地方,但其他方面則有待學習。

有何相同之處?

  • 您可以使用 STL、CRT (但有些例外) 及任何其他 C++ 程式庫,只要程式碼呼叫僅可從 Windows 執行階段環境存取的 Windows 函式即可。

  • 如果您習慣於視覺化設計介面,您仍然可以使用 Microsoft Visual Studio 內建的設計工具,也可以使用更完整的 Blend for Visual Studio。 如果您習慣手動撰寫 UI 程式碼,則可以手動撰寫 XAML 的程式碼。

  • 您仍然可以建立一些使用 Windows 作業系統類型和自訂類型的應用程式。

  • 您仍然可以使用 Visual Studio 偵錯工具、分析工具以及其他開發工具。

  • 您仍然可以建立使用 Visual C++ 編譯器編譯原生機器程式碼的應用程式。 使用 C++/CX 編譯的 UWP 應用程式不在受管理的執行階段環境中執行。

新功能

  • UWP 應用程式的設計原則與電腦應用程式的設計原則有很大的差別。 設計的重點不再強調視窗的邊框、標籤、對話方塊等。 內容才是最重要的。 完美的 UWP 應用程式會從規劃階段的開頭納入這些原則。

  • 您是使用 XAML 來定義整個 UI。 UWP 應用中 UI 與核心程式邏輯之間的界線遠比 MFC 或 Win32 應用程式清楚得多。 當您在程式碼檔案中處理行為時,其他人可以在 XAML 檔案中處理 UI 的外觀。

  • 雖然您仍然可以在 Windows 裝置上使用 Win32 的部分功能,不過主要是使用全新、易於瀏覽、物件導向的 API (Windows 執行階段) 來設計程式。

  • 您使用 C++/CX 來取用和建立 Windows 執行階段物件。 C++/CX 可啟用動態建立物件的 C++ 例外狀況處理、委派、事件及自動參考計數。 當您使用 C++/CX 時,應用程式程式碼會隱藏基礎 COM 和 Windows 結構的詳細資訊。 如需相關資訊,請參閱 C++/CX 語言參考

  • 您的應用程式會編譯成套件,其中包含應用程式所包含的類型、其使用的資源,以及它所需的功能 (檔案存取、網際網路存取、相機存取等)。

  • 在 Microsoft Store 和 Windows Phone Store 中,您的應用程式會經過認證程序檢查其安全性,然後再公開給數百萬的潛在客戶。

使用 C++/CX 的 Hello World Store 應用程式

我們的第一個應用程式是 "Hello World",將示範互動功能、配置及樣式的某些基本功能。 我們將從 Windows 通用應用程式專案範本建立應用程式。 如果您先前已開發過適用於 Windows 8.1 和 Windows Phone 8.1 的應用程式,就可能記得必須在 Visual Studio 中擁有三個專案,一個用於 Windows 應用程式、一個用於手機應用程式,另一個則包含共用程式碼。 Windows 的通用 Windows Platform (UWP) 讓您只需一個專案,就能在所有裝置 (包括執行 Windows 的桌上型電腦和膝上型電腦、平板電腦之類的裝置、行動電話、VR 裝置等) 上執行。

我們將從基本知識開始:

  • 如何在 Visual Studio 中建立通用 Windows 專案。

  • 如何瞭解建立的專案和檔案。

  • 如何瞭解 Visual C++ 元件延伸功能 (C++/CX) 中的延伸功能,以及使用它們的時機。

首先,在 Visual Studio 中建立方案

  1. 在 Visual Studio 的功能表列上,選擇 [檔案]>[新增]>[專案...]

  2. 在 [建立新專案] 對話方塊中,選取 [空白應用程式 (通用 Windows- C++/CX)]。 如果您沒有看到這些選項,請確定您已經安裝「通用 Windows 應用程式開發工具」。 如需詳細資訊,請參閱開始設定

C++/CX project templates in the Create a new project dialog box

  1. 選擇 [下一步],然後輸入專案的名稱。 我們將它命名為 HelloWorld。

  2. 選擇 [建立] 按鈕。

注意

如果這是您第一次使用 Visual Studio,您可能會看到 [設定] 對話方塊要求您啟用 [開發人員模式]。 開發人員模式是啟用某些功能的特殊設定,例如,直接執行應用程式的權限,而非只執行來自 Microsoft Store 的。 如需詳細資訊,請閱讀啟用您的裝置以進行開發。 若要繼續使用此指南,請選取 [開發人員模式],按一下 [是],並關閉對話方塊。

您的專案檔案已建立。

繼續之前,先看看方案中有些什麼功能。

Universal app solution with nodes collapsed

關於專案檔案

專案資料夾中的每一個 .xaml 檔案都有對應的 .xaml.h 檔案和相同資料夾中的 .xaml.cpp 檔案和 .g 檔案,以及 [產生的檔案] 資料夾中的 .g.hpp 檔案,該檔案位於磁碟上,但不屬於專案的一部分。 修改 XAML 檔案可建立 UI 元素,並將它們連線至資料來源 (DataBinding)。 修改 .h 和 .cpp 檔案可新增事件處理常式的自訂邏輯。 自動產生的檔案代表已從 XAML 標記轉換成 C++/CX。 不要修改這些檔案,但您可以研究它們以深入瞭解程式碼後置的運作方法。 基本上,產生的檔案包含 XAML 根元素的部分類別定義;這個類別與您在 *.xaml.h 和 .cpp 檔案修改的類別相同。 產生的檔案將 XAML UI 子元素宣告為類別成員,讓您能夠在自己撰寫的程式碼中參考它們。 建置期間,產生的程式碼會與您的程式碼合併成一個完整的類別定義,然後進行編譯。

我們先來查看專案檔案。

  • App.xaml, App.xaml.h, App.xaml.cpp: 代表應用程式進入點的應用程式物件。 App.xaml 不包含任何頁面特定的 UI 標記,但您可以新增 UI 樣式,以及您想要從任何頁面存取的其他元素。 程式碼後置檔案包含 OnLaunchedOnSuspending 事件的處理常式。 通常,您會在這裡新增自訂程式碼,在應用程式啟動時初始化應用程式,並在應用程式暫停或終止時執行清理。
  • MainPage.xaml, MainPage.xaml.h, MainPage.xaml.cpp: 包含應用程式中預設「開始」頁面的 XAML 標記和程式碼後置。 它沒有瀏覽支援或內建控制項。
  • pch.h, pch.cpp: 預先編譯的標頭檔,及將它內含在您專案中的檔案。 在 pch.h 中,您可以包含任何不常變更的標頭,以及包含在方案其他檔案的標頭。
  • Package.appxmanifest: 描述應用程式所需的裝置功能,以及應用程式版本資訊和其他中繼資料的 XML 檔案。 若要在 [資訊清單設計工具] 開啟此檔案,只要按兩下即可。
  • HelloWorld_TemporaryKey.pfx: 從 Visual Studio 將應用程式部署到此電腦所需的金鑰。

初窺程式碼

如果您在共用專案中檢查 App.xaml.h、App.xaml.cpp 中的程式碼,您會發現它主要是看起來熟悉的 C++ 程式碼。 不過,如果您是 Windows 執行階段應用程式的新手,或曾用過 C++/CLI,可能不熟悉某些語法元素。 下列是 C++/CX 中最常見的非標準語法元素:

參考類別

幾乎所有的 Windows 執行階段類別,包括 Windows API (XAML 控制項中的所有類型、您應用程式中的頁面、應用程式類別本身、所有裝置與網路物件、所有容器類型) 都會宣告為 ref 類別。 (有些 Windows 類型是 value classvalue struct)。 ref 類別可從任何語言取用。 在 C++/CX 中,這些類型的存留期由自動參考計數 (而非記憶體回收) 管理,因此絕不能明確刪除這些物件。 您也可以建立自己的 ref 類別。

namespace HelloWorld
{
   /// <summary>
   /// An empty page that can be used on its own or navigated to within a Frame.
   /// </summary>
   public ref class MainPage sealed
   {
      public:
      MainPage();
   };
}

所有 Windows 執行階段類型都必須在命名空間內宣告,與 ISO C++ 不同的是,這些類型本身有存取範圍修飾詞。 public 修飾詞可讓命名空間外的 Windows 執行階段元件看見類別。 sealed 關鍵字代表類別不能做為基底類別使用。 幾乎所有 ref 類別都是密封的;因為 JavaScript 無法理解類別繼承,所以並未受到廣泛的使用。

ref new^ (hat)

您可以使用 ^ (hat) 運算子來宣告 ref 類別的變數,並使用 ref new 關鍵字具現化物件。 之後,您就能以與 C++ 指標一樣的方式,使用 -> 運算子存取物件的執行個體方法。 和 ISO C++ 一樣,要使用 :: 運算子存取靜態方法。

在下列程式碼中,我們使用完整名稱來具現化物件,並使用 -> 運算子來呼叫執行個體方法。

Windows::UI::Xaml::Media::Imaging::BitmapImage^ bitmapImage =
     ref new Windows::UI::Xaml::Media::Imaging::BitmapImage();

bitmapImage->SetSource(fileStream);

一般而言,在 .cpp 檔案中,我們會新增 using namespace Windows::UI::Xaml::Media::Imaging 指示詞和 auto 關鍵字,讓相同的程式碼看起來像這樣:

auto bitmapImage = ref new BitmapImage();
bitmapImage->SetSource(fileStream);

屬性

ref 類別可以有屬性,與受管理的語言一樣,這些屬性是特殊成員函式,以欄位的形式顯示以取用程式碼。

public ref class SaveStateEventArgs sealed
{
   public:
   // Declare the property
   property Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ PageState
   {
      Windows::Foundation::Collections::IMap<Platform::String^, Platform::Object^>^ get();
   }
   ...
};

   ...
   // consume the property like a public field
   void PhotoPage::SaveState(Object^ sender, Common::SaveStateEventArgs^ e)
   {    
      if (mruToken != nullptr && !mruToken->IsEmpty())
   {
      e->PageState->Insert("mruToken", mruToken);
   }
}

委派

如同受管理的語言,委派是一種參考類型,可使用特定簽章封裝函式。 它們最常用於事件及事件處理常式

// Delegate declaration (within namespace scope)
public delegate void LoadStateEventHandler(Platform::Object^ sender, LoadStateEventArgs^ e);

// Event declaration (class scope)
public ref class NavigationHelper sealed
{
   public:
   event LoadStateEventHandler^ LoadState;
};

// Create the event handler in consuming class
MainPage::MainPage()
{
   auto navigationHelper = ref new Common::NavigationHelper(this);
   navigationHelper->LoadState += ref new Common::LoadStateEventHandler(this, &MainPage::LoadState);
}

將內容新增到應用程式

讓我們在應用程式中新增一些內容。

步驟 1:修改起始頁面

  1. 在 [方案總管] 中,開啟 MainPage.xaml。

  2. 將下列 XAML 新增到根 Grid (在其結束標記的正前方),以建立 UI 的控制項。 其中包含 StackPanel,其具有 TextBlock,會詢問使用者的名稱、接受使用者名稱的 TextBox 元素、Button 及另一個 TextBlock 元素。

    <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>
    
  3. 到目前為止,您已建立一個非常基本的 Windows 通用應用程式。 若要查看該 UWP 應用程式的外觀,可按 F5 在偵錯模式中組建、部署及執行該應用程式。

預設啟動顯示畫面最先出現。 它有應用程式資訊清單檔案中指定的影像 (Assets\SplashScreen.scale-100.png) 及背景色彩。 若要瞭解如何自訂啟動顯示畫面,請參閱新增啟動顯示畫面

當啟動顯示畫面消失後,您的應用程式便會出現。 它會顯示應用程式的主頁面。

UWP app screen, with controls

它還沒有太多功能,但恭喜您,您已經建立第一個通用 Windows 平台應用程式了!

若要停止偵錯並關閉應用程式,請返回 Visual Studio 並按 Shift+F5。

如需詳細資訊,請參閱從 Visual Studio 執行市集應用程式

您可以在應用程式的 TextBox 輸入文字,但按一下 [Button] 不會有任何反應。 在之後的步驟中,您要為按鈕的 Click 事件建立事件處理常式,以顯示個人化的問候語。

步驟 2:建立事件處理常式

  1. 在 MainPage.xaml 的 XAML 或設計檢視中,於 StackPanel 選取您之前新增的 "Say Hello" Button

  2. 按 F4 開啟屬性視窗,然後選擇 [事件] 按鈕 (Events button)。

  3. 尋找 Click 事件。 在文字方塊中,輸入處理 Click 事件的函式名稱。 在這個範例中,輸入 "Button_Click"。

    Properties window, Events view

  4. 按 Enter。 事件處理常式方法會在 MainPage.xaml.cpp 中建立並開啟,以便您可以新增事件發生時所執行的程式碼。

同時,在 MainPage.xaml 中,Button 的 XAML 已更新,以宣告 Click 事件處理常式,如下所示:

<Button Content="Say &quot;Hello&quot;" Click="Button_Click"/>

您也可能已直接手動將它新增至 XAML 程式碼,則這會有所幫助 (如果設計工具不會載入)。 如果您手動輸入這個資訊,請輸入 "Click",然後讓 IntelliSense 快顯出選擇加入新事件處理常式的選項。 如此一來,Visual Studio 會建立必要的方法宣告和虛設常式。

如果在轉譯期間發生無法處理的例外狀況,設計工具會無法載入。 在設計工具中的轉譯涉及了執行頁面的設計階段版本。 停用執行中的使用者程式碼會很有幫助。 您可以藉由在 [工具]、[選項] 對話方塊變更設定來執行此動作。 在 [XAML 設計工具] 下,取消核取 [在 XAML 設計工具中執行專案程式碼 (如果支援)]

  1. 在 MainPage.xaml.cpp 中,將下列程式碼新增到您剛才建立的 Button_Click 事件處理常式。 此程式碼會從 nameInputTextBox 控制項擷取使用者的名稱,並用它來建立問候語。 greetingOutputTextBlock 會顯示結果。
void HelloWorld::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    greetingOutput->Text = "Hello, " + nameInput->Text + "!";
}
  1. 將專案設定為起始專案,然後按 F5 組建並執行應用程式。 在文字方塊中輸入名稱並按一下按鈕時,應用程式會顯示個人化問候語。

App screen with message display

步驟 3:設定開始頁面的樣式

選擇佈景主題

您可以輕鬆地自訂應用程式的外觀和風格。 依據預設,您的應用程式會使用淺色樣式的資源。 系統資源也包含淺色佈景主題。 讓我們來嘗試一下,再看看它的外觀如何。

切換至深色佈景主題

  1. 開啟 App.xaml。

  2. 在開頭的 Application 標記中,編輯 RequestedTheme 屬性並將其值設定為 Dark

    RequestedTheme="Dark"
    

    以下是具有深色佈景主題的完整應用程式標籤:

    <Application
    x:Class="HelloWorld.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HelloWorld"
    RequestedTheme="Dark">
    
  3. 按 F5 以組建並執行。 請注意,它會使用深色佈景主題。

    App screen with dark theme

您應該使用哪一個佈景主題? 無論您想要哪一個。 以下是我們採取的方式:對於主要顯示圖片或影片的應用程式,建議您使用深色佈景主題;對於包含大量文字的應用程式,則建議使用淺色佈景主題。 如果您要使用自訂色彩配置,使用與您應用程式外觀及操作方式最搭配的佈景主題。 在本教學課程的其餘部分,我們會在螢幕擷取畫面中使用淺色佈景主題。

注意佈景主題會在應用程式啟動時套用,且無法在應用程式執行時進行變更。

使用系統樣式

現在,在 Windows 應用程式中,文字非常小且難以閱讀。 讓我們透過套用系統樣式來修正此問題。

變更元素的樣式

  1. 在 Windows 專案中,開啟 MainPage.xaml。

  2. 在 XAML 或設計檢視中,選取您稍早新增的 TextBlock「您的名字為何?」。

  3. 屬性視窗 (F4),選擇右上角的 [屬性] 按鈕 (Properties button)。

  4. 展開 [文字] 群組並將字型大小設定為 18 像素。

  5. 展開 [其他] 群組,找到 [樣式] 屬性。

  6. 按一下屬性標記 ([樣式] 屬性右側的綠色方塊),然後在功能表上,選擇 [系統資源]>[BaseTextBlockStyle]

    BaseTextBlockStyle 是在 <root>\Program Files\Windows Kits\10\Include\winrt\xaml\design\generic.xaml 的 ResourceDictionary 中定義的資源。

    Properties window, Properties view

    在 XAML 設計介面上,文字的外觀會變更。 在 XAML 編輯器中,會更新 TextBlock 的 XAML:

<TextBlock Text="What's your name?" Style="{ThemeResource BaseTextBlockStyle}"/>
  1. 重複此處理程序來設定字型大小,並將 BaseTextBlockStyle 指派給 greetingOutputTextBlock 元素。

    提示雖然這個 TextBlock 沒有任何文字,但是當您將指標移至 XAML 設計表面上時,會以藍色外框顯示其位置,讓您可以選取它。  

    您的 XAML 現在看起來像這樣:

<StackPanel x:Name="contentPanel" Margin="120,30,0,0">
    <TextBlock Style="{ThemeResource BaseTextBlockStyle}" FontSize="18" 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;" Click="Button_Click"/>
    </StackPanel>
    <TextBlock Style="{ThemeResource BaseTextBlockStyle}" FontSize="18" x:Name="greetingOutput"/>
</StackPanel>
  1. 按 F5 以組建並執行應用程式。 現在的樣貌如下:

App screen with larger text

步驟 4:隨著不同的視窗大小調整 UI

現在,我們將讓 UI 適應不同的螢幕大小,使其在行動裝置上看起來不錯。 若要這樣做,您可以新增 VisualStateManager,並設定不同視覺狀態套用的屬性。

調整 UI 配置

  1. 在 XAML 編輯器中,將這個 XAML 區塊新增至根目錄 Grid 元素的開頭標籤之後。
<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>
  1. 對本機電腦上的應用程式進行偵錯。 請注意,除非視窗小於 641 裝置獨立像素 (DIP),否則 UI 看起來會和以前一樣。
  2. 在行動裝置模擬器上對應用程式進行偵錯。 請注意,UI 會使用您在 narrowState 中定義的屬性,並在小螢幕上正確顯示。

Mobile app screen with styled text

如果您已在舊版 XAML 中使用 VisualStateManager,您可能會注意到這裡的 XAML 使用簡化的語法。

名為 wideStateVisualState 有一個 AdaptiveTriggerMinWindowWidth 屬性設為 641。 這表示只有在視窗寬度不小於最小值 641 DIP 時才會套用狀態。 您不需為此狀態定義任何 Setter 物件,因此其會使用您在 XAML 頁面內容中所定義的配置屬性。

第二個 VisualState (narrowState) 有一個 AdaptiveTriggerMinWindowWidth 屬性設為 0。 當視窗寬度大於 0 但小於 641 DIP 時,會套用這個狀態。 (在 641 DIP 時,會套用 wideState)。在這個狀態中,您要定義一些 Setter 物件,以變更 UI 中的控制項配置屬性:

  • 您會將 contentPanel 元素的左邊界從 120 減少到 20。
  • 您會將 inputPanel 元素的OrientationHorizontal 變更為 Vertical
  • 您會將 4 個 DIP 的上邊界新增至 inputButton 元素。

摘要

恭喜,您已完成第一個教學課程! 它教導如何將內容新增至 Windows 通用應用程式、如何將互動功能新增至 Windows 通用應用程式,以及如何變更其外觀。

下一步

如果您擁有目標為 Windows 8.1 和 (或) Windows Phone 8.1 的 Windows 通用應用程式專案時,可將它移植到 Windows 10 或 Windows 11。 沒有任何自動處理程序可用來進行此動作,但您可以手動完成此動作。 從新的 Windows 通用專案開始,以取得最新的專案系統結構和資訊清單檔案、將程式碼檔案複製到專案的目錄結構、將項目新增至您的專案,以及使用 VisualStateManager,依據本主題中的指引重寫您的 XAML。 如需詳細資訊,請參閱將 Windows 執行階段 8 專案移植到通用 Windows 平台 (UWP) 專案移植到通用 Windows 平台 (C++)

如果您有想要與 UWP 應用程式整合的現有 C++ 程式碼,例如為現有應用程式建立新的 UWP UI,請參閱如何:在通用 Windows 專案中使用現有的 C++ 程式碼