背水一战 Windows 10 (4) - UI: 多窗口

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 原文:背水一战 Windows 10 (4) - UI: 多窗口[源码下载] 背水一战 Windows 10 (4) - UI: 多窗口 作者:webabcd介绍背水一战 Windows 10 之 UI 多窗口 示例1、自定义帮助类,用于简化 SecondaryView 的管理UI/MultipleViews/SecondaryViewHelper.
原文: 背水一战 Windows 10 (4) - UI: 多窗口

[源码下载]


背水一战 Windows 10 (4) - UI: 多窗口



作者:webabcd


介绍
背水一战 Windows 10 之 UI

  • 多窗口



示例
1、自定义帮助类,用于简化 SecondaryView 的管理
UI/MultipleViews/SecondaryViewHelper.cs

/*
 * SecondaryViewHelper - 自定义的一个帮助类,用于简化 SecondaryView 的管理
 */

using System;
using System.ComponentModel;
using Windows.UI.Core;
using Windows.UI.ViewManagement;

namespace Windows10.UI.MultipleViews
{
    public class SecondaryViewHelper : INotifyPropertyChanged
    {
        // for INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        // 当前 SecondaryView 的 CoreDispatcher
        private CoreDispatcher _dispatcher;
        // 当前 SecondaryView 的 ApplicationView
        private ApplicationView _applicationView;

        // 当前 SecondaryView 的标题
        private string _title;
        // 当前 SecondaryView 的窗口标识
        private int _viewId;

        // 当前 SecondaryView 被引用的次数
        private int _refCount = 0;
        // 当前 SecondaryView 是否已经被释放
        private bool _released = false;

        // 禁止通过 new 实例化
        private SecondaryViewHelper(CoreWindow newWindow)
        {
            _dispatcher = newWindow.Dispatcher;
            _viewId = ApplicationView.GetApplicationViewIdForWindow(newWindow);

            _applicationView = ApplicationView.GetForCurrentView();

            RegisterForEvents();
        }

        // 实例化 SecondaryViewHelper
        public static SecondaryViewHelper CreateForCurrentView()
        {
            /*
             * CoreWindow.GetForCurrentThread() - 获取当前窗口的 CoreWindow
             */
            return new SecondaryViewHelper(CoreWindow.GetForCurrentThread());
        }
        private void RegisterForEvents()
        {
            /*
             * ApplicationView.GetForCurrentView() - 获取当前窗口的 ApplicationView
             * ApplicationView.Consolidated - 当前 app 存活着两个或两个以上的窗口时,此窗口关闭后触发的事件
             */
            ApplicationView.GetForCurrentView().Consolidated += SecondaryViewHelper_Consolidated;
        }

        private void UnregisterForEvents()
        {
            ApplicationView.GetForCurrentView().Consolidated -= SecondaryViewHelper_Consolidated;
        }

        private void SecondaryViewHelper_Consolidated(ApplicationView sender, ApplicationViewConsolidatedEventArgs args)
        {
            StopViewInUse();
        }

        // 当前 SecondaryView 开始使用了(与 StopViewInUse() 成对)
        // 因为每一个窗口都可以被同 app 的别的窗口调用,而每一个窗口又都是一个独立的线程,所以要做好线程处理
        public int StartViewInUse()
        {
            bool releasedCopy = false;
            int refCountCopy = 0;

            lock (this)
            {
                releasedCopy =_released;
                if (!_released)
                {
                    refCountCopy = ++_refCount;
                }
            }

            if (releasedCopy)
            {
                throw new InvalidOperationException("this view is being disposed");
            }

            return refCountCopy;
        }

        // 当前 SecondaryView 结束使用了(与 StartViewInUse() 成对)
        // 因为每一个窗口都可以被同 app 的别的窗口调用,而每一个窗口又都是一个独立的线程,所以要做好线程处理
        public int StopViewInUse()
        {
            int refCountCopy = 0;
            bool releasedCopy = false;

            lock (this)
            {
                releasedCopy = _released;
                if (!_released)
                {
                    refCountCopy = --_refCount;
                    if (refCountCopy == 0)
                    {
                        // 当前 SecondaryView 不再被任何人需要了,清理之
                        var task = _dispatcher.RunAsync(CoreDispatcherPriority.Low, FinalizeRelease);
                    }
                }
            }

            if (releasedCopy)
            {
                throw new InvalidOperationException("this view is being disposed");
            }

            return refCountCopy;
        }

        // 清理当前 SecondaryView
        private void FinalizeRelease()
        {
            bool justReleased = false;
            lock (this)
            {
                if (_refCount == 0)
                {
                    justReleased = true;
                    _released = true;
                }
            }

            if (justReleased)
            {
                UnregisterForEvents();

                // 触发 Released 事件
                OnReleased(EventArgs.Empty);
            }
        }

        // 定义 Released 事件
        public event EventHandler<EventArgs> Released;
        protected virtual void OnReleased(EventArgs e)
        {
            EventHandler<EventArgs> handler = Released;
            if (handler != null)
                handler(this, e);
        }

