Share via



Mai 2018

Band 33, Nummer 5

Universelle Windows-Plattform: Erstellen von verbundenen Apps mit der UWP und dem Projekt „Rome“

Durch Tony Experten

In der heutigen Welt bedeutet erstellen eine erfolgreiche app über ein einzelnes Gerät verschieben. Apps, die erstrecken sich über alle Geräte und auch für andere Benutzer herstellen möchten, dass Benutzer. Diese Art von Erfahrung bereitstellen kann eine Herausforderung den geringsten sagen sein. Um die Adresse eingeführt dieser zunehmende Notwendigkeit der Microsoft-Ökosystem Projekt ROM. Projekt ROM zielt darauf ab, um eine persönliche OS erstellen, die apps, Geräte und Benutzer umfasst. Während Projekt ROM SDKs für die meisten wichtigen Vorgänge Plattformen verfügbar ist, werde ich in diesem Artikel durchsuchen mithilfe von Project ROM eines Teams messaging app (Universelle Windows Plattform).

Begrüßen Sie Projekt ROM

Das Projekt „Rome“ ist eine Initiative, die Ihnen helfen soll, das Engagement der Benutzer für alle Apps und Geräte zu fördern. Es ist eine Sammlung von APIs, die Teil von Microsoft Graph und werden in zwei Bereiche unterteilt: fortfahren und später fortsetzen.

Der Remote-Dateisystem-APIs aktivieren eine app außerhalb der Grenzen des aktuellen Geräts des Benutzers, unterbrechen eine Continue-jetzt auftreten. Ob Dadurch kann der Benutzer zwei Geräte für eine einzelnes erzielen Sie, wie bei einer Begleit oder die Remotesteuerung app, oder zulassen, dass mehrere Benutzer eine Verbindung herstellen und Freigeben einer zusammenfasst, bieten diese APIs eine erweiterte Ansicht der aktuellen Engagement des Benutzers. Das Team messaging-Apps in diesem Artikel wird eine gemeinsame Benutzeroberfläche erstellt.

Die andere Hälfte des Projekt-ROM, die APIs Aktivitäten konzentriert sich auf die benutzerfreundlichkeit zu einem späteren Zeitpunkt fortsetzen. Diese APIs ermöglichen Ihnen das Erfassen und bestimmte Aktionen innerhalb der app, die der Benutzer weiterhin auf einem beliebigen Gerät abrufen. Obwohl ich in diesem Artikel besprechen werden nicht, sind dies definitiv in lohnt.

Erste Schritte

Vor dem Einstieg in die app erstellen, müssen ich meiner Umgebung einzurichten. Während die erste Version des Projekts ROM out Anspruch befunden hat, wurden einige der Funktionen, die in diesem Artikel verwendet nur während des letzten Updates der fallen Ersteller veröffentlicht. Deshalb muss Ihr Computer Buildnummer 16299 oder höher ausgeführt werden. An diesem Punkt dieser Version steht in der langsamen Ring für Updates und die meisten Computer ordnungsgemäß aktualisiert werden soll.

Ausführen von apps mit dem Remote-Dateisystem-APIs für andere Benutzer müssen gemeinschaftliche auf dem Computer aktiviert sind. Dies kann erfolgen, in den Systemeinstellungen, in den Einstellungen | System | Freigegebene Erfahrungen. Für das Team-messaging-Szenario müssen Sie verschiedene Benutzer für die Kommunikation mit Ihrem Gerät, dies bedeutet, Sie sicherstellen müssen, dass Erfahrungen freigegebene Konfigurationen aktiviert und können Sie freigeben oder von "" Jeder "nahe gelegenen" empfangen entsprechend aktivieren Abbildung 1.

Aktivieren freigegebener Erfahrungen
Abbildung 1 zu aktivieren freigegebener Erfahrungen

Die letzte Anforderung ist, dass Ihr Gerät erkannt werden, da gewisse Konnektivität. Remote Dateisystem-APIs werden von anderen Computern im selben Netzwerk sowie die in der Nähe von über Bluetooth ermittelt. Bluetooth kann auf der Seite "Bluetooth und weitere geräteeinstellungen" in den Systemeinstellungen aktiviert werden.

Fangen Sie mit dem Computer einrichten durch das Erstellen einer neuen Visual c#-app, mit der Vorlage der leeren App (universelle Windows) in Visual Studio 2017. Rufen Sie die app "TeamMessenger." Wie bereits erwähnt, ist dieses Projekt das fallen Ersteller-Update erforderlich, so festgelegt, das Ziel und den Mindest-Versionen der app auf "Build 16299" oder höher, siehe Abbildung 2. Dadurch wird verhindert, dass die app Unterstützung älterer Versionen von Windows 10, aber es ist notwendig, damit einige der Funktionen, die in diesem Artikel berührt.

Einstellung auf Versionen, für die App
Abbildung 2-Einstellung auf Versionen, für die App

Beachten Sie, dass wenn Sie den Herbst Ersteller SDKs auf Ihrem Gerät aktualisieren haben, die einfachste Möglichkeit, diese erhalten ist 2017 von Visual Studio auf die neueste Version zu aktualisieren.

Die Projekt-ROM-APIs sind Teil des Windows 10-SDK, d. Es gibt keine zusätzlichen SDKs h. herunterladen oder einem NuGet-Pakete installieren, um diese app zu erstellen. Es gibt jedoch einige Funktionen, die die app in der Reihenfolge für die Remotesitzung APIs ordnungsgemäß hinzugefügt werden müssen. Dies kann durch Öffnen der Datei "Package.appxmanifest", und wählen die Registerkarte "Funktionen" erfolgen. Stellen Sie in der Liste der verfügbaren Funktionen sicher, dass Folgendes überprüft werden: Bluetooth, Internet (Client & Server) und Remote-System.

Erstellen die Sitzungsverbindung

