【问题标题】:Slow GridView Resize in UWPUWP 中缓慢的 GridView 调整大小
【发布时间】:2016-03-02 08:17:09
【问题描述】:

为了简化示例,假设我们只是在页面中添加了一个 GridView:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <GridView x:Name="MainGrid" />
</Grid>

这是代码:

public MainPage()
{
    this.InitializeComponent();

    this.Loaded += MainPage_Loaded;
}

private async void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var collection = new ObservableCollection<String>();

        MainGrid.ItemsSource = collection;

        await Dispatcher.RunIdleAsync(test =>
        {
            for (int i = 0; i < 20000; i++)
            {
                collection.Add(i.ToString());
            }
        });

    }

GridView 充满了 ObservableCollection,我不抱怨滚动,而是抱怨调整窗口大小和最大化窗口会造成巨大的延迟,在低规格计算机中甚至更糟。

我做了以下改进:

  1. 使用 IncrementalLoadingThreshold 和 DataFetchSize 的值
<GridView x:Name="MainGrid" IncrementalLoadingThreshold="100" DataFetchSize="3"/>

有时会更好,但不确定此值是否适用于静态集合。

  1. 将对齐方式更改为顶部和左侧以跟踪 SizeChanged 并适应网格。

这会更好,但是当我点击最大化时它有很大的延迟。

我也尝试过像http://xurxodeveloper.blogspot.com.es/2014/03/scroll-infinito-en-windows-81-con-xaml.html 这样的旧示例,但是当滚动到最后时它不会添加更多项目。而且我找到的性能提示和文章只是为了滚动。

那么在这种静态情况下,是否有一种技术或其他收集源来改善调整大小的延迟?

【问题讨论】:

  • 附注:没有必要在调度程序的最后一行运行 - 从await Task... 返回后,它已经在捕获的 UI 上下文中运行。第二 - 不要在 non-UI 线程中修改 ObservableCollection(与 UI 控件一起使用) - 你会得到异常 - 你的情况是有效的,因为在集合被设置为 UI 元素的 itemssource 之后满了,如果你交换订单,它不会工作。但正如我所提到的,这些是与您的问题无关的旁注。
  • 好吧,我开始从测试中删除代码,我已经更新了代码,我认为现在更干净了,谢谢你的帮助,关于另一个可以更好地工作的集合有什么想法吗?
  • ObservableCollection 似乎是一个不错的选择——它被设计用于在这种情况下使用 UI 元素。我不知道如何让它更好地工作,我会尝试使用 GridView's (ListView's) IncrementalLoading 搜索一些东西 - 不要加载不需要时的所有项目 - 可能尝试搜索有关 ListView 和增量装货、方法 LoadMoreItemsAsync 等的内容。虽然我不确定这对你的情况如何。

标签: xaml gridview windows-10 win-universal-app


【解决方案1】:

首先创建一个允许您添加范围的新 Observable 集合。这就是我所拥有的

public class ObservableCollection2<T> : ObservableCollection<T>
{
    bool _suppressNotification = false;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!_suppressNotification)
            base.OnCollectionChanged(e);

        // do nothing
    }

    public ObservableCollection2() : base() { }
    public ObservableCollection2(IEnumerable<T> collection) : base(collection)
    { }

    public void AddRange(IEnumerable<T> list)
    {
        this._suppressNotification = true;

        if (list == null)
            throw new ArgumentNullException("list");

        int index = this.Count;

        foreach (T item in list)
        {
            base.Items.Add(item);
        }

        this._suppressNotification = false;

        OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("Count"));
        OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs("Items[]"));
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, list.ToList(), index));
    }
}

接下来,您不要在 Loaded 上实例化集合,而是在构造函数中进行实例化

public MainPage()
    {
        this.InitializeComponent();

        dataCol = new ObservableCollection2<String>();
    }

    ObservableCollection2<String> dataCol = null;

    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
    MainGrid.ItemsSource = dataCol;

    List<stirng> tempList = new List<string>();
    for (int i = 0; i < 20000; i++)
    {
        tempList .Add(i.ToString());
    }
    dataCol.AddRange(tempList);

}

简而言之,只有在集合完成处理后,您才不会在每次插入后触发 UI 更新。这意味着 GridView 会收到一次更新通知,而不是 2000 次

【讨论】:

  • 可能是我没有解释清楚,我想解决的问题是在你调整窗口大小之后,控件需要很长时间才能刷新。加载不是问题。无论如何谢谢
  • 我认为您对 GridView 布局中的滞后无能为力。您可以查看 Telerik 之类的第 3 方控件。我已经开始使用 RadDataBoundListBox,因为库存控件不提供特定的功能
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-03
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 1970-01-01
相关资源
最近更新 更多