等待页面加载 - UWP

时间:2016-07-14 04:01:39

标签: c# .net uwp uwp-xaml

所以我有一个带有Pivot项的XAML页面的Windows 10应用程序,Pivot的默认行为是每当您导航到包含Pivot的页面时, Pivot上的第一个项目会立即被选中。我想要做的是在Pivot运行的第一项之前执行一些代码

上下文代码

public sealed partial class ContentFrame : Page
{
    private IMobileServiceTable<News> NewsItems = App.MobileService.GetTable<News>();

    private List<News> AllNews;

    private List<News> Windows = new List<News>();
    private List<News> Apple = new List<News>();
    private List<News> Google = new List<News>();
    private List<News> Other = new List<News>();
    private List<News> Top = new List<News>();

    private string WeekID;

    public ContentFrame()
    {
        this.InitializeComponent();
    }

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        WeekID = e.Parameter as string;
        AllNews = await NewsItems.Where(News => News.Week == WeekID).ToListAsync();
        separateContent();
    }

    private void separateContent()
    {
        foreach (News item in AllNews)
        {
            Debug.WriteLine(item.Tag);
            if (item.Tag == "Windows")
                Windows.Add(item);
            else if (item.Tag == "Apple")
                Apple.Add(item);
            else if (item.Tag == "Google")
                Google.Add(item);
            else if (item.Tag == "Other")
                Other.Add(item);
            else
                Top.Add(item);
        }
    }

    private void Tags_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        IntroHead.FontWeight = FontWeights.Normal;
        WindowsHead.FontWeight = FontWeights.Normal;
        AppleHead.FontWeight = FontWeights.Normal;
        GoogleHead.FontWeight = FontWeights.Normal;
        OtherHead.FontWeight = FontWeights.Normal;

        switch (Tags.SelectedIndex)
        {
            case 0:
                IntroHead.FontWeight = FontWeights.SemiBold;
                StoryContent.Navigate(typeof(TopNewsPage), Top);
                break;
            case 1:
                WindowsHead.FontWeight = FontWeights.SemiBold;
                StoryContent.Navigate(typeof(OtherNews), Windows);
                break;
            case 2:
                AppleHead.FontWeight = FontWeights.SemiBold;
                StoryContent.Navigate(typeof(OtherNews), Apple);
                break;
            case 3:
                GoogleHead.FontWeight = FontWeights.SemiBold;
                StoryContent.Navigate(typeof(OtherNews), Google);
                break;
            case 4:
                OtherHead.FontWeight = FontWeights.SemiBold;
                StoryContent.Navigate(typeof(OtherNews), Other);
                break;
        }
    }
}

与问题相关的代码行:

  

StoryContent.Navigate(typeof(TopNewsPage),Top);

这执行得太快了,我想等到之前完成separateContent();方法 我允许应用程序导航我的XAML布局上的Pivot控件。如果不这样做,传入(Top)的参数将为null / empty,我的应用程序将在导航到TopNewsPage后立即抛出异常。

我该怎么做?

我理解我制作应用程序的方式并不是最好的(MVVM是我将来要探索的东西)但这是我的第一个应用程序而且我真的只想让它工作。我已经用Task进行了一些探索,但似乎没有任何帮助我的原因,因为Pivot导航太快了。

3 个答案:

答案 0 :(得分:0)

在评论中,您已经提到,在您希望WeekID工作并Tags_SelectionChanged设置为WeekID之前,您主要希望OnNavigatedTo拥有值。事件。只要Tags_SelectionCHanged尚未设置,我建议您不要对WeekID事件做任何事情。

尝试:

private void Tags_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if(string.IsNullOrEmpty(WeekID))
        return;

    IntroHead.FontWeight = FontWeights.Normal;
    WindowsHead.FontWeight = FontWeights.Normal;
    AppleHead.FontWeight = FontWeights.Normal;
    GoogleHead.FontWeight = FontWeights.Normal;
    OtherHead.FontWeight = FontWeights.Normal;

    switch (Tags.SelectedIndex)
    {
        case 0:
            IntroHead.FontWeight = FontWeights.SemiBold;
            StoryContent.Navigate(typeof(TopNewsPage), Top);
            break;
        case 1:
            WindowsHead.FontWeight = FontWeights.SemiBold;
            StoryContent.Navigate(typeof(OtherNews), Windows);
            break;
        case 2:
            AppleHead.FontWeight = FontWeights.SemiBold;
            StoryContent.Navigate(typeof(OtherNews), Apple);
            break;
        case 3:
            GoogleHead.FontWeight = FontWeights.SemiBold;
            StoryContent.Navigate(typeof(OtherNews), Google);
            break;
        case 4:
            OtherHead.FontWeight = FontWeights.SemiBold;
            StoryContent.Navigate(typeof(OtherNews), Other);
            break;
    }
}