Dieser app besteht aus zwei Seiten, mit der ersten Seite, die verantwortlich für das Erstellen oder verknüpfen eine Remotesitzung mit dem Remote-Dateisystem-APIs. Aus Gründen der Einfachheit werde ich diese Seite, die mit der Datei "MainPage.xaml", die mit der Projektmappe erstellt wurde, und ist bereits in der app, die erste Seite geladen werden verkabelte erstellen. Die Benutzeroberfläche verfügt über zwei Modi: Erstellen oder eine Sitzung zu hosten und beitreten zu einer vorhandenen Sitzung. Erstellen eine Sitzung erfordert einen Sitzungsnamen, die öffentlich sein, um Benutzer verknüpfen möchten. Beitreten zu einer vorhandenen Sitzung benötigt, um eine Liste der verfügbaren nahegelegene Sitzungen anzuzeigen. Beide Modi benötigen einen Namen für den Benutzer angezeigt werden. Abbildung 3 wird gezeigt, wie die resultierende Benutzeroberfläche aussehen soll für MainPage, und der XAML-Code zum Erstellen dieser Seite finden Sie im können Abbildung 4.

Der MainPage-Benutzeroberfläche
Abbildung 3 der MainPage-Benutzeroberfläche

Abbildung 4 der MainPage-XAML

<Page
  x:Class="TeamMessenger.MainPage"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:remotesystems="using:Windows.System.RemoteSystems"
  mc:Ignorable="d">
  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel Width="400"
                HorizontalAlignment="Center"
                BorderBrush="Gray"
                BorderThickness="1"
                MaxHeight="600"
                VerticalAlignment="Center"
                Padding="10">
    <RadioButton x:Name="rbCreate"
                GroupName="options"
                IsChecked="True"
                Checked="{x:Bind ViewModel.CreateSession}"
                Content="Create a New Session"/>
    <StackPanel Orientation="Horizontal" Margin="30,10,20,30">
      <TextBlock VerticalAlignment="Center">Session Name :</TextBlock>
      <TextBox Text="{x:Bind ViewModel.SessionName, Mode=TwoWay}"
               Width="200"
               Margin="20,0,0,0"/>
    </StackPanel>
    <RadioButton x:Name="rbJoin"
                GroupName="options"
                Checked="{x:Bind ViewModel.JoinSession}"
                Content="Join Session"/>
    <ListView ItemsSource="{x:Bind ViewModel.Sessions}"
              SelectedItem="{x:Bind ViewModel.SelectedSession, Mode=TwoWay}"
              IsItemClickEnabled="True"
              Height="200"
              BorderBrush="LightGray"
              BorderThickness="1"
              Margin="30,10,20,30">
      <ListView.ItemTemplate>
        <DataTemplate x:DataType="remotesystems:RemoteSystemSessionInfo">
          <TextBlock Text="{x:Bind DisplayName}"/>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
    <StackPanel Orientation="Horizontal">
      <TextBlock VerticalAlignment="Center">Name : </TextBlock>
      <TextBox Text="{x:Bind ViewModel.JoinName, Mode=TwoWay}"
               Width="200"
               Margin="20,0,0,0"/>
    </StackPanel>
    <Button Content="Start"
            Margin="0,30,0,0"
            Click="{x:Bind ViewModel.Start}"/>
    </StackPanel>
  </Grid>
</Page>

Nach dem Erstellen des XAML-Code für die Seite, erstellen Sie einen neuen ViewModels-Ordner in der app, und fügen Sie eine neue öffentliche Klasse hinzu, in diesem Ordner MainViewModel.cs aufgerufen. Dieses Modell der Sicht wird in der Ansicht, um die Funktionalität zu behandeln verbunden sein.

Der erste Teil des Modells anzeigen behandelt wird, Verwalten des Zustands für die Optionsfelder, die bestimmen, ob der Benutzer eine neue Sitzung erstellt oder eine vorhandene verknüpfen. Der Status wird in Bool aufgerufen IsNewSession aufrechterhalten. Es werden zwei Methoden verwendet, um den Status dieser Bool CreateSession und JoinSession zu wechseln:

public bool IsNewSession { get; set; } = true;
public void CreateSession()
{
  IsNewSession = true;
}
public void JoinSession()
{
  IsNewSession = false;
}

Checked-Ereignis für jedes Optionsfeld wird an eine der folgenden Methoden gebunden.

Die übrigen Benutzeroberflächenelemente sind bei der einfachen Eigenschaften nachverfolgt. Die Sitzung und Benutzernamen sind für den Sitzungsname und JoinName gebunden. Die SelectedSession-Eigenschaft für die Eigenschaft "SelectedItem" in der Listenansicht bindet und ItemsSource an die Sessions-Eigenschaft gebunden ist:

public string JoinName { get; set; }
public string SessionName { get; set; }
public object SelectedSession { get; set; }
public ObservableCollection<
  RemoteSystemSessionInfo> Sessions { get; } =
  new —ObservableCollection<
  RemoteSystemSessionInfo>();

Das Ansichtsmodell verfügt über zwei Ereignisse, die verwendet werden, lassen die Sicht, die wissen, ob eine Verbindung mit einer Sitzung erfolgreich oder nicht war:

public event EventHandler SessionConnected =
  delegate { };
public event EventHandler<SessionCreationResult> ErrorConnecting = delegate { };

Schließlich wird die Schaltfläche "Start" an eine Start-Methode gebunden. Diese Methode kann im Moment leer gelassen werden.

Nach Abschluss der Ansichtsmodell muss das Codebehind für MainPage eine öffentliche Eigenschaft erstellen, die eine Instanz des MainViewModel ist. Dies ist der Optionen X: binden, um den Zeitpunkt der Kompilierung Bindungen zu erstellen. Darüber hinaus muss es in das Ansichtsmodell erstellt zwei Ereignisse abonnieren. Wenn eine Verbindung erfolgreich hergestellt wird, werde ich zu einer neuen Seite MessagePage navigieren. Wenn die Verbindung fehlschlägt, wird eine MessageDialog informiert den Benutzer, der die fehlerhafte Verbindung angezeigt. Abbildung 5 enthält den Code für die Datei "MainPage.Xaml.cs".

Abbildung 5 "MainPage.xaml" Codebehind

public sealed partial class MainPage : Page
{
  public MainPage()
  {
    this.InitializeComponent();
    ViewModel.SessionConnected += OnSessionConnected;
    ViewModel.ErrorConnecting += OnErrorConnecting;
  }
  private async void OnErrorConnecting(object sender, SessionCreationResult e)
  {
    var dialog = new MessageDialog("Error connecting to a session");
    await dialog.ShowAsync();
  }
  private void OnSessionConnected(object sender, EventArgs e)
  {
    Frame.Navigate(typeof(MessagePage));
  }
  public MainViewModel ViewModel { get; } = new MainViewModel();
}

Definieren die Datenmodelle

Vor dem vertiefende im Zentrum der app, müssen Sie ein Paar von Datenmodellen, die verwendet werden, in der app definieren. Erstellen Sie einen Ordner Models in der app, und erstellen Sie zwei Klassen darin: Benutzer und UserMessage. Wie der Name bereits vermuten lässt, wird das Benutzermodell Informationen zur app verbundenen Benutzer überwacht:

public class User
{
  public string Id { get; set; }
  public string DisplayName { get; set; }
}

Die Klasse UserMessage enthält den Nachrichteninhalt der Benutzer den Inhalt und der Erstellung der Nachricht erstellen:

public class UserMessage
{
  public User User { get; set; }
  public string Message { get; set; }
  public DateTime DateTimeStamp { get; set; }
}

Erstellen einer Sitzung

Durch den Code für die Hauptseite angezeigt, die relativ abgeschlossen kann ich Einrichtung RemoteSessionManager, starten, der verwendet wird, um die Remote-Systeme-API umschließen. Fügen Sie eine neue öffentliche Klasse RemoteSessionManager in das Stammverzeichnis der app aufgerufen. Die app wird eine einzelne freigegebene Instanz dem RemoteSessionManager verwenden, damit Sie die App-Klasse in App.xaml.cs eine statische Eigenschaft hinzufügen können:

public static RemoteSessionManager SessionManager { get; } = new RemoteSessionManager();

Bevor die Anwendung eine der RAS-Systeme-APIs zugreifen kann, müssen sie zunächst Berechtigung des Benutzers abrufen. Durch diese Berechtigung wird durch Aufrufen der statischen Methode RemoteSystem.RequestAccessAsync abgerufen:

RemoteSystemAccessStatus accessStatus = 
  await RemoteSystem.RequestAccessAsync();
if (accessStatus != RemoteSystemAccessStatus.Allowed)
{
  // Access is denied, shortcut workflow
}

Die Methode gibt eine Enumeration RemoteSystemAccessStatus zurück, die verwendet werden kann, um festzustellen, ob der Zugriff gewährt wurde. Diese Methode muss durch den Benutzeroberflächenthread aufgerufen werden, damit sie erfolgreich den Benutzer aufzufordern, kann. Sobald der Benutzer hat erteilte oder verweigerte Berechtigung für die app, werden alle nachfolgenden Aufrufe automatisch den Einstellungen des Benutzers zurück. Für diese app wird durch diese Berechtigung mit der Ermittlung der Sitzung hinzugefügt werden, da sie zunächst im Workflow aufgerufen wird.

Beachten Sie, dass alle Remote Dateisystem-APIs im Namespace Windows.System.RemoteSystem gefunden werden können.

Die erste Methode zum Hinzufügen zu der RemoteSessionManager-Klasse ist die CreateSession-Methode. Kommen mehrere Ergebnisse, die von dieser Methode zurückgegeben werden können, ich werde Wrappen diese in eine neue Enumeration – SessionCreationResult. SessionCreationResult hat vier mögliche Werte: Erfolg und drei anderen Fehlern. Eine Sitzung kann nicht erstellt werden, weil der Benutzer Zugriff auf die app erteilt haben nicht; die app verfügt zurzeit über zu viele Sitzungen ausgeführt; oder ein Systemfehler: Fehler beim Erstellen der Sitzung:

public enum SessionCreationResult
{
  Success,
  PermissionError,
  TooManySessions,
  Failure
}

Remotesitzungen werden von einem RemoteSystemSessionController verwaltet. Wenn Sie eine neue Instanz der RemoteSystemSessionController erstellen zu können, müssen Sie einen Namen übergeben, die auf Geräten, bei dem Versuch, die an der Sitzung teilnehmen angezeigt werden.

Nachdem der Controller angefordert wird, kann eine Sitzung gestartet werden, durch Aufrufen der CreateSession-Methode. Diese Methode gibt ein RemoteSystemSessionCreationResult, enthält einen Status und die neue Instanz der Sitzung, wenn er erfolgreich war. Die RemoteSessionManager wird der neue Controller und die Sitzung in privaten Variablen gespeichert.

Eine neue öffentliche Eigenschaft IsHost, sollten auf den Manager, sowie zum Bestimmen der Workflow hinzugefügt werden. Dieser Wert wird während der Ausführung der Methode CreateSession festgelegt auf "true", diese app wie der Host identifiziert. Eine andere öffentliche Eigenschaft mit dem CurrentUser, eine Instanz des Benutzers auf dem Computer bereitgestellt und für messaging verwendet werden. Die Sitzungs-Manager verwaltet auch eine ObservableCollection von Benutzern in der aktuellen Sitzung. Diese Auflistung wird mit den neu erstellten Benutzer initialisiert. Für den Host der Sitzung ruft diese Instanz in der CreateSession-Methode erstellt. Der resultierenden Hinzufügungen zu den RemoteSessionManager werden angezeigt, Abbildung 6.

Abbildung 6 CreateSession-Methode

private RemoteSystemSessionController _controller;
private RemoteSystemSession _currentSession;
public bool IsHost { get; private set; }
public User CurrentUser { get; private set; }
public ObservableCollection<User> Users { get; } =
  new ObservableCollection<User>();
public async Task<SessionCreationResult> CreateSession(
  string sessionName, string displayName)
{
  SessionCreationResult status = SessionCreationResult.Success;
  RemoteSystemAccessStatus accessStatus = await RemoteSystem.RequestAccessAsync();
  if (accessStatus != RemoteSystemAccessStatus.Allowed)
  {
    return SessionCreationResult.PermissionError;
  }
  if (_controller == null)
  {
    _controller = new RemoteSystemSessionController(sessionName);
    _controller.JoinRequested += OnJoinRequested;
  }
  RemoteSystemSessionCreationResult createResult =
    await _controller.CreateSessionAsync();
  if (createResult.Status == RemoteSystemSessionCreationStatus.Success)
  {
    _currentSession = createResult.Session;
    InitParticipantWatcher();
    CurrentUser = new User() { Id = _currentSession.ControllerDisplayName,
      DisplayName = displayName };
    Users.Add(CurrentUser);
    IsHost = true;
  }
  else if(createResult.Status ==
    RemoteSystemSessionCreationStatus.SessionLimitsExceeded)
  {
    status = SessionCreationResult.TooManySessions;
  } else
  {
    status = SessionCreationResult.Failure;
  }
  return status;
}

Es gibt drei weitere Elemente, die RemoteSessionManager Abschließens CreateSession-Methode hinzugefügt werden müssen. Das erste ist ein Ereignishandler für aus, sobald ein Benutzer versucht, eine Sitzung verknüpfen und das JoinRequested-Ereignis in der Sitzung ausgelöst wird. Die Methode OnJoinRequested akzeptiert automatisch jeder Benutzer verknüpfen möchten. Dies kann erweitert werden, um den Host für die Genehmigung eine Aufforderung, bevor der Benutzer mit der Sitzung verbunden ist. Die Anforderungsinformationen dient als ein RemoteSystemSessionJoinRequest im Parameters RemoteSystemSessionJoinRequestedEventArgs des ereignishandlers enthalten. Aufrufen der Accept-Methode wird der Benutzer mit der Sitzung hinzufügen. Der folgende Code enthält das neue Ereignis so RemoteSessionManager als auch die abgeschlossenen OnJoinRequested-Methode hinzu:

private void OnJoinRequested(RemoteSystemSessionController sender,
  RemoteSystemSessionJoinRequestedEventArgs args)
{
  var deferral = args.GetDeferral();
  args.JoinRequest.Accept();
  deferral.Complete();
}

Die Sitzungs-Manager kann überwachen, wenn Teilnehmer hinzugefügt oder werden aus der aktuellen Sitzung über die RemoteSystemSessionParticipantWatcher entfernt. Diese Klasse überwacht die Teilnehmern und löst entweder eine Added "oder" entfernt Ereignis bei Bedarf. Wenn ein Benutzer eine Sitzung bereits läuft beitritt, wird jeder Teilnehmer in der aktuellen Sitzung bereits eine Added-Ereignis empfangen. Die app übernimmt diese Reihe von Ereignissen und bestimmen, welcher Teilnehmer der Host ist, durch den DisplayName für die Sitzung ControllerDisplayName abgleichen. Dadurch können Teilnehmer direkt mit dem Host kommunizieren. Die Sitzungs-Manager verwaltet einen Teilnehmer Watcher als eine private Variable, die in der InitParticipantWatcher initialisiert wird. Diese Methode wird aufgerufen, ob eine Sitzung zu erstellen oder beitreten zu einer vorhandenen Sitzung. Abbildung 7 neue Mitglieder enthält. Sie werden bemerken, dass für diesen Workflow müssen Sie wissen, wenn ein Teilnehmer entfernt wird, nur dann, wenn Sie den Host sind, und wenn ein Teilnehmer hinzugefügt wird, wenn Sie eine Sitzung beitreten. Als Host hat die RemoteSessionManager bedenken, nur, wenn ein Teilnehmer die Sitzung verlässt. Der Host wird direkt vom Teilnehmer benachrichtigt, wenn sie teilnehmen möchten, wie Sie später in diesem Artikel sehen. Teilnehmer müssen nur das aktuelle Hostkonto zu bestimmen.

Abbildung 7 InitParticipantWatcher

private RemoteSystemSessionParticipantWatcher _participantWatcher;
private void InitParticipantWatcher()
{
  _participantWatcher = _currentSession.CreateParticipantWatcher();
  if (IsHost)
  {
    _participantWatcher.Removed += OnParticipantRemoved;
  }
  else
  {
    _participantWatcher.Added += OnParticipantAdded;
  }
  _participantWatcher.Start();
}
private void OnParticipantAdded(RemoteSystemSessionParticipantWatcher watcher,
  RemoteSystemSessionParticipantAddedEventArgs args)
{
  if(args.Participant.RemoteSystem.DisplayName ==
    _currentSession.ControllerDisplayName)
  {
    Host = args.Participant;
  }
}
private async void OnParticipantRemoved(RemoteSystemSessionParticipantWatcher watcher,
  RemoteSystemSessionParticipantRemovedEventArgs args)
{
  var qry = Users.Where(u => u.Id == args.Participant.RemoteSystem.DisplayName);
  if (qry.Count() > 0)
  {
    var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
      () => { Users.Remove(qry.First()); });
    await BroadCastMessage("users", Users);
  }
}

