4

我正在使用 OOTB Grid App 模板构建 Windows Store App。我注意到当我从一个页面向前或向后导航时有 500-1000 毫秒的暂停。当我点击后退按钮时(后退箭头在 500-1000 毫秒内保持在“命中”状态),这主要是值得注意的。继续前进并没有那么糟糕,因为通常屏幕有动画和过渡来填充大部分加载时间。

我的第一个想法是该LoadState方法中存在导致速度减慢的某些东西,但我唯一拥有的不是来自我在后台线程上运行并使用async前言调用它的模板。

我的第二个想法是我将一个复杂的对象传递给每个页面navigationParameter,而不仅仅是传递一个简单的字符串。我不认为这可能是原因,因为对象应该通过引用传递,所以真的不应该有任何减速,因为我将非字符串传递到NavigateTo方法中。

(我还没有阅读任何关于这方面的指导,所以我不知道在页面之间传递非字符串时页面导航是否不那么活泼。如果有人对此有任何见解,那就太好了)

我的下一个想法是我的 Xaml 太复杂了,暂停是 Xaml 将所有项目加载到列表中,什么不是。这可能是问题所在,如果是这样,我不知道如何测试或修复它。加载完所有内容后,用户界面感觉流畅(页面上的所有项目都滚动而不会卡顿)

如果是这种情况,是否有任何方法可以显示 Xaml 生成的加载圆圈,然后一旦完成生成,淡入内容并淡出圆圈?

我要修复的主要问题是我不希望后退按钮在点击中“冻结”。任何帮助或指导都会很棒!


基本应用信息:

页面具有列表和网格视图控件与不同项目模板的组合。没有使用图像或图形,但我确实在一些项目模板上使用了渐变画笔(不是超级复杂,类似于开始屏幕项目渐变)。大多数列表只有 20-30 项,有些则更少。

平均页面有 1 个项目源和 2 个项目显示控件、一个列表和一个包含所选项目详细信息的滚动查看器。

任何项目的详细信息大约是 2-3 个普通段落的详细信息文本和 3-4 < 20 个字符字符串。


编辑:项目代码:

第 1 页代码

    protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
    {
        if (navigationParameter == null)
            this.DefaultViewModel["Groups"] = GlobalData.Catalog.Catalog;
        else
            this.DefaultViewModel["Groups"] = navigationParameter;

        await GlobalData.LibraryDownload.DiscoverActiveDownloadsAsync();
    }

DiscoverActiveDownloadsAsync方法与此示例代码中的代码相同

SaveStateOnNavigateToOnNavigateFrom方法尚未从LayoutAwarePage基类修改。

第 2 页代码

    protected async override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
    {
        if (navigationParameter is CatalogBook)
        {
            var catBook = (CatalogBook)navigationParameter;
            var book = catBook.Book;
            await book.InitializeAsync();

            this.DefaultViewModel["Group"] = catBook;
            this.DefaultViewModel["Items"] = book.Items;
        }
        else if (navigationParameter is IBook)
        {
            var book = await Task.Run<IBook>(async () =>
                {
                    var b = (IBook)navigationParameter;
                    await b.InitializeAsync();
                    return b;
                });

            this.DefaultViewModel["Group"] = book;
            this.DefaultViewModel["Items"] = book.Chapters;
        }

        if (pageState == null)
        {
            // When this is a new page, select the first item automatically unless logical page
            // navigation is being used (see the logical page navigation #region below.)
            if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
            {
                this.itemsViewSource.View.MoveCurrentToFirst();
            }
        }
        else
        {
            // Restore the previously saved state associated with this page
            if (pageState.ContainsKey("SelectedItem") && this.itemsViewSource.View != null)
            {
                var number = 0;
                if(!int.TryParse(pageState["SelectedItem"].ToString(), out number)) return;

                var item = itemsViewSource.View.FirstOrDefault(i => i is ICanon && ((ICanon)i).Number == number);
                if (item == null) return;

                this.itemsViewSource.View.MoveCurrentTo(item);

                itemListView.UpdateLayout();
                itemListView.ScrollIntoView(item);
            }
        }
    }


    ...


    protected override void SaveState(Dictionary<String, Object> pageState)
    {
        if (this.itemsViewSource.View != null)
        {
            var selectedItem = this.itemsViewSource.View.CurrentItem;
            pageState["SelectedItem"] = ((ICanon)selectedItem).Number;
        }
    }

