【问题标题】:Overridden winform ListBox.Sort() not getting called as expected覆盖的 winform ListBox.Sort() 未按预期调用
【发布时间】:2015-08-16 13:29:42
【问题描述】:

我正在尝试覆盖列表框中的排序方法以按降序排序。

代码:

public CustomSortListBox()
    : base()
{
}

protected override void Sort()
{
    if (this.Items.Count > 1)
    {
        bool swapped;
        do
        {
            int counter = this.Items.Count - 1;
            swapped = false;

            while (counter > 0)
            {
                // set this to != to reverse sorting
                if (this.Items[counter].ToString().CompareTo(this.Items[counter - 1].ToString()) != -1)
                {
                    object temp = Items[counter];
                    this.Items[counter] = this.Items[counter - 1];
                    this.Items[counter - 1] = temp;
                    swapped = true;
                }

                counter -= 1;
            }
        }
        while (swapped);
    }
}

现在,我直观地期望每当将项目添加到列表时都会调用此方法,这似乎是当 ListBox.Sorted = true 时它与基本 ListBox 一起工作的方式。但是,在将项目添加到列表后使用我的 CustomSortListBox 时,我的自定义排序没有得到尊重,此外,当项目列表发生更改时,没有调用被覆盖的方法,甚至没有遇到断点。

然后我读到了这个https://gfaraj.wordpress.com/2008/07/31/custom-sorting-for-listbox-in-c/,上面写着“不要忘记只有在 Sorted 属性从 false 变为 true 时才会调用 Sort”这对我来说似乎很荒谬,但可以肯定的是,当切换 Sorted 并重新打开时,我的自定义排序被调用并工作。

有趣的是,在这之后,保留 Sorted = true,添加的新项目使用基本的 Sort() 方法进行排序,创建升序和降序项目的混合。直到您再次切换 Sorted false -> true。

我什至会接受将 Sorted = false; 设置为 hacky 的解决方案。排序=真;在 ItemsChanged 的​​事件处理程序中,但这样的事件不存在。

我做错了什么以及如何在添加列表时尊重此排序覆盖?

(我见过C#'s ListBox doesn't see my overrided Sort() method,但他的问题不清楚,似乎刚刚“消失”,他随机选择的答案并不理想,甚至由于无法访问保护级别而无法编译)

【问题讨论】:

  • 不必从 MSDN 文章中复制粘贴代码。您可以指出您希望每次添加项目时都调用一些自定义 Sort 方法
  • 完全同意@SergeyBerezovskiy!关于这个“复制粘贴”问题(re:msdn.microsoft.com/en-us/library/…),我也想说同样的话。另外,问题海报到底在问什么?一些清晰会有所帮助。最好的问候,
  • 查看 ListBox 源代码可以看到 Add 方法没有调用 Sort,它只是调用(内部)BinarySearch 方法来获取放置新项目的索引。所以覆盖排序将无济于事。但是为什么要对 ListBox 进行排序。对我来说,ListBox 是用来显示数据而不是对数据进行排序的东西。如果您想对某些内容进行排序,请将您的数据放入列表中,对该列表进行排序并将该列表绑定到 ListBox。
  • 这种行为有据可查。它以这种方式工作是有充分理由的,本机 ListBox 控件保留自己的列表中显示的字符串的副本。因此,为了对它们进行排序,必须首先清空该列表,然后按照排序顺序重新添加已排序的项目。这非常昂贵,每次添加一个项目时都这样做的成本太高。
  • @SergeyBerezovskiy 这实际上与 MSDN 上的代码不同。但我明白你的意思,帖子中并不真正需要它。

标签: c# winforms sorting listbox


【解决方案1】:

您似乎明白,要调用您的Sort() 方法,ListBox.Sorted 属性需要转换为true。这是有记录的,虽然很差。据我所知,这是唯一一次调用Sort()方法,这个理解和文档是一致的。

有趣的是,在这之后,保留 Sorted = true,添加的新项目使用基本的 Sort() 方法进行排序,创建升序和降序项目的混合。直到您再次切换 Sorted false -> true。

当您向ListBox 添加项目时,订单不是由Sort() 方法处理,而是由控件的集合对象处理。该对象进行二分搜索以找到插入新项目的正确位置。不幸的是,为此在列表框项文本上使用字符串比较是硬编码的。

这就是为什么添加项目会导致它们根据默认实现进行排序。但它并没有使用“基础Sort() 方法”来做到这一点。

对于 Winforms ListBox 类,如果您想要有效地排序项目,最好的选择可能是不覆盖 Sort() 或使用 Sorted 属性。相反,提供一个帮助方法来添加新项目,并让该方法对 Items 集合进行适当的二进制搜索以找到插入位置。

无论如何,您都必须实现一个辅助方法来获得添加项目的通知,并且执行排序插入比在每次插入时重新排序整个集合更有效。

您可以(如 cmets 中建议的那样)将已排序的集合绑定到 ListBox,但这将需要更多工作,特别是因为 AFAIK 没有任何支持绑定的内置集合类型,并且它们本质上是排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-20
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多