listbox error: Items collection cannot be modified when the DataSource property is set

荒凉一梦 提交于 2019-12-12 04:49:12

问题


I have 2 listboxes in a window form, one on left and one on right. The 1st listbox have some items while the 2nd listbox is empty. Also there are 2 buttons between the 2 listboxes which used to move item from/to the 1st and 2nd listbox

My problem here is that after I bind the data to the 1st listbox (from a database, using DisplayMember and ValueMember) , and I try to move 1 of the item from this 1st listbox to the 2nd listbox and I want that the selected item is also removed from the 1st listbox by:

    private void btnMoveRight_Click(object sender, EventArgs e)
    {
        ADD();

    }

    private void ADD()
    {
        int c = listJobBox.Items.Count - 1;

  ` for(int i= c; i>=0; i--)
        {
        if(listJobBox.GetSelected(i))
        {

        lstAssignedJobs.Items.Add(listJobBox.Items[i]);

            listJobBox.Items.Remove(listJobBox.SelectedItem); ---error line

But the selected item is not removed from the 1st listbox.

it displays error message "Items collection cannot be modified when the DataSource property is set."

can any one give me the solution to my problem.


回答1:


Add a boolean column to your DataTable object, something like IsSelected.

Then instead of binding your listbox1 directly to the table, bind it to a BindingSource. Add 2 bindingsources to your form using the designer. And place this code in your code behind file.

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
        this.InitializeDataObjects();
    }

    private void InitializeDataObjects()
    {
        this.InitData();
        this.InitBindingSources();
    }

    private void InitData()
    {
        ds = new DataSet();
        var dt = new DataTable("Table1");
        dt.Columns.Add("Name", typeof(string));
        ds.Tables.Add(dt);
    }

    private void InitBindingSources()
    {
        bindingSource1 = new BindingSource();
        bindingSource2 = new BindingSource();

        bindingSource1.DataSource = ds;
        bindingSource1.DataMember = "Table1";
        bindingSource2.DataSource = ds;
        bindingSource2.DataMember = "Table1";

        listBox1.DataSource = bindingSource1;
        listBox1.DisplayMember = "Name";
        listBox2.DataSource = bindingSource2;
        listBox2.DisplayMember = "Name";
    }
}

Then when you load your data, do the following:

    private void btnLoadAndBind_Click(object sender, EventArgs e)
    {
        this.FetchData(this.ds.Tables["Table1"]);
        this.AddSelectedColumn(this.ds.Tables["Table1"]);

        this.bindingSource1.Filter = "IsSelected = false";
        this.bindingSource2.Filter = "IsSelected = true";
    }

    private void FetchData(DataTable dataTable)
    {
        string CS = "your connectionstring";
        using (SqlConnection con = new SqlConnection(CS))
        {
            try
            {
                SqlDataAdapter da = new SqlDataAdapter();

                con.Open();
                var sqlcmd = new SqlCommand("SELECT Name FROM sometable", con);
                sqlcmd.CommandType = CommandType.Text;
                da.SelectCommand = sqlcmd;
                da.Fill(dataTable);
            }
            catch (Exception ex)
            {
                MessageBox.Show("exception raised");
                throw ex;
            }
        }
    }

    private void AddSelectedColumn(DataTable suppliersDataTable)
    {
        var dc = new DataColumn("IsSelected", typeof(bool));
        suppliersDataTable.Columns.Add(dc);

        foreach (DataRow dr in suppliersDataTable.Rows)
        {
            dr["IsSelected"] = false;
        }
    }    

Now your listboxes are both connected to the same datatable and filtered based on the IsSelected property / column. Just set this column to true or false and it will flip from box to box. Your eventhandler of a button could look like this:

public void button_Click(object sender, EventArgs e)
{
    if (this.bindingSource1.Current!= null)
    {
         var dr = ((DataRowView)this.bindingSource1.Current).Row;
         dr["IsSelected"] = true;
     }
}

This works!

Things will be become much simpeler if you use a typed dataset. Most of the bindings then can be done in the designer and your code behind will shrink to 20 lines of code....




回答2:


Lets say listbox1 is bound to datatable1 (it could be any other collection type) and listbox2 is bound to datatable2. When you click on move button, remove the selected item from the collection i.e datatable1 and add that item to other collection i.e. datatable2 and re-bind the listbox1 and lisbox2.




回答3:


Here is a rough working example:

public partial class Form1 : Form
{
    private DataTable _dataSource1;
    private DataTable _dataSource2;
    public Form1()
    {
        InitializeComponent();

        _dataSource1 = GetData1();
        _dataSource2 = GetData2();
        Initialize();
    }



    private void btnMove_Click(object sender, EventArgs e)
    {
        MoveItem();
    }

    void Initialize()
    {
        listBox1.DataSource = _dataSource1;
        listBox1.DisplayMember = "Fruits";
        listBox1.ValueMember = "Fruits";

        listBox2.DataSource = _dataSource2;
        listBox2.DisplayMember = "Fruits";
        listBox2.ValueMember = "Fruits";
    }

    DataTable GetData1()
    {
        var dt = new DataTable();
        dt.Columns.Add("Fruits");
        dt.Rows.Add(new object[] {"Apple"});
        dt.Rows.Add(new object[] { "Orange" });
        dt.Rows.Add(new object[] { "Grapes" });
        return dt;
    }
    DataTable GetData2()
    {
        var dt = new DataTable();
        dt.Columns.Add("Fruits");
        return dt;
    }

    void MoveItem()
    {
        var index = listBox1.SelectedIndex;
        var dataRowToRemove = _dataSource1.Rows[index];
        var listItem = dataRowToRemove[0] as string;
        _dataSource1.Rows.Remove(dataRowToRemove);


        var dataRowToAdd = _dataSource2.NewRow();
        dataRowToAdd[0] = listItem;
        _dataSource2.Rows.Add(dataRowToAdd); 
        Initialize();

    }

}


来源:https://stackoverflow.com/questions/26454622/listbox-error-items-collection-cannot-be-modified-when-the-datasource-property

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!