【问题标题】:WinRT Enhancing performance for adding Items of Collection to ListWinRT 增强将集合项添加到列表的性能
【发布时间】:2014-07-01 08:59:54
【问题描述】:

我在尝试将 ObservableCollection 的一些项添加到 ListView 时遇到了一个小性能问题。

这是 ObservableCollection:

    private ObservableCollection<object> children = new ObservableCollection<object>();
    public ObservableCollection<object> Children
    {
        get
        {
            return children;
        }
    }

我也在使用 ContentProperty:

[ContentProperty(Name="Children")]

这是我需要开始添加列表的 CollectionChanged 事件:

void children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        InitGraphics();
    }  

在 InitGraphics() 中,我将创建我的列表并绘制它所需的所有元素。还有一个名为 SynchronizeList() 的函数,它在 InitGraphics() 的开头被调用。

SynchronizeList() 看起来像这样:

private void SynchronizeList()
    {
        foreach (var item in children)
        {
            //Casting ListViewItem as ValueBoxControl
            ValueBoxControl control = (ValueBoxControl)item;

            //Standards and needed attributes
            control.ValueTextBox.IsHitTestVisible = false;
            control.ClipColor = ClipColor;
            control.Foreground = this.Foreground;

            //Add the Item to the List
            List.Items.Add(item);
        }
    }

现在,如您所见,我的 ListView 称为 List,而 Items 是称为 ValueBoxControl 的用户控件。每个项目的标准和属性必须相同,并且不能更改。

我需要在其他几个函数中使用 SynchronizeList() 函数(例如:当 List 被切换两次时,我删除所有 Items 并使用 SynchronizeList() 再次添加它们等)。

当我添加大约 50 多个项目时会出现问题,因为它显然必须通过 foreach 循环运行 50 次并添加每个项目。在调试时,我注意到子集合从一开始就没有全部 50 个项目。它首先有 1 个项目,然后是 2 个,然后是 3 个,以此类推。 这意味着 SynchronizeList() 被调用了 50 次,首先添加 1 个项目,然后是 2,然后是 3,等等。

我已经尝试了很多事情(例如在 CollectionChangedEvent 中使用 e.NewItems),但目前我认为没有可能的解决方案。

这是我的片段中的一个完整示例,它显示了我的问题:

//ContentProperty to receive Items from XAML with the help of an ObservableCollection
[ContentProperty(Name="Children")]
public sealed partial class ListViewControl : ValueBoxControl
{
    //Create a new ListView
    ListView List = new ListView();

    //Initialization
    public ListViewControl()
    { 
        //Events
        children.CollectionChanged += children_CollectionChanged;
    }

    //ObservableCollection to receive Items from XAML
    private ObservableCollection<object> children = new ObservableCollection<object>();
    public ObservableCollection<object> Children
    {
        get
        {
            return children;
        }
    }

    //Event which gets called whenever the List in XAML gets changed
    void children_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        //Calls the function to draw the List
        InitGraphics();
    }    

    private void InitGraphics()
    {
        SynchronizeList();
        if (List.Items.Counter >= 1)
        {
            //Draw the ListView with a custom design
        }
    }

    private void SynchronizeList()
    {
        //Get each item in the ObservableCollection and add some attributes
        foreach (var item in children)
        {
            //ListViewItem casted as ValueBoxControl
            ValueBoxControl control = (ValueBoxControl)item;
            //Standards & Limitations
            control.ValueTextBox.IsHitTestVisible = false;
            control.ClipColor = ClipColor;
            control.Foreground = this.Foreground;
            //Add Item to ListView
            List.Items.Add(item);
        }
    }
}

我在这里遇到的主要问题是 CollectionChanged 事件被调用了 50 次 50 个项目,每次接收一个新项目,而不是一次性接收所有项目。

【问题讨论】:

  • 我对 List 属性是什么感到困惑 - 那是 ObservableCollection 吗?
  • @JonSkeet 我已经在最后一个代码sn-p之后的第一句话中写了。这是一个简单的 ListView:ListView List = new ListView();
  • 啊,对。你的代码很难理解,因为它是零散的,而且你有一些需要额外描述的部分。一个简短但完整的示例会更容易理解...
  • 嗯,我使用这些函数的整个 ListControl 有 600 行代码,所以我提取了这些函数以保持简短。如果您认为它有优势,我仍然可以发布整个代码。但简而言之,我的问题是 CollectionChanged 事件为 50 个项目被调用 50 次,而不是为所有 50 个项目调用一次。
  • 我并没有说我想要你的全部实际代码。我想要一个简短但完整的示例来演示问题,并且什么都不做。不过,您可能想查看ReplaceAll 方法。

标签: c# listview windows-runtime


【解决方案1】:

鉴于ItemCollection 的文档,我怀疑您想要ReplaceAll 方法:

对于跟踪“已更改”事件的实现,初始重置会触发事件,但添加的项目不会触发离散的每个项目事件。

比如:

private void SynchronizeList()
{
    // Set properties in each item
    foreach (var item in children)
    {
        //ListViewItem casted as ValueBoxControl
        ValueBoxControl control = (ValueBoxControl)item;
        //Standards & Limitations
        control.ValueTextBox.IsHitTestVisible = false;
        control.ClipColor = ClipColor;
        control.Foreground = this.Foreground;
    }
    List.Items.ReplaceAll(children.ToArray());
}

不幸的是,AddRange 似乎并不是您真正想要的……至少值得一试。

【讨论】:

  • 好吧,这个想法对我来说似乎不错,我会尝试实现它:) 谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
  • 1970-01-01
  • 2022-12-11
  • 2016-10-10
  • 1970-01-01
相关资源
最近更新 更多