如果这适合您,您可能希望在导航到另一个页面之前将事件设置为WeekID为null或为空,或者当页面关闭时,因为我不知道{{1在此类事件中将保留ContentFrame的值。只是一个提示。

答案 1 :(得分:0)

注意:我不认为这是解决我的问题的好方法,但它是有效的。

以下是我的所作所为:

  1. Top.Count中添加了对Tags_SelectionChanged的检查,以便在List为空时无法运行。
  2. separateContent();的末尾添加了两行代码,以便在Pivot包含项目后执行第​​一个Top项目。
  3. 如果您有更好的方法,请分享!

        private void separateContent()
        {
            foreach (News item in AllNews)
            {
                Debug.WriteLine(item.Tag);
                if (item.Tag == "Windows")
                    Windows.Add(item);
                else if (item.Tag == "Apple")
                    Apple.Add(item);
                else if (item.Tag == "Google")
                    Google.Add(item);
                else if (item.Tag == "Other")
                    Other.Add(item);
                else
                    Top.Add(item);
            }
            IntroHead.FontWeight = FontWeights.SemiBold;
            StoryContent.Navigate(typeof(TopNewsPage), Top);
        }
    
        private void Tags_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (Top.Count < 6)
                return;
            IntroHead.FontWeight = FontWeights.Normal;
            WindowsHead.FontWeight = FontWeights.Normal;
            AppleHead.FontWeight = FontWeights.Normal;
            GoogleHead.FontWeight = FontWeights.Normal;
            OtherHead.FontWeight = FontWeights.Normal;
    
            switch (Tags.SelectedIndex)
            {
                case 0:
                    IntroHead.FontWeight = FontWeights.SemiBold;
                    StoryContent.Navigate(typeof(TopNewsPage), Top);
                    break;
                case 1:
                    WindowsHead.FontWeight = FontWeights.SemiBold;
                    StoryContent.Navigate(typeof(OtherNews), Windows);
                    break;
                case 2:
                    AppleHead.FontWeight = FontWeights.SemiBold;
                    StoryContent.Navigate(typeof(OtherNews), Apple);
                    break;
                case 3:
                    GoogleHead.FontWeight = FontWeights.SemiBold;
                    StoryContent.Navigate(typeof(OtherNews), Google);
                    break;
                case 4:
                    OtherHead.FontWeight = FontWeights.SemiBold;
                    StoryContent.Navigate(typeof(OtherNews), Other);
                    break;
            }
        }
    

答案 2 :(得分:0)

TLDR:https://github.com/baskren/P42.Uno.AsyncNavigation/tree/main

要考虑的事情:如果可以预加载页面,则可以异步/等待页面预加载完成,然后再显示它。但是,等等,您说,UWP导航不允许预加载页面-它不是异步/等待!

是的,但是有一种解决方法。首先,请考虑Page继承自FrameworkElement。这意味着Page可以是Grid的子级,也可以是ContentPresenter的内容。这是显示此内容的快速实验:

ChildPage.xaml(在展示前我要预加载的页面):

<Page
    x:Class="NestedPagesExperiment.Shared.ChildPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:NestedPagesExperiment.Shared"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <Page.Content>
        <Grid>
            <Grid.Children>
                <TextBlock Text="I AM THE CHILD PAGE CONTENT!!!!" />
            </Grid.Children>
        </Grid>
    </Page.Content>
</Page>

MainPage.xaml(托管页面-将向其中添加预加载的ChildPage):

<Page
    x:Class="NestedPagesExperiment.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:NestedPagesExperiment"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Content>

        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition Height="40" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.Children>
                <TextBlock
                    Margin="20"
                    FontSize="30"
                    Text="Hello, world!" />
                <Button
                    x:Name="_button"
                    Grid.Row="1"
                    Click="OnButtonClick"
                    Content="Add Content" />
                <ContentPresenter x:Name="_contentPresenter" Grid.Row="2" />
            </Grid.Children>
        </Grid>
    </Page.Content>
</Page>

MainPage.xaml.cs(后面的代码):

using NestedPagesExperiment.Shared;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace NestedPagesExperiment
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private void OnButtonClick(object sender, RoutedEventArgs e)
        {
            var content = new ChildPage();
            _contentPresenter.Content = content;
        }
    }
}

