cortana在后台任务中拥有自己的命令

cortana own command in backgroundtask

我正在尝试编写一个 c# 程序来为 cortana 定义自定义命令!

首先我创建一个默认的应用程序并加载 VCD 文件...

我创建了第二个项目 link 到主项目并在其中创建一个后台任务来处理 cortana 请求!

现在 cortana 知道我的命令,但如果我告诉她一些事情,她就会回答 "Es ist etwas schief gelaufen"(英语:"it fails")。

我认为 BackgroundTask 调用不正确。

App.cs

namespace CortanaCommandsStart
{
/// <summary>
/// Stellt das anwendungsspezifische Verhalten bereit, um die Standardanwendungsklasse zu ergänzen.
/// </summary>
sealed partial class App : Application
{
    /// <summary>
    /// Initialisiert das Singletonanwendungsobjekt.  Dies ist die erste Zeile von erstelltem Code
    /// und daher das logische Äquivalent von main() bzw. WinMain().
    /// </summary>
    public App()
    {
        Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(Microsoft.ApplicationInsights.WindowsCollectors.Metadata | Microsoft.ApplicationInsights.WindowsCollectors.Session);
        this.InitializeComponent();
        this.Suspending += OnSuspending;
    }

    /// <summary>
    /// Wird aufgerufen, wenn die Anwendung durch den Endbenutzer normal gestartet wird. Weitere Einstiegspunkte
    /// werden z. B. verwendet, wenn die Anwendung gestartet wird, um eine bestimmte Datei zu öffnen.
    /// </summary>
    /// <param name="e">Details über Startanforderung und -prozess.</param>
    protected override async void OnLaunched(LaunchActivatedEventArgs e)
    {
        Frame rootFrame = Window.Current.Content as Frame;

        // App-Initialisierung nicht wiederholen, wenn das Fenster bereits Inhalte enthält.
        // Nur sicherstellen, dass das Fenster aktiv ist.
        if (rootFrame == null)
        {
            // Frame erstellen, der als Navigationskontext fungiert und zum Parameter der ersten Seite navigieren
            rootFrame = new Frame();

            rootFrame.NavigationFailed += OnNavigationFailed;

            if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
            {
                //TODO: Zustand von zuvor angehaltener Anwendung laden
            }

            // Den Frame im aktuellen Fenster platzieren
            Window.Current.Content = rootFrame;
        }

        if (rootFrame.Content == null)
        {
            // Wenn der Navigationsstapel nicht wiederhergestellt wird, zur ersten Seite navigieren
            // und die neue Seite konfigurieren, indem die erforderlichen Informationen als Navigationsparameter
            // übergeben werden
            rootFrame.Navigate(typeof(MainPage), e.Arguments);
        }

        try {
            StorageFile vcdStorageFile = await Package.Current.InstalledLocation.GetFileAsync(@"LEDControll.xml");
            await VoiceCommandDefinitionManager.InstallCommandDefinitionsFromStorageFileAsync(vcdStorageFile);
            System.Diagnostics.Debug.WriteLine("There was no error registering the Voice Command Definitions");
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("There was an error registering the Voice Command Definitions", ex);
        }

        // Sicherstellen, dass das aktuelle Fenster aktiv ist
        Window.Current.Activate();
    }

    /// <summary>
    /// Wird aufgerufen, wenn die Navigation auf eine bestimmte Seite fehlschlägt
    /// </summary>
    /// <param name="sender">Der Rahmen, bei dem die Navigation fehlgeschlagen ist</param>
    /// <param name="e">Details über den Navigationsfehler</param>
    void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
    {
        throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
    }

    /// <summary>
    /// Wird aufgerufen, wenn die Ausführung der Anwendung angehalten wird.  Der Anwendungszustand wird gespeichert,
    /// ohne zu wissen, ob die Anwendung beendet oder fortgesetzt wird und die Speicherinhalte dabei
    /// unbeschädigt bleiben.
    /// </summary>
    /// <param name="sender">Die Quelle der Anhalteanforderung.</param>
    /// <param name="e">Details zur Anhalteanforderung.</param>
    private void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        //TODO: Anwendungszustand speichern und alle Hintergrundaktivitäten beenden
        deferral.Complete();
    }
}
}

应用程序清单:

