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的下拉式選擇完,自動觸發事件,而不必再點其他欄位的寫法:

https://stackoverflow.com/questions/4827182/how-to-bind-datagridviewcomboboxcolumn-to-a-onchange-event-c

DGV只要點一次就可以的修改方法:

https://blog.csdn.net/jiankunking/article/details/46696057

DropDown=true的另一種方法--SendKeys.Send("{F4}");

https://cloud.tencent.com/developer/article/1343173

兩層連動:

https://www.itread01.com/content/1527151107.html

arrow
arrow
    文章標籤
    C# DGV ComboBox
    全站熱搜
    創作者介紹
    創作者 wings890109 的頭像
    wings890109

    幽嵐飋翼

    wings890109 發表在 痞客邦 留言(0) 人氣()