我的开发环境是VS2003。DataGrid嵌入ComboBox列,我一直用《Visual C#.NET 数据库开发经典案例解析》(王晟编著_清华出版)提供的DataGridComboBoxColumn类来实现,这个类可以实现ComboBox用DataTable的列作DisplayMember、ValueMember。但是它有个bug:DataTable中不同类型的列作DisplayMember、ValueMember,运行时操作ComboBox就要报错,比如DataTable中name列(字符型)作DisplayMember,ID列(整数型)作ValueMember,运行时操作ComboBox就要报错。大家有好的DataGrid嵌入ComboBox列的类吗?要求是没有上述的bug。
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Data;
namespace 管理系统
{
public class DataGridComboBox:ComboBox
{
// 继承下拉列表框类
public DataGridComboBox()
{
//this.DropDownStyle = ComboBoxStyle.DropDownList;
}
private void InitializeComponent()
{ }
}
public class DataGridComboBoxColumn:DataGridColumnStyle
{
//在dataGrid中创建一个下拉列表框,dataGrid中的这一列都拥有相同的下拉选项
private int xMargin = 2;
private int yMargin = 1;
private DataGridComboBox Combo;
private string _DisplayMember;
private string _ValueMember;
//获取编辑状态
private string OldVal=new string(string.Empty.ToCharArray());
private bool InEdit= false;
// 根据顺序号建立一个新的下拉列
public DataGridComboBoxColumn(DataTable DataSource, int DisplayMember,int ValueMember)
{
Combo = new DataGridComboBox();
_DisplayMember = DataSource.Columns[DisplayMember].ToString();
_ValueMember = DataSource.Columns[ValueMember].ToString();
Combo.Visible=false;
Combo.DataSource = DataSource;
Combo.DisplayMember = _DisplayMember;
Combo.ValueMember = _ValueMember;
Combo.DropDownStyle = ComboBoxStyle.DropDownList;
}
//根据字符串建立新的下拉列
public DataGridComboBoxColumn(DataView DataSource,string DisplayMember,string ValueMember,ComboBoxStyle comboboxstyle)
{
Combo = new DataGridComboBox();
Combo.Visible = false;
Combo.DataSource = DataSource;
Combo.DisplayMember = DisplayMember;
Combo.ValueMember = ValueMember;
Combo.DropDownStyle = comboboxstyle;
}
public DataGridComboBoxColumn(DataTable DataSource,string DisplayMember,string ValueMember,ComboBoxStyle comboboxstyle) :
this(DataSource.DefaultView,DisplayMember,ValueMember,comboboxstyle)
{
}
// 重写DataGridColumnStyle中的方法
// 重写Abort
protected override void Abort(int RowNum)
{
System.Diagnostics.Debug.WriteLine("Abort()");
RollBack();
HideComboBox();
EndEdit();
}
// 重写Commit
protected override bool Commit(CurrencyManager DataSource,int RowNum)
{
HideComboBox();
if(!InEdit)
{
return true;
}
try
{
//如果是: Combo.DropDownStyle = ComboBoxStyle.DropDownList;
//object Value = Combo.SelectedValue;
//如果是: Combo.DropDownStyle = ComboBoxStyle.DropDown;
object Value = Combo.Text;
if(NullText.Equals(Value))
{
Value = System.Convert.DBNull;
}
SetColumnValueAtRow(DataSource, RowNum, Value);
}
catch
{
RollBack();
return false;
}
this.EndEdit();
return true;
}
//移出焦点
protected override void ConcedeFocus()
{
Combo.Visible=false;
}
//重写编辑dataGrid的方法edit////////下面是出错的函数!!!!!!!
protected override void Edit(CurrencyManager Source ,int Rownum,Rectangle Bounds, bool ReadOnly,string InstantText, bool CellIsVisible)
{
Combo.Text = string.Empty;
Rectangle OriginalBounds = Bounds;
OldVal = Combo.Text;
if(CellIsVisible)
{
Bounds.Offset(xMargin, yMargin);
Bounds.Width -= xMargin * 2;
Bounds.Height -= yMargin;
Combo.Bounds = Bounds;
Combo.Visible = true;
}
else
{
Combo.Bounds = OriginalBounds;
Combo.Visible = false;
}
Combo.SelectedValue = GetText(GetColumnValueAtRow(Source, Rownum));////////下面是出错的地方!!!!!!!
if(InstantText!=null)
{
Combo.SelectedValue = InstantText;
}
Combo.RightToLeft = this.DataGridTableStyle.DataGrid.RightToLeft;
if(InstantText==null)
{
Combo.SelectAll();
}
else
{
int End = Combo.Text.Length;
Combo.Select(End, 0);
}
if(Combo.Visible)
{
DataGridTableStyle.DataGrid.Invalidate(OriginalBounds);
} InEdit = true;
}
protected override int GetMinimumHeight()
{
// 设置combobox的最小高度
return Combo.PreferredHeight + yMargin;
}
protected override int GetPreferredHeight(Graphics g ,object Value)
{
System.Diagnostics.Debug.WriteLine("GetPreferredHeight()");
int NewLineIndex = 0;
int NewLines = 0;
string ValueString = this.GetText(Value);
do
{
NewLineIndex = ValueString.IndexOf("r\n", NewLineIndex + 1);
NewLines += 1;
}while(NewLineIndex != -1);
return FontHeight * NewLines + yMargin;
}
protected override Size GetPreferredSize(Graphics g, object Value)
{
Size Extents = Size.Ceiling(g.MeasureString(GetText(Value), this.DataGridTableStyle.DataGrid.Font));
Extents.Width += xMargin * 2 + DataGridTableGridLineWidth ;
Extents.Height += yMargin;
return Extents;
}
protected override void Paint(Graphics g,Rectangle Bounds,CurrencyManager Source,int RowNum)
{
Paint(g, Bounds, Source, RowNum, false);
}
protected override void Paint(Graphics g,Rectangle Bounds,CurrencyManager Source,int RowNum,bool AlignToRight)
{
string Text = GetText(GetColumnValueAtRow(Source, RowNum));
PaintText(g, Bounds, Text, AlignToRight);
}
protected override void Paint(Graphics g,Rectangle Bounds,CurrencyManager Source,int RowNum,Brush BackBrush ,Brush ForeBrush ,bool AlignToRight)
{
string Text = GetText(GetColumnValueAtRow(Source, RowNum));
PaintText(g, Bounds, Text, BackBrush, ForeBrush, AlignToRight);
}
protected override void SetDataGridInColumn(DataGrid Value)
{
base.SetDataGridInColumn(Value);
if(Combo.Parent!=Value)
{
if(Combo.Parent!=null)
{
Combo.Parent.Controls.Remove(Combo);
}
}
if(Value!=null)
{
Value.Controls.Add(Combo);
}
}
protected override void UpdateUI(CurrencyManager Source,int RowNum, string InstantText)
{
Combo.Text = GetText(GetColumnValueAtRow(Source, RowNum));
if(InstantText!=null)
{
Combo.Text = InstantText;
}
}
private int DataGridTableGridLineWidth
{
get
{
if(this.DataGridTableStyle.GridLineStyle == DataGridLineStyle.Solid)
{
return 1;
}
else
{
return 0;
}
}
}
public void EndEdit()
{
InEdit = false;
Invalidate();
}
private string GetText(object Value)
{
if(Value==System.DBNull.Value)
{
return NullText;
}
if(Value!=null)
{
return Value.ToString();
}
else
{
return string.Empty;
}
}
private void HideComboBox()
{
if(Combo.Focused)
{
this.DataGridTableStyle.DataGrid.Focus();
}
Combo.Visible = false;
}
private void RollBack()
{
Combo.Text = OldVal;
//编辑结束
}
private void PaintText(Graphics g ,Rectangle Bounds,string Text,bool AlignToRight)
{
Brush BackBrush = new SolidBrush(this.DataGridTableStyle.BackColor);
Brush ForeBrush= new SolidBrush(this.DataGridTableStyle.ForeColor);
PaintText(g, Bounds, Text, BackBrush, ForeBrush, AlignToRight);
}
private void PaintText(Graphics g , Rectangle TextBounds, string Text, Brush BackBrush,Brush ForeBrush,bool AlignToRight)
{
Rectangle Rect = TextBounds;
RectangleF RectF = Rect;
StringFormat Format = new StringFormat();
if(AlignToRight)
{
Format.FormatFlags = StringFormatFlags.DirectionRightToLeft;
}
switch(this.Alignment)
{
case HorizontalAlignment.Left:
Format.Alignment = StringAlignment.Near;
break;
case HorizontalAlignment.Right:
Format.Alignment = StringAlignment.Far;
break;
case HorizontalAlignment.Center:
Format.Alignment = StringAlignment.Center;
break;
}
Format.FormatFlags =Format.FormatFlags;
Format.FormatFlags =StringFormatFlags.NoWrap;
g.FillRectangle(BackBrush, Rect);
Rect.Offset(0, yMargin);
Rect.Height -= yMargin;
g.DrawString(Text, this.DataGridTableStyle.DataGrid.Font, ForeBrush, RectF, Format);
Format.Dispose();
}
}
}
大家如有好的DataGrid嵌入ComboBox列的类发在这里可以,发到我邮箱:[email protected]也可以。
谢谢!!!!!
好象本身DataGridColumnStyle类都有BUG,所以几乎所有自定义的类似ComboBoxColumn的类,全都不合人意,包括微软自己也曾做过一个,就在.Net1.0或1.1中,具体哪个库我记不太清了,而且那个类在MSDN中可以查到,命名空间是Microsoft的下层,具体叫什么空间也记不清了,好象是和安全有关的一个命名空间中.实际上关于DataGrid微软已承认自己设计失败了,所以在2.0中推出了DataGridView,但为了顾全颜面,保留了DataGrid
推荐现成控件:Janus GridX!