【问题标题】:UWP problems with multiple views多个视图的 UWP 问题
【发布时间】:2020-07-08 18:43:46
【问题描述】:

我正在编写一个应用程序,它应该能够运行多个视图以在各自的窗口中编辑不同的文档。我写了一些有效的代码,但是我遇到了一些问题。我编写的代码基于 Microsoft (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 文档以尝试了解问题所在,但我仍然不明白多视图究竟是如何工作的,例如每次打开新视图/窗口时都会实例化 App 类。

非常感谢您的帮助。

【问题讨论】:

  • 此代码 currentPage.LoadNewFile(); 正在调用主页的 LoadNewFile。您是否在 Mainpage.xaml.cs 中编写了另一个 LoadNewFile() 方法?为什么将所有代码都放在 App.xaml.cs 中?最好上传所有代码。
  • 是的,我确实在 MainPage.xaml.cs 中编写了 LoadNewFile() 方法,并将多个视图的所有代码放在 App.xaml.cs 中,因此我不必重写代码,但我确实尝试从我的 MainPage.xaml.cs 创建新的视图/窗口,但错误相同。当 CoreApplication.CreateNewView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 在 createMainPageAsync() 方法中运行时应用程序崩溃,最奇怪的是它试图打开另一个调试器而不是 Visual Studio
  • 在这种情况下,请上传所有代码,否则没有错误代码,错误详细信息,人们无法帮助您。

标签: c# uwp windows-10 win-universal-app


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      您可以选择在您的应用程序中使用multiple instances。您可以按照我在here 中的描述同步设置更改。

      【讨论】:

        【解决方案4】:

        不要查看(你的)终生...干杯,

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

        【讨论】:

        • 如果你想删除你的答案,只需点击删除按钮。
        • @FrankerZ,未注册用户无法删除他们的答案。
        猜你喜欢
        • 1970-01-01
        • 2019-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-11
        • 2017-11-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多