Kolumne XAML Expertise: WPF und Windows-Apps

XAML-Tipp: Kommunikation zwischen Universal-Windows-Apps und WPF mit dem App-Service
Kommentare

In der neuen Kolumne „XAML Expertise“ des Windows Developer präsentiert Gregor Biswanger Top-How-tos zum Thema XAML. Einsteiger und fortgeschrittene XAML-Experten sollen hier durch geballtes Wissen gesättigt werden. Heute gibt es folgende Expertise: „XAML: Kommunikation zwischen Universal-Windows-Apps und WPF mit dem App-Service“.

Der App-Service ist eine Möglichkeit zur Kommunikation zwischen Universal-Windows-Apps und WPF/WinForms. Einige Universal-Windows-Apps behandeln Background-Tasks wie einen App-Service, um einen Vorgang abzuschließen. Es ist ähnlich wie mit einem Web Service, bei dem der Benutzer die Daten an den Dienst zur Verarbeitung sendet und die Antwortdaten innerhalb der App entgegennimmt. Aber hier benutzen wir kein HTTP-Protokoll oder beliebigen Web Service. Stattdessen verwenden wir einen Background-Task, der die Daten einer anderen App übernimmt. Er fungiert hierbei als App-Service.

Kommunikation zwischen Universal-Windows-Apps und WPF mit dem App-Service

In diesem Beispiel werden wir eine einfache Universal-Windows-App erstellen, die eingegebene Daten an einen Background-Task sendet und eine WPF-Anwendung, die sie entgegennimmt. Erstellen Sie dazu in Visual Studio ein neues Universal-Windows-App-Projekt und fügen Sie eine TextBox und einen Button zur Oberfläche hinzu. Wird der Button geklickt, soll der Code aus Listing 2 ausgeführt werden.

Die AppServiceConnection-Klasse ermöglicht die Verbindung zu anderen App-Service-Background-Tasks. Bei PackageFamilyName muss der vorgegebene Name aus der Package.appxmanifest-Datei übernommen werden. Machen Sie einfach einen Doppelklick auf diese Datei und wählen Sie im geöffneten Fenster den Packaging-Tab aus. Am Ende finden Sie den nötigen Namen (Abb. 1). Die OpenAsync-Methode baut dann die tatsächliche Verbindung auf. War diese erfolgreich, können Daten übermittelt werden, was zum Beispiel durch die SendMessageAsync-Methode erfolgt. Gibt der Background-Task einen Wert zurück, befindet er sich in AppServiceResponse.

AppServiceConnection appService = new AppServiceConnection();
appService.AppServiceName = "appservicesdemo";
appService.PackageFamilyName = "PackageFamilyName";
AppServiceConnectionStatus connectionStatus = await appService.OpenAsync();

if (connectionStatus == AppServiceConnectionStatus.Success)
{
  var message = new ValueSet(); 
  message.Add("Command", "SayHello");
  message.Add("UserInput", textBox.Text);

  AppServiceResponse response = await appService.SendMessageAsync(message);

  if (response.Status == AppServiceResponseStatus.Success)
  {
    string result = (string)response.Message["Result"];
    await new MessageDialog(result).ShowAsync();
  }
}
else
{
  await new MessageDialog("Connection Failed ").ShowAsync();
}

Abb. 1: „PackageFamilyName“ in der „Package.appxmanifest“-Datei ermitteln

