2012-03-07 40 views
15

Tôi đã thiết lập một ComboBoxColumn cho DataGridView của tôi và thiết lập các giá trị có thể lựa chọn của nó từ một liệt kê. Nó chủ yếu hoạt động như tôi muốn với ngoại lệ sau đây.Cột ComboBox DataGridView: Thay đổi giá trị ô sau khi chọn từ menu thả xuống được thực hiện?

Bất cứ khi nào tôi nhấp vào mũi tên thả xuống và sau đó chọn một trong các giá trị enum, nó vẫn ở trạng thái "trung gian" khi sự kiện CellValueChanged không được kích hoạt. Tôi cần phải tập trung vào một tế bào khác hoặc một điều khiển khác cho sự kiện này để bắn.

Tôi cũng có trình xử lý sự kiện cho sự kiện Rời khỏi DataGridView để "xác thực" nội dung bằng cách đảm bảo rằng không có ô nào trống. Vì vậy, nếu tôi tạo ra một hàng và điền vào tất cả các tế bào và đến cột ComboBox (hiện đang trống), thay đổi nó thành một giá trị, và sau đó nhấp vào nút Run; hộp thoại lỗi của tôi bật lên vì lựa chọn ComboBox không được "lưu".

Làm cách nào để giải quyết vấn đề này? Có cách nào sau khi tôi chọn một giá trị từ trình đơn thả xuống, nó sẽ tự động "đặt" giá trị không?

Cảm ơn!

Trả lời

19

Bạn nên sử dụng CurrentCellDirtyStateChanged sự kiện và buộc một cam kết chỉnh sửa trên lưới:

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

Hy vọng nó sẽ giúp!

+0

Nó chắc chắn nhất đã làm! Cảm ơn! – john

3

Tôi sẽ mở rộng câu trả lời của ionden bằng cách kiểm tra xem DataGridViewColumn có phải là loại DataGridViewComboBoxColumn trước khi bắt buộc CommitEdit hay không. Điều này sẽ ngăn các đối tượng khác DataGridViewColumn cam kết quá sớm.

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

Đây là cách tôi giải quyết được vấn đề

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

Vui lòng xem thẻ C#. –

1

Trong một số trường hợp, giá trị sẽ không dính cho đến khi tập trung đã để lại hàng hoàn toàn. Trong trường hợp đó, cách duy nhất để buộc các chỉnh sửa hiện tại để cuối cùng là để kết thúc nó vào bối cảnh ràng buộc toàn bộ:

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

tôi thấy mẹo này here.

11

Tôi sẽ mở rộng câu trả lời của Moop bằng cách chọn loại ô thay vì loại cột.

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

Một vấn đề mà tôi thấy: Nó sẽ không hoạt động nếu bạn chọn: GridView.EditMode = System.Windows.Forms.DataGridViewEditMode.EditOnEnter;

0

tôi dành như hai giờ tìm kiếm một lỗi vì tôi không nhận thấy rằng các giá trị của ô không không được lưu nếu nó không defocused, hoặc tốt hơn để nói rằng tôi chỉ nhận thấy rằng các tế bào không defocused vì combobox whited ra trong khi tiết kiệm (btn sự kiện). Không chỉ vậy, Chế độ EditOnEnter chiếm ưu thế mà hầu hết các phương pháp khác được hiển thị ở trên hoạt động. Lý do để sử dụng EditOnEnter là khi bạn sử dụng một DataGridViewComboBoxColumn, bạn phải bấm hai lần để mở menu thả xuống nếu bạn không đặt EditMode để EditOnEnter.

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

Tôi hy vọng điều này sẽ hữu ích.Nó chi phí cho tôi khoảng hai giờ tự hỏi tại sao giá trị trong đối tượng là không giống nhau sau đó hiển thị trên GUI.

0

Tôi đang thêm câu trả lời của mình để theo dõi cuộc thảo luận đã xảy ra. Tôi đã cố gắng để xây dựng một DataGridView có comboboxes khác nhau cho mỗi hàng. Họ cũng phải đáp ứng với một nhấp chuột duy nhất. Và, khi lựa chọn được thực hiện, một ô khác trong hàng cần phải được thay đổi theo lựa chọn combobox. Sự thay đổi cần thiết xảy ra ngay khi lựa chọn được thực hiện. Vấn đề chính của tôi, giống như của OP, là sự thay đổi sẽ không xảy ra cho đến khi combobox mất tập trung.

Vì vậy, đây là một ví dụ tối thiểu làm việc đầy đủ của một DataGridView như vậy. Tôi phải đưa nó xuống mức tối thiểu bởi vì nhận được tất cả các yêu cầu của tôi để làm việc cùng một lúc là khó khăn. Một số bài viết SO đã đi vào thực hiện điều này, và tôi sẽ cập nhật bài viết của tôi với các tài liệu tham khảo sau này. Nhưng bây giờ, ở đây đi ...

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

Bạn nên sử dụng CellValueChanged mà cháy sự kiện thay đổi trên lưới và bên trong trường hợp bạn cần cam kết thay đổi và để lại sự kiểm soát để lưu các mục sau khi nó đã được chọn.

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

    FilterdataGrid.EndEdit(DataGridViewDataErrorContexts.LeaveControl); 
} 

Hy vọng điều đó sẽ hữu ích!

+2

Bạn có thể thử và thêm một số bối cảnh và giải thích cho câu trả lời của bạn để người dùng trong tương lai có thể hưởng lợi từ nó? Trả lời bằng mã đơn giản ít có khả năng phân phối như một câu trả lời chung hơn cho người dùng trong tương lai. Hãy xem [answer] để biết thêm thông tin. –

0

Cảm ơn Droj về mẹo về EndCurrentEdit, mà tôi cần để làm cho nó hoạt động cho tôi. Đây là những gì tôi đã kết thúc làm để ngay lập tức cam kết DataGridViewComboBoxColumns và 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

Sự kiện cố định CurrentCellDirtyStateChanged tương tác chuột cho vấn đề này, nhưng nó phá vỡ sự tương tác bàn phím - sử dụng F4 sau đó lên/xuống mũi tên, mỗi mũi tên nhấp chuột kết quả trong trạng thái bẩn thay đổi và cam kết chỉnh sửa. Các giải pháp tôi tìm thấy, là lấy "DataGridViewComboBoxEditingControl" khi nó được tạo ra, và đính kèm một sự kiện DropDownClosed với nó. Điều này làm việc cho tương tác bàn phím và chuột. Trong ví dụ này, chúng tôi đã mở rộng DataGridView để mọi trường hợp sẽ kế thừa chức năng này:

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(); 
     } 
    } 
Các vấn đề liên quan