2010-03-01 2 views
15

Я хочу, чтобы OpenFileDialog появился, когда пользователь нажимает на ячейку, а затем отображает результат в ячейке.DataGridView throwing «InvalidOperationException: операция недопустима ...» при добавлении строки

Все работает, за исключением того, что DataGridView отображает дополнительную строку для добавления значений в список, к которому он привязан. Строка отображается, если dataGridView.AllowUserToAddNewRows == true, что я и хочу. Я не хочу, чтобы приложение зависало, когда эта строка редактируется программно; вместо этого он должен делать то, что он сделал бы, если бы пользователь отредактировал эту строку вручную (добавьте новую строку в базовый список, нажмите еще одну пустую строку в сетку для добавления значений).

Я прочитал о SendKeys.Send(), который должен заставить DataGridView вести себя точно так, как если бы пользователь набрал значение; однако он тоже не работает. Вот что я пытаюсь:

if (openFileDialog1.ShowDialog() == DialogResult.OK) 
{ 
    dataGridView1.CurrentCell = cell; 

    //simply doing a cell.Value = etc. will cause the program to crash 
    cell.ReadOnly = false; 
    dataGridView1.Columns[cell.ColumnIndex].ReadOnly = false; 
    dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter; 
    dataGridView1.BeginEdit(true); 
    SendKeys.Send(openFileDialog1.FileName + "{Enter}"); 
    dataGridView1.EndEdit(); 
    cell.ReadOnly = true; 
    dataGridView1.Columns[cell.ColumnIndex].ReadOnly = true; 
} 
//I would expect the FileName would be in the cell now, and a new empty 
//row tacked onto the end of the DataGridView, but it's not; the DataGridView 
//is not changed at all. 
+0

Какое исключение вы получаете, когда устанавливаете 'cell.Value'? –

+0

@Zach: Когда я нажимаю на пустую ячейку, она правильно заполняет значение, но не добавляет еще одну пустую строку. Когда я выхожу из строки, значения во всех ячейках этой последней строки исчезают (это происходит только для этой последней строки). Когда я снова нажимаю на последнюю строку, я получаю InvalidOperationException: «Операция недействительна из-за текущего состояния объекта». dataGridView1_CellClick - единственное событие, которое я обрабатываю в этой форме (показано выше). –

ответ

9

У меня была такая же проблема при попытке программно редактировать ячейки с источником привязки. «» Операция недопустима из-за текущего состояния объекта»

Какая операция? В каком состоянии? Поэтому полезно.

Мой код, кажется, работает нормально, за исключением, когда редактирование последней строки в сетке.

оказывается, ключ является DataGridView.NotifiyCurrentCelldirty (истинный)

правильная последовательность для редактирования программно ячейки, так что он работает так же, как если бы пользователь сделал. (новая пустая строка появляется при изменении ячейки в последней строке) выглядит примерно так:

1) Сделать ячейку для редактирования текущей ячейки (делать то, что никогда не нужно текущий currentcell, первый как вызов EndEdit, если он находится в режиме редактирования.)

2) Вызов DataGridview.BeginEdit (ложь)

3) Вызов DataGridView.NotifyCurrentCellDirty (истинный)

4) Изменение значения.

5) Позвоните в DataGridView.EndEdit()

И вы хотите что-то сделать для событий RowValidating и RowValidated.

Один из моих процедур для обновления значения ячейки выглядит следующим образом:

Это из метода в моем классе, полученном из DataGridView. Вы можете сделать то же самое из содержащейся формы, вызвав через экземпляр DataGridView, потому что методы являются общедоступными. Здесь вызовы используют 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; 

    } 

Я не уверен, зачем нужен отдельный звонок.

Почему не BeginEdit, или, фактически, изменение значения ячейки, вызывает правильные события?

И если вы переместите вызов NotifyCurrentCellDirty после того, как вы действительно изменили ячейку, также не ведет себя правильно. Все очень раздражает.

+0

Спасибо, что нашли время, чтобы добавить это, Даррел. Я давно забыл об этой проблеме, но я буду отмечать это как правильно, потому что я понятия не имею, почему мой обходной путь работал. –

+0

В моем случае мне также нужно было вызвать CurrentCell.NotifyCurrentCellDirty (false) после EndEdit() – synergetic

1

Попробуйте это:

 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 я не заметил, что вы являются обязательными для вашего DataGridView :( Ok, чтобы решить : используйте источник привязки, установите его свойство DataSource в свой список, затем установите источник данных в виде сетки данных в этот источник привязки. Теперь код должен выглядеть так:

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

«Строки не могут быть программно добавлены в коллекцию строк DataGridView, когда элемент управления привязан к данным». –

+0

И если я попытаюсь добавить в BindingList вместо этого, это даст мне то же самое "Операция недействительна из-за текущего состояния объекта" –

+0

К сожалению! Я не заметил, что вы привязываете gridview к списку! Я обновил свой ответ выше. Пожалуйста, проверьте это и сообщите нам результат. –

16

Я нашел обходной путь на this page, хотя я не знаю, почему это работает

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

я получаю очень болен тратить столько времени решения визуальных ошибок студии ...

+3

+1 для вопросов и ответов - спасибо, это просто работает и нам очень помогло. –

+0

+1 Спасибо! –

+0

+1 Спасибо! это сработало для меня = D – ch2o

3

Это старый, но я бегу VS2010 и просто сталкиваюсь с этой проблемой. У меня есть DataGridView, связанный с List<T> с использованием BindingList<T>. У меня есть событие перетаскивания n 'на моем DataGridView, и оно выкинет это исключение после, удалив все строки из DGV (за исключением последнего пустого, который нельзя удалить) и , затем, добавив новые строки в DGV в DragDrop обработчик через BindingList<T>. Это исключение не было выбрано, если я просто добавил строки вручную, редактируя отдельные ячейки.

Одно решение, которое я прочитал, сказал, чтобы справиться с BindingList<T>.AddNew событие, но я обнаружил, что это событие не срабатывает при вызове BindingList<T>.Add() внутри обработчика DragDrop событий (я не знаю, почему). Я решил проблему, добавив

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

внутри обработчика событий DragDropперед тем добавление новых объектов в bindingList. Казалось, что добавление объекта к bindingList завершилось неудачно, когда единственным «объектом» в bindingList был тот, который связан с последней пустой строкой. Точка BindingList<T> должна позволить разработчику работать с ней вместо DGV напрямую, но, похоже, это может вызвать проблемы в пограничных случаях.

Связь между строками DGV и строками BindingList<T> кажется немного серой областью. Я не проводил много времени, исследуя это, но мне непонятно, какое состояние «объекта» в BindingList<T> связано с конечной (пустой) строкой DGV. Однако, похоже, что «объект» в конце создается только «правильно», когда вы взаимодействуете с последней строкой напрямую (не через DataSource).

+2

Awesome. У меня была такая же проблема. Я использовал 'if (DataGridView.Rows.Count == bindingList.Count) {bindingList.RemoveAt (source.Count - 1); } 'в начале обработчика капли, и это сработало. –

0

Не забудьте использовать Row.BeginEdit() и Row.EndEdit(), если вы получите эту ошибку при редактировании значения в строке, используя DataGrid или GridEX от Janus (в моем случае). Пример кода, который Darrel Lee опубликовал здесь (https://stackoverflow.com/a/9143590/1278771), напоминает мне использовать эти инструкции, которые я забыл использовать, и это решило проблему для меня.