使用語音命令在 Cortana 中啟用背景應用程式

警告

自 Windows 10 May 2020 更新版 (版本 2004,代號「20H1」) 起,不再支援此功能。

除了在 Cortana 中使用語音命令來存取系統功能之外,您也可以使用指定動作或命令來執行的語音命令,將 Cortana 與應用程式的功能 (做為背景工作) 擴充。 當應用程式在背景處理語音命令時,不會取得焦點。 相反地,它會透過 Cortana 畫布和 Cortana 語音傳回所有意見反應和結果。

應用程式可能會啟用到前景 (應用程式取得焦點) 或在背景中啟用 (Cortana 會保留焦點),視互動的複雜度而定。 例如,需要其他內容或使用者輸入的語音命令 (例如將訊息傳送至特定聯絡人) 最好在前景應用程式中處理,而基本命令 (例如列出即將來臨的旅程) 可以在 Cortana 中透過背景應用程式處理。

如果您想要使用語音命令將應用程式啟用至前景,請參閱透過 Cortana 啟用具有語音命令的前景應用程式)

注意

語音命令是具有特定意圖的單一語句,在語音命令定義 (VCD) 檔案中定義,透過 Cortana 針對已安裝的應用程式。

VCD 檔案會定義一或多個語音命令,每個命令都有唯一的意圖。

語音命令定義可能會因複雜度而異。 他們可以支援任何項目,從單一、限制語句到更有彈性、自然語言語句的集合,都表示相同的意圖。

我們使用整合到 Cortana UI 中的名為 Adventure Works 的旅行規劃和管理應用程式 (如下所示) 來示範我們討論的許多概念和功能。 如需詳細資訊,請參閱 Cortana 語音命令範例

Cortana 啟動前景應用程式的螢幕快照

若要在沒有 Cortana 的情況下檢視 Adventure Works 旅程,使用者需要啟動應用程式並瀏覽到「即將到來的旅程」頁面。

透過 Cortana 使用語音命令在背景啟用您的應用程式,使用者可能會改為直接說Adventure Works, when is my trip to Las Vegas?。 您的應用程式會處理命令,Cortana 會顯示結果以及您的應用程式圖示和其他應用程式資訊 (如果提供)。

在背景中使用 AdventureWorks 應用程式,使用基本查詢和結果畫面的 Cortana 螢幕快照

下列基本步驟會新增語音命令功能,並使用語音或鍵盤輸入從您的應用程式擴展 Cortana 的背景功能。

  1. 建立 Cortana 在背景呼叫的應用程式服務 (請參閱 Windows.ApplicationModel.AppService)。
  2. 建立 VCD 檔案。 VCD 檔案是一份 XML 文件,可定義使用者可能會在啟用應用程式時說要起始動作或叫用命令的所有口語命令。 請參閱 VCD 元素和屬性 v1.2
  3. 啟動應用程式時,請在 VCD 檔案中註冊命令集。
  4. 處理應用程式服務的背景啟用,以及語音命令的執行。
  5. Cortana 內對語音命令顯示並說出適當的意見反應。

提示

先決條件

如果您是開發通用 Windows 平台 (UWP) 應用程式的新手,請瀏覽這些主題以熟悉此處討論的技術。

使用者體驗指引

如需如何整合應用程式與 Cortana語音互動的資訊,請參閱 Cortana 設計指導方針,以取得設計實用且吸引人的語音啟用應用程式的實用秘訣。

在 Visual Studio 中使用主要專案建立新方案

  1. 啟動 Microsoft Visual Studio 2015。
    將顯示 Visual Studio 2015 起始頁。

  2. 在 [檔案] 功能表上選取 [新增]>[專案]
    [新增專案] 對話方塊隨即出現。 對話方塊的左窗格可讓您選取要顯示的範本類型。

  3. 在左側窗格中,展開已安裝的 > 範本 > Visual C# > Windows,然後選擇通用範本群組。 對話方塊的中央窗格會顯示通用 Windows 平台 (UWP) 應用程式的專案範本清單。

  4. 在中央窗格中,選取空白應用程式 (通用 Windows) 範本。
    空白應用程式範本會建立編譯和執行的最低 UWP 應用程式。 空白應用程式範本沒有使用者介面控制項或資料。 您可以使用此頁面做為指南,將控制項新增至應用程式。

  5. 名稱文字方塊中,輸入您的專案名稱。 範例:使用 AdventureWorks

  6. 按一下 [確定] 按鈕以建立專案。
    Microsoft Visual Studio 建立您的專案並顯示在方案總管中。

