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
兩層連動:
