DataGridView throwing “InvalidOperationException: Operation is not valid…” when adding a row

前端 未结 5 1616
失恋的感觉
失恋的感觉 2021-02-07 05:00

I want an OpenFileDialog to come up when a user clicks on a cell, then display the result in the cell.

It all works, except that the DataGridView displays an extra row,

相关标签:
5条回答
  • 2021-02-07 05:40

    Remember to use Row.BeginEdit() and Row.EndEdit() if you get this error while editing a value in a row, using DataGrid or GridEX from Janus (in my case). The sample code that Darrel Lee posted here (https://stackoverflow.com/a/9143590/1278771) remind me to use these instructions that I forgot to use and this solved the problem for me.

    0 讨论(0)
  • 2021-02-07 05:41

    This is old, but I am running VS2010 and just come across this issue. I have a DataGridView bound to a List<T> using a BindingList<T>. I have a drag n' drop event on my DataGridView and it would throw this exception after deleting all rows from the DGV (except for the last blank one which one cannot delete) and then adding new rows to the DGV in the DragDrop handler via the BindingList<T>. This exception was not thrown if I simply added rows manually editing individual cells.

    One solution I read said to handle the BindingList<T>.AddNew event, but I found that this event did not fire when calling BindingList<T>.Add() within the DragDrop event handler (I'm not sure why). I solved the issue by adding

    if(bindingList.Count == 0)
        bindingList.RemoveAt(0)
    

    inside of the DragDrop event handler before adding new objects to bindingList. It seemed that adding an object to the bindingList failed when the only "object" in the bindingList was the one associated to the final blank row. The point of a BindingList<T> is to allow the developer to work with it instead of the DGV directly, but it seems doing so can cause problems in border cases.

    The relationship between DGV rows and BindingList<T> rows seems to be a bit of a gray area. I have not spent much time investigating this, but it is not clear to me what is the state of the "object" in the BindingList<T> associated to the final (empty) row of the DGV. However, it does seem like the "object" at the end is only instantiated "correctly" when you interact with the final row directly (not via a DataSource).

    0 讨论(0)
  • 2021-02-07 05:44

    I found a workaround on this page, though I don't know why it works

    public MyForm()
    {
        InitializeComponent();
        //Create a BindingSource, set its DataSource to my list,
        //set the DataGrid's DataSource to the BindindingSource...
        _bindingSource.AddingNew += OnAddingNewToBindingSource;
    }
    
    private void OnAddingNewToBindingSource(object sender, AddingNewEventArgs e)
    {
        if(dataGridView1.Rows.Count == _bindingSource.Count)
        {
            _bindingSource.RemoveAt(_bindingSource.Count - 1);
        }
    }
    

    I'm getting very sick of spending so much time dealing with Visual Studio bugs...

    0 讨论(0)
  • 2021-02-07 05:51

    I was having the same problem when trying to programattically edit cells with a binding source. ""Operation is not valid due to the current state of the object"

    Which operation? What State? So helpful.

    My code seem to work fine except when editing the last row in the grid.

    Turns out the key is DataGridView.NotifiyCurrentCelldirty(true)

    The correct sequence for programatically editing a cell, so it works the same as if the user did it. (A new empty row appears when changing a cell in the last row) is something like this:

    1) Make the cell to edit the current cell (do what ever you need to the current currentcell, first like calling endEdit if it is in edit mode.)

    2) Call DataGridview.BeginEdit(false)

    3) Call DataGridView.NotifyCurrentCellDirty(true)

    4) Modify the value.

    5) Call DataGridView.EndEdit()

    And you'll want to do something for the RowValidating and RowValidated events.

    One of my routines for updating a cell value looks like this:

    This is from a method in my class derived from DataGridView. You could do the same thing from the containing form, calling through a DataGridView instance, because the methods are public. Here the calls are using an impliciit 'this.'

        private void EnterTime()
        {
            if (CurrentRow == null) return;
    
            SaveCurrentCell(); // Calls EndEdit() if CurrentCell.IsInEditMode
            DataGridViewCell previous = CurrentCell;
    
            CurrentCell = CurrentRow.Cells[CatchForm.TimeColumn];
            BeginEdit(false);
            NotifyCurrentCellDirty(true);
            CurrentCell.Value = DateTime.Now;
            EndEdit();
    
            CurrentCell = previous;
    
        }
    

    I’m not sure why a separate call is needed.

    Why doesn’t BeginEdit, or actually modifying the cell value, cause the right things to happen?

    And if you move the NotifyCurrentCellDirty call to after you actually modify the cell, it doesn’t behave correctly either. All very annoying.

    0 讨论(0)
  • 2021-02-07 06:04

    Try this:

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                int row = e.RowIndex;
                int clmn = e.ColumnIndex;
                if(e.RowIndex == dataGridView1.Rows.Count- 1)
                    dataGridView1.Rows.Add();
                dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName;
            }
    

    EDIT I didn't notice that you are binding your datagridview :( Ok, to solve it: use binding source, set its DataSource property to your list, then set the data source of the data grid view to this binding source. Now, the code should look like so:

    public partial class frmTestDataGridView : Form
        {
            BindingSource bindingSource1 = new BindingSource();
            List<string> datasource = new List<string>();
            public frmTestDataGridView()
            {
                InitializeComponent();
                datasource.Add("item1");
                datasource.Add("item2");
                datasource.Add("item3");
    
                bindingSource1.DataSource = datasource;
                dataGridView1.DataSource = bindingSource1;
            }
    
            private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
            {
                if (openFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    int row = e.RowIndex;
                    int clmn = e.ColumnIndex;
    
                    if (e.RowIndex == dataGridView1.Rows.Count - 1)
                    {
                        bindingSource1.Add("");
                    }
                    dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName;
                }
            }
    
        }
    
    0 讨论(0)
提交回复
热议问题