將影像資產新增至主要專案,並在應用程式資訊清單中指定它們

UWP 應用程式應該會自動選取最適當的影像。 選取項目是以特定設定和裝置功能為基礎 (高對比度、有效像素、地區設定等等)。 您必須提供影像,並確定您在應用程式專案中針對不同的資源版本使用適當的命名慣例和資料夾組織。
如果您未提供建議的資源版本,則使用者體驗可能會以下列方式受到影響。

  • 協助工具選項
  • 當地語系化
  • 影像品質
    資源版本可用來調整使用者體驗中的下列變更。
  • 使用者喜好設定
  • 能力
  • 裝置類型:
  • Location

如需高對比度和縮放比例影像資源的詳細資料,請瀏覽位於 msdn.microsoft.com/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets 的圖塊和圖示資產指導方針頁面。

您必須使用限定詞來命名資源。 資源限定詞是資料夾和檔名修飾詞,可識別應使用特定資源版本的內容。

標準命名慣例為 foldername/qualifiername-value[_qualifiername-value]/filename.qualifiername-value[_qualifiername-value].ext
範例:images/logo.scale-100_contrast-white.png,它可能只使用根資料夾和檔名來參考程式碼:images/logo.png
如需詳細資訊,請瀏覽如何使用限定詞頁面命名資源,頁面位於 msdn.microsoft.com/library/windows/apps/xaml/hh965324.aspx

Microsoft 建議您在字串資源檔案上標示預設語言 (例如 en-US\resources.resw),以及影像上的預設縮放比例 (例如 logo.scale-100.png),即使您目前不打算提供當地語系化或多個解析度資源。 不過,Microsoft 至少建議您提供 100、200 和 400 個縮放比例的資產。

重要

Cortana 畫布的標題區域中使用的應用程式圖示是 Package.appxmanifest 檔案中指定的 Square44x44Logo 圖示。
您也可以指定 Cortana 畫布內容區域中每個項目的圖示。 結果圖示的有效影像大小如下:

  • 68w x 68h
  • 68w x 92h
  • 280w x 140h

VoiceCommandResponse 物件傳遞至 VoiceCommandServiceConnection 類別之前,才會驗證內容圖塊。 如果您將 VoiceCommandResponse 物件傳遞至 Cortana,其中包含影像不符合這些大小比例的內容圖塊,則可能發生例外狀況。 

範例:Adventure Works 應用程式 (VoiceCommandService\\AdventureWorksVoiceCommandService.cs) 會使用 TitleWith68x68IconAndText 圖塊範本,在 VoiceCommandContentTile 類別上指定簡單、灰色的方形 (GreyTile.png)。 標誌變體位於 VoiceCommandService\\Images 中 ,並使用 GetFileFromApplicationUriAsync 方法擷取。

var destinationTile = new VoiceCommandContentTile();  

destinationTile.ContentTileType = VoiceCommandContentTileType.TitleWith68x68IconAndText;
destinationTile.Image = await StorageFile.GetFileFromApplicationUriAsync(
    new Uri("ms-appx:///AdventureWorks.VoiceCommands/Images/GreyTile.png")
);  