<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
  <Identity Name="32ed3ec5-2e4a-4517-ae2b-842653ab8a8e" Publisher="CN=Flo" Version="1.0.0.0" />
  <mp:PhoneIdentity PhoneProductId="32ed3ec5-2e4a-4517-ae2b-842653ab8a8e" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
  <Properties>
    <DisplayName>CortanaCommandsStart</DisplayName>
    <PublisherDisplayName>Flo</PublisherDisplayName>
    <Logo>Assets\StoreLogo.png</Logo>
  </Properties>
  <Dependencies>
    <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
  </Dependencies>
  <Resources>
    <Resource Language="x-generate" />
  </Resources>
  <Applications>
    <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="CortanaCommandsStart.App">
      <uap:VisualElements DisplayName="CortanaCommandsStart" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="CortanaCommandsStart" BackgroundColor="transparent">
        <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
        </uap:DefaultTile>
        <uap:SplashScreen Image="Assets\SplashScreen.png" />
      </uap:VisualElements>

      <Extensions>
        <uap:Extension Category="windows.appService" EntryPoint="CortanaCommand.CortanaCommandService">
          <uap:AppService Name="CortanaCommandService" />
        </uap:Extension>
      </Extensions>

    </Application>
  </Applications>
</Package>

CortanaCommand.cs

namespace CortanaCommand
{
    public sealed class CortanaCommandService : IBackgroundTask
    {
        private VoiceCommandServiceConnection voiceServiceConnection;
        private BackgroundTaskDeferral _deferral;

        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            _deferral = taskInstance.GetDeferral();

            voiceServiceConnection.VoiceCommandCompleted += VoiceCommandCompleted;

            AppServiceTriggerDetails triggerDetails = taskInstance.TriggerDetails as AppServiceTriggerDetails;

            if (triggerDetails != null && triggerDetails.Name.Equals("CortanaCommandService"))
            {
                try
                {
                    voiceServiceConnection = VoiceCommandServiceConnection.FromAppServiceTriggerDetails(triggerDetails);
                    VoiceCommand voiceCommand = await voiceServiceConnection.GetVoiceCommandAsync();

                    // Perform the appropriate command depending on the operation defined in VCD
                    VoiceCommandUserMessage userMessage = new VoiceCommandUserMessage();
                    switch (voiceCommand.CommandName)
                    {
                        case "LedChangeColor":
                            var destination = voiceCommand.Properties["color"][0];
                            SendCompletionMessageForDestination(destination);
                            break;
                        default:
                            LaunchAppInForeground();
                            break;
                    }
                }
                finally
                {
                    _deferral.Complete();
                }
            }

        }

        private void VoiceCommandCompleted(VoiceCommandServiceConnection sender, VoiceCommandCompletedEventArgs args)
        {
            if (this._deferral != null)
            {
                this._deferral.Complete();
            }
        }

        private async void SendCompletionMessageForDestination(string destination)
        {
            // Take action and determine when the next trip to destination
            // Inset 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>();

            // Create the VoiceCommandResponse from the userMessage and list    
            // of content tiles.
            var response = VoiceCommandResponse.CreateResponse(userMessage, destinationsContentTiles);

            // 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);
        }
    }
}

VCD:

<?xml version="1.0" encoding="utf-8"?>
<VoiceCommands xmlns="http://schemas.microsoft.com/voicecommands/1.2">

  <CommandSet xml:lang="de-de" Name="LEDControll">
    <CommandPrefix>LED</CommandPrefix>
    <Example>Steuere die LEDs</Example>

    <Command Name="LedChangeColor">
      <Example>LED Farbe grün</Example>
      <ListenFor>farbe {color}</ListenFor>
      <Feedback>Farbe wird geändert in {color}</Feedback>
      <VoiceCommandService Target="CortanaCommandService"/>
    </Command>

    <PhraseList Label="color">
      <Item> grün </Item>
      <Item> blau </Item>
      <Item> rot </Item>
    </PhraseList>

  </CommandSet>

</VoiceCommands>

感谢您的帮助!

只需在此处添加答案,这样就清楚了:

为确保后台任务正确添加到应用程序包中,您可以在VS中添加从启动项目到后台任务项目的引用:

  1. 右键单击启动项目中的引用
  2. 转到添加参考
  3. Select"Projects"左边
  4. 勾选包含后台任务的项目旁边的框。
  5. 点击确定。

这样可以确保 VS 在您部署时构建后台任务并将其复制到包中。否则,您 运行 会遇到像这样难以调试的问题。

通常,当您三重检查包清单 uap:Extension 条目是否包含正确的详细信息时,您可以判断发生了这种情况,但是当您尝试时无法在后台任务中设置断点激活它。我还将检查是否有任何可以查找的事件日志类型条目,以便更轻松地查看。