none
在 DataGridView 上加上可編輯的combobox後的items重複問題 RRS feed

  • 問題

  • 我在網上找到了在 DataGridView 上加上可編輯的combobox的代碼,分享如下:
    
    可以實現出來,它本身就會記下之前輸入的column的記錄,但對於我來說是多此一舉,
    因為我自己也有在另外的一個資料庫裏讀取記錄,這樣就導致重複記錄.
    請問一下怎樣才可以不用這個DataGridViewComboEditBoxColumn本身的記錄功能呢?
            public class DataGridViewComboEditBoxColumn : DataGridViewComboBoxColumn
            {
                public DataGridViewComboEditBoxColumn()
                {
                    DataGridViewComboEditBoxCell obj = new DataGridViewComboEditBoxCell();
                    this.CellTemplate = obj;
                }
            }
            public class DataGridViewComboEditBoxCell : DataGridViewComboBoxCell
            {
                public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
                {
                    base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
    
                    ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
                    if (comboBox != null)
                    {
                        comboBox.DropDownStyle = ComboBoxStyle.DropDown;
                        comboBox.AutoCompleteMode = AutoCompleteMode.Suggest; 
                           comboBox.Validating += new CancelEventHandler(comboBox_Validating);
                    }
                }
                
                protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
                {
                    if (value != null)
                    {
                        if (value.ToString().Trim() != string.Empty)
                        {
                            if (Items.IndexOf(value) == -1)
                            {
                                Items.Add(value);
                                DataGridViewComboBoxColumn col = OwningColumn as DataGridViewComboBoxColumn;
                                col.Items.Add(value);
                            }
                        }
                    }
                    return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
                }
                
                
                void comboBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
                {
                    DataGridViewComboBoxEditingControl cbo = sender as DataGridViewComboBoxEditingControl;
                    if (cbo.Text.Trim() == string.Empty) return;
    
                    DataGridView grid = cbo.EditingControlDataGridView;
                    object value = cbo.Text;
                    // Add value to list if not there
                    if (cbo.Items.IndexOf(value) == -1)
                    {
                        DataGridViewComboBoxColumn cboCol = grid.Columns[grid.CurrentCell.ColumnIndex] as DataGridViewComboBoxColumn;
                        // Must add to both the current combobox as well as the template, to avoid duplicate entries
                        cbo.Items.Add(value);
                        cboCol.Items.Add(value);
                        grid.CurrentCell.Value = value;
                    }
                }
                
            }
    
    






    • 已編輯 KyleLove 2009年4月21日 上午 07:55
    2009年4月15日 上午 04:38

