1

I have a ListBox bound to a BindingList which is empty by default.
When the selected index changes it's supposed to update other controls with data from the selected object.
The problem is that the SelectedIndexChanged event is not firing on the first entry (index changing from -1 to 0).
It does fire however when I'm clicking on the first entry again (although index is not changing in this case) and when adding any more entries.
I checked the property myListBox.SelectedIndex and it does in fact change from -1 to 0 but for some reason doesn't call the event handler. Does anyone know why it's doing this and how to fix it?

Here's my code:

public partial class main : Form
{
    // The class of objects in my BindingList
    [Serializable]
    public class DisplayDefinition : INotifyPropertyChanged
    {
        private string _name;
        private int _width, _height, _posx, _posy;

        public string Name { get { return _name; } set { _name = value; NotifyPropertyChanged("Name"); } }
        public int Width { get { return _width; } set { _width = value; NotifyPropertyChanged("Width"); } }
        public int Height { get { return _height; } set { _height = value; NotifyPropertyChanged("Height"); } }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string s)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(s));
        }
    }

    // Defining the BindingList 
    BindingList<DisplayDefinition> displaydefinitions = new BindingList<DisplayDefinition>();

    // Binding the list to my listbox 
    public main()
    {
        InitializeComponent();
        listDisplays.DataSource = displaydefinitions;
        listDisplays.DisplayMember = "Name";
    }

    // Button adding a new object to the list
    private void btnNewDisplay_Click(object sender, EventArgs e)
    {
        DisplayDefinition d = new DisplayDefinition();
        displaydefinitions.Add(d);
        listDisplays.SelectedItem = d;
    }

    private void listDisplays_SelectedIndexChanged(object sender, EventArgs e)
    {
        DisplayDefinition d = (DisplayDefinition)listDisplays.SelectedItem;
        // Do something with "d" ...
    }
}
chmied
  • 31
  • 1
  • 4
  • 7
    Do not just describe the problem. Add the relevant code to reproduce your problem – Steve Jun 25 '17 at 16:03
  • Just added the code. Don't think it really matters (especially because it only affects the first entry), but I guess you can never be sure. – chmied Jun 25 '17 at 16:22
  • 1
    I confirm the behavior mentioned in the question. I can actually reproduce the problem **only** when binding the `ListBox` to a DataSource, but **not** when filling the `ListBox` manually. In the first case *(using a DataSource)*, the `SelectedIndex` property does change from -1 to 0, but the `SelectedIndexChanged` event does **not** fire. – 41686d6564 stands w. Palestine Jun 25 '17 at 17:03
  • 1
    By design (or at least, that's the intended behavior now, since Microsoft won't be changing Winforms at this late date). See marked duplicate. The `SelectedIndex` property returns `-1` explicitly under certain conditions, so the underlying field isn't really changing. As such, it doesn't raise a property-changed event. Arguably, it should...it's common practice in similar scenarios to explicitly raise the event when the data "synthesized" property values depend on changes. But it's well-documented on Stack Overflow that it doesn't. No need to ask again. – Peter Duniho Jun 26 '17 at 05:27

1 Answers1

6

The problem:

This behavior only occurs when using the ListBox with a data source, and doesn't occur when filling the ListBox manually.

The reason:

When adding the first item to the data source, the first item gets selected by default without firing the SelectedIndexChanged event (not sure why!) which seems to be a bug in ListBox, and that makes setting the SelectedItem or SelectedIndex property useless.

A solution (more like a workaround):

You can change the SelectedIndex property to a temporary index (-1) before setting the actual SelectedIndex/SelectedItem in order to trigger the SelectedIndexChanged event.

Something like the following should work:

// Button adding a new object to the list
private void btnNewDisplay_Click(object sender, EventArgs e)
{
    DisplayDefinition d = new DisplayDefinition();
    d.Name = "SomeName";
    displaydefinitions.Add(d);
    listDisplays.SelectedIndex = -1;
    listDisplays.SelectedItem = d;
}

private void listDisplays_SelectedIndexChanged(object sender, EventArgs e)
{
    if (listDisplays.SelectedIndex == -1) return;
    DisplayDefinition d = (DisplayDefinition)listDisplays.SelectedItem;
    // Do something with "d" ...
    Console.WriteLine(d.Name);
}

Hope that helps :)