但是,等一下,您说,我仍然想进行页面转换!看看Xamarin.Forms是如何做到这一点的:

首先,Xamarin有一个页面容器(FormsEmbeddedPageWrapper),该容器托管着动态生成的页面。 FormsEmbeddedPageWrapper.xaml

<Page
    x:Class="Xamarin.Forms.Platform.UWP.FormsEmbeddedPageWrapper"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Xamarin.Forms.Platform.UAP"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <ContentPresenter Name="Root" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

    </ContentPresenter>
</Page>

注意以下几点:

  • 它的重量很轻,所以这里没有使用传统的UWP页面导航无法快速加载的东西。
  • 第10行上有一个ContentPresenter,我们将看到,这是放置预加载内容的位置。

同样重要的是,看看后面的代码:

    public sealed partial class FormsEmbeddedPageWrapper : Windows.UI.Xaml.Controls.Page
    {
        internal static Dictionary<Guid, ContentPage> Pages = new Dictionary<Guid, ContentPage>();

        public FormsEmbeddedPageWrapper()
        {
            InitializeComponent();
        }

        protected override void OnNavigatedTo(Windows.UI.Xaml.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (e.Parameter == null)
            {
                throw new InvalidOperationException($"Cannot navigate to {nameof(FormsEmbeddedPageWrapper)} without "
                    + $"providing a {nameof(Xamarin.Forms.Page)} identifier.");
            }

            // Find the page instance in the dictionary and then discard it so we don't prevent it from being collected
            var key = (Guid)e.Parameter;
            var page = Pages[key];
            Pages.Remove(key);

            // Convert that page into a FrameWorkElement we can display in the ContentPresenter
            FrameworkElement frameworkElement = page.CreateFrameworkElement();

            if (frameworkElement == null)
            {
                throw new InvalidOperationException($"Could not find or create a renderer for the Page {page}");
            }

            Root.Content = frameworkElement;
        }
    }

并且,为了完成谜题,我们还需要一件-一种扩展方法:

        internal static bool Navigate(this Windows.UI.Xaml.Controls.Frame frame, ContentPage page, Windows.UI.Xaml.Media.Animation.NavigationTransitionInfo infoOverride)
        {

            if (page == null)
            {
                throw new ArgumentNullException(nameof(page));
            }

            Guid id = Guid.NewGuid();

            FormsEmbeddedPageWrapper.Pages.Add(id, page);
            if (infoOverride != null)
                return frame.Navigate(typeof(FormsEmbeddedPageWrapper), id, infoOverride);

            return frame.Navigate(typeof(FormsEmbeddedPageWrapper), id);
        }

因此,当需要导航到新页面时,这就是Xamarin.Forms正在做的事情:

  1. 其Navigate扩展功能将预先生成的页面放入到静态字典(FormsEmbeddedPageWrapper.Pages)中,并键入到新生成的GUID。
  2. 使用非常轻量级的frame.Navigate(Type, object)类型和上面生成的GUID密钥作为参数调用UWP FormsEmbeddedPageWrapper方法。
  3. UWP实例化并显示FormsEmbeddedPageWrapper的新实例。
  4. OnNavigatedTo实例上的UWP调用的FormsEmbeddedPageWrapper-在参数中包含GUID键。
  5. FormsEmbeddedPageWrapper实例使用GUID键从Pages静态字典中提取预加载的页面内容。
  6. FormsEmbeddedPageWrapper将其Content的{​​{1}}设置为从ContentPresenter静态字典检索的预加载页面内容。

这种方法保留了UWP页面过渡动画的使用,并允许预加载页面内容。

尽管使用Xamarin.Forms代码片段来解释这种方法,但是这种方法没有什么可以在现成的UWP应用中使用的。