BindingList with my class populating a ComboBox using a property of it?

Guapo picture Guapo · May 28, 2011 · Viewed 8.8k times · Source

I have a BindingList with my class where I would like to populate a ComboBox using a property of it so when my list changes the ComboBox would change as well.

public class UserAccess
{
    public override string ToString()
    {
        return Access;
    }
    public int AccessId { get; set; }
    public string Access { get; set; }
    public List<string> Command = new List<string>();

    public bool HasCommand(string cmd)
    {
        return this.Command.Any(x => x == cmd);
    }
}

public BindingList<UserAccess> accessList = new BindingList<UserAccess>();

On my form load I assign it to the ComboBox:

myComboBox.DataSource = accessList;

I want to populate the box with Access or with the AccessId as value and Access as the printed name.

Problem is that it will print only the last item of the list to the combobox what am I doing wrong ?

Answer

Alex Aza picture Alex Aza · May 28, 2011

Use DisplayMember to specify what field to use for display in the ComboBox.
Make accessList readonly to guarantee that you never recreate a new instance of the list. If you don't make it readonly, this may introduce a subtle bug, if you don't reassign DataSource whenever you recereate accessList.

private readonly BindingList<UserAccess> accessList = new BindingList<UserAccess>();

public Form1()
{
    InitializeComponent();

    comboBox1.ValueMember = "AccessId";
    comboBox1.DisplayMember = "Access";
    comboBox1.DataSource = accessList;
}

private void button1_Click(object sender, EventArgs e)
{
    accessList.Add(new UserAccess { AccessId = 1, Access = "Test1" });
    accessList.Add(new UserAccess { AccessId = 2, Access = "Test2" });
}

If you need to be able to change items properties in accessList (like accessList[0].Access = "Test3") and see the changes reflected in UI, you need to implement INotifyPropertyChanged.

For example:

public class UserAccess : INotifyPropertyChanged
{
    public int AccessId { get; set; }

    private string access;

    public string Access
    {
        get
        {
            return access;
        }

        set
        {
            access = value;
            RaisePropertyChanged("Access");
        }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var temp = PropertyChanged;
        if (temp != null)
            temp(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}