建立應用程式服務專案

  1. 右鍵按一下「解決方案名稱」,選取新 >專案

  2. 已安裝的 > 範本 > Visual C# > Windows > 通用下,選取 Windows 執行階段元件Windows 執行階段元件是實作應用程式服務的元件 (Windows.ApplicationModel.AppService)。

  3. 輸入專案的名稱,然後按一下 [確定] 按鈕。
    範例:VoiceCommandService

  4. 方案總管 中,選取VoiceCommandService專案,然後重新命名 Class1.csVisual Studio 所產生的檔案。 範例:Adventure Works 使用 AdventureWorksVoiceCommandService.cs

  5. 按一下 [是] 按鈕;當系統詢問您是否要重新命名所有出現的Class1.cs時。

  6. AdventureWorksVoiceCommandService.cs 檔案中:

    1. 新增以下 using 指示詞。
      using Windows.ApplicationModel.Background;
    2. 當您建立新專案時,專案名稱會當做所有檔案中的預設根命名空間使用。 重新命名命名空間以將應用程式服務程式碼巢狀化在主專案下。 範例:namespace AdventureWorks.VoiceCommands
    3. 在方案總管中以滑鼠右鍵按一下應用程式服務專案名稱,然後選取「屬性」
    4. [程式庫] 索引標籤上,以這個相同的值更新 [預設命名空間] 欄位。
      範例:AdventureWorks.VoiceCommands)。
    5. 建立一個實作 IBackgroundTask 介面的新類別。 這個類別需要 Run 方法,這是 Cortana 辨識語音命令時的進入點。

    範例:Adventure Works 應用程式的基本背景工作類別。

    注意

    背景工作類別本身以及背景工作專案中的所有類別都必須是密封的公用類別。

    namespace AdventureWorks.VoiceCommands
    {
        ...
    
        /// <summary>
        /// The VoiceCommandService implements the entry point for all voice commands.
        /// The individual commands supported are described in the VCD xml file. 
        /// The service entry point is defined in the appxmanifest.
        /// </summary>
        public sealed class AdventureWorksVoiceCommandService : IBackgroundTask
        {
            ...
    
            /// <summary>
            /// The background task entrypoint. 
            /// 
            /// Background tasks must respond to activation by Cortana within 0.5 second, and must 
            /// report progress to Cortana every 5 seconds (unless Cortana is waiting for user
            /// input). There is no running time limit on the background task managed by Cortana,
            /// but developers should use plmdebug (https://msdn.microsoft.com/library/windows/hardware/jj680085%28v=vs.85%29.aspx)
            /// on the Cortana app package in order to prevent Cortana timing out the task during
            /// debugging.
            /// 
            /// The Cortana UI is dismissed if Cortana loses focus. 
            /// The background task is also dismissed even if being debugged. 
            /// Use of Remote Debugging is recommended in order to debug background task behaviors. 
            /// Open the project properties for the app package (not the background task project), 
            /// and enable Debug -> "Do not launch, but debug my code when it starts". 
            /// Alternatively, add a long initial progress screen, and attach to the background task process while it runs.
            /// </summary>
            /// <param name="taskInstance">Connection to the hosting background service process.</param>
            public void Run(IBackgroundTaskInstance taskInstance)
            {
              //
              // TODO: Insert code 
              //
              //
        }
      }
    }
    
  7. 在應用程式資訊清單中將您的背景工作宣告為 AppService

    1. 方案總管中,右鍵按一下 Package.appxmanifest 檔案並選檢視程式碼
    2. 尋找 Application 項目。
    3. Extensions 元素中加入一個 Application 元素。
    4. uap:Extension 項目加入至 Extensions 項目。
    5. uap:Extension 元素中新增 Category 屬性,並將 Category 屬性的值設為 windows.appService
    6. uap: Extension 元素中新增 EntryPoint 屬性,並將 EntryPoint 屬性的值設定為實現 IBackgroundTask 的類別的名稱。
      範例:AdventureWorks.VoiceCommands.AdventureWorksVoiceCommandService
    7. uap:AppService 項目加入至 uap:Extension 項目。
    8. Name 屬性新增至 uap:AppService 元素,並將 Name 屬性的值設定為應用程式服務的名稱,在本例中為 AdventureWorksVoiceCommandService
    9. 將第二個 uap:Extension 元素新增至 Extensions 元素。
    10. uap:Extension 元素中新增 Category 屬性,並將 Category 屬性的值設為 windows.personalAssistantLaunch

    範例:Adventure Works 應用程式的資訊清單。

    <Package>
        <Applications>
            <Application>
    
                <Extensions>
                    <uap:Extension Category="windows.appService" EntryPoint="CortanaBack1.VoiceCommands.AdventureWorksVoiceCommandService">
                        <uap:AppService Name="AdventureWorksVoiceCommandService"/>
                    </uap:Extension>
                    <uap:Extension Category="windows.personalAssistantLaunch"/>
                </Extensions>
    
            <Application>
        <Applications>
    </Package>
    
  8. 將此 App Service 專案新增為主要專案中的參考。

    1. 以滑鼠右鍵按一下 [參考]
    2. 選取 [新增參考...]
    3. 參考管理員對話方塊中,展開專案並選取應用程式服務專案。
    4. 按一下 [確定] 按鈕。

