2012-03-07 33 views
15

Ho installato un ComboBoxColumn per il mio DataGridView e ho impostato i suoi valori selezionabili da un'enumerazione. Funziona principalmente come vorrei con la seguente eccezione.Colonna ComboBox DataGridView: modifica il valore della cella dopo aver effettuato la selezione dal menu a discesa?

Ogni volta che faccio clic sulla freccia del menu a discesa e quindi seleziono uno dei valori enum, rimane in una sorta di stato "intermedio" in cui l'evento CellValueChanged non viene attivato. Devo concentrarmi su un'altra cella o su un altro controllo perché l'evento possa sparare.

Ho anche un gestore di eventi per l'evento Leaving di DataGridView che "convalida" i contenuti assicurandosi che nessuna cella sia vuota.

Quindi, se creo una riga e riempio tutte le celle e vieni alla colonna ComboBox (attualmente vuota), modificala in un valore, quindi fai clic su un pulsante Esegui; la mia finestra di errore si apre perché la selezione di ComboBox non è stata "salvata".

Come posso aggirare questo? C'è un modo in cui, dopo aver selezionato un valore dal menu a discesa, "imposta" automaticamente il valore?

Grazie!

risposta

19

Si dovrebbe usare CurrentCellDirtyStateChanged evento e forzare un commit modifica sulla griglia di partenza:

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

Speranza che aiuta!

+0

Lo ha fatto sicuramente! Grazie! – john

3

Vorrei estendere la risposta di ionden controllando se il DataGridViewColumn è il tipo di DataGridViewComboBoxColumn prima di forzare lo CommitEdit. Ciò impedirà ad altri oggetti DataGridViewColumn di commettere troppo presto.

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

Ecco come ho risolto il 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

Si prega di guardare il tag C#. –

1

In alcuni casi, il valore non si attacchi fino a quando il fuoco ha lasciato la fila del tutto. In tal caso, l'unico modo per forzare la modifica corrente di fine deve terminare su tutto il contesto vincolante:

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

Ho trovato questo suggerimento here.

11

Estenderei la risposta di Moop controllando il tipo di cella anziché il tipo di colonna.

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 che ho visto: Non funzionerà se si sceglie: GridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;

0

li spendo come due ore alla ricerca di un errore perché non ho notato che il valore della cella fa non si salverà se non è defocused, o meglio per dire che ho appena notato che la cella non è defocused perché la casella combinata è bianca durante il salvataggio (evento btn). Non solo, la modalità EditOnEnter prevale sul fatto che la maggior parte degli altri metodi mostrati sopra funzionano. Il motivo per utilizzare EditOnEnter è che quando si utilizza DataGridViewComboBoxColumn, è necessario fare clic due volte per aprire il menu a discesa se non si imposta EditMode su EditOnEnter.

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

Spero che questo aiuta.Mi è costato circa due ore a chiedermi perché il valore nell'oggetto non è lo stesso mostrato sulla GUI.

0

Sto aggiungendo la mia risposta come follow-up alla discussione che è già avvenuta. Stavo cercando di creare un DataGridView con diverse caselle combinate per riga. Dovevano anche essere sensibili a un singolo clic. E, quando è stata effettuata la selezione, è necessario modificare un'altra cella nella riga in base alla selezione della casella combinata. Il cambiamento doveva avvenire non appena la selezione è stata fatta. Il mio problema principale, come gli OP, era che il cambiamento non sarebbe successo fino a quando il combobox non ha perso lo stato attivo.

Quindi, ecco un esempio minimamente funzionante di un DataGridView. Ho dovuto ridurlo al minimo perché ottenere tutti i miei requisiti per lavorare allo stesso tempo era complicato. Diversi post SO sono andati a fare questo, e aggiornerò il mio post con i riferimenti più tardi. Ma per ora, qui 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

Si dovrebbe usare CellValueChanged che genera l'evento cambiamento sulla rete e all'interno della manifestazione si dovrebbe commettere modifiche e lasciare il controllo al fine di salvare l'elemento dopo che è stato selezionato.

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

    FilterdataGrid.EndEdit(DataGridViewDataErrorContexts.LeaveControl); 
} 

Spero che sia d'aiuto!

+2

Puoi provare ad aggiungere qualche contesto e spiegazione alla tua risposta in modo che gli utenti futuri possano trarne vantaggio? Rispondere con un codice semplice è molto meno probabile che serva da risposta più generale per gli utenti futuri. Dai un'occhiata a [risposta] per maggiori informazioni. –

0

Grazie a Droj per il suggerimento su EndCurrentEdit, che avevo bisogno di farlo funzionare per me. Questo è quello che ho finito per fare di impegnarsi immediatamente DataGridViewComboBoxColumns e 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

L'evento fisso interazione CurrentCellDirtyStateChanged del mouse per questo problema, ma si rompe l'interazione keyboard - utilizzando F4 poi freccia su/giù, ogni freccia fare clic su Risultati in uno stato di sporco cambia e conferma la modifica. La soluzione che ho trovato, è stato quello di prendere "DataGridViewComboBoxEditingControl" quando è stato creato e allegare un evento DropDownClosed ad esso. Funziona per l'interazione con tastiera e mouse. In questo esempio, abbiamo esteso DataGridView in modo che ogni istanza ereditasse questa funzionalità:

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(); 
     } 
    } 
Problemi correlati