多视图的UWP问题

我正在编写一个应用程序,它应该能够运行多个视图,以便在各自的窗口中编辑不同的文档。 我写了一些有用的代码,但是我遇到了一些问题。 我编写的代码基于Microsoft提供的Multiple Views示例( https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews )。

我主要有两个问题。 第一个是如果我关闭主视图,这是启动应用程序时打开的第一个窗口,那么我无法通过单击应用程序磁贴或打开关联的文件类型打开任何新的视图/窗口,直到我关闭所有视图/窗口并重新启动应用程序。 第二个是,当我尝试从MainPage.xaml.cs打开一个新的视图/窗口时,应用程序崩溃了。

我用来管理App.xaml.cs中的视图的代码如下:

sealed partial class App : Application { //I use this boolean to determine if the application has already been launched once private bool alreadyLaunched = false; public ObservableCollection SecondaryViews = new ObservableCollection(); private CoreDispatcher mainDispatcher; public CoreDispatcher MainDispatcher { get { return mainDispatcher; } } private int mainViewId; public int MainViewId { get { return mainViewId; } } public App() { this.InitializeComponent(); this.Suspending += OnSuspending; } protected override async void OnLaunched(LaunchActivatedEventArgs e) { Frame rootFrame = Window.Current.Content as Frame; if (rootFrame == null) { rootFrame = new Frame(); rootFrame.NavigationFailed += OnNavigationFailed; if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: Load state from previously suspended application } // Place the frame in the current Window Window.Current.Content = rootFrame; } if (rootFrame.Content == null) { alreadyLaunched = true; rootFrame.Navigate(typeof(MainPage), e.Arguments); } else if(alreadyLaunched) { var selectedView = await createMainPageAsync(); if (null != selectedView) { selectedView.StartViewInUse(); var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync( selectedView.Id, ViewSizePreference.Default, ApplicationView.GetForCurrentView().Id, ViewSizePreference.Default ); await selectedView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var currentPage = (MainPage)((Frame)Window.Current.Content).Content; Window.Current.Activate(); }); selectedView.StopViewInUse(); } } // Ensure the current window is active Window.Current.Activate(); } protected override async void OnFileActivated(FileActivatedEventArgs args) { base.OnFileActivated(args); if (alreadyLaunched) { //Frame rootFrame = Window.Current.Content as Frame; //((MainPage)rootFrame.Content).OpenFileActivated(args); var selectedView = await createMainPageAsync(); if (null != selectedView) { selectedView.StartViewInUse(); var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync( selectedView.Id, ViewSizePreference.Default, ApplicationView.GetForCurrentView().Id, ViewSizePreference.Default ); await selectedView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var currentPage = (MainPage)((Frame)Window.Current.Content).Content; Window.Current.Activate(); currentPage.OpenFileActivated(args); }); selectedView.StopViewInUse(); } } else { Frame rootFrame = new Frame(); rootFrame.Navigate(typeof(MainPage), args); Window.Current.Content = rootFrame; Window.Current.Activate(); alreadyLaunched = true; } } partial void Construct(); partial void OverrideOnLaunched(LaunchActivatedEventArgs args, ref bool handled); partial void InitializeRootFrame(Frame frame); partial void OverrideOnLaunched(LaunchActivatedEventArgs args, ref bool handled) { // Check if a secondary view is supposed to be shown ViewLifetimeControl ViewLifetimeControl; handled = TryFindViewLifetimeControlForViewId(args.CurrentlyShownApplicationViewId, out ViewLifetimeControl); if (handled) { var task = ViewLifetimeControl.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { Window.Current.Activate(); }); } } partial void InitializeRootFrame(Frame frame) { mainDispatcher = Window.Current.Dispatcher; mainViewId = ApplicationView.GetForCurrentView().Id; } bool TryFindViewLifetimeControlForViewId(int viewId, out ViewLifetimeControl foundData) { foreach (var ViewLifetimeControl in SecondaryViews) { if (ViewLifetimeControl.Id == viewId) { foundData = ViewLifetimeControl; return true; } } foundData = null; return false; } private async Task createMainPageAsync() { ViewLifetimeControl viewControl = null; await CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // This object is used to keep track of the views and important // details about the contents of those views across threads // In your app, you would probably want to track information // like the open document or page inside that window viewControl = ViewLifetimeControl.CreateForCurrentView(); viewControl.Title = DateTime.Now.ToString(); // Increment the ref count because we just created the view and we have a reference to it viewControl.StartViewInUse(); var frame = new Frame(); frame.Navigate(typeof(MainPage), viewControl); Window.Current.Content = frame; // This is a change from 8.1: In order for the view to be displayed later it needs to be activated. Window.Current.Activate(); //ApplicationView.GetForCurrentView().Title = viewControl.Title; }); ((App)App.Current).SecondaryViews.Add(viewControl); return viewControl; } void OnNavigationFailed(object sender, NavigationFailedEventArgs e) { throw new Exception("Failed to load Page " + e.SourcePageType.FullName); } private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); //TODO: Save application state and stop any background activity deferral.Complete(); } //I call this function from MainPage.xaml.cs to try to open a new window public async void LoadNewView() { var selectedView = await createMainPageAsync(); if (null != selectedView) { selectedView.StartViewInUse(); var viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync( selectedView.Id, ViewSizePreference.Default, ApplicationView.GetForCurrentView().Id, ViewSizePreference.Default ); await selectedView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var currentPage = (MainPage)((Frame)Window.Current.Content).Content; Window.Current.Activate(); currentPage.LoadNewFile(); }); selectedView.StopViewInUse(); } } } 

我用来尝试从MainPage.xaml.cs启动新视图/窗口的代码:

