【问题标题】:Adding Items to ListView too slow in C#在 C# 中向 ListView 添加项目太慢
【发布时间】:2011-12-20 03:35:15
【问题描述】:

我想将项目添加到列表视图控件。这是一段代码:

    this.lView.ListViewItemSorter = null;
    ListViewItem[] lvitems = new ListViewItem[ListMyObjects.Count];
    int index = 0;
    foreach (MyObject object in ListMyObjects)
        {
            ListViewItem item = new ListViewItem();               
            item.Text = object.Name;
            lvitems[index++] = item;
        }
    this.lView.BeginUpdate();
    this.lView.Items.AddRange(lvitems); // Slow in here with debugger
    this.lView.EndUpdate();

我只添加了大约 1000 个项目,但速度非常慢。大约需要 15 秒才能完成。 为什么有人知道原因?预先感谢。

编辑

我以前定制过列表视图。

public partial class MyListView: ListView
{        
    public MyListView()
    {
        InitializeComponent();
        this.View = View.Details;
        this.FullRowSelect = true;
        this.DoubleBuffered = true;
    }
    private bool mCreating;
    private bool mReadOnly;
    protected override void OnHandleCreated(EventArgs e)
    {
        mCreating = true;
        base.OnHandleCreated(e);
        mCreating = false;
    }
    public bool ReadOnly
    {
        get { return mReadOnly; }
        set { mReadOnly = value; }
    }
    protected override void OnItemCheck(ItemCheckEventArgs e)
    {
        if (!mCreating && mReadOnly) e.NewValue = e.CurrentValue;
        base.OnItemCheck(e);
    }   
}

我这样做是因为我不想在使用多线程时挂起。不知道这对它有什么影响?

【问题讨论】:

标签: c# winforms listview


【解决方案1】:

您可以通过启用virtual mode 来加快速度。
但是,这需要一些工作。

【讨论】:

  • 你知道这种行为的原因是什么吗?正如我对这个问题的评论,它适用于整数。
  • @Slaks,强制垃圾收集器在 foreach 循环中运行。我认为在 GC 自动运行之前内存中的对象太多了。您可能需要添加以下代码行: GC.Collect(); GC.WaitForPendingFinalizers();
  • @BishnuPaudel:那根本没有用;循环中没有可收集的内容。
【解决方案2】:

添加多个项目的首选方法是使用AddRange() method。但是,如果您必须一一添加项目,您可以在循环周围使用 BeginUpdate() 和 EndUpdate() 方法。以下来自MSDN

将多个项目添加到 ListView 的首选方法是使用 ListView.ListViewItemCollection 的 AddRange 方法(通过 ListView 的 Items 属性访问)。这使您能够在单个操作中将一组项目添加到列表中。但是,如果您想使用 ListView.ListViewItemCollection 类的 Add 方法一次添加一项,则可以使用 BeginUpdate 方法来防止控件在每次添加项时重新绘制 ListView。

【讨论】:

    【解决方案3】:

    适用于更具架构性的解决方案,但如果您的域对象很大,这可能会导致瓶颈(读取 cmets 听起来它们可能会减慢速度)。在进入表示层之前,您可以将它们扁平化为一些(非常简单的)域传输对象 (DTO):实际上只是一袋 getter-and-setter。

    AutoMapper 之类的工具可能会完成大量的工作

    这样,您的域对象将保留在业务逻辑域(它们所属的位置)中,而您的表示层只需从 DTO 获取所需的数据。

    对不起,非基于代码的建议 :) 祝你好运!

    【讨论】:

    • 您能否解释一下“大”对象与您的 DTO 的不同之处 (=[POCO's|en.wikipedia.org/wiki/Plain_Old_CLR_Object) 吗?属性只是一堆引用?
    • 咆哮:所以评论系统没有预览,我需要收集更多积分才能编辑/修复我自己的评论?耶..
    • DTO 发送的数据与支持依赖系统所需的数据一样多,而 POCO 也可能包含大量其他数据。通常在系统内使用 POCO,在两个系统之间使用 DTO(系统是物理实体或逻辑实体)。希望对您有所帮助,对不起,cmets系统让您感到悲伤。
    • 感谢您的澄清,但这仅在您的数据必须被序列化和反序列化时才相关?对于大型对象,循环遍历对象列表不会变慢。这只是一个参考列表!
    • 这取决于里面有什么——如果域对象是 10 个整数、69 个字符串、12 个双精度对象和 49 个复杂对象,那么将它压缩成一个 DTO 可能是值得的。如果它由一个 get/set int 组成,那么可能不是:) +1
    猜你喜欢
    • 2013-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多