56

Form has one Combobox and one ListBox. When the "Add" button is clicked, I want to add the selected item from the ComboBox to the ListBox.

public partial class MyForm:Form
{
    List<MyData> data = new List<MyData>();
    private void ShowData()
    {
       listBox1.DataSource = data;
       listBox1.DisplayMember = "Name";
       listBox1.ValueMember = "Id";
    }

    private void buttonAddData_Click(object sender, EventArgs e)
    {
       var selection = (MyData)comboBox1.SelectedItem;
       data.Add(selection);
       ShowData();
    }
}

With this example, the selected item is replaced with the new selection inside ListBox. I need to add the item to the list.

What is wrong with my code?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
panjo
  • 3,467
  • 11
  • 48
  • 82

7 Answers7

82

listbox1.DataSource property looks for value changes but by assigning the same list all the time the value won't really change.

You can use a BindingList<T>, instead of your List<T>, to automatically recognize new items added. Your ShowData() method must be called once at startup.

public partial class MyForm:Form
{
    public MyForm(){
        InitializeComponent();
        ShowData();
    }

    BindingList<MyData> data = new BindingList<MyData>();

    private void ShowData()
    {
       listBox1.DataSource = data;
       listBox1.DisplayMember = "Name";
       listBox1.ValueMember = "Id";
    }

    private void buttonAddData_Click(object sender, EventArgs e)
    {
       var selection = (MyData)comboBox1.SelectedItem;
       data.Add(selection);
    }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
dwonisch
  • 5,595
  • 2
  • 30
  • 43
  • 3
    just add `listBox1.DataSource = null;` as the first line to your `ShowData()` method – NoviceProgrammer Jul 12 '13 at 13:14
  • 2
    thanks a bunch for this, I have spent an hour trying to figure out why my listbox wouldnt show my items properly, even after following microsoft's tutorial here closely http://msdn.microsoft.com/en-us/library/system.windows.forms.listcontrol.datasource.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2 – Aralox Oct 29 '13 at 08:34
  • Oh, this is pretty. I can use this to refresh the ListBox when editing items in it without it unnecessarily messing up the scroll position. – Nyerguds Mar 29 '17 at 10:16
  • Thank you for the solution. – Matt Allen Jan 16 '19 at 16:59
  • But if you use BindingList, you can no longer select multiple items from the list at once. I mean, the control let's you "try" and it will highlight multiple still, but only the first one will end up in the SelectedItems collection. – DiggyJohn Oct 14 '22 at 17:44
37

I would suggest to use BindingSource as it would properly update connected controls.

public partial class MyForm : Form
{
    List<MyData> data = new List<MyData>();
    BindingSource bs = new BindingSource();

    public MyForm()
    {
        IntializeComponents();
        bs.DataSource = data;

       listBox1.DisplayMember = "Name";
       listBox1.ValueMember = "Id";
       listBox1.DataSource = bs;
    }

    private void buttonAddData_Click(object sender, EventArgs e)
    {
       var selection = (MyData)comboBox1.SelectedItem;
       data.Add(selection);

       bs.ResetBindings(false);
    }
}

Changing controls data source on fly produces strange result sometime.

gzaxx
  • 17,312
  • 2
  • 36
  • 54
20

The listbox didn't detect that you have changed the DataSource. It will only refresh when Datasource has changed, so set DataSource to null first:

listBox1.DataSource = null;
listBox1.DataSource = data;

You could also clear the items then set the DataSource again:

listBox1.Items.Clear();
listBox1.DataSource = data;
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
rajeemcariazo
  • 2,476
  • 5
  • 36
  • 62
  • 11
    Items collection cannot be modified when the DataSource property is set. So the second example won't work. – Christian Junk Jun 02 '15 at 09:09
  • 9
    **A cautionary note:** Setting `listBox1.DataSource = null` *also* sets `DisplayMember` to the empty string (but not `ValueMember`). (Discovered this in the debugger with .NET 4.0 WinForms.) So, if you are using `DisplayMember` and `ValueMember`, be sure to reassign `DisplayMember` after setting `DataSource` to `null`. – DavidRR Dec 18 '15 at 15:11
  • use BindingList<> – Tom Jun 27 '21 at 20:29
2

Alternatively and probably the most correct way to implement this is to use the provided ObservableCollection<T>. It is designed with the sole purpose of implementing INotifyCollectionChanged.

public partial class MyForm : Form
{
    ObservableCollection<MyData> data = new ObservableCollection<MyData>();

    public MyForm()
    {
        listBox1.DataSource = data;
        listBox1.DisplayMember = "Name";
        listBox1.ValueMember = "Id";
    }

    private void buttonAddData_Click(object sender, EventArgs e)
    {
       var selection = (MyData)comboBox1.SelectedItem;
       data.Add(selection);
    }
}

Because ObservableCollection<T> implements INotifyCollectionChanged the DataSource binding will automatically update the ListBox whenever your data changes.

jduncanator
  • 2,154
  • 1
  • 22
  • 39
  • Good point, but not sure about the "the most correct way". Have a look at this discussion: https://www.c-sharpcorner.com/interview-question/what-is-the-difference-between-list-and-observable-collection#:~:text=The%20true%20difference%20is%20rather%20straightforward%3AObservableCollection%20implements%20INotifyCollectionChanged,notification%20on%20collection%20changes%2C%20but%20not%20only%20that. – batpox Aug 07 '22 at 10:36
1

Maybe this solution has not the better performance, but after many tries and a few hours it was what it worked for me:

This line was executed on the form constructor:

listBox1.DataSource = myData;

This lines were executed after the information was modified:
listBox1.DataSource = new List<Movil>();
listBox1.DataSource = myData;

Hope it helps!

Io-oI
  • 2,514
  • 3
  • 22
  • 29
0

Call ShowData() when the form initializes to populate your listbox on initialization

 public Department()
        {
            InitializeComponent();
            ShowData();
        }

ShowData() Method, where BindingSource, DisplayMember and ValueMember are set

private void ShowData()
            {
                using (var uow = new UnitOfWork(new SellContext()))
                {
                    listBox1.DataSource = uow.Departments.GetAll().ToList();
                    listBox1.DisplayMember = "DepartmentName";
                    listBox1.ValueMember = "DepartmentId"; 
                    //listBox1.Invalidate();       
                }
            }

In the implementation below when a department is deleted from database the listbox refreshes with the current collection

private void button1_Click(object sender, EventArgs e)
    {
        try {
            using (var uow = new UnitOfWork(new SellContext()))
            {
                int count = uow.Departments.FindDepartmentByName(txtDeptName.Text.ToString());
                if (count>0)
                {
                    MessageBox.Show("This Department Already Exists", "SellRight", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                }

                else
                {
                    department dept = new department();
                    dept.DepartmentName = txtDeptName.Text.ToString();
                    uow.Departments.Create(dept);
                    if (uow.Complete() > 0)
                    {           
                        MessageBox.Show("New Department Created", "SellRight", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        txtDeptName.Text = "";
                        ShowData();      
                    }
                    else
                    {
                        MessageBox.Show("Unable to add Department", "SellRight", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        txtDeptName.Text = "";
                        ShowData();
                    }
                }
            }                              
        }
        catch(Exception ex)
        {
            ex.ToString();
        }
    }
Frank Odoom
  • 1,545
  • 18
  • 19
0

refreshing also works via

listbox.ItemsSource = null;
listbox.ItemsSource = data;
Pixel_95
  • 954
  • 2
  • 9
  • 21