        public int Id
        {
            get
            {
                return _viewId;
            }
        }

        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                if (_title != value)
                {
                    _title = value;

                    if (PropertyChanged != null)
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs(nameof(Title)));
                    }
                }
            }
        }

        public bool IsReleased
        {
            get
            {
                return _released;
            }
        }

        public ApplicationView ApplicationView
        {
            get
            {
                return _applicationView;
            }
        }
    }
}


2、扩展 Application 对象,定义一些需要用到的全局变量
UI/MultipleViews/AppPartial.cs

/*
 * 扩展 Application 对象,定义一些需要用到的全局变量
 */

using Windows.ApplicationModel.Activation;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Windows10
{
    public partial class App
    {
        // PrimaryView 的 CoreDispatcher
        private CoreDispatcher _mainDispatcher;
        // PrimaryView 的窗口标识
        private int _mainViewId;

        // partial method,实现了 App.xaml.cs 中的声明
        partial void OnLaunched_MultipleViews(LaunchActivatedEventArgs args)
        {
            _mainDispatcher = Window.Current.Dispatcher;
            _mainViewId = ApplicationView.GetForCurrentView().Id;
        }
        
        public CoreDispatcher MainDispatcher
        {
            get
            {
                return _mainDispatcher;
            }
        }
        
        public int MainViewId
        {
            get
            {
                return _mainViewId;
            }
        }
    }
}


3、用于演示 SecondaryView 的示例
UI/MultipleViews/SecondaryViewPage.xaml

<Page
    x:Class="Windows10.UI.MultipleViews.SecondaryViewPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.UI.MultipleViews"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="0 10 0 0" />

            <Button Name="btnGoToMain" Content="切换到主窗口" Click="btnGoToMain_Click" Margin="0 10 0 0" />

            <Button Name="btnGoToMainAndHideThisView" Content="切换到主窗口,并关闭此窗口" Click="btnGoToMainAndHideThisView_Click" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

UI/MultipleViews/SecondaryViewPage.xaml.cs

/*
 * 演示“多窗口”相关知识点。本页是 SecondaryView
 */

using System;
using System.ComponentModel;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Windows10.UI.MultipleViews
{
    public sealed partial class SecondaryViewPage : Page
    {
        private SecondaryViewHelper _secondaryViewHelper;

        public SecondaryViewPage()
        {
            this.InitializeComponent();
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            _secondaryViewHelper = (SecondaryViewHelper)e.Parameter;
            _secondaryViewHelper.Released += _secondaryViewHelper_Released;

            // 设置当前窗口的 Title
            ApplicationView.GetForCurrentView().Title = _secondaryViewHelper.Title;
            _secondaryViewHelper.PropertyChanged += _secondaryViewHelper_PropertyChanged;
        }

        private void _secondaryViewHelper_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(_secondaryViewHelper.Title))
            {
                _secondaryViewHelper.ApplicationView.Title = _secondaryViewHelper.Title;
            }
        }

        private async void _secondaryViewHelper_Released(object sender, EventArgs e)
        {
            ((SecondaryViewHelper)sender).Released -= _secondaryViewHelper_Released;

            await ((App)App.Current).MainDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                // 调用主窗口线程,执行逻辑
            });

            Window.Current.Close();
        }

        private async void btnGoToMain_Click(object sender, RoutedEventArgs e)
        {
            _secondaryViewHelper.StartViewInUse();

            /*
             * ApplicationViewSwitcher.SwitchAsync() - 切换到指定的窗口
             */
            await ApplicationViewSwitcher.SwitchAsync
            (
                ((App)App.Current).MainViewId // 准备显示的窗口的 id
            );

            _secondaryViewHelper.StopViewInUse();
        }

        private async void btnGoToMainAndHideThisView_Click(object sender, RoutedEventArgs e)
        {
            _secondaryViewHelper.StartViewInUse();

            /*
             * ApplicationViewSwitcher.SwitchAsync() - 切换到指定的窗口
             */
            await ApplicationViewSwitcher.SwitchAsync
            (
                ((App)App.Current).MainViewId, // 准备显示的窗口的 id
                ApplicationView.GetForCurrentView().Id, // 调用者的窗口 id
                ApplicationViewSwitchingOptions.ConsolidateViews // 切换行为选项(Default - 标准动画切换; SkipAnimation - 不使用动画切换; ConsolidateViews - 切换后关闭调用者窗口)
            );

            _secondaryViewHelper.StopViewInUse();
        }
    }
}


4、用于演示 PrimaryView 的示例
UI/MultipleViews/Demo.xaml

<Page
    x:Class="Windows10.UI.MultipleViews.Demo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Windows10.UI.MultipleViews"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="Transparent">
        <StackPanel Margin="10 0 10 10">

            <TextBlock Name="lblMsg" Margin="0 10 0 0" />

            <Button Name="btnShow" Content="创建并显示一个新的窗口" Click="btnShow_Click" Margin="0 10 0 0" />

            <Button Name="btnChangeLastSecondaryViewTitle" Content="修改最近一个被我打开的 SecondaryView 的 Title" Click="btnChangeLastSecondaryViewTitle_Click" Margin="0 10 0 0" />

        </StackPanel>
    </Grid>
