2010-03-01 23 views
15

Quiero que aparezca un OpenFileDialog cuando un usuario hace clic en una celda y luego muestra el resultado en la celda.Lanzamiento de DataGridView "InvalidOperationException: operación no válida ..." al agregar una fila

Todo funciona, excepto que DataGridView muestra una fila adicional, para agregar valores a la lista a la que está vinculado. La fila aparece si dataGridView.AllowUserToAddNewRows == true, que es lo que quiero. Lo que no quiero es que la aplicación se cuelgue cuando esa fila se edita programáticamente; en su lugar, debería hacer exactamente lo que haría si el usuario hubiera editado esa fila manualmente (agregue la nueva fila a la lista subyacente, inserte otra fila vacía en la cuadrícula para agregar valores).

He leído acerca de SendKeys.Send(), que debe hacer que DataGridView se comporte exactamente como si el usuario hubiera tecleado el valor; sin embargo, tampoco funciona. Esto es lo que estoy tratando:

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

¿Qué tipo de excepción recibes cuando configuras 'cell.Value'? –

+0

@Zach: Cuando hago clic en la celda vacía, rellena el valor correctamente, pero no agrega otra fila vacía. Cuando hago clic fuera de la fila, los valores en todas las celdas en esa fila final desaparecen (esto solo ocurre en esa última fila). Cuando vuelvo a hacer clic en la fila final, aparece InvalidOperationException: "La operación no es válida debido al estado actual del objeto". dataGridView1_CellClick es el único evento que estoy manejando en ese formulario (mostrado arriba) –

Respuesta

9

Estaba teniendo el mismo problema al tratar de editar programáticamente las celdas con una fuente de enlace. "" Operación no es válida debido al estado actual del objeto"

qué operación? ¿Qué Estado? Así útil.

Mi código parecen funcionar bien, excepto cuando se edita la última fila de la parrilla.

Resulta que la clave es DataGridView.NotifiyCurrentCelldirty (verdadero)

la secuencia correcta para la edición de una célula mediante programación, por lo que funciona de la misma como si el usuario lo hizo. (una nueva fila vacía aparece cuando se cambia una celda en la última fila) es algo como esto:

1) Hacer la celda para editar la celda actual (hacer lo que usted necesita para la currentCell actual, primero como llamar EndEdit si está en modo de edición.)

2) Llamada DataGridview.BeginEdit (falso)

3) Llame DataGridView.NotifyCurrentCellDirty (true)

4) Modificar el valor.

5) Llamar a DataGridView.EndEdit()

Y deseará hacer algo para los eventos RowValidating y RowValidated.

Una de mis rutinas para actualizar un valor de celda tiene el siguiente aspecto:

Se trata de un método en mi clase derivada de DataGridView. Puede hacer lo mismo desde el formulario que lo contiene, llamando al a través de una instancia de DataGridView, porque los métodos son públicos. Aquí las llamadas usan 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; 

    } 

No estoy seguro de por qué es necesaria una llamada por separado.

¿Por qué no BeginEdit, o en realidad modificar el valor de la celda, causa que ocurra lo correcto ?

Y si mueve la llamada NotifyCurrentCellDirty a después de que realmente modifique la celda, tampoco se comporta correctamente. Todo muy molesto

+0

Gracias por tomarse el tiempo para agregar esto, Darrel. Hace tiempo que me olvidé de este problema, pero lo marcaré como correcto, porque no tengo idea de por qué funcionó mi solución. –

+0

En mi caso, también necesitaba llamar a CurrentCell.NotifyCurrentCellDirty (falso) después de EndEdit() – synergetic

1

Prueba esto:

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

EDITAR No me di cuenta de que va a enlazar su DataGridView :( Ok, para resolverlo : use el origen de enlace, establezca su propiedad DataSource en su lista, luego establezca el origen de datos de la vista de cuadrícula de datos a esta fuente de enlace. Ahora, el código debería verse así:

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

"Las filas no se pueden agregar programáticamente a la colección de filas de DataGridView cuando el control está enlazado a datos". –

+0

Y si trato de agregar a BindingList en su lugar, me da el mismo "La operación no es válida debido al estado actual del objeto" –

+0

¡Uy! ¡No noté que estás vinculando la vista de cuadrícula a una lista! Actualicé mi respuesta más arriba. Por favor, compruébalo y cuéntanos el resultado. –

16

He encontrado una solución en this page, aunque no sé por qué funciona

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

Me estoy poniendo muy enfermo de gastar tanto tiempo se trata de errores de Visual Studio ...

+3

+1 para preguntas y respuestas - gracias, esto solo funciona y nos ayudó mucho. –

+0

+1 ¡Gracias! –

+0

+1 ¡Gracias! esto funcionó para mí = D – ch2o

3

Esto es antiguo, pero estoy ejecutando VS2010 y me he encontrado con este problema. Tengo un DataGridView vinculado a un List<T> usando un BindingList<T>. Tengo un evento arrastrar y soltar en mi DataGridView y arrojaría esta excepción después de borrar todas las filas de la DGV (excepto la última en blanco que no se puede eliminar) y luego agregar nuevas filas a la DGV en el DragDrop controlador a través del BindingList<T>. Esta excepción no se lanzó si simplemente agregué filas editando manualmente celdas individuales.

Una solución que leí dijo para controlar el evento BindingList<T>.AddNew, pero he encontrado que este evento no disparó al llamar BindingList<T>.Add() dentro del manejador DragDrop evento (no estoy seguro de por qué). He resuelto el problema agregando

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

dentro del manejador de eventos DragDrop antes de la adición de nuevos objetos para bindingList. Parecía que al agregar un objeto al bindingList se produjo un error cuando el único "objeto" en el bindingList era el asociado a la fila en blanco final. El objetivo de un BindingList<T> es permitir que el desarrollador trabaje con él en lugar de de la DGV directamente, pero parece que hacerlo puede causar problemas en casos de frontera.

La relación entre las filas de DGV y BindingList<T> filas parece ser un poco un área gris. No he dedicado mucho tiempo a investigar esto, pero no me queda claro cuál es el estado del "objeto" en el BindingList<T> asociado a la fila final (vacía) de la DGV. Sin embargo, parece que el "objeto" al final solo se instancia "correctamente" cuando interactúas directamente con la fila final (no a través de un DataSource).

+2

Awesome. Tuve el mismo problema. Usé 'if (DataGridView.Rows.Count == bindingList.Count) {bindingList.RemoveAt (source.Count - 1); } 'al comienzo del controlador de caída y eso funcionó. –

0

Recuerde utilizar Row.BeginEdit() y Row.EndEdit() si obtiene este error mientras edita un valor en una fila, utilizando DataGrid o GridEX de Janus (en mi caso). El código de muestra que Darrel Lee publicó aquí (https://stackoverflow.com/a/9143590/1278771) me recuerda usar estas instrucciones que olvidé usar y esto me solucionó el problema.

Cuestiones relacionadas