2012-03-07 42 views
15

He configurado un ComboBoxColumn para mi DataGridView y establezco sus valores seleccionables de una enumeración. Funciona principalmente como me gustaría con la siguiente excepción.Columna ComboBox de DataGridView: ¿Cambia el valor de la celda después de que se realiza la selección del menú desplegable?

Cada vez que hago clic en la flecha desplegable y selecciono uno de los valores enum, permanece en una especie de estado "intermedio" donde el evento CellValueChanged no se desencadena. Necesito enfocarme en otra celda u otro control para que el evento se dispare.

También tengo un controlador de eventos para el evento Leaving de DataGridView que "valida" el contenido asegurándose de que ninguna celda esté vacía.

Por lo tanto, si creo una fila y llene todas las celdas y vengo a la columna (actualmente en blanco) ComboBox, cámbiela a un valor y luego haga clic en el botón Ejecutar; mi cuadro de diálogo de error aparece porque la selección de ComboBox no fue "guardada".

¿Cómo puedo evitar esto? ¿Hay alguna manera de que después de seleccionar un valor del menú desplegable automáticamente "establezca" el valor?

Gracias!

Respuesta

19

Debe utilizar CurrentCellDirtyStateChanged evento y forzar una confirmación de edición en la parrilla:

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
    { 
     dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit); 
    } 

espero que ayude!

+0

¡Sin duda lo hizo! ¡Gracias! – john

3

Extendería la respuesta de ionden comprobando si el DataGridViewColumn es del tipo DataGridViewComboBoxColumn antes de forzar el CommitEdit. Esto evitará que otros objetos DataGridViewColumn se comprometan demasiado pronto.

dataGridView1.CurrentCellDirtyStateChanged += dataGridView1_CurrentCellDirtyStateChanged; 

    void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
    { 
     DataGridViewColumn col = dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex]; 
     if (col is DataGridViewComboBoxColumn) 
     { 
      dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit); 
     } 
    } 
0

Así es como he resuelto el problema

Private Sub dgvEcheancier_CurrentCellDirtyStateChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dgvEcheancier.CurrentCellDirtyStateChanged 
     nbreClick += 1 
      With dgvEcheancier 
       Select Case .CurrentCell.ColumnIndex 
       Case 9 
        Dim col As DataGridViewComboBoxColumn = .Columns(9) 
        If TypeOf (col) Is DataGridViewComboBoxColumn Then 
         dgvEcheancier.CommitEdit(DataGridViewDataErrorContexts.Commit) 
         If nbreClick = 2 Then 
          MessageBox.Show("y" & "val=" & .CurrentCell.Value) 
          nbreClick = 0 
         End If 
        End If 

      End Select 
      End With 
+0

Mire la etiqueta C#. –

1

En algunos casos, el valor no se pegue hasta que el enfoque se ha marchado de la fila por completo. En ese caso, la única manera de forzar la edición actual al final es para acabar con ella en todo el contexto de unión:

mGridView.CommitEdit(DataGridViewDataErrorContexts.Commit); 
mGridView.BindingContext[mGridView.DataSource].EndCurrentEdit(); // <<=== 

me encontré con este consejo here.

11

Extendería la respuesta de Moop al marcar el tipo de celda en lugar del tipo de columna.

dataGridView1.CurrentCellDirtyStateChanged += dataGridView1_CurrentCellDirtyStateChanged; 

void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
{ 
    if (CurrentCell is DataGridViewComboBoxCell) 
    { 
     dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit); 
     dataGridView1.EndEdit(); 
    } 
} 
0
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
{ 
    dataGridView1.BeginEdit(true); 
    ComboBox cmbMiCtrl=(ComboBox)dataGridView1.EditingControl; 
    string Valor= cmbMiCtrl.Text; 
    dataGridView1.EndEdit(); 
} 
0

Un problema que vi: No funcionará si elige: GridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;

0

me paso como dos horas en busca de un error porque no se dio cuenta de que el valor de la celda hace no se guardará si no está desenfocado, o mejor dicho, acabo de notar que la celda no está desenfocada porque el cuadro desplegable se bloqueó mientras se guardaba (evento btn). No solo eso, prevalece el modo EditOnEnter que la mayoría de los otros métodos mostrados anteriormente funcionan. El motivo para utilizar EditOnEnter es que cuando utiliza un DataGridViewComboBoxColumn, debe hacer clic dos veces para abrir el menú desplegable si no configura EditMode en EditOnEnter.

this.dataGridView.EditMode = DataGridViewEditMode.EditOnKeystrokeOrF2; this.dataGridView.EndEdit(); this.dataGridView.EditMode = DataGridViewEditMode.EditOnEnter;

espero que esto ayude.Me costó alrededor de dos horas preguntarme por qué el valor en el objeto no es el mismo que el que se muestra en la GUI.

0

añado mi respuesta como un seguimiento de la discusión que ya ha ocurrido. Intentaba construir un DataGridView que tuviera diferentes comboboxes por fila. También tenían que responder a un solo clic. Y, cuando se hizo la selección, otra celda de la fila necesitaba ser cambiado de acuerdo a la selección de cuadro combinado. El cambio tenía que suceder tan pronto como se hizo la selección. Mi principal problema, al igual que los OP, era que el cambio no ocurriría hasta que el cuadro combinado perdiera enfoque.

lo tanto, aquí es un ejemplo completo de un mínimo de trabajo de un DataGridView tales. Tuve que reducirlo al mínimo porque conseguir todos mis requisitos para trabajar al mismo tiempo era complicado. Varias publicaciones de SO entraron en hacer esto, y actualizaré mi publicación con referencias posteriores. Pero por ahora, aquí va ...

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Forms; 

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

    private Panel panel2; 
    private DataGridView TestGrid; 

    private void InitializeComponent() 
    { 
     this.panel2 = new System.Windows.Forms.Panel(); 
     this.SuspendLayout(); 
     // 
     // panel2 
     // 
     this.panel2.Dock = DockStyle.Fill; 
     this.panel2.Name = "panel2"; 
     this.panel2.TabIndex = 1; 
     // 
     // Form1 
     // 
     this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
     this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
     this.ClientSize = new System.Drawing.Size(661, 407); 
     this.Controls.Add(this.panel2); 
     this.Name = "Form1"; 
     this.Text = "Form1"; 
     this.Load += new System.EventHandler(this.Form1_Load); 
     this.ResumeLayout(false); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     //basic grid properties 
     TestGrid = new DataGridView(); 
     TestGrid.Dock = DockStyle.Fill; 
     TestGrid.AutoGenerateColumns = false; 
     TestGrid.Name = "TestGrid"; 
     TestGrid.ReadOnly = false; 
     TestGrid.EditMode = DataGridViewEditMode.EditOnEnter; 

     //Event handlers 
     TestGrid.DataBindingComplete += TestGrid_DataBindingComplete; 
     TestGrid.CurrentCellDirtyStateChanged += TestGrid_CurrentCellDirtyStateChanged; 
     TestGrid.CellValueChanged += TestGrid_CellValueChanged; 

     //columns 
     var textCol = new DataGridViewTextBoxColumn(); 
     textCol.HeaderText = "Text"; 
     textCol.Name = "Text"; 
     textCol.DataPropertyName = "Text"; 
     textCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; 
     TestGrid.Columns.Add(textCol); 

     var comboCol = new DataGridViewComboBoxColumn(); 
     comboCol.HeaderText = "ComboBox"; 
     comboCol.Name = "ComboBox"; 
     comboCol.AutoComplete = true; 
     comboCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells; 
     TestGrid.Columns.Add(comboCol); 

     var resultCol = new DataGridViewTextBoxColumn(); 
     resultCol.HeaderText = "Result"; 
     resultCol.Name = "Result"; 
     resultCol.DataPropertyName = "Result"; 
     resultCol.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; 
     TestGrid.Columns.Add(resultCol); 

     //Bind the data 
     Datum.TestLoad(); 
     TestGrid.DataSource = Datum.Data; 

     panel2.Controls.Add(TestGrid); 
    } 

    void TestGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
    { 
     if (e.RowIndex < 0 || e.ColumnIndex < 0) 
      return; 

     var row = TestGrid.Rows[e.RowIndex]; 
     var cell = row.Cells[e.ColumnIndex]; 
     if (cell is DataGridViewComboBoxCell) 
     { 
      var val = cell.Value as string; 
      var datum = row.DataBoundItem as Datum; 
      datum.Current = val; 
      row.Cells["Result"].Value = datum.Result; 
      TestGrid.InvalidateRow(e.RowIndex); 
     } 
    } 


    void TestGrid_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
    { 
     if(TestGrid.CurrentCell is DataGridViewComboBoxCell) 
     { 
      TestGrid.CommitEdit(DataGridViewDataErrorContexts.Commit); 
      TestGrid.EndEdit(); 
     } 
    } 

    void TestGrid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) 
    { 
     foreach (DataGridViewRow row in TestGrid.Rows) 
     { 
      var datum = row.DataBoundItem as Datum; 
      if (datum == null) 
       return; 

      var cell = row.Cells["ComboBox"] as DataGridViewComboBoxCell; 
      if (cell.DataSource == null) 
      { 
       cell.DisplayMember = "KeyDisplayValue"; 
       cell.ValueMember = "KeyValue"; 
       cell.DataSource = (row.DataBoundItem as Datum).Combo; 
       cell.Value = (row.DataBoundItem as Datum).Current; 
      } 
     } 
     TestGrid.DataBindingComplete -= TestGrid_DataBindingComplete; 
    } 

    public class Datum 
    { 
     public static void TestLoad() 
     { 
      var t1 = new Triplet[] { 
        new Triplet("1", "World", "Everyone"), 
        new Triplet("2", "Charlie", "Friend of Algernon"), 
        new Triplet("3", "Lester", "Phenomenal programmer"), 
      }; 
      var t2 = new Triplet[] { 
        new Triplet("1", "World", "Everyone"), 
        new Triplet("4", "Mary", "Wife of George Bailey"), 
        new Triplet("3", "Lester", "Phenomenal programmer"), 
      }; 
      Data.Add(new Datum("hello, ", t1.ToList())); 
      Data.Add(new Datum("g'bye, ", t2.ToList())); 
     } 
     public static List<Datum> Data = new List<Datum>(); 

     public Datum(string text, List<Triplet> combo) 
     { 
      this._text = text; 
      this._combo = combo.ToDictionary<Triplet,string>(o => o.KeyValue); 
      this.Current = combo[0].KeyValue; 
     } 

     private string _text; 
     public string Text 
     { 
      get 
      { 
       return _text; 
      } 
     } 

     private Dictionary<string, Triplet> _combo; 
     public List<Triplet> Combo 
     { 
      get 
      { 
       return _combo.Values.ToList(); 
      } 
     } 

     private string _result; 
     public string Result 
     { 
      get 
      { 
       return _result; 
      } 
     } 

     private string _current; 
     public string Current 
     { 
      get 
      { 
       return _current; 
      } 
      set 
      { 
       if (value != null && _combo.ContainsKey(value)) 
       { 
        _current = value; 
        _result = _combo[value].Description; 
       } 
      } 
     } 
    } 

    public class Triplet 
    { 
     public string KeyValue { get; set; } 
     public string KeyDisplayValue { get; set; } 
     public string Description { get; set; } 
     public Triplet(string keyValue, string keyDisplayValue, string description) 
     { 
      KeyValue = keyValue; 
      KeyDisplayValue = keyDisplayValue; 
      Description = description; 
     } 
    } 
} 
} 
0

Debe utilizar CellValueChanged que dispara el evento de cambio de la red y dentro del evento que debe confirmar los cambios y dejar el control con el fin de guardar el artículo después de que se ha seleccionado.

private void FilterdataGrid_CellValueChanged(object sender, DataGridViewCellEventArgs e) 
{ 
    FilterdataGrid.CommitEdit(DataGridViewDataErrorContexts.Commit);  

    FilterdataGrid.EndEdit(DataGridViewDataErrorContexts.LeaveControl); 
} 

Espero que ayude!

+2

Podría tratar de añadir un poco de contexto y explicación de su respuesta para que los futuros usuarios puedan beneficiarse de ella? La respuesta con código simple es mucho menos probable que sirva como una respuesta más general para futuros usuarios. Eche un vistazo a [respuesta] para más información. –

0

Gracias a Droj por la punta sobre EndCurrentEdit, que necesitaba para hacer que funcione para mí. Esto es lo que terminé haciendo para cometer instante DataGridViewComboBoxColumns y DataGridViewCheckBoxColumns:

private void dataGridViewEnumerable_CurrentCellDirtyStateChanged(object sender, EventArgs e) 
{ 
    var dataGridView = sender as DataGridView; 
    if (dataGridView == null || dataGridView.CurrentCell == null) 
    return; 
    var isComboBox = dataGridView.CurrentCell is DataGridViewComboBoxCell; 
    if ((isComboBox || dataGridView.CurrentCell is DataGridViewCheckBoxCell) 
    && dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit) 
    && isComboBox && dataGridView.EndEdit()) 
    dataGridView.BindingContext[dataGridView.DataSource].EndCurrentEdit(); 
} 
2

El evento fijo interacción CurrentCellDirtyStateChanged ratón para este problema, pero se rompe interacción con el teclado - con ayuda de F4 y luego flecha arriba/abajo, cada flecha haga clic en Resultados en un cambio de estado sucio y confirma la edición. La solución que encontré, era para agarrar el "DataGridViewComboBoxEditingControl" cuando se crea, y adjuntar un evento DropDownClosed a ella. Esto funciona para la interacción del teclado y el mouse. En este ejemplo, ampliamos DataGridView para que cada instancia herede esta funcionalidad:

protected override void OnEditingControlShowing(DataGridViewEditingControlShowingEventArgs e) 
    { 
     DataGridViewComboBoxEditingControl control = e.Control as DataGridViewComboBoxEditingControl; 
     if (control != null) 
     { 
      control.DropDownClosed -= ComboBoxDropDownClosedEvent; 
      control.DropDownClosed += ComboBoxDropDownClosedEvent; 
     } 
     base.OnEditingControlShowing(e); 
    } 

    void ComboBoxDropDownClosedEvent(object sender, EventArgs e) 
    { 
     DataGridViewComboBoxCell cell = CurrentCell as DataGridViewComboBoxCell; 
     if ((cell != null) && cell.IsInEditMode) 
     { 
      CommitEdit(DataGridViewDataErrorContexts.Commit); 
      EndEdit(); 
     } 
    } 
Cuestiones relacionadas