InitializeAsync方法从 SQLite 数据库中读取有关一本书的一些基本信息(章节、作者等),并且通常运行速度非常快(< 10ms)

网格代码

我通过使用 SQLite-net Nuget 包的异步方法查询 SQLite 数据库来获取数据。查询通常如下所示:

    public async Task InitializeAsync()
    {
        var chapters = await _db.DbContext.Table<ChapterDb>().Where(c => c.BookId == Id).OrderBy(c => c.Number).ToListAsync();

        Chapters = chapters
            .Select(c => new Chapter(_db, c))
            .ToArray();

        HeaderText = string.Empty;
    }

我使用以下 Xaml 填充网格:

    <CollectionViewSource
        x:Name="groupedItemsViewSource"
        Source="{Binding Groups}"
        IsSourceGrouped="true"
        ItemsPath="Items"
        d:Source="{Binding DisplayCatalog, Source={d:DesignInstance Type=data:DataCatalog, IsDesignTimeCreatable=True}}"/>

    <common:CatalogItemTemplateSelector x:Key="CatalogItemTemplateSelector" />

    ...

    <GridView
        Background="{StaticResource ApplicationPageLightBackgroundThemeBrushGradient}"
        ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}" 
        SelectionMode="Multiple"            
        Grid.Row="1" 
        ItemTemplateSelector="{StaticResource CatalogItemTemplateSelector}" 
        IsItemClickEnabled="True"
        ItemClick="ItemView_ItemClick" Margin="-40,0,0,0">
        <GridView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" Height="628" Margin="120,10,0,0" />
            </ItemsPanelTemplate>
        </GridView.ItemsPanel>
        <GridView.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <Grid Margin="1,10,0,6">
                            <Button
                                AutomationProperties.Name="Group Title"
                                Click="Header_Click"
                                Style="{StaticResource TextPrimaryButtonStyle}" >
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding Name}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
                                    <TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
                                </StackPanel>
                            </Button>
                        </Grid>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
                <GroupStyle.Panel>
                    <ItemsPanelTemplate>
                        <VariableSizedWrapGrid Margin="0,0,80,0" ItemHeight="{StaticResource ItemHeight}" ItemWidth="{StaticResource ItemWidth}"/>
                    </ItemsPanelTemplate>
                </GroupStyle.Panel>
            </GroupStyle>
        </GridView.GroupStyle>

    </GridView>

CatalogItemTemplateSelector看起来像这样:

public class CatalogItemTemplateSelector : DataTemplateSelector
{
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        // cast item to your custom item class
        var customItem = item as ICatalogItem;
        if (customItem == null)
            return null;

        string templateName = String.Empty;
        if (customItem is CatalogFolder || customItem is CatalogMoreFolder)
        {
            templateName = "FolderItemDataTemplate";
        }
        else if (customItem is CatalogBook || customItem is CatalogMoreBook)
        {
            templateName = "BookItemDataTemplate";
        }

        object template = null;
        // find template in App.xaml
        Application.Current.Resources.TryGetValue(templateName, out template);
        return template as DataTemplate;
    }
}

两个模板都是约 20 行 Xaml,没什么特别的

如果还有其他我没有包含的代码,请告诉我,我会添加它们。

4

2 回答 2

0

您的内存使用情况如何?您可能正在分页到磁盘吗?

摘自http://paulstovell.com/blog/wpf-navigation

Page Lifecycles ....
假设您的页面需要将某种参数数据传递给它: ... 导航时,如果单击“返回”,WPF 不可能知道要传递给构造函数的值;因此它必须使页面保持活动状态。
...如果您直接导航传递一个对象,WPF 将使该对象保持活动状态。

于 2013-04-23T05:22:26.707 回答
0

我没有答案,但是这个 Channel 9 (Microsoft) 视频在 XAML 性能方面非常好。也许它可以帮助您解决问题。

http://channel9.msdn.com/Events/Build/2012/4-103

于 2013-04-21T23:13:23.237 回答