利用 RemoteSystemSessionInfo 可以讓多個設備進入同一個 Session (如同進到包廂),並在裏面方便的交換訊息。
因此,下面範例分別用建立 Session 與加入 Session,最後再説明怎麽交換訊息。
在使用這些功能前,要記得呼叫 RemoteSystem.RequestAccessAsync,讓用戶允許 App 有權限。
* 利用 RemoteSystemSessionController 建立 Session,並處理相關事件
public async void OnCreateRemoteSystemSessionClick(object sender, RoutedEventArgs e)
{
// 加入 option 限制只有被邀請的人才可以加入
//RemoteSystemSessionOptions options = new RemoteSystemSessionOptions()
//{
// IsInviteOnly = true
//};
sessionController = new RemoteSystemSessionController("today is happy day");
sessionController.JoinRequested += SessionController_JoinRequested;
// 建立一個 Remote Session
RemoteSystemSessionCreationResult result = await sessionController.CreateSessionAsync();
if (result.Status == RemoteSystemSessionCreationStatus.Success)
{
currentSession = result.Session;
currentSession.Disconnected += (obj, args) =>
{
// 代表從該 Session 離線了
Debug.WriteLine($"session_disconnected: {args.Reason.ToString()}");
};
// 注冊訊息通道做資料傳遞
RegistMessageChannel(currentSession, currentSession.DisplayName);
// 註冊有哪些參與者加入或離開
SubscribeParticipantWatcher(currentSession);
// 假設有選到特定的設備,也可以直接發邀請給對放
if (currentRemoteSystem != null)
{
var inviationResult = await currentSession.SendInvitationAsync(currentRemoteSystem);
}
}
}
private async void SessionController_JoinRequested(RemoteSystemSessionController sender, RemoteSystemSessionJoinRequestedEventArgs args)
{
var deferral = args.GetDeferral();
var remoteSystem = args.JoinRequest.Participant.RemoteSystem;
await dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var dialog = new MessageDialog($"do you access {remoteSystem.DisplayName} to join the session?");
dialog.Commands.Add(new UICommand("Accept", (cmd) =>
{
args.JoinRequest.Accept();
}));
dialog.Commands.Add(new UICommand("Abort"));
dialog.DefaultCommandIndex = 0;
await dialog.ShowAsync();
});
deferral.Complete();
}
如果是被邀請的參與者,需要註冊 RemoteSystemSessionInvitationListener 來處理被邀請的事件通知,如下範例:
private RemoteSystemSessionInvitationListener invitationListener;
public async void OnSubscribeAndHandleInvoke()
{
invitationListener = new RemoteSystemSessionInvitationListener();
// 註冊處理來自其他 RemoteSystem 發出的 RemoteSession 邀請
invitationListener.InvitationReceived += async (sender, args) =>
{
// 未加入前,是利用 RemoteSystemInfo 做 JoinAsync()
RemoteSystemSessionJoinResult joinResult = await args.Invitation.SessionInfo.JoinAsync();
if (joinResult.Status == RemoteSystemSessionJoinStatus.Success)
{
// 注冊訊息通道做資料傳遞
RegistMessageChannel(currentSession, currentSession.DisplayName);
// 註冊有哪些參與者加入或離開
SubscribeParticipantWatcher(currentSession);
}
};
}
* 利用 RemoteSystemSessionWatcher 找到可以加入的 Sessions,並請求加入
public void OnDescoverSessionAsync(object sender, RoutedEventArgs e)
{
// 建立 Watcher 來查看有哪些 Sessions 被建立或是刪除
sessionWatcher = RemoteSystemSession.CreateWatcher();
sessionWatcher.Added += (s, a) => {
// 將找到的 RemoteSystemInfo 加入 UI 顯示
RemoteSystemSessionInfo sessionInfo = a.SessionInfo;
var addedTask = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
sessionList.Add(sessionInfo);
});
};
sessionWatcher.Removed += (s, a) => {
// 將已經結束的 session 從 UI 移除
var removedSession = a.SessionInfo;
var exist = sessionList.Where(x => x.ControllerDisplayName == removedSession.ControllerDisplayName && x.DisplayName == removedSession.DisplayName).FirstOrDefault();
if (exist!= null)
{
var removedTask = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
sessionList.Remove(exist);
});
}
};
sessionWatcher.Updated += (s, a) => {
// 講更新的 RemoteSystemInfo 加入到 UI
var updatedSession = a.SessionInfo;
var exist = sessionList.Where(x => x.ControllerDisplayName == updatedSession.ControllerDisplayName && x.DisplayName == updatedSession.DisplayName).FirstOrDefault();
if (exist != null)
{
var updatedTask = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
sessionList.Remove(exist);
sessionList.Add(updatedSession);
});
}
};
sessionWatcher.Start();
}
選擇找到的 RemoteSystemInfo 來請求加入:
public async void OnJoinSessionSelectChangedAsync(object sender, SelectionChangedEventArgs e)
{
var listView = sender as ListView;
var session = listView.SelectedItem as RemoteSystemSessionInfo;
if (session!= null)
{
// 請求加入 session
var result = await session.JoinAsync();
Debug.WriteLine($"join {session.DisplayName}: {result.Status.ToString()}");
if (result.Status == RemoteSystemSessionJoinStatus.Success)
{
this.currentSession = result.Session;
// 注冊訊息通道做資料傳遞
RegistMessageChannel(currentSession, currentSession.DisplayName);
// 註冊有哪些參與者加入或離開
SubscribeParticipantWatcher(currentSession);
}
}
}
* 註冊 Session 的交易資料通道來發送或接收訊息
private RemoteSystemSessionMessageChannel appMessageChannel;
private void RegistMessageChannel(RemoteSystemSession session, string channelName)
{
if (appMessageChannel != null)
{
appMessageChannel.ValueSetReceived -= AppMessageChannel_ValueSetReceived;
appMessageChannel = null;
}
// 利用 RemoteSystemSession 注冊訊息通道
appMessageChannel = new RemoteSystemSessionMessageChannel(session, channelName);
appMessageChannel.ValueSetReceived += AppMessageChannel_ValueSetReceived;
}
private void AppMessageChannel_ValueSetReceived(RemoteSystemSessionMessageChannel sender, RemoteSystemSessionValueSetReceivedEventArgs args)
{
// 處理收到的訊息
ValueSet receivedMessage = args.Message;
if (receivedMessage != null)
{
// 建立一個假的 MessageData 類別來做為交易訊息的内容
MessageData msgData = new MessageData();
byte[] data = receivedMessage["Key"] as byte[];
using (MemoryStream ms = new MemoryStream(data))
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(msgData.GetType());
msgData = ser.ReadObject(ms) as MessageData;
}
}
}
要在 session 裏面傳遞訊息要記得註冊 RemoteSystemSessionMessageChannel。發送訊息的範例程式如下:
public void OnSendMessageToSessionClick(object sender, RoutedEventArgs e)
{
// 準備要發送的訊息内容
var msg = new MessageData
{
Content = "test"
};
using (var stream = new MemoryStream())
{
new DataContractJsonSerializer(message.GetType()).WriteObject(stream, message);
byte[] data = stream.ToArray();
// 將内容包裝到 ValueSet
ValueSet sentMessage = new ValueSet { ["Key"] = data };
// 可以選擇發給全部的參與者或是特定的參與者們
await appMessageChannel.BroadcastValueSetAsync(sentMessage);
}
}
public class MessageData
{
public string Content { get; set; }
}
如果想要發訊息給特定的參與者,可以參考:private RemoteSystemSessionParticipantWatcher participantWatcher;
public ObservableCollection Participants => watchedParticipants;
private ObservableCollection watchedParticipants;
private void SubscribeParticipantWatcher(RemoteSystemSession session)
{
if (participantWatcher != null)
{
participantWatcher.Stop();
}
participantWatcher = null;
// 當加入或建立 RemoteSystemSession 之後,利用 ParticipantWatcher 來看有那些參與者
participantWatcher = session.CreateParticipantWatcher();
participantWatcher.Added += (s, a) => {
watchedParticipants.Add(a.Participant);
};
participantWatcher.Removed += (s, a) => {
watchedParticipants.Remove(a.Participant);
};
participantWatcher.Start();
}
上面的範例可以到 26-RemoteSystemSample 下載來使用。
幾個重要的元素:
- RemoteSystemSessionController
負責建立與管理 new remote session 讓其他設備可以加入。每一個 session 都有一位參與者扮演管理者角色,只有管理者才能設定 session 的特性,允許誰可以加入,或是把人踢出。Constructors RemoteSystemSessionController(String,
RemoteSystemSessionOptions)給與 remote session 的公開名稱,
並設定相關特性 RemoteSystemSessionOptionsMethods CreateSessionAsync() 非同步建立 RemoteSystemSession。 RemoveParticipantAsync(
RemoteSystemSessionParticipant)從 Session 移除特定參與者(RemoteSystemSessionParticipant)。 Events JoinRequested 當有另一個設備找到該 Session 並請求加入時會觸發。 - RemoteSystemSessionWatcher監視與發現遠端會話相關的活動並引發相應的事件。
Status 取得 RemoteSystemSessionWatcher 的運作狀態 Added 當發現有新的 Session 被找到時會觸發 Removed 當之前被找到的 Session 消失時會觸發 Updated 當先前被找到的 Session 有部分資訊被更新時會觸發 - RemoteSystemSession表示和處理可在兩個或多個連接的設備之間共用的遠端會話。
它是更廣泛的遠端系統功能集的一部分,它被建立之後可以讓多個設備加入並裏面交換訊息,實現跨裝置的資訊交換。
CreateParticipantWatcher() 初始化 RemoteSystemSessionParticipantWatcher 來監看裏面的參與者 CreateWatcher() 實例化取得 RemoteSystemSessionWatcher 來監控可能的 session SendInvitationAsync(RemoteSystem) 邀請某個 RemoteSystem 加入 Session。
接受邀請的設備需要搭配 RemoteSystemSessionInvitationListener 來處理。Disconnected 當這個設備從這個 remote session 斷線時被觸發 - RemoteSystemSessionInfo内容包含 Remote Session 的相關資訊。它與 RemoteSystemSession 最大差別在於,已經加入的 session 用 RemoteSystemSession 代表,未加入的 session 則是 RemoteSystemSessionInfo (因爲它才有 JoinAsync 的 method 可以用)。
- RemoteSystemSessionParticipantWatcher負責監控 remote session 有哪些參與者加入/離開。
- RemoteSystemSessionMessageChannel在 remote session 中處理訊息專用的資料傳輸通道,包括:傳送與接收。
BroadcastValueSetAsync(ValueSet) 傳送訊息給所有的參與者 SendValueSetAsync(ValueSet, RemoteSystemSessionParticipant) 傳送訊息給特定的一位參與者 SendValueSetToParticipantsAsync(ValueSet, IIterable ) 傳訊訊息給特定一群參與者 ValueSetReceived 當收到訊息時會觸發該事件
另外 Windows Holographic 利用 SpatialEntityStore 建立多個設備之間訊息的傳遞與資料管理,更多細範例可參考 Quiz Game sample app。
這篇内容參考 Connect devices through remote sessions 來加以説明,希望對大家有所幫助。
References:
沒有留言:
張貼留言