</Page>

UI/MultipleViews/Demo.xaml.cs

/*
 * 演示“多窗口”相关知识点。本页是 PrimaryView
 *
 *
 * 解释一下本例中用于说明的几个名词:PrimaryView - 主窗口; SecondaryView - 新开窗口
 */

using System;
using Windows.ApplicationModel.Core;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Windows10.UI.MultipleViews
{
    public sealed partial class Demo : Page
    {
        // 自定义的用于简化 SecondaryView 管理的帮助类
        SecondaryViewHelper _secondaryViewHelper = null;

        public Demo()
        {
            this.InitializeComponent();

            this.Loaded += Demo_Loaded;
        }

        private void Demo_Loaded(object sender, RoutedEventArgs e)
        {
            ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.Auto;
        }

        private async void btnShow_Click(object sender, RoutedEventArgs e)
        {
            /*
             * CoreApplication.CreateNewView() - 创建一个新的 SecondaryView(只是新建一个 SecondaryView 实例,并不会显示出来)
             */
            await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                _secondaryViewHelper = SecondaryViewHelper.CreateForCurrentView();
                _secondaryViewHelper.Title = "i am secondary view";

                _secondaryViewHelper.StartViewInUse();

                var frame = new Frame();
                frame.Navigate(typeof(SecondaryViewPage), _secondaryViewHelper);
                Window.Current.Content = frame;
                Window.Current.Activate();

                // 这里通过 ApplicationView.GetForCurrentView() 获取到的是新开窗口的 ApplicationView 对象
                ApplicationView secondaryView = ApplicationView.GetForCurrentView();
            });

            try
            {
                _secondaryViewHelper.StartViewInUse();

                /*
                 * ApplicationViewSwitcher.TryShowAsStandaloneAsync() - 在当前窗口的相邻位置显示另一个窗口
                 */
                ApplicationViewSwitcher.DisableShowingMainViewOnActivation();
                var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync
                (
                    _secondaryViewHelper.Id, // 需要显示的 SecondaryView 的窗口 id
                    ViewSizePreference.Default, // 需要显示的 SecondaryView 的尺寸首选项(经测试,此参数无效)
                    ApplicationView.GetForCurrentView().Id, // 调用者的窗口 id
                    ViewSizePreference.Default // 调用者的尺寸首选项(经测试,此参数无效)
                );

                if (!viewShown)
                {
                    lblMsg.Text = "显示 SecondaryView 失败";
                }

                _secondaryViewHelper.StopViewInUse();
            }
            catch (Exception ex)
            {
                lblMsg.Text = ex.ToString();
            }
        }

        // 修改最近一个被我打开的 SecondaryView 的 Title
        private void btnChangeLastSecondaryViewTitle_Click(object sender, RoutedEventArgs e)
        {
            if (_secondaryViewHelper != null && !_secondaryViewHelper.IsReleased)
                _secondaryViewHelper.Title = new Random().Next().ToString();
        }
    }
}



OK
[源码下载]

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
1天前
|
算法 API 开发者
【Qt UI相关】Qt中如何控制 窗口的最大化、最小化和关闭按钮?一文带你掌握用法
【Qt UI相关】Qt中如何控制 窗口的最大化、最小化和关闭按钮?一文带你掌握用法
167 1
|
Web App开发 安全 Linux
Windows 10 大更新:界面更流畅、新 UI、字体商店,还有这些新功能……
Windows 10 大更新:界面更流畅、新 UI、字体商店,还有这些新功能……
windows 2019 无UI版的常见问题
windows 2019 无UI版的常见问题
|
UED Windows
Windows 11 发布 6 个月以来 UI / UX 设计仍不一致:媒体喊话微软“先做好基础功能”
Windows 11 发布 6 个月以来 UI / UX 设计仍不一致:媒体喊话微软“先做好基础功能”
108 0
Windows 11 发布 6 个月以来 UI / UX 设计仍不一致:媒体喊话微软“先做好基础功能”
|
编解码 安全 Linux
flutter 在windows和linux上运行IOS UI模拟器
之前发视频总是有人留言,我用的什么模拟器,今天给大家说一下 我一般用的是device_preview这个插件,这个插件的闲置是只能做UI上的模拟,并没有真正的运行环境。 近似您的应用程序在另一台设备上的外观和性能。
351 0
|
Windows
如何在SAP CRM WebClient UI的弹出窗口里绘制附件(Attachment)控件
如何在SAP CRM WebClient UI的弹出窗口里绘制附件(Attachment)控件
如何在SAP CRM WebClient UI的弹出窗口里绘制附件(Attachment)控件
|
Windows
windows 2019 无UI版的常见问题
windows 2019 无UI版的常见问题
3123 0
windows 2019 无UI版的常见问题
|
C#
WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口)
原文 WPF 同一窗口内的多线程/多进程 UI(使用 SetParent 嵌入另一个窗口) WPF 的 UI 逻辑只在同一个线程中,这是学习 WPF 开发中大家几乎都会学习到的经验。如果希望做不同线程的 UI,大家也会想到使用另一个窗口来实现,让每个窗口拥有自己的 UI 线程。
2930 0