所有回覆

  • 請問有沒有高手知道嗎?
    2009年4月16日 上午 04:25
  • 您可以試看看在加入Combobox的item之前, 把先前有的item清空.
    ex: cbo.Items.Clear();
    微軟技術支援中心(CSS) - http://twitter.com/msdn_taiwan
    2009年4月20日 上午 03:38
  • 好像不行哦,
    而且如果把它們清空,好像是治標不治本的辦法,對嗎?
    2009年4月20日 上午 03:55
  • Hi,

    因為我是根據您說的:
    "可以實現出來,它本身就會記下之前輸入的column的記錄,但對於我來說是多此一舉,因為我自己也有在另外的一個資料庫裏讀取記錄,這樣就導致重複記錄."

    如果是這樣, 您自己有記錄了, 那就是把原本有的清掉, 然後填入您在資料庫紀錄的, 這樣不就不會重複了?  :-)
    微軟技術支援中心(CSS) - http://twitter.com/msdn_taiwan
    2009年4月20日 上午 04:04
  • 我剛試過了,還是不行,
    因為這一段CODE也是從網上Copy的, 所以不是太熟悉, 而且
    作者說"代碼的關鍵點為兩處,一是在顯示時將ComboBoxColumn以及ComboBox的Items添加入所有可能出現的項,在GetFormattedValue時實現,二是在編輯驗證ComboBox資料時即時插入新項,在ComboBox.Validating時實現。"

    不知有沒有幫助...

    參考網址:
    http://www.msuniversity.edu.cn/m_FegoArticle/Detail.aspx?articleid=298&category=technology.language&username=besti_ait&portalid=
    2009年4月20日 上午 04:17
  • 如果你要拿掉的功能是指
    當使用者在下拉區域輸入項目
    會被自動加到下拉清單的話

    應該拿掉comboBox.Validating += new CancelEventHandler(comboBox_Validating);這行
    與comboBox_Validating和GetFormattedValue函式就可以了

    http://www.dotblogs.com.tw/larrynung/
    2009年4月20日 上午 05:26
  • 如果你要拿掉的功能是指
    當使用者在下拉區域輸入項目
    會被自動加到下拉清單的話

    應該拿掉comboBox.Validating += new CancelEventHandler(comboBox_Validating);這行
    與comboBox_Validating和GetFormattedValue函式就可以了

    http://www.dotblogs.com.tw/larrynung/

    我剛剛試過,把它註解,但它還是有記錄....
    我懷疑是GetFormattedValue的問題...
    2009年4月20日 上午 06:32
  • 也要拿掉ㄚ
    有Items.Add的部分都要拿掉

    http://www.dotblogs.com.tw/larrynung/
    2009年4月20日 上午 06:36
  • 也要拿掉ㄚ
    有Items.Add的部分都要拿掉

    http://www.dotblogs.com.tw/larrynung/

    也試過,它說"DataGridViewComboBoxCell的值無效".
    2009年4月20日 上午 06:39
  • 我試驗是正常的
        public class DataGridViewComboEditBoxCell : DataGridViewComboBoxCell
        {
            public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
            {
                base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

                ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
                if (comboBox != null)
                {
                    comboBox.DropDownStyle = ComboBoxStyle.DropDown;
                }
            }

         
        }

        public class DataGridViewComboEditBoxColumn : DataGridViewComboBoxColumn
        {
            public DataGridViewComboEditBoxColumn()
            {
                DataGridViewComboEditBoxCell obj = new DataGridViewComboEditBoxCell();
                this.CellTemplate = obj;
            }
        }

    http://www.dotblogs.com.tw/larrynung/
    2009年4月20日 上午 06:56
  • 我試驗是正常的
        public class DataGridViewComboEditBoxCell : DataGridViewComboBoxCell
        {
            public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
            {
                base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

                ComboBox comboBox = base.DataGridView.EditingControl as ComboBox;
                if (comboBox != null)
                {
                    comboBox.DropDownStyle = ComboBoxStyle.DropDown;
                }
            }

         
        }

        public class DataGridViewComboEditBoxColumn : DataGridViewComboBoxColumn
        {
            public DataGridViewComboEditBoxColumn()
            {
                DataGridViewComboEditBoxCell obj = new DataGridViewComboEditBoxCell();
                this.CellTemplate = obj;
            }
        }

    http://www.dotblogs.com.tw/larrynung/
    哦,我想是Datagridview的資料不對應,因為我這個datagridview 的Comboeditbox的資料是可以由使用者自行輸入,但Combobox入面的資料只是其中的一部份,一定是不能一一完全對應的,所以發生錯誤.請問大大有沒有解決方法呢?
    2009年4月20日 上午 08:05

  • 我在datagridview是這樣加上去的:

                DataGridViewComboEditBoxColumn colCombobox = new DataGridViewComboEditBoxColumn();
    
                colCombobox.DataPropertyName = "myCombobox";
    
                colCombobox.Items.AddRange(new string[] { "aaa", "bbb", "ccc" });
    
                dataGridView1.Columns.Add(colCombobox);
    

     現在我想問問, 使用者可以在"myCombobox" column 上自行輸入它想要的文字, 也可以選 Combobox中的"aaa", "bbb" 或者 "ccc",
    怎樣能實現?

    2009年4月21日 上午 08:04
  • 請問有人知道怎做嗎?
    2009年4月23日 上午 03:24
  • 這個討論串一整個看完我自己也測試過一遍,其實原開發者的程式碼我幾乎都沒有修改(只有稍微調 一下排版及個人習慣寫法),功能正常,
    user 可以選擇 ComboEditBox 裡原本就有的值,若沒有, user 也可自行登打,並會自動加到 ComboEditBox 的選項中,也不會有重複的
    情況發生...

    我先拉一個 DataGridView 到 WinForm 上,原開發者的程式碼直接貼到 Form1.cs,然後直接在設計階段加入資料行,選擇型別
    DataGridViewComboEditBoxColumn ,最後在 Form_Load 時加入選項(模擬從資料庫撈資料),主要程式碼如下:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            this.Column1.Items.AddRange(new string[] { "aaa", "bbb", "ccc" });
        }
    }
    
    public class DataGridViewComboEditBoxColumn : DataGridViewComboBoxColumn
    {
        public DataGridViewComboEditBoxColumn()
        {
            DataGridViewComboEditBoxCell obj = new DataGridViewComboEditBoxCell();
            this.CellTemplate = obj;
        }
    }
    
    public class DataGridViewComboEditBoxCell : DataGridViewComboBoxCell
    {
        public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
        {
            base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
    
            ComboBox comboBox = (ComboBox)base.DataGridView.EditingControl;
    
            if (comboBox != null)
            {
                comboBox.DropDownStyle = ComboBoxStyle.DropDown;
                comboBox.AutoCompleteMode = AutoCompleteMode.Suggest;
                comboBox.Validating += new CancelEventHandler(comboBox_Validating);
            }
        }
    
        protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
        {
            if (value != null)
            {
                if (value.ToString().Trim() != string.Empty)
                {
                    if (Items.IndexOf(value) == -1)
                    {
                        Items.Add(value);
                        DataGridViewComboBoxColumn col = (DataGridViewComboBoxColumn)OwningColumn;
                        col.Items.Add(value);
                    }
                }
            }
            return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
        }
    
        void comboBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
        {
            DataGridViewComboBoxEditingControl cbo = (DataGridViewComboBoxEditingControl)sender;
            if (cbo.Text.Trim() == string.Empty) return;
    
            DataGridView grid = cbo.EditingControlDataGridView;
            object value = cbo.Text;
    
            // Add value to list if not there
            if (cbo.Items.IndexOf(value) == -1)
            {
                DataGridViewComboBoxColumn cboCol = (DataGridViewComboBoxColumn)grid.Columns[grid.CurrentCell.ColumnIndex];
                // Must add to both the current combobox as well as the template, to avoid duplicate entries
                cbo.Items.Add(value);
                cboCol.Items.Add(value);
                grid.CurrentCell.Value = value;
            }
        }
    }


    第一張圖為剛載入時,選項就是 Form_Load 時加入的那三個。


    第二張圖表示使用連續自行登打兩個選項(第一次登打的,在第二個 ComboEditBox 已經可以選)


    第三張也是說明第二次登打的選項立即可以選擇。

    • 已標示為解答 KyleLove 2009年4月27日 上午 09:50
    • 已取消標示為解答 KyleLove 2009年4月27日 上午 09:51
    2009年4月27日 上午 07:04
  • 非常感謝您自己測試一遍,之後我也重新做了一次, 我終於發現是甚麼問題了:
    因為你是用this.Column1.Items.AddRange(new string[] { "aaa", "bbb", "ccc" });
    而我是重數據庫裏提出資料,原來要在這些記錄加上trim()來移除不必要的空格:
                                    string tmp = myReader.GetSqlString(0).ToString();
                                    tmp = tmp.ToString().Trim();
                                    colCombobox.Items.Add(tmp);
    這樣做就可以沒有重複的記錄了,
    但是,我資料庫的這些記錄本來就沒有多餘空格的(因為我測試過),
    但實際上我加上trim()上去就解決了...(暈) @@|||

    不管怎樣,謝謝哦


    =========我是分隔線========================

    其實我最想的,就是說,因為這個column有太多不同的items,
    如果打了一次之後立即可以選擇,
    這麼就有很多很多的items在這個選項裏頭, 造成使用者的不便@@"
    所以就想這個選項只含有一些常用的item,其它的就不用了(因為大多數只出現一次)
    真希望有其它人可以解決這個問題.
    • 已標示為解答 KyleLove 2009年4月27日 上午 09:50
    • 已取消標示為解答 KyleLove 2009年4月27日 上午 09:51
    2009年4月27日 上午 09:49
  • 看來你想做的是類似選項建議清單,卻又不能限制使用者輸入清單以外的項目...
    其實這樣的需求,我倒是建議你擺 TextBox 即可,讓使用者可以利用功能鍵(比如說 F4 或滑鼠 DoubleClick )開啟選項視窗取值回來,
    若沒有合用的則自行輸入,畢竟你不想限制使用者輸入的值,用下拉選單沒什麼意思...
    2009年4月28日 上午 09:31