具有多个视图的UWP问题
本文关键字:UWP 问题 视图 | 更新日期: 2024-09-22 07:26:21
我正在编写一个应用程序,该应用程序应该能够运行多个视图,在各自的窗口中编辑不同的文档。我写了一些有效的代码,但我有一些问题。我写的代码是基于微软提供的多视图示例(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<ViewLifetimeControl> SecondaryViews = new ObservableCollection<ViewLifetimeControl>();
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<ViewLifetimeControl> 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文档,试图了解问题所在,但我仍然不明白多视图究竟是如何工作的,比如每次打开新视图/窗口时都会实例化应用程序类。
我真的很感激你的帮助。
实际上,在主窗口关闭后仍然能够打开新窗口的正确方法是使用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<CoreApplicationView> secondaryViews = new ObservableCollection<CoreApplicationView>();
//...
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<int> idSaved = new List<int>();
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();
}