控件
Datagrid是由多个表(table)组成的,table是由行(row)与列(column)组成的,行与列的交互,组成的一个个单元(cell)。我们的需要就是能控制每一个cell的变化,从而使row与column发生变化,最终形成table的变化。这每一种变化都可视为是Datagrid中table的一种风格格式(style)。
我们在往form上部署Datagrid控件后,会在其属性窗口下方会出现“自动套用格式”,它们的变化多是背景色(Backcolor)与前景色(Forecolor)与字体(Font)的变化。经过本文的讲述后,您将能够实现更多的格式变化。
平常所看到的默认结构Datagrid,即把DatagridColumnStyle设定为DatagridTextBoxColumn列结构,把datagrid的列设为由textbox组成。从而我们就可以看到的那种效果就是每一个cell里都是一个textbox。同理,我们就知道如果把某一列的DatagridColumnStyle设定为DatagridBoolColumn列结构,就可以在该列中用checkbox控件显示与更改boolean类型的值了。我们甚至可以自定义某一列的列类型,加入combox等等.。
要实现创建一个列类,应该很好地再次研究一下DataGridTextBoxColumn类,并据此相似的创建一个新类,本次示例是要创建一个具有下拉框的列,因此,它应该与DataGridTextBoxColumn类是同级的,也就是说它们应该是从同个父类派生出来的,这样才可以在保证在使用上的相似性与一致性。
我们可以方便的了解到下拉框列的处理过程,在平常状况下,colboBox列中的cell还是以textbox的形式进行显示的,下拉框的出现是被textbox中落入焦点才激发的,而后,该cell就是一个实实在在的下拉框了,当焦点离开该cell后,cell又恢复成一个textbox的模样了。
正式要开工了,先理一下思路,我们要做些什么事:
(1)     从DataGridTextBoxColumn类的父类DataGridColumnStyle继承一个自定义列类:DataGridComboBoxColumn;
(2)     在列中加入一个ComboBox实例,用于聚焦后的出现,与DataGridTextBoxColumn类使用的textbox所属的DataGridTextBox类相似的,我们应该设计一个专用的combobox类提供给DataGridComboBoxColumn类使用。
(3)     跟踪cell的状态,当聚焦时在textbox的外面添加一个combobox,失去焦点后隐藏起combobox,恢复成textbox模样;
(4)    重写父类的Edit与Paint方法,以适应Combobox的使用,在Edit中将Combobox中产生的(用户输入或在下拉框中选择)变化记录入cell中,这也便于在更改后更新到相关的数据源中去。
现在来了解一下DataGridComboBox的运行机制。当第一次加载数据的时候,comboBox根据ValueMember绑定vaule,DisplayMember则绑定为text显示给大家看。ComboBoxColumn的显示则通过DataGrid的source和rowNum来决定,也就是将cell中的内容通过GetComboBoxText进行转换然后paint显示。为什么只需要source和rowNum来决定呢?那是因为DataGrid能够自动记录列号。

代码如下:
DataGridComboBox.cs
程序代码: [ 复制代码 ] [ 运行代码 ] 
using System;
using System.Windows.Forms;

namespace DataGridComboBoxColumn
{
    /// <summary>
    /// DataGridComboBox 的摘要说明。
    /// </summary>
    public class DataGridComboBox:ComboBox
    {
        private const int WM_KEYUP = 0x101;

        protected override void WndProc(ref System.Windows.Forms.Message message) 
        {            
            if (message.Msg == WM_KEYUP) 
            {
                return;
            }

            base.WndProc(ref message);
        } 

        //通过索引取得items的value。
        public string GetValueText(int index)
        {
            if(index < 0 || index >= base.Items.Count)
            {
                //抛出索引超出异常
                throw new IndexOutOfRangeException("无效索引。");
            }
            else
            {
                string text = string.Empty;
                int memIndex =  -1;
                try
                {
                    base.BeginUpdate();
                    memIndex = base.SelectedIndex;
                    base.SelectedIndex = index;
                    text = base.SelectedValue.ToString();
                    base.SelectedIndex = memIndex;
                }
                catch
                {}
                finally
                {
                    base.EndUpdate();
                }
                return text;
            }            
        }


        //通过索引取得items的text        
        public string GetDisplayText(int index)
        {
            if(index <0 || index >=base.Items.Count)
            {
                //抛出索引超出异常
                throw new IndexOutOfRangeException("无效索引。");
            }
            else
            {
                string text = string.Empty;
                int memIndex = -1;
                try
                {
                    base.BeginUpdate();
                    memIndex = base.SelectedIndex;
                    base.SelectedIndex = index;
                    text = base.Text.ToString();
                    base.SelectedIndex = memIndex;
                }
                catch
                {}
                finally
                {
                    base.EndUpdate();
                }
                return text;
            }
        }