建立 VCD 檔案

  1. 在 Visual Studio 中,以滑鼠右鍵按一下主要專案名稱,選取 [新增] >[新項目]。 新增 XML 檔案
  2. 輸入 VCD 檔案的名稱。
    範例:AdventureWorksCommands.xml
  3. 按一下 [新增] 按鈕。
  4. 方案總管中,選取 VCD 檔案。
  5. 屬性視窗中,將建置動作設為內容,然後將複製到輸出目錄設為如果較新則複製

編輯 VCD 檔案

  1. 新增一個 VoiceCommands 元素,其 xmlns 屬性指向 https://schemas.microsoft.com/voicecommands/1.2

  2. 針對應用程式所支援的每個語言,建立包含應用程式所支援語音命令的 CommandSet 元素。
    您可以宣告多個 CommandSet 元素,每個元素都有不同的 xml:lang 屬性,以便您的應用程式在不同的市場中使用。 例如,針對美國的應用程式可能會使用 CommandSet 表示英文,並使用 CommandSet 表示西班牙文。

    重要

    若要啟用應用程式並使用語音命令啟動操作,應用程式必須註冊一個 VCD 檔案,其中包含 CommandSet 元素,該元素的語言與使用者裝置中指示的語音語言相符。 語音語言位於「設定」>「系統>語音」>「語音語言」

  3. 為您想要支援的每個命令新增 Command 元素。
    VCD 檔案中宣告的每個 Command 必須包含以下資訊:

    • 您的應用程式用於在執行階段識別語音命令的 Name 屬性。

    • Example 元素,其中包含描述使用者如何呼叫命令的片語。 當使用者說出 What can I say?Help 或點選「查看更多」時,Cortana 會顯示範例。

    • ListenFor 元素,其中包含您的應用程式識別為命令的單字或片語。 每個 ListenFor 元素可能包含對一個或多個 PhraseList 元素的參考,這些元素包含與命令相關的特定單字。

      注意

      ListenFor 元素不得以程式設計方式修改。 然而,與 ListenFor 元素關聯的 PhraseList 元素可以透過程式設計方式修改。 應用程式應根據使用者使用應用程式時產生的資料集在執行階段修改 PhraseList 元素的內容。

      如需詳細資訊,請參閱動態修改 Cortana VCD 片語清單

    • Feedback 元素,其中包含 Cortana 在應用程式啟動時顯示和講話的文字。

Navigate 元素表示語音命令將應用程式啟用至前景。 在此範例中,showTripToDestination 命令是前景工作。

VoiceCommandService 元素表示語音命令將應用程式啟用至背景。 此元素的 Target 屬性值應與 package.appxmanifest 檔案中 uap:AppService 元素的 Name 屬性值相符。 在此範例中,whenIsTripToDestinationcancelTripToDestination 命令是將應用程式服務名稱指定為 AdventureWorksVoiceCommandService 的背景工作。

如需詳細資訊,請參閱VCD 元素和屬性 v1.2 參考。

範例:VCD 檔案的一部分,定義 Adventure Works 應用程式的 en-us 語音命令。

<?xml version="1.0" encoding="utf-8" ?>
<VoiceCommands xmlns="https://schemas.microsoft.com/voicecommands/1.2">
<CommandSet xml:lang="en-us" Name="AdventureWorksCommandSet_en-us">
    <AppName> Adventure Works </AppName>
    <Example> Show trip to London </Example>
    
    <Command Name="showTripToDestination">
        <Example> Show trip to London </Example>
        <ListenFor RequireAppName="BeforeOrAfterPhrase"> show [my] trip to {destination} </ListenFor>
        <ListenFor RequireAppName="ExplicitlySpecified"> show [my] {builtin:AppName} trip to {destination} </ListenFor>
        <Feedback> Showing trip to {destination} </Feedback>
        <Navigate />
    </Command>
      
    <Command Name="whenIsTripToDestination">
        <Example> When is my trip to Las Vegas?</Example>
        <ListenFor RequireAppName="BeforeOrAfterPhrase"> when is [my] trip to {destination}</ListenFor>
        <ListenFor RequireAppName="ExplicitlySpecified"> when is [my] {builtin:AppName} trip to {destination} </ListenFor>
        <Feedback> Looking for trip to {destination}</Feedback>
        <VoiceCommandService Target="AdventureWorksVoiceCommandService"/>
    </Command>
    
    <Command Name="cancelTripToDestination">
        <Example> Cancel my trip to Las Vegas </Example>
        <ListenFor RequireAppName="BeforeOrAfterPhrase"> cancel [my] trip to {destination}</ListenFor>
        <ListenFor RequireAppName="ExplicitlySpecified"> cancel [my] {builtin:AppName} trip to {destination} </ListenFor>
        <Feedback> Cancelling trip to {destination}</Feedback>
        <VoiceCommandService Target="AdventureWorksVoiceCommandService"/>
    </Command>

    <PhraseList Label="destination">
        <Item>London</Item>
        <Item>Las Vegas</Item>
        <Item>Melbourne</Item>
        <Item>Yosemite National Park</Item>
    </PhraseList>
</CommandSet>

安裝 VCD 命令

您的應用程式必須執行一次,才能安裝 VCD。

注意

應用程式安裝不會保留語音命令資料。 為了確保應用程式的語音命令資料保持不變,請考慮在每次啟動或啟用應用程式時初始化 VCD 檔案,或維護指出 VCD 目前是否已安裝的設定。

app.xaml.cs 檔案中:

  1. 新增以下 using 指示詞:

    using Windows.Storage;
    
  2. 使用 async 修飾詞標記 OnLaunched 方法。

    protected async override void OnLaunched(LaunchActivatedEventArgs e)
    
  3. 呼叫 OnLaunched 處理常式中的 InstallCommandDefinitionsFromStorageFileAsync 方法來註冊應識別的語音命令。
    範例:Adventure Works 應用程式會定義 StorageFile 物件。
    範例:呼叫 GetFileAsync 方法用 AdventureWorksCommands.xml 檔案初始化 StorageFile 物件。
    然後 StorageFile 物件被傳遞給 InstallCommandDefinitionsFromStorageFileAsync 方法。

    try {
       // Install the main VCD. 
       StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(
             @"AdventureWorksCommands.xml"
       );
    
       await Windows.ApplicationModel.VoiceCommands.VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
    
       // Update phrase list.
       ViewModel.ViewModelLocator locator = App.Current.Resources["ViewModelLocator"] as ViewModel.ViewModelLocator;
       if(locator != null) {
             await locator.TripViewModel.UpdateDestinationPhraseList();
         }
     }
     catch (Exception ex) {
         System.Diagnostics.Debug.WriteLine("Installing Voice Commands Failed: " + ex.ToString());
     }
    

處理啟用

指定您的應用程式如何回應後續的語音命令啟用。

注意

