我的开发环境是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。

解决方案 »

  1.   

    下面我列出这个类的源代码,并指出当DataTable中name列(字符型)作DisplayMember,ID列(整数型)作ValueMember,运行时操作报错的地方:using System.Collections;
    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;
    }
      

  2.   

    //续上贴
    //重写编辑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();
    }
    }
    }
      

  3.   

    出错的地方是DataGridComboBoxColumn类重载的Edit函数。
    大家如有好的DataGrid嵌入ComboBox列的类发在这里可以,发到我邮箱:[email protected]也可以。
    谢谢!!!!!
      

  4.   

    没有好的代码
    好象本身DataGridColumnStyle类都有BUG,所以几乎所有自定义的类似ComboBoxColumn的类,全都不合人意,包括微软自己也曾做过一个,就在.Net1.0或1.1中,具体哪个库我记不太清了,而且那个类在MSDN中可以查到,命名空间是Microsoft的下层,具体叫什么空间也记不清了,好象是和安全有关的一个命名空间中.实际上关于DataGrid微软已承认自己设计失败了,所以在2.0中推出了DataGridView,但为了顾全颜面,保留了DataGrid
      

  5.   


    推荐现成控件:Janus GridX!
      

  6.   

    电驴上有developer.exepress 2.24