需求:DataGridViewComboBoxColumn 可编辑/输入版本。
实现方法:将EditingControl改成ComboBox,再输入完成和验证完成之间检查Items,如果不存在该值则插入。
本人目前搜集到的版本有两个。1.GetFormattedValue版本:http://blog.csdn.net/maji9370/archive/2009/09/16/4557770.aspx
2.OnEditingControlShowing版本:http://www.cnblogs.com/michaelhuwei/archive/2008/09/28/1301290.html就本人使用体验,
GetFormattedValue版本 将造成每次频繁触发GetFormattedValue事件(鼠标滑过该列、窗口重绘、单元格赋值等),如果在插入Items前还要处理(验证/修正)值则将明显造成显示刷新延迟,因为触发常常是整列每个单元格多次触发。
OnEditingControlShowing版本没有显示刷新延迟,因为只有在需要验证时才处理Items插入事件,缺点是每次进入编辑都要重载DorDownStyle,如果该Items.Count太大则进入编辑将有明显延迟(我的是123,延迟600毫秒左右)。论题:
看过VC(MFC)的类似实现并没有明显延迟,请试论C#是否能实现?

解决方案 »

  1.   

    private void dataGridView1_EditingControlShowing(object sender,
        DataGridViewEditingControlShowingEventArgs e)
    {
        ComboBox combo = e.Control as ComboBox;
        if (combo != null)
        {
            combo.SelectedIndexChanged +=
                new EventHandler(ComboBox_SelectedIndexChanged);
        }
    }
    private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
     ComboBox cb=(ComboBox)sender;
    }
    一般使用这个
      

  2.   

    Win or web?
    以前好像写过一个DataGrid(VS03)版本的下拉框组件,并没什么明显刷新的现象啊。
      

  3.   


    貌似 SelectIndexChanged 比 EditingControlShowing早触发,实际运行效果是从一个TextBox列改选到ComboBox列不触发SelectIndexChanged ,要在ComboBox里切换单元格才会有效果。
    我换用了Enter事件,结果每次进入(鼠标单击或设置为CurrentCell)都会触发两次,有延迟。
      

  4.   

    最新发现:
    经过多次断点测试分析发现:combo.DropDownStyle = ComboBoxStyle.DropDown; //此处将重新触发Enter,在此之前需清除事件绑定。
    目前延时100ms我的机器配置:E2180(双核 2.00GHz) 2.0GB内存 NVIDIA 8600GT 显卡
            EventHandler eventHandler;
            private void ChannelDgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
            {                ComboBox combo = e.Control as ComboBox;
                    if (combo != null)
                    {
                        if (eventHandler == null)
                        {
                            eventHandler  = new EventHandler(combo_Enter);
                            //eventHandler = new EventHandler(combo_SelectedIndexChanged);
                        }
                        //combo.SelectedIndexChanged += eventHandler;
                        combo.Enter -= eventHandler;   //取消可能的事件绑定
                        combo.Enter += eventHandler; //绑定事件
                    }
            }
            void combo_Enter(object sender, EventArgs e)
            {
                DateTime st = DateTime.Now;            ComboBox combo = sender as ComboBox;
                if (combo != null)
                {
                    combo.Enter -= eventHandler;   //取消事件绑定
                      combo.DropDownStyle = ComboBoxStyle.DropDown; //此处将重新触发Enter
                    //cb.AutoCompleteMode = AutoCompleteMode.Suggest;
                    combo.MaxLength = 5;
                }
                labTimeSpan.Text = (DateTime.Now - st).ToString();
            }
      

  5.   


    确实,经测试combo.DropDownStyle = ComboBoxStyle.DropDown;放在EditingControlShowing里和放在Enter或者其他事件里区别不大,之前看到的区别仅仅是因为我的机器状态不一样,早上刚开机就快得多...然则,即使快得多也还是显得慢,100毫秒的延迟是可视,如果不转换的话EditingControlShowing时间几乎为0。同时如果Items.Count == 1;时间约等于20毫秒,显然DropDownStyle改变时重载了Items。combo.DropDownStyle = ComboBoxStyle.DropDown; //100ms
    cb.DropDownStyle = ComboBoxStyle.DropDownList; //0ms(默认属性,等于没改)
    cb.DropDownStyle = ComboBoxStyle.Simple; //20ms由上时间可知时间花费应与下拉列表有关,仅仅是允许编辑花费的时间固定为20ms,其他时间用于下拉列表重新生成?Items内容并没有变更,有何办法避免这些时间花费?
      

  6.   


    using System; using WeifenLuo.WinFormsUI.Docking;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;namespace FisClient.NetborClass
    {
        class Netbor
        {
        }
        public class DataGridViewComboBoxExEditingControl : ComboBox, IDataGridViewEditingControl
        {
            protected int rowIndex;
            protected DataGridView dataGridView;
            protected bool valueChanged = false;        protected override void OnTextChanged(System.EventArgs e)
            {
                base.OnTextChanged(e);
                NotifyDataGridViewOfValueChange();        }        private void NotifyDataGridViewOfValueChange()
            {
                valueChanged = true;
                dataGridView.NotifyCurrentCellDirty(true);
            }
            protected override void OnSelectedIndexChanged(EventArgs e)
            {
                base.OnTextChanged(e);
                NotifyDataGridViewOfValueChange();
            }        public Cursor EditingPanelCursor
            {
                get { return Cursors.IBeam; }
            }        public DataGridView EditingControlDataGridView
            {
                get { return dataGridView; }
                set { dataGridView = value; }
            }        public object EditingControlFormattedValue
            {
                set
                {
                    Text = value.ToString();
                    NotifyDataGridViewOfValueChange();
                }
                get
                {
                    return this.Text;
                }        }        public virtual object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
            {
                return Text;        }        public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
            {            switch (key & Keys.KeyCode)
                {
                    case Keys.Left:
                    case Keys.Up:
                    case Keys.Down:
                    case Keys.Right:
                    case Keys.Home:
                    case Keys.End:
                    case Keys.Escape:
                    case Keys.Enter:
                    case Keys.PageDown:
                    case Keys.PageUp:
                        return true;
                    default:
                        return false;
                }
            }        public void PrepareEditingControlForEdit(bool selectAll)
            {
                if (selectAll)
                {
                    SelectAll();
                }
                else
                {
                    this.SelectionStart = this.ToString().Length;
                }
            }
            public virtual bool RepositionEditingControlOnValueChange
            {
                get
                {
                    return false;
                }
            }        public int EditingControlRowIndex
            {
                get { return this.rowIndex; }
                set { this.rowIndex = value; }
            }        public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
            {
                this.Font = dataGridViewCellStyle.Font;
                this.ForeColor = dataGridViewCellStyle.ForeColor;
                this.BackColor = dataGridViewCellStyle.BackColor;
            }        public bool EditingControlValueChanged
            {
                get { return valueChanged; }
                set { this.valueChanged = value; }
            }
        }    //定制该扩展列的单元格
        public class DataGridViewComboBoxExCell : DataGridViewTextBoxCell
        {
            public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
            {
                base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);            DataGridViewComboBoxExEditingControl clt = DataGridView.EditingControl as DataGridViewComboBoxExEditingControl;            DataGridViewComboBoxExColumn col = (DataGridViewComboBoxExColumn)OwningColumn;            clt.DataSource = col.DataSource;
                clt.DisplayMember = col.DisplayMember;
                clt.ValueMember = col.ValueMember;            clt.Text = Convert.ToString(this.Value);
            }        public override Type EditType
            {
                get
                {
                    return typeof(DataGridViewComboBoxExEditingControl);
                }
            }        public override Type ValueType
            {
                get
                {
                    return typeof(string);
                }
            }        public override object DefaultNewRowValue
            {
                get
                {
                    return "";
                }
            }
        }    //定制该扩展列
        public class DataGridViewComboBoxExColumn : DataGridViewColumn
        {
            private object dataSoruce = null;        public object DataSource
            {
                get 
                { 
                    return dataSoruce; 
                }
                set 
                { 
                    dataSoruce = value; 
                }
            }
            private string valueMember;        public string ValueMember
            {
                get 
                { 
                    return valueMember;
                }
                set 
                { 
                    valueMember = value; 
                }
            }
            private string displayMember;        public string DisplayMember
            {
                get 
                { 
                    return displayMember; 
                }
                set 
                { 
                    displayMember = value; 
                }
            }        public DataGridViewComboBoxExColumn() : base(new DataGridViewComboBoxExCell())
            {        }        public override DataGridViewCell CellTemplate
            {
                get
                {
                    return base.CellTemplate;
                }
                set
                {
                    if (value != null && !value.GetType().IsAssignableFrom(typeof(DataGridViewComboBoxExCell)))
                    {
                        throw new InvalidCastException("is not DataGridViewComboxExCell");
                    }
                    base.CellTemplate = value;
                }
            }
            private DataGridViewComboBoxExCell ComboBoxCellTemplate
            {
                get
                {
                    return (DataGridViewComboBoxExCell)this.CellTemplate;
                }
            }
        }
        //另一个Combox
        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.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;
                }
            }
        }    public class DataGridViewComboEditBoxColumn : DataGridViewComboBoxColumn
        {
            public DataGridViewComboEditBoxColumn()
            {
                DataGridViewComboEditBoxCell obj = new DataGridViewComboEditBoxCell();
                this.CellTemplate = obj;
            }
        }
    }