首页 > 代码库 > UI: 多窗口

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();        }    }}

UI: 多窗口