多视图的 UWP 问题 [英] UWP problems with multiple views

查看:19
本文介绍了多视图的 UWP 问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing an app which should be able to run multiple views to edit different documents each in their own window. I've wrote some code which works, but I'm having some problems with it. The code I wrote is based upon the Multiple Views sample provided by Microsoft (https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MultipleViews).

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

I have mainly two problems. The first one is if I close the main view, that is the first window that was open when the application was launched, then I cannot open any new views/windows by clicking in the app tile or opening an associated file type, until I close all views/windows and relaunch the app. The second one, is that when I try to open a new view/window from MainPage.xaml.cs, the app just crashes.

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

The code that I use to manage the views in App.xaml.cs is the following:

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 启动新视图/窗口的代码:

The code I use to try to launch a new view/window from MainPage.xaml.cs:

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

我一直在阅读 Microsoft 文档以尝试了解问题所在,但我仍然不明白多视图究竟是如何工作的,就像每次打开新视图/窗口时都会实例化 App 类一样.

I've been reading the Microsoft documentation to try and understand what is the issue, but I still don't understand how exactly do Multiple Views work, like if the App class instantiated every time I open a new view/window.

非常感谢您的帮助.

推荐答案

我已经找到了解决问题的方法,实际上我已经决定不使用示例附带的 ViewLifeTime 控件.

I've found the solution to my problems, and I've actually decided not to use the ViewLifeTime control that comes with the sample.

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

The problem is that when the Main view is closed you have to use the Dispatcher.RunAsync() method from one of the other views that are still open to run it that thread

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

Here's the code that I've changed in my App.xaml.cs for anyone that is interested:

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

这篇关于多视图的 UWP 问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