Das letzte Ereignis benötigten CreateSession-Methode der-Klasse hinzugefügt ist ein Ereignis können Consumer kennen, wenn die Sitzung getrennt wird. Das neue SessionDisconnected-Ereignis kann wie folgt definiert werden:

public event EventHandler<RemoteSystemSessionDisconnectedEventArgs> SessionDisconnected =
  delegate { };

Beitreten zu einer Sitzung

Nun, dass die app eine neue Remotesitzung übertragen werden kann, wird Sie als nächste implementieren Sie die Möglichkeit, diese Sitzung von einem anderen Computer zu verknüpfen. Es sind zwei Schritte erforderlich, um eine Remotesitzung beitreten: Ermittlung und anschließend mit der Sitzung miteinander verbinden.

Ermittlung von einer Sitzung eine app kann in der Nähe Remotesitzungen über die RemoteSystemSessionWatcher ermitteln, die von der statischen CreateWatcher-Methode erstellt wird. Diese Klasse löst Ereignisse, die jedes Mal, wenn eine Sitzung hinzugefügt oder entfernt wird. Fügen Sie eine neue Methode – DiscoverSessions – auf die RemoteSessionManager. Diese Methode erstellt eine RemoteSystemSessionWatcher als eine private Variable, die die Klasse und behandelt die Ereignisse Added "und" entfernt. Diese Ereignisse werden durch zwei neue Ereignisse RemoteSessionManager hinzugefügt umschlossen werden: SessionAdded und SessionRemoved. Da dies für Benutzer, die beim Initialisieren des Remotesitzungen einem anderen Einstiegspunkt ist, müssen Sie sicherstellen, dass einen Aufruf von RemoteSystem.RequestAccessAsync hinzufügen. Abbildung 8 enthält private Variablen, die zwei Ereignisse und die vollständige DiscoverSessions-Methode.

Abbildung 8 Ermittlung von Sitzungen

private RemoteSystemSessionWatcher _watcher;
public event EventHandler<RemoteSystemSessionInfo> SessionAdded = delegate { };
public event EventHandler<RemoteSystemSessionInfo> SessionRemoved = delegate { };
public async Task<bool> DiscoverSessions()
{
  RemoteSystemAccessStatus status = await RemoteSystem.RequestAccessAsync();
  if (status != RemoteSystemAccessStatus.Allowed)
  {
    return false;
  }
  _watcher = RemoteSystemSession.CreateWatcher();
  _watcher.Added += (sender, args) =>
  {
    SessionAdded(sender, args.SessionInfo);
  };
  _watcher.Removed += (sender, args) =>
  {
    SessionRemoved(sender, args.SessionInfo);
  };
  _watcher.Start();
  return true;
}

Es ist jetzt möglich, die von Netzwerkdaten in der MainViewModel so aktualisieren Sie die Sitzungen-Eigenschaft mit Sitzungen lokal verfügbar. Die DiscoverSessions-Methode asynchron ist, daher muss der Konstruktor der MainViewModel initialisiert werden, eine Aufgabe, um es aufzurufen. Die Initialisierung von Methode sollte auch registrieren und die SessionAdded und SessionRemoved-Ereignisse behandeln. Da diese Ereignisse an den UI-Thread ausgelöst wird, werden wird nicht wenn die Sessions-Eigenschaft aktualisieren, ist es wichtig, eine CoreDispatcher verwendet wird. Die Aktualisierungen MainViewModel werden Abbildung 9.

Abbildung 9 hinzufügen Sitzung Ermittlung

public MainViewModel()
{
  _initSessionManager = InitSessionManager();
}
private Task _initSessionManager;
private async Task InitSessionManager()
{
  App.SessionManager.SessionAdded += OnSessionAdded;
  App.SessionManager.SessionRemoved += OnSessionRemoved;
  await App.SessionManager.DiscoverSessions();
}
private async void OnSessionAdded(object sender, RemoteSystemSessionInfo e)
{
  var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
  await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
    () => { Sessions.Add(e); });
}
private async void OnSessionRemoved(object sender, RemoteSystemSessionInfo e)
{
  if (Sessions.Contains(e))
  {
    var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
    await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
      () => { Sessions.Remove(e); });
  }
}

Herstellen einer Verbindung mit der Sitzung nachdem ein Benutzer die Sitzung, die sie hinzufügen möchten, und liefert einen Namen identifiziert, die RemoteSessionManager muss möglicherweise zum Verbinden der Computer mit der ausgewählten Sitzung. Dies wird durch eine neue JoinSession-Methode auf die RemoteSessionManager verarbeitet werden, die der ausgewählten Sitzung und der eingegebene Anzeigename als Parameter akzeptiert.

Die Methode JoinSession beginnt durch Aufrufen der JoinAsync-Methode für die angegebene Sitzung. Im Gegenzug wird dies auf die hostsitzung Auslösen des Ereignisses JoinRequested zu. Wenn der Host die Anforderung genehmigt, Status "Erfolg" zurückgegeben, und der Speicher CurrentUser mit dem Anzeigenamen festgelegt ist. Als wird mit der CreateSession-Methode, die InitParticipantWatcher-Methode aufgerufen, um einen Ereignishandler für registrieren, wenn die Sitzung Teilnehmer hinzugefügt werden. Die Methode JoinSession wird angezeigt, Abbildung 10.

Abbildung 10 die JoinSession-Methode

public async Task<bool> JoinSession(RemoteSystemSessionInfo session, string name)
{
  bool status = true;
  RemoteSystemSessionJoinResult joinResult = await session.JoinAsync();
  if (joinResult.Status == RemoteSystemSessionJoinStatus.Success)
  {
    _currentSession = joinResult.Session;
    CurrentUser = new User() { DisplayName = name };
  }
  else
  {
    status = false;
  }
  InitParticipantWatcher();
  return status;
}