安裝語音命令集之後,您必須至少啟動您的應用程式一次。

  1. 確認您的應用程式已由語音命令啟動。

    覆寫 Application.OnActivated 事件並檢查 IActivatedEventArgs.Kind 是否為 VoiceCommand

  2. 判斷命令的名稱和說話內容。

    IActivatedEventArgs 取得 VoiceCommandActivatedEventArgs 物件的參考,並查詢 Result 屬性以取得 SpeechRecognitionResult 物件。

    若要判斷使用者說的內容,請檢查文字的值,或 SpeechRecognitionSemanticInterpretation 字典中已辨識片語語意屬性。

  3. 在您的應用程式中採取適當的動作,例如瀏覽至所需的頁面。

    注意

    如果您需要參考 VCD,請造訪編輯 VCD 檔案一節。

    收到語音命令的語音辨識結果後,您可以從 RulePath 陣列中的第一個值取得命令名稱。 由於 VCD 檔案定義了多個可能的語音命令,因此您必須確認值符合 VCD 中的命令名稱,並採取適當的動作。

    應用程式最常見的動作是瀏覽至與語音命令內容相關的頁面。
    範例:開啟 TripPage 頁面並傳入語音命令的值、命令的輸入方式,以及辨識的目的片語 (如果適用的話)。 或者,應用程式可以在瀏覽至 TripPage 頁面時向 SpeechRecognitionResult 傳送瀏覽參數。

    您可以使用 commandMode 鍵從 SpeechRecognitionSemanticInterpretation.Properties 字典中找出啟動應用程式的語音命令是否實際上是說出的,或者是否是以文字形式輸入的。 該鍵的值會是 voicetext。 如果該鍵的值為 voice,請考慮在應用程式中使用語音合成 (Windows.Media.SpeechSynthesis) 為使用者提供語音意見反應。

    使用 SpeechRecognitionSemanticInterpretation.Properties 尋找 ListenFor 元素的 PhraseListPhraseTopic 限制中所說的內容。 字典索引鍵是 PhraseListPhraseTopic 元素的 Label 屬性值。 範例:以下程式碼說明如何存取 {destination} 片語的值。

    /// <summary>
    /// Entry point for an application activated by some means other than normal launching. 
    /// This includes voice commands, URI, share target from another app, and so on. 
    /// 
    /// NOTE:
    /// A previous version of the VCD file might remain in place 
    /// if you modify it and update the app through the store. 
    /// Activations might include commands from older versions of your VCD. 
    /// Try to handle these commands gracefully.
    /// </summary>
    /// <param name="args">Details about the activation method.</param>
    protected override void OnActivated(IActivatedEventArgs args) {
        base.OnActivated(args);
    
        Type navigationToPageType;
        ViewModel.TripVoiceCommand? navigationCommand = null;
    
        // Voice command activation.
        if (args.Kind == ActivationKind.VoiceCommand) {
            // Event args may represent many different activation types. 
            // Cast the args so that you only get useful parameters out.
            var commandArgs = args as VoiceCommandActivatedEventArgs;
    
            Windows.Media.SpeechRecognition.SpeechRecognitionResult speechRecognitionResult = commandArgs.Result;
    
            // Get the name of the voice command and the text spoken.
            // See VoiceCommands.xml for supported voice commands.
            string voiceCommandName = speechRecognitionResult.RulePath[0];
            string textSpoken = speechRecognitionResult.Text;
    
            // commandMode indicates whether the command was entered using speech or text.
            // Apps should respect text mode by providing silent (text) feedback.
            string commandMode = this.SemanticInterpretation("commandMode", speechRecognitionResult);
    
            switch (voiceCommandName) {
                case "showTripToDestination":
                    // Access the value of {destination} in the voice command.
                    string destination = this.SemanticInterpretation("destination", speechRecognitionResult);
    
                    // Create a navigation command object to pass to the page.
                    navigationCommand = new ViewModel.TripVoiceCommand(
                        voiceCommandName,
                        commandMode,
                        textSpoken,
                        destination
                    );
    
                    // Set the page to navigate to for this voice command.
                    navigationToPageType = typeof(View.TripDetails);
                    break;
                default:
                    // If not able to determine what page to launch, then go to the default entry point.
                    navigationToPageType = typeof(View.TripListView);
                    break;
            }
        }
        // Protocol activation occurs when a card is selected within Cortana (using a background task).
        else if (args.Kind == ActivationKind.Protocol) {
            // Extract the launch context. In this case, use the destination from the phrase set (passed
            // along in the background task inside Cortana), which makes no attempt to be unique. A unique id or 
            // identifier is ideal for more complex scenarios. The destination page is left to check if the 
            // destination trip still exists, and navigate back to the trip list if it does not.
            var commandArgs = args as ProtocolActivatedEventArgs;
            Windows.Foundation.WwwFormUrlDecoder decoder = new Windows.Foundation.WwwFormUrlDecoder(commandArgs.Uri.Query);
            var destination = decoder.GetFirstValueByName("LaunchContext");
    
            navigationCommand = new ViewModel.TripVoiceCommand(
                "protocolLaunch",
                "text",
                "destination",
                destination
            );
    
            navigationToPageType = typeof(View.TripDetails);
        }
        else {
            // If launched using any other mechanism, fall back to the main page view.
            // Otherwise, the app will freeze at a splash screen.
            navigationToPageType = typeof(View.TripListView);
        }
    
        // Repeat the same basic initialization as OnLaunched() above, taking into account whether
        // or not the app is already active.
        Frame rootFrame = Window.Current.Content as Frame;
    
        // Do not repeat app initialization when the Window already has content,
        // just ensure that the window is active.
        if (rootFrame == null) {
            // Create a frame to act as the navigation context and navigate to the first page.
            rootFrame = new Frame();
            App.NavigationService = new NavigationService(rootFrame);
    
            rootFrame.NavigationFailed += OnNavigationFailed;
    
            // Place the frame in the current window.
            Window.Current.Content = rootFrame;
        }
    
        // Since the expectation is to always show a details page, navigate even if 
        // a content frame is in place (unlike OnLaunched).
        // Navigate to either the main trip list page, or if a valid voice command
        // was provided, to the details page for that trip.
        rootFrame.Navigate(navigationToPageType, navigationCommand);
    
        // Ensure the current window is active
        Window.Current.Activate();
    }
    
    /// <summary>
    /// Returns the semantic interpretation of a speech result. 
    /// Returns null if there is no interpretation for that key.
    /// </summary>
    /// <param name="interpretationKey">The interpretation key.</param>
    /// <param name="speechRecognitionResult">The speech recognition result to get the semantic interpretation from.</param>
    /// <returns></returns>
    private string SemanticInterpretation(string interpretationKey, SpeechRecognitionResult speechRecognitionResult) {
        return speechRecognitionResult.SemanticInterpretation.Properties[interpretationKey].FirstOrDefault();
    }
    