Die Logik für die Universal-Windows-App ist fertig, jetzt wird der dazugehörige App-Service-Background-Task benötigt. Erstellen Sie ein neues „Windows Runtime Component (Universal Windows)“-Projekt und eine AppServiceBGTask-Klasse, die das IBackgroundTask-Interface implementiert. Das bereits erzeugte Universal-Windows-App-Projekt muss anschließend das neue Projekt referenzieren. Die Logik zur Verarbeitung der Daten wird in Listing 2 gezeigt. Beim Aufrufen des Background-Tasks wird die RequestReceived-Methode ausgelöst. Sie nimmt die überreichten Daten entgegen, verarbeitet sie und sendet sie daraufhin wieder an alle Interessierten zurück. Damit der Background-Task jetzt auch als App-Service aktiv werden kann, muss er vorher bei der Package.appxmanifest-Datei registriert werden. Abbildung 2 zeigt die AppManifest-Datei mit dem eingetragenen App-Service-Background-Task. Wichtig sind die beiden Parameter Name und Entry Point. Der Name kann frei definiert werden, und der Entry Point baut sich auf Namespace- und Background-Task-Klassennamen auf. Um den App-Service nun auf dem Betriebssystem zur Verfügung zu stellen, muss das Projekt im Menü unter Build | Deploy Solution veröffentlicht werden.

Listing 3: Universal-Windows-App-Background-Task
namespace AppServiceDemo
{
  public sealed class AppServiceBGTask : IBackgroundTask
  {
    private static BackgroundTaskDeferral serviceDeferral;

    public void Run(IBackgroundTaskInstance taskInstance)
    {
      serviceDeferral = taskInstance.GetDeferral();
      var appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
      if (appService.Name == "appservicesdemo")
      {
        appService.AppServiceConnection.RequestReceived += RequestReceived;
      }
    }

    private async void RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
    {
      var messageDeferral = args.GetDeferral();
      var message = args.Request.Message;
      string userInput = (string)message["UserInput"];
      string result = "Hallo " + userInput;

      var returnMessage = new ValueSet();
      returnMessage.Add("Result", result);
      var responseStatus = await args.Request.SendResponseAsync(returnMessage);
      messageDeferral.Complete();
    }

  }
}

Abb. 2: App-Service in der „Package.appxmanifest“-Datei registrieren

Die Universal-Windows-App und der Background-Task als App-Service sind nun implementiert. Als Nächstes folgt die Implementierung der WPF-Anwendung. Erstellen Sie dazu in Visual Studio ein neues WPF-Projekt und fügen Sie die nötigen DLL-Dateien sowie die Windows.winmd-Datei unter den Referenzen hinzu: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Runtime.WindowsRuntime.dll und C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Windows.winmd.

Jetzt ist der direkte Zugriff auf das Windows-10-API und die registrierten App-Services von der WPF-Anwendung aus möglich. Der Code dazu ist zu dem von Listing 1 sehr ähnlich. Der einzige Unterschied ist, dass hierbei auf das RequestReceived-Event gelauscht wird. Wenn der App-Service neue Informationen bereitstellt, wird dieses Event ausgelöst, und die Daten stehen der WPF-Anwendung zur Verfügung. Wichtig hierbei ist auch, dass PackageFamilyName wieder mit dem aus Ihrer Universal-Windows-App ersetzt wird. In Listing 3 steht der gesamte Code für die WPF-Anwendung. Nach dem Starten der Universal-Windows-App wird der App-Service auch automatisch geladen. Nun muss die WPF-Anwendung gestartet werden. Schreiben Sie jetzt in die TextBox der Universal-Windows-App Ihren Namen und bestätigen Sie mit einem Buttonklick. Der App-Service empfängt dann Ihren Namen, baut eine Begrüßung ein und sendet sie an die App und WPF-Anwendung zurück.

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
  AppServiceConnection appService = new AppServiceConnection();
  appService.AppServiceName = "appservicedemo";
  appService.PackageFamilyName = "PackageFamilyName";
  AppServiceConnectionStatus connectionStatus = await appService.OpenAsync();

  if (connectionStatus == AppServiceConnectionStatus.Success)
  {
    appService.RequestReceived += OnRequestReceived;
  }
}

private void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
  string result = (string)args.Request.Message["Result"];
  MessageBox.Show(result);
}

Abb. 3: Kommunikation zwischen Universal-Windows-Apps und WPF mit dem App-Service

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist der Windows Developer ferner im Abonnement oder als Einzelheft erhältlich.

 

 

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -