Monday, April 25, 2011

How do you cache a row without raising a "Row provided already belongs to a DataGridView" error?

I want to cache a DataGridView row between 'refreshes' i.e. between a Rows.Clear() and a Columns.Clear(). However it seems that calling the Clear() methods does not unbind the data from the DataGridView instance, An example,


    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        DataGridViewRow cachedRow = new DataGridViewRow();

        private void button1_Click(object sender, EventArgs e)
        {
            this.dataGridView1.Rows.Clear();
            this.dataGridView1.Columns.Clear();
            DataGridViewColumn aColumn = new DataGridViewTextBoxColumn();
            this.dataGridView1.Columns.Add(aColumn);
            this.dataGridView1.Rows.Add(cachedRow);
        }
    }

This is done on a Form containing a DataGridView and a Button. Clicking the button twice gives the "Row provided already belongs to a DataGridView" error.

There has been some discussion online about this that suggests that it may be a bug, however this was around 2004.

From stackoverflow
  • Once a row is part of a gridview, you can't re-add it. The row itself keeps track of what DataGridView it is in. I would suggest making a copy of the cached row and adding the copy to the view. Since you make a new copy each time it won't be in the view. Alternatively, you can go through and remove only those rows that have not been cached from the view, leaving the cached rows behind so that you don't need to re-add it.

    Brendan : The link given is to a DataRow method, not a DataGridViewRow method. Is this also the case for DataGridViewRows as well?
    tvanfosson : Sorry. The principle is the same -- it does keep track. I've updated the post and link.
  • I'm not sure why you'd want this behviour? You should only remove the rows in the grid that you want to remove.

    You should look into implementing ObservableCollection and a Binding component. This way, if an item is removed from your object model, then it is automatically removed from the grid. This saves you having to perform what sounds like manual data binding and avoids this problem altogether.

    If you're using DataSet or typed DataSets, then the observable functionality is already implemented for you - you just need to bind the datatable to the grid. If you have a table object in memory, you'll notice that you can load another one, then use the DataTable.Merge function to combine the results.

    Brendan : My dialog previews a CSV file of numerical data in a read-only DataGridView. If the headers are not in the preview it can include an editable line where the user can input their own headers. This may be switched off/on and needs to be cached in these cases
    Neil Barnwell : In that case, I'd *always* filter the headers out of the input prior to binding, and use the file contents to build actual column headers for the grid.
    Brendan : The dialog is one to parse an arbitrary CSV file, the file may not include headers at all - hence the option to add some. I tried using a separate cache list of cell contents but it turned out to be a lot of hassle keeping the two concurrent.

0 comments:

Post a Comment