Yar*_*nov 7 c# win-universal-app windows-10 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<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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我用来尝试从MainPage.xaml.cs启动新视图/窗口的代码:
((App)App.Current).LoadNewView();
Run Code Online (Sandbox Code Playgroud)
我一直在阅读Microsoft文档以尝试理解问题是什么,但我仍然不明白多个视图究竟是如何工作的,就像每次打开新视图/窗口时App类都实例化一样.
我非常感谢你的帮助.
实际上,在主窗口关闭后仍能够打开新窗口的正确方法是使用其中一个重载TryShowAsStandaloneAsync.
protected override async void OnLaunched(LaunchActivatedEventArgs e)
{
// Create the newWindowId and stuff...
await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newWindowId,
ViewSizePreference.Default,
e.CurrentlyShownApplicationViewId,
ViewSizePreference.Default);
Run Code Online (Sandbox Code Playgroud)
基本上,你需要指定第三个参数 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();
}
Run Code Online (Sandbox Code Playgroud)