UWP多视图问题

7
我正在编写一个应用程序,可以运行多个视图以编辑不同的文档,每个文档都在自己的窗口中。我已经编写了一些代码,可以工作,但是我遇到了一些问题。我编写的代码基于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();
        }
    }
}

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

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

我一直在阅读微软文档,试图理解问题所在,但我仍然不明白多视图是如何工作的,比如当我打开一个新的视图/窗口时,App类是否会被实例化每次都是。我非常感谢你的帮助。

这段代码 currentPage.LoadNewFile(); 是调用了Mainpage的LoadNewFile方法。你在Mainpage.xaml.cs中写了另一个LoadNewFile()方法吗?为什么把所有代码都放在App.xaml.cs中?最好上传所有代码。 - Sunteen Wu
是的,我确实在我的MainPage.xaml.cs中编写了LoadNewFile()方法,并将多个视图的所有代码放在App.xaml.cs中,以便我不必重写代码,但我尝试从我的MainPage.xaml.cs创建新的视图/窗口时出现了相同的错误。当CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>在createMainPageAsync()方法中运行时,应用程序会崩溃,最奇怪的是它尝试打开另一个调试器而不是Visual Studio。 - Yaroslav de la Peña Smirnov
在这种情况下,请上传您的所有代码,否则人们无法在没有错误代码和错误详细信息的情况下帮助您。 - Sunteen Wu
4个回答

8
实际上,在主窗口关闭后仍然能够打开新窗口的正确方法是使用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即可。

3

我已经找到了解决我的问题的方法,实际上我决定不使用附带示例的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();
    }

0

如果需要,您可以在应用程序中使用多个实例。您可以按照我在这里描述的方式同步设置更改。


-1

不要把你的生命浪费在观看上...干杯!

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

3
如果您想删除您的回答,只需点击删除按钮即可。 - Blue
@FrankerZ,未注册用户无法删除他们的答案。 - Brock Adams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接