處理應用程式服務中的語音命令

在應用程式服務中處理語音命令。

  1. 將下列 using 指示詞新增至您的語音命令服務檔案。
    範例:AdventureWorksVoiceCommandService.cs

        using Windows.ApplicationModel.VoiceCommands;
        using Windows.ApplicationModel.Resources.Core;
        using Windows.ApplicationModel.AppService;
    
  2. 接受服務延遲,以便在處理語音命令時,您的應用程式服務不會終止。

  3. 確認背景工作是以語音命令啟動的應用程式服務身分執行。

    1. IBackgroundTaskInstance.TriggerDetails 轉換成 Windows.ApplicationModel.AppService.AppServiceTriggerDetails
    2. 檢查 IBackgroundTaskInstance.TriggerDetails.NamePackage.appxmanifest 檔案中的應用程式服務名稱。
  4. 使用 IBackgroundTaskInstance.TriggerDetails 建立 VoiceCommandServiceConnectionCortana 以擷取語音命令。

  5. 註冊 VoiceCommandServiceConnection 的事件處理常式。 VoiceCommandCompleted 會在應用程式服務因為使用者取消而關閉時接收通知。

  6. 註冊 IBackgroundTaskInstance.Canceled 的事件處理常式,以在應用程式服務因未預期的失敗而關閉時接收通知。

  7. 判斷命令的名稱和說話內容。

    1. 使用 VoiceCommand.CommandName 屬性來決定語音命令的名稱。
    2. 若要判斷使用者說的內容,請檢查文字的值,或 SpeechRecognitionSemanticInterpretation 字典中已辨識片語語意屬性。
  8. 在您的應用程式服務中採取適當的動作。

  9. 使用 Cortana 向語音命令顯示並說出意見反應。

    1. 判斷您想要 Cortana 向使用者顯示及說話的字串,以回應語音命令並建立 VoiceCommandResponse 物件。 如需如何選取 Cortana 顯示和說話的意見反應字串的指引,請參閱 Cortana 設計指導方針。
    2. 使用 VoiceCommandServiceConnection 執行個體,藉由使用 VoiceCommandServiceConnection 物件呼叫 ReportProgressAsyncReportSuccessAsync,將進度或完成報告至 Cortana

    注意

    如果您需要參考 VCD,請造訪編輯 VCD 檔案一節。

    public sealed class VoiceCommandService : IBackgroundTask {
        private BackgroundTaskDeferral serviceDeferral;
        VoiceCommandServiceConnection voiceServiceConnection;
    
        public async void Run(IBackgroundTaskInstance taskInstance) {
            //Take a service deferral so the service isn&#39;t terminated.
            this.serviceDeferral = taskInstance.GetDeferral();
    
            taskInstance.Canceled += OnTaskCanceled;
    
            var triggerDetails = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    
            if (triggerDetails != null &amp;&amp; 
                triggerDetails.Name == "AdventureWorksVoiceServiceEndpoint") {
                try {
                    voiceServiceConnection = 
                    VoiceCommandServiceConnection.FromAppServiceTriggerDetails(
                        triggerDetails);
                    voiceServiceConnection.VoiceCommandCompleted += 
                    VoiceCommandCompleted;
    
                    VoiceCommand voiceCommand = await 
                    voiceServiceConnection.GetVoiceCommandAsync();
    
                    switch (voiceCommand.CommandName) {
                        case "whenIsTripToDestination":
                            {
                                var destination = 
                                voiceCommand.Properties["destination"][0];
                                SendCompletionMessageForDestination(destination);
                                break;
                            }
    
                            // As a last resort, launch the app in the foreground.
                        default:
                            LaunchAppInForeground();
                            break;
                    }
                }
                finally {
                    if (this.serviceDeferral != null) {
                        // Complete the service deferral.
                        this.serviceDeferral.Complete();
                    }
                }
            }
        }
    
        private void VoiceCommandCompleted(VoiceCommandServiceConnection sender,
            VoiceCommandCompletedEventArgs args) {
            if (this.serviceDeferral != null) {
                // Insert your code here.
                // Complete the service deferral.
                this.serviceDeferral.Complete();
            }
        }
    
        private async void SendCompletionMessageForDestination(
            string destination) {
            // Take action and determine when the next trip to destination
            // Insert code here.
    
            // Replace the hardcoded strings used here with strings 
            // appropriate for your application.
    
            // First, create the VoiceCommandUserMessage with the strings 
            // that Cortana will show and speak.
            var userMessage = new VoiceCommandUserMessage();
            userMessage.DisplayMessage = "Here's your trip.";
            userMessage.SpokenMessage = "Your trip to Vegas is on August 3rd.";
    
            // Optionally, present visual information about the answer.
            // For this example, create a VoiceCommandContentTile with an 
            // icon and a string.
            var destinationsContentTiles = new List<VoiceCommandContentTile>();
    
            var destinationTile = new VoiceCommandContentTile();
            destinationTile.ContentTileType = 
                VoiceCommandContentTileType.TitleWith68x68IconAndText;
            // The user taps on the visual content to launch the app. 
            // Pass in a launch argument to enable the app to deep link to a 
            // page relevant to the item displayed on the content tile.
            destinationTile.AppLaunchArgument = 
                string.Format("destination={0}", "Las Vegas");
            destinationTile.Title = "Las Vegas";
            destinationTile.TextLine1 = "August 3rd 2015";
            destinationsContentTiles.Add(destinationTile);
    
            // Create the VoiceCommandResponse from the userMessage and list    
            // of content tiles.
            var response = VoiceCommandResponse.CreateResponse(
                userMessage, destinationsContentTiles);
    
            // Cortana displays a "Go to app_name" link that the user 
            // taps to launch the app. 
            // Pass in a launch to enable the app to deep link to a page 
            // relevant to the voice command.
            response.AppLaunchArgument = string.Format(
                "destination={0}", "Las Vegas");
    
            // Ask Cortana to display the user message and content tile and 
            // also speak the user message.
            await voiceServiceConnection.ReportSuccessAsync(response);
        }
    
        private async void LaunchAppInForeground() {
            var userMessage = new VoiceCommandUserMessage();
            userMessage.SpokenMessage = "Launching Adventure Works";
    
            var response = VoiceCommandResponse.CreateResponse(userMessage);
    
            // When launching the app in the foreground, pass an app 
            // specific launch parameter to indicate what page to show.
            response.AppLaunchArgument = "showAllTrips=true";
    
            await voiceServiceConnection.RequestAppLaunchAsync(response);
        }
    }
    

啟用之後,應用程式服務有 0.5 秒可呼叫 ReportSuccessAsyncCortana 會顯示並說出意見反應字串。

注意

您可以在 VCD 檔案中宣告意見反應字串。 此字串不會影響 Cortana 畫布上顯示的 UI 文字,只會影響 Cortana 所讀出的文字。

如果應用程式需要超過 0.5 秒的時間進行呼叫,Cortana 會插入切換畫面,如下所示。 Cortana 會顯示切換畫面,直到應用程式呼叫 ReportSuccessAsync,或最多 5 秒。 如果應用程式服務未呼叫 ReportSuccessAsync,或提供 Cortana 資訊的任何VoiceCommandServiceConnection方法,則使用者會收到錯誤訊息,並取消應用程式服務。

在背景中使用 AdventureWorks 應用程式的 Cortana 和具有進度和結果畫面的基本查詢螢幕快照