UWP 支持一个 App 打开多个窗口,使得 App 更像传统的桌面应用,使用更加灵活,但是由于文档提及的内容实在太少,于是自己摸索了一阵,遇到了很多问题,也总结了一些经验。
UWP API 中,关于一个窗口的一共有四个类,分别是:
Windowclass,表示一个 Windows 下可见的窗口,负责 host 窗口内容CoreWindowclass,负责接收和翻译 Windows 窗口消息并在CoreApplicationView.Dispatcher上 dispatch(类似 WindowProc)ApplicationViewclass,表示窗口的状态,比如大小和全屏状态CoreApplicationViewclass,抽象的窗口,可以 host 在各种父窗口里,负责 dispatch 窗口消息和事件。如果是启动的第一个 View(MainView),App 的启动代码也运行在此。
然后是关闭窗口时的操作:
当用户对着你的 App 的一个窗口,也就是一个 Window,按下右上角的 X 的时候,实际被关闭的是关联的 CoreApplicationView,换句话说,窗口被“关闭”之后,它的 Content 还在继续运行。对于单窗口的 App,最后一个 View 被关闭的时候 App 就退出了;但对于多窗口的 App,必须自行维护窗口,一般用户不会注意到,但是会造成内存占用,正在播放的媒体也会继续播放。
解决方法:在 ApplicationView 被关闭时把关联的 Window.Content 设置成 null。**不要使用 Window.Current.Close()**,首先 App 的主要代码运行在启动的第一个 Window 里(其实是 CoreApplicationView 里),所以这个 Window 是无法 Close 的(会丢出异常);而对于其它 App 自己打开的 CoreApplicationView,Close() 会导致 Dispatcher 立即被终结,任何排队的操作都会丢出异常,对于一个复杂的程序,特别是调用了第三方 UI 控件的 App 来说,很可能导致崩溃。
如何创建一个新窗口
关键 API:
CoreApplicationView CoreApplication.CreateNewView()
创建一个新的 ViewIAsyncAction CoreApplicationView.Dispatcher.RunAsync(CoreDispatcherPriority, DispatchedHandler)
在新的 View 的 Dispatcher 上执行代码,这里需要对新窗口设置内容(任何UIElement都可以,比如Frame和Page,甚至是UserControl),然后Window.Current.Activate()(必须!否则无法显示内容),然后获得ApplicationView.IdIAsyncOperation<bool> ApplicationViewSwitcher.TryShowAsStandaloneAsync(int)
把上面的ApplicationView.Id对应的ApplicationView作为独立窗口显示
组合起来:
1 | public static async void CreateNewViewAsync(Action initialize) |
如何实现像计算器一样每次启动都是新窗口
启动时显示新窗口并不像上面一样使用 ApplicationViewSwitcher.TryShowAsStandaloneAsync,而是需要使用 OnLaunched() 里 LaunchActivatedEventArgs 的 ViewSwitcher。
正常启动时这个属性总是为 null,第一次必须以正常方式启动,并且调用 ApplicationViewSwitcher.DisableSystemViewActivationPolicy() 声明接下来的启动会由 App 自行维护窗口激活逻辑,之后的启动时就会提供一个 ActivationViewSwitcher 用于显示新的窗口。
1 | protected override void OnLaunched(LaunchActivatedEventArgs e) |
上面的代码还包括一个设置 StatusBar.BackgroundOpacity 的部分,是为了解决 Win10 Mobile 上 StatusBar 全黑或全白的 bug(需要给 project 添加 Mobile Extension 的 Reference)。原因是系统在启动 App 的时候将这个属性设成了 0,这样 SplashScreen 的时候 StatusBar 就是透明的,然而 App 完成启动后并没有自动改回来。至今这个 bug 也没有修好。