        //通过value取得items的text
        public string GetDisplayText(object value)
        {            
            string text = string.Empty;
            int memIndex= -1;
            try
            {
                base.BeginUpdate();
                memIndex = base.SelectedIndex;
                base.SelectedValue = value.ToString();
                text = base.Text.ToString();                
                base.SelectedIndex = memIndex;
            }
            catch
            {}
            finally
            {
                base.EndUpdate();
            }
            return text;
        }


        //循环获取items的text
        public string[] GetDisplayText()
        {
            string[] text = new string[base.Items.Count];
            int memIndex = -1;
            try
            {
                base.BeginUpdate();
                memIndex = base.SelectedIndex;
                for(int i=0;i<base.Items.Count;i++)
                {
                    base.SelectedIndex = i;
                    text[i] = base.Text.ToString();                    
                }
                base.SelectedIndex = memIndex;
            }
            catch
            {}
            finally
            {
                base.EndUpdate();
            }
            return text;
        }
    }

}



DataGridComboBoxColumn.cs

程序代码: [ 复制代码 ] [ 运行代码 ] 
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace DataGridComboBoxColumn
{
    /// <summary>
    /// DataGridComboBoxColumn 的摘要说明。
    /// </summary>
    public class DataGridComboBoxColumn : DataGridColumnStyle
    {

        private DataGridComboBox m_comboBox;
        private bool m_edit;
        public DataGridComboBoxColumn()
        {
            this.m_comboBox = new DataGridComboBox();
            this.m_comboBox.Visible = false;
            this.m_comboBox.DropDownStyle = ComboBoxStyle.DropDownList;            
            this.m_comboBox.Leave +=new EventHandler(m_comboBox_Leave);
            this.m_comboBox.SelectionChangeCommitted +=new EventHandler(m_comboBox_SelectedIndexChanged);
            this.m_edit = false;
        }

        

        public ComboBox comboBox
        {
            get
            {
                return m_comboBox;
            }
        }


        //comboBox事件
        //失去焦点后comboBox隐藏
        private void m_comboBox_Leave(object sender,EventArgs e)
        {
            this.m_comboBox.Hide();
        }

        //选定项发生更改并提交更改通知用户开始编辑列
        private void m_comboBox_SelectedIndexChanged(object sender,EventArgs e)
        {
            this.m_edit = true;
            base.ColumnStartedEditing((Control)sender);
        }

        //重写DataGridColunmStyle
        protected override void SetDataGridInColumn(DataGrid value)
        {
            //将comboBox加入到DataGrid控件集合中
            //确保正确的DataGrid scrolling
            value.Controls.Add(this.m_comboBox);
            base.SetDataGridInColumn (value);
        }


        //当 DataGridColumnStyle 方法的 Commit 方法返回 false 时,Abort 方法被 DataGrid 使用。
        //在这种情况下,列值滚动回原先的值。
        //在返回之前,DataGridColumnStyle 必须结束所有编辑操作。使用 Abort 方法来实现该操作。
        //System.Windows.Forms.DataGrid 控件的 EndEdit 方法间接调用 Abort(如果其 ShouldAbort 参数设置为 true)。
        protected override void Abort(int rowNum)
        {
            this.m_edit=false;
            Invalidate();
            this.m_comboBox.Hide();
        }


        //准备单元格以便进行编辑。
        protected override void Edit(CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
        {
            this.m_comboBox.Parent = this.DataGridTableStyle.DataGrid;
            this.m_comboBox.Bounds = bounds;
            this.m_comboBox.Size = new System.Drawing.Size(this.Width,this.comboBox.Height);
            this.m_comboBox.SelectedValue = base.GetColumnValueAtRow(source,rowNum).ToString();
            this.m_comboBox.Visible = (!readOnly) && cellIsVisible;
            this.m_comboBox.BringToFront();
            this.m_comboBox.Focus();
        }


        
        //如果编辑过程成功提交,则为 true;否则为 false。
        protected override bool Commit(CurrencyManager dataSource, int rowNum)
        {
            if(this.m_edit==true)
            {
                this.m_edit = false;
                //保存值
                this.SetColumnValueAtRow(dataSource, rowNum, this.m_comboBox.SelectedValue);
            }
            return true;
        }


        //获取指定 CurrencyManager 中指定行内的值。
        protected override object GetColumnValueAtRow(CurrencyManager source, int rowNum)
        {
            //return base.GetColumnValueAtRow (source, rowNum);
            return this.m_comboBox.GetDisplayText(base.GetColumnValueAtRow(source,rowNum));
        }


        //用来自指定 CurrencyManager 的值设置指定行中的值。
        protected override void SetColumnValueAtRow(CurrencyManager source, int rowNum, object value)
        {
            try
            {
                base.SetColumnValueAtRow (source, rowNum, value.ToString());
                return;
            }
            catch
            {}
            //下面是另外一种方法,对于使用GUID全局唯一标识符有效
            try
            {
                base.SetColumnValueAtRow (source, rowNum, new Guid(value.ToString()));
                return;
            }
            catch
            {}
        }


        protected override int GetMinimumHeight()
        {
            return this.m_comboBox.PreferredHeight+2;
        }
                    

        //在派生类中被重写时,将获取自动调整列的大小所用的高度。
        protected override int GetPreferredHeight(System.Drawing.Graphics g, object value)
        {
            return FontHeight + 2 ;
        }

        //在派生类中被重写时,将获取指定值的宽度和高度。
        //在用户定位到使用 DataGridColumnStyle 的 DataGridTableStyle 时将使用该宽度和高度。
        protected override System.Drawing.Size GetPreferredSize(System.Drawing.Graphics g, object value)
        {
            //return new System.Drawing.Size ();
            int widths = 0;
            SizeF strF = new SizeF(0,0);
            foreach (string str in this.m_comboBox.GetDisplayText())
            {
                strF = g.MeasureString(str, base.DataGridTableStyle.DataGrid.Font);
                if(strF.Width > widths)
                {
                    widths = (int)Math.Ceiling(strF.Width);///////////////////////////////////////////////////////////////////////////////////////////////////////
                }
            }
            return new System.Drawing.Size (widths +25,this.m_comboBox.PreferredHeight+2);
        }


        //绘制具有指定 Graphics、Rectangle、CurrencyManager 和行号的 DataGridColumnStyle。
        protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, CurrencyManager source, int rowNum)
        {
            //绘制具有指定 Graphics、Rectangle、CurrencyManager、行号和对齐方式的 DataGridColumnStyle。
            Paint(g, bounds, source, rowNum, false);
        }


        //绘制具有指定 Graphics、Rectangle、CurrencyManager、行号、背景色、前景色和对齐方式的 DataGridColumnStyle。
        protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, CurrencyManager source, int rowNum, bool alignToRight)
        {
            //string text = this.GetColumnValueAtRow(source,rowNum).ToString();
            string text = GetColumnValueAtRow(source,rowNum).ToString();
            Brush backBrush = new SolidBrush(base.DataGridTableStyle.BackColor);
            Brush foreBrush    = new SolidBrush(base.DataGridTableStyle.ForeColor);
            Rectangle rect = bounds;
            StringFormat format    = new StringFormat();

            // 单元格被选中
            if (base.DataGridTableStyle.DataGrid.IsSelected(rowNum) == true) 
            {
                backBrush = new SolidBrush(base.DataGridTableStyle.SelectionBackColor);
                foreBrush = new SolidBrush(base.DataGridTableStyle.SelectionForeColor);
            }
            if (alignToRight == true) 
            {
                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;
            }
            // Paint.
            format.FormatFlags = StringFormatFlags.NoWrap;
            g.FillRectangle(backBrush, rect);
            rect.Offset(0, 0);
            rect.Height = 0;
            g.DrawString(text,this.DataGridTableStyle.DataGrid.Font, foreBrush, rect, format);
            format.Dispose();
        }


    }
}



