C# – how to update listbox items with INotifyPropertyChanged

c++data-bindinginotifypropertychangedwinforms

I have a listbox which is databound to a collection of objects.
I want to modify the way the items are displayed to show the user which one of these objects is the START object in my program.

I tried to do this the following way, but the listbox does not automatically update.
Invalidating the control also didn't work.

The only way I can find is to completely remove the databindings and add it back again. but in my case that is not desirable.

Is there another way?

class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    public string Name
    {
        get
        {
            if (PersonManager.Instance.StartPerson == this)
                return _name + " (Start)";                      
            return _name;
        }
        set
        {
            _name = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
        }
    }

    public Person(string name)
    {
        Name = name;
    }
}

This is the class wich manages the list and the item that is the start

class PersonManager
{
    public BindingList<Person> persons { get; set; }
    public Person StartPerson { get; set; }

    private static PersonManager _instance;
    public static PersonManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new PersonManager();
            }
            return _instance;
        }
    }

    private PersonManager()
    {
        persons = new BindingList<Person>();
    }
}

In the form I use the following code

    private void button1_Click(object sender, EventArgs e)
    {
        PersonManager.Instance.StartPerson = (Person)listBox1.SelectedItem;
    }

Best Solution

I'm pretty sure that the problem is that, when you do this, you're effectively making the Person.Name properties "get" accessor change the value (and act like a set accessor as far as the UI is concerned).

However, there is nothing that's updating the bindings to say that this is happening. If PropertyChanged got called when you set start, I believe this would update.

It's clunky, but the way you have it written, I believe you could add this and make it work (NOTE: I didn't test this, so it ~may~ have issues):

private void button1_Click(object sender, EventArgs e)
{
    Person newStart = (Person)listBox1.SelectedItem;
    if (newStart != null)
    {
        PersonManager.Instance.StartPerson = newStart;
        newStart.Name = newStart.Name; // Dumb, but forces a PropertyChanged event so the binding updates
    }
}