 ((App)App.Current).LoadNewView(); 

我一直在阅读Microsoft文档以尝试了解问题是什么,但我仍然不明白多个视图的工作原理是什么,就像每次打开新视图/窗口时App类都实例化一样。

我非常感谢你的帮助。

实际上,在主要窗口关闭后仍能够打开新窗口的正确方法是使用TryShowAsStandaloneAsync提供的重载TryShowAsStandaloneAsync

 protected override async void OnLaunched(LaunchActivatedEventArgs e) { // Create the newWindowId and stuff... await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newWindowId, ViewSizePreference.Default, e.CurrentlyShownApplicationViewId, ViewSizePreference.Default); 

基本上,你需要指定第三个参数 anchorViewId

调用(锚点)窗口的ID。

在这种情况下,您只需要传入e.CurrentlyShownApplicationViewId

我找到了解决问题的方法,实际上我决定不使用样本附带的ViewLifeTime控件。

问题是当主视图关闭时,您必须使用仍然打开的其他视图中的Dispatcher.RunAsync()方法来运行该线程

这是我在App.xaml.cs中为所有感兴趣的人更改的代码:

 public bool isMainViewClosed = false; public ObservableCollection secondaryViews = new ObservableCollection(); //... protected override async void OnLaunched(LaunchActivatedEventArgs e) { Frame rootFrame = Window.Current.Content as Frame; if (rootFrame == null) { rootFrame = new Frame(); rootFrame.NavigationFailed += OnNavigationFailed; if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) { //TODO: Load state from previously suspended application } Window.Current.Content = rootFrame; } if (rootFrame.Content == null) { alreadyLaunched = true; rootFrame.Navigate(typeof(MainPage), e.Arguments); } else if(alreadyLaunched) { //If the main view is closed, use the thread of one of the views that are still open if(isMainViewClosed) { int newViewId = 0; await secondaryViews[0].Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var currentPage = (MainPage)((Frame)Window.Current.Content).Content; Window.Current.Activate(); currentPage.NewWindow(); newViewId = ApplicationView.GetForCurrentView().Id; }); bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId); } else { CoreApplicationView newView = CoreApplication.CreateNewView(); int newViewId = 0; await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { Frame frame = new Frame(); frame.Navigate(typeof(MainPage), null); Window.Current.Content = frame; var currentPage = (MainPage)((Frame)Window.Current.Content).Content; Window.Current.Activate(); secondaryViews.Add(CoreApplication.GetCurrentView()); newViewId = ApplicationView.GetForCurrentView().Id; }); bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId); } } Window.Current.Activate(); } 

不要查看(你的)终生…欢呼,

 int idCreate = 0; List idSaved = new List(); protected override async void OnLaunched(LaunchActivatedEventArgs e) { Frame rootFrame = Window.Current.Content as Frame; if (rootFrame == null) { rootFrame = new Frame(); rootFrame.NavigationFailed += OnNavigationFailed; Window.Current.Content = rootFrame; } if (rootFrame.Content == null) { rootFrame.Navigate(typeof(MainPage), e.Arguments); idSaved.Add(ApplicationView.GetForCurrentView().Id); } else { var create = CoreApplication.CreateNewView(); await create.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var frame = new Frame(); frame.Navigate(typeof(MainPage), e.Arguments); Window.Current.Content = frame; Window.Current.Activate(); idCreate = ApplicationView.GetForCurrentView().Id; }); for(int i = idSaved.Count - 1; i >= 0; i--) if (await ApplicationViewSwitcher.TryShowAsStandaloneAsync( idCreate, ViewSizePreference.UseMinimum, idSaved[i], ViewSizePreference.UseMinimum) ) break; idSaved.Add(idCreate); } Window.Current.Activate(); }