Der letzte Schritt beim Beitreten zu einer Sitzung ist die Verwendung der Funktionen in der RemoteSessionManager erstellt, entweder erstellen oder beitreten zu einer Sitzung. Abbildung 11 zeigt die Start-Methode in der MainViewModel, die auf die Schaltfläche "Start" im MainPage gebunden ist. Der Workflow der Methode ist einfach. Je nach IsNewSession ruft er die CreateSession-Methode oder die JoinSession-Methode. Die Ergebnisse werden zurückgegeben, indem Sie entweder die SessionConnected oder ErrorConnecting Ereignisse auslösen. Wenn die Sitzung erfolgreich ist, navigiert die app auf die MessagePage, die ich im nächsten Abschnitt erstellen.

Abbildung 11 Start einer Sitzung

public async void Start()
{
  if(IsNewSession)
  {
    var result = await App.SessionManager.CreateSession(SessionName, JoinName);
    if(result == SessionCreationResult.Success)
    {
      SessionConnected(this, null);
    } else
    {
      ErrorConnecting(this, result);
    }
  } else
  {
    if(SelectedSession != null)
    {
      var result = await App.SessionManager.JoinSession(
        SelectedSession as RemoteSystemSessionInfo, JoinName);
      if(result)
      {
        SessionConnected(this, null);
      } else
      {
        ErrorConnecting(this, SessionCreationResult.Failure);
      }
    }
  }
}

Behalten Sie die Apps kommuniziert

An diesem Punkt von die app erfolgreich zu erstellen oder beitreten zu einer Sitzung werden kann und entspricht einer messaging-Benutzeroberfläche, die verwendet werden kann. Der einzige verbleibende Schritt ermöglicht die Geräte, die miteinander kommunizieren. Dies erfolgt mithilfe der Remote-System-API zum Senden von ValueSet Instanzen zwischen den Computern. Jede ValueSet ist ein Satz von Schlüssel/Wert-Paare von serialisierten Nutzlasten.

Empfangen von Nachrichten Nachrichten innerhalb einer Sitzung über einen RemoteSystemSessionMessageChannel übertragen werden. Eine Sitzung können mehrere Kanäle; Diese app benötigen jedoch nur einen einzigen Kanal. In der RemoteSessionManager werde ich eine StartReceivingMessages-Methode hinzufügen. Diese Methode wird einen neuer Nachrichtenkanal erstellt, der in einer privaten Variable gespeichert ist, und fügen einen Handler an das ValueSetReceived-Ereignis.

Nachrichten werden als Text gesendet, und weil die app Klassen als Nachrichten verwendet wird, muss ich die Daten zu serialisieren. Wenn die ValueSet aus dem Kanal empfangen wird, dient ein DataContractJsonSerializer Orchestrierungsinstanz Nachrichtenklassen in der DeserializeMessage-Klasse. Da ich nicht erkennen bin, welche Art von Nachricht serialisiert wird, wird die app jeden Typ der Nachricht als einen anderen Wert in der ValueSet senden. Die DeserializeMessage-Klasse wird bestimmen, welcher Schlüssel verwendet wird und die richtige Klasse zurückzugeben.

Sobald die Message-Klasse bereit ist, fungiert der Klasse des Managers für die Nachricht je nach Typ. Wie Sie sehen, werden Teilnehmer sich an den Host ankündigen durch Senden ihre CurrentUser-Instanz. Als Antwort wird der Host die aktualisierte Benutzerliste an alle Teilnehmer übermittelt. Wenn die Sitzungs-Manager die Liste der Teilnehmer empfängt, wird es der Benutzer Sammlungen mit den neuen Daten aktualisiert. Die letzte Option, eine UserMessage wird ein neues MessageReceived-Ereignis auszulösen, das übergibt die Nachricht und der Teilnehmer, der die Nachricht gesendet hat. Diese Hinzufügungen zu den RemoteSessionManager finden Sie im Abbildung 12.

Abbildung 12 empfangen von Nachrichten

private RemoteSystemSessionMessageChannel _messageChannel;
public event EventHandler<MessageReceivedEventArgs> MessageReceived = delegate { };
public void StartReceivingMessages()
{
  _messageChannel = new RemoteSystemSessionMessageChannel(_currentSession, "OpenChannel");
  _messageChannel.ValueSetReceived += OnValueSetReceived;
}
private object DeserializeMessage(ValueSet valueSet)
{
  Type serialType;
  object data;
   if(valueSet.ContainsKey("user"))
   {
    serialType = typeof(User);
    data = valueSet["user"];
  } else if (valueSet.ContainsKey("users"))
  {
    serialType = typeof(List<User>);
    data = valueSet["users"];
  } else
  {
    serialType = typeof(UserMessage);
    data = valueSet["message"];
  }
  object value;
  using (var stream = new MemoryStream((byte[])data))
  {
    value = new DataContractJsonSerializer(serialType).ReadObject(stream);
  }
  return value;
}
private async void OnValueSetReceived(RemoteSystemSessionMessageChannel sender,
  RemoteSystemSessionValueSetReceivedEventArgs args)
{
  var data = DeserializeMessage(args.Message);
  if (data is User)
  {
    var user = data as User;
    user.Id = args.Sender.RemoteSystem.DisplayName;
    if (!Users.Contains(user))
    {
      var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
      await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High,
        () => { Users.Add(user); });
    }
    await BroadcastMessage("users", Users.ToList());
  }
  else if (data is List<User>)
  {
    var users = data as List<User>;
    Users.Clear();
    foreach(var user in users)
    {
      Users.Add(user);
    }
  }
  else
  {
    MessageReceived(this, new MessageReceivedEventArgs()
    {
      Participant = args.Sender,
      Message = data
    });
  }
}

Abbildung 12 enthält neue Ereignishandlerklasse "MessageReceivedEventArgs", die auch erstellt werden müssen. Diese Klasse enthält zwei Eigenschaften: der Absender und der Meldung:

