2020年的UWP(5)——UWP和Desktop Extension的雙向交互


上一篇我們提到了怎么在Desktop Extension中等待並處理UWP端發出的request。本篇將討論UWP和Desktop Extension雙向交互的場景,即存在從兩端各自發出request,交由對方接受處理。
依然是回顧之前總結的四個場景分類:

  • 執行后立即退出
  • 等待request,處理完后退出
  • 一或多個request/response周期
  • 和UWP程序相同生命周期

這種存在多個request/response周期的場景,具有以下特征:

  1. UWP和Desktop Extension兩端雙向通訊
  2. 通過request傳遞參數
  3. Desktop Extension端存在用戶交互
  4. Desktop Extension端滿足條件時退出

該場景示意圖如下:

上圖顯示了最簡化的雙向交互流程,在Sample工程中,以互相發文字消息的UWP和WPF窗體舉例。兩個窗體始終保持在前台,也不存在AppServiceConnection被銷毀的問題。

而實際的業務場景中,可能存在復雜的變化。即特征中提到的“Desktop Extension端滿足條件時退出“這一點。

上圖為Sample工程運行時的界面。如何使用Desktop Extension,及建立AppServiceConnection,之前的文章已解釋過,不再提及。本篇僅對不同之處進行分析。
TwoWayExchange.FrontUWP是一個UWP工程,在MainPage.cs的構造函數中我們通過AppServiceHandler這個幫助類來注冊Connected事件。

        public MainPage()
        {
            this.InitializeComponent();

            if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
            {
                AppServiceHandler.Instance.Connected += Instance_Connected;
                FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
            }
        }

該事件會在App.xaml.cs中的OnBackgroundActived方法中被觸發。這也是工程代碼中,實際和AppServiceConnection建立關聯的起點。

        protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
        {
            base.OnBackgroundActivated(args);
            if (args.TaskInstance.TriggerDetails is AppServiceTriggerDetails details)
            {
                if (details.CallerPackageFamilyName == Package.Current.Id.FamilyName)
                {
                    var deferral = args.TaskInstance.GetDeferral();
                    args.TaskInstance.Canceled += (sender, e) => { deferral?.Complete(); };
                    AppServiceHandler.Instance.OnBackgroundActivated(details);
                }
            }
        }

在觸發Connected事件后,我們在獲得的AppServiceConnection對象上注冊RequestReceived事件,同時保存AppServiceConnection對象以供SendMessage時使用。

        private void Instance_Connected(object sender, AppServiceConnectionConnectedEventArgs e)
        {
            AppServiceHandler.Instance.Connected -= Instance_Connected;
            Connection = e.Connection;
            Connection.RequestReceived += Connection_RequestReceived;
        }

        private async void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            var message = args.Request.Message;
            if (message.TryGetValue("Desktop", out object content))
            {
                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                { this.textBoxReceive.Text += $"{content}\n"; });
            }
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            var valueSet = new ValueSet();
            valueSet.Add("UWP", this.textBoxSend.Text);
            var response = await Connection.SendMessageAsync(valueSet);
        }

而在Desktop Extension的WPF工程中,幾乎是對稱的代碼結構,不同之處無非AppServiceConnection源頭是通過Desktop端的OpenAsync方法建立。

        public async Task InitializeAsync()
        {
            Connection = new AppServiceConnection();
            Connection.PackageFamilyName = Package.Current.Id.FamilyName;
            Connection.AppServiceName = "TwoWayExchangeAppService";
            AppServiceConnectionStatus status = await Connection.OpenAsync();
            if (status == AppServiceConnectionStatus.Success)
            {
                Connection.RequestReceived += Connection_RequestReceived;
            }
        }

        private void Connection_RequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
        {
            if (args.Request.Message.TryGetValue("UWP", out object content))
            {
                Dispatcher.Invoke(() => { this.textBoxReceive.Text += $"{content}\n"; });
            }
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            var message = new ValueSet();
            message.Add("Desktop", this.textBoxSend.Text);
            await Connection.SendMessageAsync(message);
        }

至於打包用的Packaging工程,創建及注意事項,和前一篇完全一致,不再贅述。
本篇側重於雙向交互,在Desktop端注意Windows.mind和System.Runtime.WindowsRuntime兩個引用的添加,否則是無法利用AppServiceConnection來通訊的。
雖然文中示例極為簡單,似沒有實用價值。而在實際開發中,多有遇到UWP端暫時無法實現的UI及功能,諸如不規則的,透明的,或需要錨定的窗體,Windows桌面右下角的Systray等。均可以通過文中的方式來實現交互。
Github:
https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/DataExchangeUWP/TwoWayExchange


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM