需求: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#是否能实现?
实现方法:将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#是否能实现?
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;
}
一般使用这个
以前好像写过一个DataGrid(VS03)版本的下拉框组件,并没什么明显刷新的现象啊。
貌似 SelectIndexChanged 比 EditingControlShowing早触发,实际运行效果是从一个TextBox列改选到ComboBox列不触发SelectIndexChanged ,要在ComboBox里切换单元格才会有效果。
我换用了Enter事件,结果每次进入(鼠标单击或设置为CurrentCell)都会触发两次,有延迟。
经过多次断点测试分析发现: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();
}
确实,经测试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内容并没有变更,有何办法避免这些时间花费?
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;
}
}
}