Reputation: 830
I'm trying to override the sort method in a listbox to sort in descending order.
Code:
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);
}
}
Now, I would intuitively expect that this method would get called whenever items are added to the list, and this seems to be how it works with the base ListBox when ListBox.Sorted = true. However, with my CustomSortListBox after adding items to the list, my custom sort was not being respected, and furthermore, the overridden method was not getting called, not even hitting breakpoints, when the item list is changed.
Then I read this https://gfaraj.wordpress.com/2008/07/31/custom-sorting-for-listbox-in-c/ and it says "Don’t forget that Sort is only called when the Sorted property goes from false to true" This seems rediculous to me, but sure enough, when toggling Sorted off and back on, my custom sort gets called and works.
Interestingly, after this, leaving Sorted = true, new items added are sorted using the base Sort() method, creating a mixture of ascending and descending items. Until you toggle Sorted false -> true again.
I would even settle with the hacky solution of putting Sorted = false; Sorted = true; in an event handler for ItemsChanged, but such an event doesn't exist.
What am I doing wrong and how can I make this Sort override be respected when the list is added to?
(I have seen C#'s ListBox doesn't see my overrided Sort() method but his issue isn't clear, seems to have just "gone away" and the answer he randomly selected is not ideal, or even compilable due to inaccessible protection level)
Upvotes: 1
Views: 392
Reputation: 70661
It seems you understand that to have your Sort()
method called, the ListBox.Sorted
property needs to transition to true
. This is documented, though poorly. This is the only time, as far as I know, that the Sort()
method is called, and this understanding is consistent with the documentation.
Interestingly, after this, leaving Sorted = true, new items added are sorted using the base Sort() method, creating a mixture of ascending and descending items. Until you toggle Sorted false -> true again.
When you add items to the ListBox
, the order is handled not by the Sort()
method, but by the control's collection object. This object does a binary search to find the correct place to insert the new item. Unfortunately, it is hard-coded to use a string comparison on the list box item text for this.
This is why adding items causes them to be ordered according to the default implementation. But it's not using "the base Sort()
method" to do it.
For the Winforms ListBox
class, if you want efficiently sorted items, your best bet is probably to not override Sort()
nor to use the Sorted
property. Instead, provide a helper method to add new items and have that method do the appropriate binary search on the Items
collection to find the insertion location.
You would have to implement a helper method anyway to get notification of items being added, and it will be more efficient to do sorted insertions than to re-sort the entire collection on every insertion.
You could (as suggested in the comments) bind a sorted collection to the ListBox
, but that's going to be more work, especially since AFAIK there aren't any built-in collection types that support binding and which are inherently sorted.
Upvotes: 1