public class MessageReceivedEventArgs
{
  public RemoteSystemSessionParticipant Participant { get; set; }
  public object Message { get; set; }
}

Senden von Nachrichten die Remote-Systeme-API bietet zwei Methoden für die Übermittlung von Nachrichten an andere Benutzer. Die erste besteht in einer Nachricht an alle Benutzer in der Sitzung zu übertragen. Dieser Ansatz wird für zwei dieser unsere Nachrichtentypen, die UserMessage und die Liste der Benutzer verwendet werden. Erstellen wir eine neue Methode, BroadcastMessage, in der RemoteSystemManager an. Diese Methode nimmt einen Schlüssel und die Nachricht als Parameter an. Mit einem DataContractJsonSerializer, ich serialisieren Sie die Daten und zum Senden der Nachricht an alle Benutzer, die BroadcastValueSetAsync-Methode verwenden, wie im gezeigt Abbildung 13.

Abbildung 13 Senden einer Nachricht

public async Task<bool> BroadcastMessage(string key, object message)
{
  using (var stream = new MemoryStream())
  {
    new DataContractJsonSerializer(message.GetType()).WriteObject(stream, message);
    byte[] data = stream.ToArray();
    ValueSet msg = new ValueSet();
    msg.Add(key, data);
    await _messageChannel.BroadcastValueSetAsync(msg);
  }
  return true;
}

Der zweite Ansatz ist zum Senden einer Nachricht an einen einzelnen Teilnehmer. Dieser Ansatz ist ähnlich wie eine Nachricht sendet, außer es die SendValueSetAsync-Methode verwendet, einen Teilnehmer direkt Nachricht. Diese letzte Methode der RemoteSystemManager SendMessage, finden Sie in Abbildung 14.

Abbildung 14, die eine direkte Nachricht senden

public async Task<bool> SendMessage(string key, 
  object message, 
  RemoteSystemSessionParticipant participant)
{
  using (var stream = new MemoryStream())
  {
    new DataContractJsonSerializer(message.GetType()).WriteObject(stream, message);
    byte[] data = stream.ToArray();
    ValueSet msg = new ValueSet();
    msg.Add(key, data);
    await _messageChannel.SendValueSetAsync(msg, participant);
  }
  return true;
}

Erstellen die Seite "Messaging"

Mit dem messaging nun festliegen, ist es Zeit, eingefügt werden soll, um verwenden und die app zu beenden. Fügen Sie eine neue leere Seite, an die app, MessagePage.xaml. Auf dieser Seite besteht aus einer Liste von Benutzern, ein Meldungsfenster an und Eingabefelder zum Hinzufügen einer Nachricht. Der vollständigen XAML-Code finden Sie im Abbildung 15.

Abbildung 15 MessagePage XAML

<Page
  x:Class="TeamMessenger.MessagePage"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="using:TeamMessenger"
  xmlns:models="using:TeamMessenger.Models"
  xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:remotesystems="using:Windows.System.RemoteSystems"
  mc:Ignorable="d">
  <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.ColumnDefinitions>
      <ColumnDefinition MinWidth="200" Width="Auto"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid VerticalAlignment="Stretch"
          BorderBrush="Gray" BorderThickness="0,0,1,0">
      <ListView ItemsSource="{x:Bind ViewModel.Users}">
        <ListView.ItemTemplate>
          <DataTemplate x:DataType="models:User">
            <TextBlock Height="25"
                       FontSize="16"
                       Text="{x:Bind DisplayName}"/>
          </DataTemplate>
        </ListView.ItemTemplate>
      </ListView>
    </Grid>
    <Grid Grid.Column="1" Margin="10,0,10,0">
      <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
      </Grid.RowDefinitions>
      <ListView x:Name="lvMessages" ItemsSource="{x:Bind ViewModel.Messages}">
        <ListView.ItemTemplate>
          <DataTemplate x:DataType="models:UserMessage">
            <StackPanel Orientation="Vertical"
                        Margin="10,20,10,5">
              <TextBlock TextWrapping="WrapWholeWords"
                         Height="Auto"
                         Text="{x:Bind Message}"/>
              <StackPanel Orientation="Horizontal"
                          Margin="20,5,0,0">
                <TextBlock Text="{x:Bind User.DisplayName}"
                           FontSize="12"
                           Foreground="Gray"/>
                <TextBlock Text="{x:Bind DateTimeStamp}"
                           Margin="20,0,0,0"
                           FontSize="12"
                           Foreground="Gray"/>
              </StackPanel>
            </StackPanel>
          </DataTemplate>
        </ListView.ItemTemplate>
      </ListView>
      <Grid Grid.Row="1" Height="60"
            Background="LightGray">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBox Text="{x:Bind ViewModel.NewMessage, Mode=TwoWay}"
                 Margin="10"/>
        <Button Grid.Column="1" Content="Send"
                Click="{x:Bind ViewModel.SubmitMessage}"
                Margin="10"/>
      </Grid>
    </Grid>
  </Grid>
</Page>

Wie MainPage benötigen MessagePage ein Modell anzeigen. Fügen Sie eine neue Klasse, MessageViewModel, zu dem Ordner ViewModels ein. Diese Ansichtsmodell müssen unterstützt "INotifyPropertyChanged", um die bidirektionale Bindung an die ordnungsgemäße Funktion zu ermöglichen ". Dieses Ansichtsmodell enthält drei Eigenschaften: Benutzer, Nachrichten und NewMessage. Der Benutzer werden einfach der RemoteSessionManager User-Auflistung zur Ansicht verfügbar machen. Nachrichten werden ObservableCollection UserMessage-Objekten, die empfangen wurden, und eine NewMessage-Zeichenfolge, die mit dem Text als eine neue Nachricht zu senden. Es gibt auch ein einzelnes Ereignis, MessageAdded, die von Codebehind in MessagePage verwendet wird. Im Konstruktor des Modells anzeigen, ich möchte Zuordnungseigenschaft für den Benutzer, rufen die Methode StartReceivingMessages in RemoteSessionManager und Register für das Ereignis "MessageReceived" entsprechend Abbildung 16. Der Konstruktor enthält auch die Implementierung der INotifiyPropertyChanged.

