views:

266

answers:

5

Totally stumped by something that seems easy, and has been done to death... Yet still stumped.

What I want to do: I've got a WinForms ListBox. Its items are populated with objects, the DisplayMember is set. As the app runs, the data in the listed items might change, including the field behind the DisplayMember. I want the text displayed in the ListBox to change when this happens, and I also want the ListBox to re-sort itself so the items remain in alphabetical order.

A BindingList works fine to update the displayed text when the data changes, but for the life of me, I can't get it to sort.

I reviewed this: http://msdn.microsoft.com/en-us/library/ms993236.aspx

Plus numerous threads here about how to do this, but none of it seems to work for a ListBox.

Setting the Sorted property on the ListBox is similarly unhelpful.

What do I need to do to get a ListBox to sort itself?

+1  A: 
 private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
      //Sorting function
    }

What about this??

Pramodh
The data behind the ListBox will actually change independant of when the selected item changes. The user will select the item, that will populate a form with the item's information, allowing them to change it. In doing so, they might change the property behind the DisplayMember on the Listbox. That's when I'd want it to re-sort, which would actually be when they hit Save on the other form.I tried wiring up to the ListChanged event of the BindingList behind the ListBox, sorted there, saw the BindingList sort, but the ListBox didn't redraw itself, it'd only update the changed item.
Jack
+1  A: 

You can use a BindingSource object. Just drag-n-drop it into your form and point your ListBox.DataSource property to this BindingSource object. Then go to the BindingSource's properties and define Sort as you need.

Then in code you can set myBindingSource.DataSource = myCollection and voila, your listbox is populated and sorted. Easy.

Patrol02
The BindingSource doesn't seem to re-sort after a change. It ends up behaving pretty much like the BindingList did. It shows the rename of the DisplayMember, but doesn't sort the items. I tried putting a SortableBindingList as its DataSource, it showed as SupportsSorting, but when things change, still no sort.
Jack
+1  A: 

As with Patrol02's post, however you may want to try setting the DataSource to null and then reassigning it based on an event triggered by the list size changing. You could use the observer pattern on the collection, overriding the Add and Remove methods to notify watchers to rebind themselves.

Antony Koch
One option that does work is to use a BindingList, which has an event for ListChanged, wire to that event, detect a change, and use that as a cue to repopulate the ListBox. I found that binding to the DataSource didn't work well here, and instead one has to Clear and repopulate the Items in the ListBox. This is a bit inelegant, I'm hoping there's a better solution...But it does work.
Jack
+1  A: 

Resetting the DataSource will effectively sort the ListBox:

    listBox1.DataSource = null;
    listBox1.DataSource = myBindingList;
    listBox1.DisplayMember = "MyField";

But that's not automatic. As I understand, sorting should happen whenever the field behind the DisplayMember is updated, through an event or something like that...

See my complete test anyway:

public partial class Form1 : Form
{
    public BindingList<ABC> myBindingList = new BindingList<ABC>();

    public Form1() {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e) {
        myBindingList.Add(new ABC("zzz"));
        myBindingList.Add(new ABC("aaa"));
    }

    private void button2_Click(object sender, EventArgs e) {
        myBindingList[0].MyField = "ccc"; // was "zzz"
        myBindingList[1].MyField = "ddd"; // was "aaa"

        listBox1.DataSource = null;
        listBox1.DataSource = myBindingList;
        listBox1.DisplayMember = "MyField";
    }

    private void Form1_Load(object sender, EventArgs e) {
        listBox1.DataSource = myBindingList;
        listBox1.DisplayMember = "MyField";

    }
}

public class ABC  {
    public string MyField { get; set; } 
    public ABC(string val) {
        MyField = val;
    }
}
Gabriel
+1  A: 

The LVS_SORT style on the list control should work, but you say it doesn't. I've never had any trouble with a self-sorting list control. Note this is a list control we're speaking of, not a listview control.

Jeremy Collake