private void DispDgList()
程序代码: [ 复制代码 ] [ 运行代码 ] 
private void DispDgList()
        {
            //创建一个新的DataGrid表格样式
            DataGridTableStyle ts = new DataGridTableStyle();
            ts.MappingName = this.DsBook.Tables[0].TableName;
            //创建一个ComboBox控件的列
            DataGridComboBoxColumn.DataGridComboBoxColumn cboCol = null;
            //创建一个textBox控件的列
            DataGridTextBoxColumn txtCol= null;

            //计算列数
            int numCols=this.DsBook.Tables[0].Columns.Count;

            for (int i=0;i<numCols;i++)
            {
                if(this.DsBook.Tables[0].Columns[i].ColumnName.Equals("studentid"))
                {
                    cboCol = new DataGridComboBoxColumn.DataGridComboBoxColumn();                    
                    cboCol.comboBox.DataSource = this.DsStudent.Tables[0];
                    cboCol.comboBox.DisplayMember = "name";
                    cboCol.comboBox.ValueMember = "studentid";
                    cboCol.HeaderText = "student";
                    cboCol.MappingName =  "studentid";                    
                    ts.GridColumnStyles.Add(cboCol);
                }
                else
                {
                    txtCol = new DataGridTextBoxColumn();
                    txtCol.HeaderText = this.DsBook.Tables[0].Columns[i].ColumnName;
                    txtCol.MappingName = this.DsBook.Tables[0].Columns[i].ColumnName;    
                    ts.GridColumnStyles.Add(txtCol);
                }
            }
            this.dataGrid1.TableStyles.Clear();
            this.dataGrid1.TableStyles.Add(ts);
            this.dataGrid1.DataSource = this.DsBook.Tables[0];
            this.dataGrid1.CaptionText = "book";
        }

 

 


posted on 2006-07-20 11:56  阿米  阅读(2336)  评论(0编辑  收藏  举报