Abbildung 16 MessageViewModel-Konstruktor

public event PropertyChangedEventHandler PropertyChanged = delegate { };
public event EventHandler MessageAdded = delegate { };
public ObservableCollection<UserMessage> Messages { get; private set; }
public ObservableCollection<User> Users { get; private set; }
private string _newMessage;
public string NewMessage {
  get { return _newMessage; }
  set
  {
    _newMessage = value;
    PropertyChanged(this, new
    PropertyChangedEventArgs(nameof(NewMessage)));
  }
}
public MessageViewModel()
{
  Users = App.SessionManager.Users;
  Messages = new ObservableCollection<UserMessage>();
  App.SessionManager.StartReceivingMessages();
  App.SessionManager.MessageReceived += OnMessageRecieved;
  RegisterUser();
}

Im Konstruktor wird ein Aufruf von RegisterUser vorhanden. Diese Methode sendet den Speicher CurrentUser, die bei der Verknüpfung von einer Sitzungs mit dem Host erstellt wurde. Diese Ankündigung auf dem Host, den ein neuer Benutzer hinzugefügt wurde und welche der angezeigte Name ist. Als Antwort wird der Host die aktuelle Liste der Benutzer senden, um in der Anwendung angezeigt werden:

private async void RegisterUser()
{
  if(!App.SessionManager.IsHost)
    await App.SessionManager.SendMessage("user", App.SessionManager.CurrentUser,
                                                 App.SessionManager.Host);
}

Letzte Teil des Modells anzeigen wird eine neue Nachricht vom Benutzer zu übertragen. Die SubmitMessage-Methode erstellt eine neue UserMessage und ruft die BroadcastMessage-Methode für die RemoteSessionManager. Anschließend löscht den Wert NewMessage und löst das Ereignis MessageAdded entsprechend Abbildung 17.

Abbildung 17 Übermitteln einer Nachricht

public async void SubmitMessage()
{
  var msg = new UserMessage()
  {
    User = App.SessionManager.CurrentUser,
    DateTimeStamp = DateTime.Now,
    Message = NewMessage
  };
  await App.SessionManager.BroadcastMessage("message", msg);
  Messages.Add(msg);
  NewMessage = "";
  MessageAdded(this, null);
}

Im Codebehind für MessagePage angezeigt, Abbildung 18, ich möchte zwei Dinge tun: Erstellen Sie eine Instanz von der MessageViewModel für den XAML-Code zum Verweisen auf und behandelt das MessageAdded-Ereignis. Ereignishandler weisen ich im Ereignistext ListView an das Ende der Liste einen Bildlauf durchführen, auf dem die neueste Meldung angezeigt wird.

Abbildung 18 MessagePage Codebehind

public sealed partial class MessagePage : Page
{
  public MessagePage()
  {
    this.InitializeComponent();
    ViewModel.MessageAdded += OnMessageAdded;
  }
  private void OnMessageAdded(object sender, EventArgs e)
  {
    lvMessages.ScrollIntoView(ViewModel.Messages.Last());
  }
  public MessageViewModel ViewModel { get; } = new MessageViewModel();
}

Die app mit Messaging-Team sollte jetzt für die Ausführung bereit. Führen Sie die app auf einem Computer aus, und erstellen Sie eine neue Sitzung. Starten Sie die app auf einem zweiten Computer, auf der die neu erstellte Nachricht angezeigt werden sollen. Nachdem Sie die Sitzung Sie verknüpfen entsprechend auf die neue Nachrichtenseite, wo Sie beginnen können, chatten mit anderen in der Sitzung, geschaltet werden müssen Abbildung 19. Sie haben jetzt eine Mehrbenutzer-app mithilfe der Remote-System-API erstellt.

Mehrbenutzer Messaging
Abbildung 19 Mehrbenutzer Messaging

Zusammenfassung

Erfolgreiche Benutzeroberflächen in apps häufig erstellen erfordert hinter einem Einzelgerät oder Plattform oder sogar Benutzer suchen. Microsoft entwickelt, Projekt-ROM, um Entwicklern das Bereitstellen dieses Maß an Erfahrung in ihren apps aktivieren. In diesem Artikel erstellt ich eine uwp-app mithilfe der Remote-Systeme-API. Verwenden Sie die Projekt-ROM-SDKs verfügbar, für andere Plattformen, konnte Sie jedoch diese app auf mehreren Plattformen funktioniert erweitern. Denken Sie daran, weiter problembehandlungserlebnis für Ihre Benutzer zu erstellen, erwägen Sie, wie ROM Projekt die app persönliche stellen helfen kann. Der Quellcode für diesen Artikel finden Sie unter bit.ly/2FWtCc5.


Tony Championist ein Softwarearchitekt mit mehr als 20 Jahren Erfahrung in der Entwicklung mit Microsoft-Technologien. Als Präsidenten des Experten DS und die Lead-Software-Architekt bleibt er aktiv in der aktuellen Trends und Technologien, erstellen benutzerdefinierte Lösungen für Microsoft-Plattformen. Seine Liste der Clients erstrecken sich über mehrere Branchen und Unternehmen wie z. B. enthält: Schlumberger, Microsoft, Boeing, MLB und Chevron/überprüft. Champion ist ein aktive Teilnehmer in der Community als sechs Jahren Microsoft MVP, internationale sprechender Benutzer, veröffentlichten Autor und Blogger.

Unser Dank gilt dem folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Shawn Henry


Diesen Artikel im MSDN Magazine-Forum diskutieren