如何刷新ListBox的DataSource

56

表单中有一个组合框和一个列表框。当点击“添加”按钮时,我希望将组合框中选定的项目添加到列表框中。

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();
    }
}

使用这个示例,选定的项将被新选择的项替换到 ListBox 中。我需要将该项添加到列表中。

我的代码有什么问题?

7个回答

82

listbox1.DataSource属性寻找值的更改,但如果始终分配相同的列表,则值实际上不会发生变化。

您可以使用BindingList<T>代替List<T>,以自动识别添加的新项。您的ShowData()方法必须在启动时调用一次。

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);
    }
}

3
请将 listBox1.DataSource = null; 添加为您的 ShowData() 方法的第一行。 - NoviceProgrammer
2
非常感谢您提供的帮助,我已经花了一个小时来解决我的列表框无法正确显示项目的问题,即使我仔细遵循了微软在这里的教程: http://msdn.microsoft.com/en-us/library/system.windows.forms.listcontrol.datasource.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2 - Aralox
哦,这很不错。我可以使用它在编辑列表框项时刷新列表框,而无需使滚动位置混乱不堪。 - Nyerguds
感谢您提供的解决方案。 - Matt Allen
但是如果您使用BindingList,您将无法同时从列表中选择多个项目。我的意思是,控件会让您“尝试”,并且它仍然会突出显示多个项目,但只有第一个项目最终会出现在SelectedItems集合中。 - DiggyJohn

37

我建议使用BindingSource,因为它可以正确更新连接的控件。

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);
    }
}

在运行时更改控件数据源有时会产生奇怪的结果。


这是最佳方法,因为不会影响所选的值。 - Tanner Ornelas

20

列表框没有检测到您已更改DataSource。只有在DataSource更改时才会刷新,因此请首先将DataSource设置为null:

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

您也可以清除项目,然后再次设置数据源:

listBox1.Items.Clear();
listBox1.DataSource = data;

11
当设置了DataSource属性时,无法修改项目集合。因此第二个示例将无法工作。 - Christian Junk
9
一条注意事项:设置 listBox1.DataSource = null 也会将 DisplayMember 设置为空字符串(但不包括 ValueMember)。 (我在使用 .NET 4.0 WinForms 调试器时发现了这一点。)因此,如果您正在使用 DisplayMemberValueMember,请确保在将 DataSource 设置为 null 后重新分配 DisplayMember - DavidRR
使用 BindingList<> - Tom

2

另一种实现方式,也可能是最正确的方式,是使用提供的ObservableCollection<T>。它的设计目的就是实现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);
    }
}

因为ObservableCollection<T>实现了INotifyCollectionChanged,所以当您的数据发生更改时,数据源绑定将自动更新ListBox。

好的观点,但不确定“最正确的方法”。请看一下这个讨论: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

1
也许这个解决方案的性能不是最好的,但经过多次尝试和几个小时的努力,它对我有效:

此行代码在表单构造函数上执行:

listBox1.DataSource = myData;

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

希望它有所帮助!

0

刷新也可以通过

listbox.ItemsSource = null;
listbox.ItemsSource = data;

0
在表单初始化时调用ShowData()以在初始化时填充您的列表框。
 public Department()
        {
            InitializeComponent();
            ShowData();
        }

ShowData() 方法,其中设置了 BindingSourceDisplayMemberValueMember

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

在下面的实现中,当从数据库中删除一个部门时,列表框会刷新为当前集合。
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();
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接