DataGridView的ComboBox是一個常用且很方便的功能,但寫起來卻不太簡單,要注意的細節稍微多了一點。
分別在兩個專案裡寫到它之後,認為必須做點筆記,往後會比較容易上手,不用再查東查西。
自己的寫法
1.先創造一個DataTable
public DataTable Create_DDESymbolSettingDataTable() { DataTable dt = new DataTable(); dt.Columns.Add("DDESymbol", typeof(String)); dt.Columns.Add("BrokerSymbol", typeof(String)); dt.Columns.Add("AutoChangedMethod", typeof(Int32)); dt.Columns.Add("AutoChangedMethodName", typeof(String)); dt.Columns.Add("DelayChangeMth", typeof(Boolean)); dt.Columns.Add("CombineSymbol", typeof(String)); dt.Columns.Add("Remark", typeof(String)); return dt; }
2.創造DataGridViewComboBoxColumn
public DataGridViewComboBoxColumn Create_AutoChangedMethodNameComboBox() { DataGridViewComboBoxColumn AutoChangedMethodNameComboBox = new DataGridViewComboBoxColumn(); var AutoChangedMethodNameSet = from value in StaticObjectClass.FUTCHANGEDMETHOSLIST select new { value.MethodName, value.Serial }; List<string> AutoChangedMethodNameList = AutoChangedMethodNameSet.AsEnumerable().Select(a => a.MethodName).ToList(); AutoChangedMethodNameComboBox.Name = "AutoChangedMethodNameComboBox"; AutoChangedMethodNameComboBox.DataSource = AutoChangedMethodNameList; AutoChangedMethodNameComboBox.HeaderText = "AutoChangedMethodName"; //AutoChangedMethodNameComboBox.DataPropertyName = "AutoChangedMethodName"; AutoChangedMethodNameComboBox.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing; return AutoChangedMethodNameComboBox; }
3.將DataTable和DataGridViewComboBoxColumn與DataGridView綁在一起
private void Set_SymbolSettingDGV(string brokerName) { DataTable dt = symbolSettingFormLogic.Create_DDESymbolSettingDataTable(); DataGridViewComboBoxColumn autoChangedMethodNameComboBox = symbolSettingFormLogic.Create_AutoChangedMethodNameComboBox(); SymbolSettingDGV.DataSource = dt; SymbolSettingDGV.Columns.Add(autoChangedMethodNameComboBox); SymbolSettingDGV.Columns["AutoChangedMethod"].Visible = false; SymbolSettingDGV.Columns["AutoChangedMethodName"].Visible = false; SymbolSettingDGV.Columns["AutoChangedMethodNameComboBox"].DisplayIndex = 2; }
4.把DataGridView的EditMode改成EditOnEnter,這樣就可以點一下就開啟ComboBox的下拉式選單
5.註冊DataGridView.EditingControlShowing
private void SymbolSettingDGV_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { //DataGridView dgv = (DataGridView)sender; if (e.Control is ComboBox) { ComboBox cb = e.Control as ComboBox; if (cb != null) { //給予初始選項 cb.SelectedIndex = 0; //自己寫ComboBox選項改變的事件註冊 cb.SelectedIndexChanged += AutoChangedMethodNameComboBoxSelectionIndexChanged; //自己寫ComboBox離開Focus的時候要取消其他事件註冊 cb.Leave += AutoChangedMethodNameComboBoxLeave; } } }
6.把自建的事件寫入
private void AutoChangedMethodNameComboBoxSelectionIndexChanged(object sender, EventArgs e) { ComboBox cb = (ComboBox)sender; int selectedindex = cb.SelectedIndex; if (selectedindex > -1) { var AutoChangedMethodNameSet = from value in StaticObjectClass.FUTCHANGEDMETHOSLIST select new { value.MethodName, value.Serial }; List<string> AutoChangedMethodNameList = AutoChangedMethodNameSet.AsEnumerable().Select(a => a.MethodName).ToList(); List<int> AutoChangedMethodSerialList = AutoChangedMethodNameSet.AsEnumerable().Select(a => a.Serial).ToList(); string selectedMethodName = AutoChangedMethodNameList[selectedindex]; int selectedSerial = AutoChangedMethodSerialList[selectedindex]; DataGridViewComboBoxEditingControl dgvcb = (DataGridViewComboBoxEditingControl)sender; int rowidx = dgvcb.EditingControlRowIndex; SymbolSettingDGV.Rows[rowidx].Cells["AutoChangedMethodName"].Value = selectedMethodName; SymbolSettingDGV.Rows[rowidx].Cells["AutoChangedMethod"].Value = selectedSerial; } }
/// <summary> /// 自創的ComboBox離開Focus的事件,主要用於取消其他事件註冊,避免發生CheckNoDataSource的錯誤 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void AutoChangedMethodNameComboBoxLeave(object sender, EventArgs e) { ComboBox cb = (ComboBox)sender; cb.SelectedIndexChanged -= AutoChangedMethodNameComboBoxSelectionIndexChanged; }
7.註冊DataGridView.CellClick事件
private void SymbolSettingDGV_CellClick(object sender, DataGridViewCellEventArgs e) { //cb.DroppedDown=true搭配將DGV的EditMode改成EditOnEnter可以實現單點就展開ComboBox if (SymbolSettingDGV.Rows.Count <= e.RowIndex) return; if (e.RowIndex < 0) return; if (e.ColumnIndex < 0) return; if (SymbolSettingDGV.Columns[e.ColumnIndex] is DataGridViewComboBoxColumn) { SymbolSettingDGV.BeginEdit(true); ((ComboBox)SymbolSettingDGV.EditingControl).DroppedDown = true; } }
8.其中有用到BeginEdit事件,如果ComboBox的選單內容會受其他資料影響而有所改變,可以在這裡寫入變化,以下內容是從我的另一個傳按抓出來的,與上述的內容完全無關,僅作為筆記備註
private void CriticalValueGirdView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { if (CriticalValueGirdView.Rows.Count <= e.RowIndex) return; if (e.RowIndex < 0) return; //在按鍵按下ComboBox準備編輯前,先判斷應該有幾個選項 DataGridViewCell cell_FuturesCode = CriticalValueGirdView.Rows[e.RowIndex].Cells[FuturesCode_ColumnNumber]; DataGridViewCell cell_S_or_F = CriticalValueGirdView.Rows[e.RowIndex].Cells[S_or_F_ColumnNumber]; DataGridViewComboBoxCell cbCell_SF = cell_S_or_F as DataGridViewComboBoxCell; string tempValue = (string)cbCell_SF.Value; //重寫選單會讓值歸0,所以要先記下原本的值 if (cell_FuturesCode.FormattedValue.ToString() == "") { string[] data = { "預設", "股票" }; cbCell_SF.DataSource = data; } else { string[] data = { "預設", "股票", "期貨" }; cbCell_SF.DataSource = data; } cbCell_SF.Value = tempValue; //改變最佳買賣價的下拉內容 DataGridViewCell cell_Better = CriticalValueGirdView.Rows[e.RowIndex].Cells[Better_ColumnNumber]; DataGridViewComboBoxCell cbCell_Better = cell_Better as DataGridViewComboBoxCell; Int16[] data2 = { 1, 2, 3 }; //cbCell_Better.DataSource = null; //cbCell_Better.DisplayMember = null; //cbCell_Better.ValueMember = null; cbCell_Better.DataSource = data2; ////改變最佳買賣價的下拉內容 //Int16[] data2 = { 1, 2, 3 }; ////((DataGridViewComboBoxColumn)CriticalValueGirdView.Columns[Better_ColumnNumber]).DataSource = data2; //DataGridViewColumn Better_Col = CriticalValueGirdView.Columns[Better_ColumnNumber]; //DataGridViewComboBoxColumn cb_Better_Col = Better_Col as DataGridViewComboBoxColumn; //cb_Better_Col.DataSource = data2; }
9.註冊DataGridView.CurrentCellDirtyStateChanged事件,可以讓ComboBox選完不用LeaveFocus就能執行DataGridView.CellValueChanged事件了。
private void SymbolSettingDGV_CurrentCellDirtyStateChanged(object sender, EventArgs e) { //搭配CellValueChanged可以實現選完ComboBox直接執行CellValueChanged的程式碼 //SymbolSettingDGV.CommitEdit(DataGridViewDataErrorContexts.Commit); }
10.註冊DataGridView.CellValueChanged事件,讓選單選完就能直接運行後續變動,但我在這個專案裡有先註冊自建事件cb.SelectedIndexChanged += AutoChangedMethodNameComboBoxSelectionIndexChanged;了,所以兩邊會有重工的問題,故本次專案裡,CellValueChanged就不寫內容了。
private void SymbolSettingDGV_CellValueChanged(object sender, DataGridViewCellEventArgs e) { if (SymbolSettingDGV.Rows.Count <= e.RowIndex) return; if (e.RowIndex < 0) return; //DataGridView dgv = (DataGridView)sender; //if (dgv.Columns[e.ColumnIndex].Name == "AutoChangedMethodNameComboBox") //{ // DataGridViewComboBoxCell dgvcbc = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[e.ColumnIndex]; // int selectedindex = dgvcbc.Items.IndexOf(dgvcbc.Value); // var AutoChangedMethodNameSet = from value in StaticObjectClass.FUTCHANGEDMETHOSLIST // select new { value.MethodName, value.Serial }; // List<int> AutoChangedMethodSerialList = AutoChangedMethodNameSet.AsEnumerable().Select(a => a.Serial).ToList(); // dgv.Rows[e.RowIndex].Cells["AutoChangedMethod"].Value = AutoChangedMethodSerialList[selectedindex]; //} }
*********************************************************************************************************************************************************************
網路上找到其他寫法,但沒有很理想的使用方法歸納如下:
1.註冊DataGridView.CellClick事件用以觸發cb.DroppedDown=true,跟註冊DataGridView.CellEnter事件模擬SendKeys.Send("{F4}");有異曲同工之妙,但是如果DataGrideView本身是可以讓User手動新增列時,就會發生虛增很多不必要的資料列的問題。
private void SymbolSettingDGV_CellEnter(object sender, DataGridViewCellEventArgs e) { //DataGridView dgv = (DataGridView)sender; //if (dgv.Rows.Count <= e.RowIndex) return; //if (e.RowIndex < 0) return; //if (e.ColumnIndex < 0) return; //if (dgv != null) //{ // if (dgv.Columns[e.ColumnIndex].Name == "AutoChangedMethodNameComboBox" && // dgv.Columns[e.ColumnIndex] is DataGridViewComboBoxColumn) // { // SendKeys.Send("{F4}"); // 選種ComboBox時,相當於按下鍵盤的F4(快速鍵下拉)。 // } //} }
2.創造DataGridViewComboBoxColumn時其實可以用AutoChangedMethodNameComboBox.DataPropertyName = "AutoChangedMethodName";把資料聯繫到AutoChangedMethodName這一欄,但是這是必須建立在ComboBox離開Focus才會寫入資料。本次專案選擇ComboBox後會寫入兩欄資料,為求程式一致性,也便於之後維護,故不使用.DataPropertyName的聯繫方法,而是將寫入值的過程放在cb.SelectedIndexChanged += AutoChangedMethodNameComboBoxSelectionIndexChanged;裡的SymbolSettingDGV.Rows[rowidx].Cells["AutoChangedMethodName"].Value = selectedMethodName;和SymbolSettingDGV.Rows[rowidx].Cells["AutoChangedMethod"].Value = selectedSerial;。
*********************************************************************************************************************************************************************
參考來源:
當DGV的下拉式選擇完,自動觸發事件,而不必再點其他欄位的寫法:
DGV只要點一次就可以的修改方法:
https://blog.csdn.net/jiankunking/article/details/46696057
DropDown=true的另一種方法--SendKeys.Send("{F4}");
https://cloud.tencent.com/developer/article/1343173
兩層連動: