Part 1 先列出下拉列表框与按钮的类代码:
a. DataGridComboBoxColumn
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace BookingCar.SubSystem
{
// Step 1. Derive a custom column style from DataGridTextBoxColumn
// a) add a ComboBox member
// b) track when the combobox has focus in Enter and Leave events
// c) override Edit to allow the ComboBox to replace the TextBox
// d) override Commit to save the changed data
public class DataGridComboBoxColumn : DataGridTextBoxColumn
{
public NoKeyUpCombo ColumnComboBox;
private System.Windows.Forms.CurrencyManager _source;
private int _rowNum;
private bool _isEditing;
public static int _RowCount;
public DataGridComboBoxColumn() : base()
{
_source = null;
_isEditing = false;
_RowCount = -1;
ColumnComboBox = new NoKeyUpCombo();
ColumnComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
ColumnComboBox.Leave += new EventHandler(LeaveComboBox);
// ColumnComboBox.Enter += new EventHandler(ComboMadeCurrent);
ColumnComboBox.SelectionChangeCommitted += new EventHandler(ComboStartEditing);
}
private void ComboStartEditing(object sender, EventArgs e)
{
_isEditing = true;
base.ColumnStartedEditing((Control) sender);
}
private void HandleScroll(object sender, EventArgs e)
{
if(ColumnComboBox.Visible)
ColumnComboBox.Hide();
}
// private void ComboMadeCurrent(object sender, EventArgs e)
// {
// _isEditing = true;
// }
//
private void LeaveComboBox(object sender, EventArgs e)
{
if(_isEditing)
{
SetColumnValueAtRow(_source, _rowNum, ColumnComboBox.Text);
_isEditing = false;
Invalidate();
}
ColumnComboBox.Hide();
this.DataGridTableStyle.DataGrid.Scroll -= new EventHandler(HandleScroll);
}
protected override void Edit(System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
{
base.Edit(source,rowNum, bounds, readOnly, instantText , cellIsVisible);
_rowNum = rowNum;
_source = source;
ColumnComboBox.Parent = this.TextBox.Parent;
ColumnComboBox.Location = this.TextBox.Location;
ColumnComboBox.Size = new Size(this.TextBox.Size.Width, ColumnComboBox.Size.Height);
ColumnComboBox.SelectedIndex = ColumnComboBox.FindStringExact(this.TextBox.Text);
ColumnComboBox.Text = this.TextBox.Text;
this.TextBox.Visible = false;
ColumnComboBox.Visible = true;
this.DataGridTableStyle.DataGrid.Scroll += new EventHandler(HandleScroll);
ColumnComboBox.BringToFront();
ColumnComboBox.Focus();
}
protected override bool Commit(System.Windows.Forms.CurrencyManager dataSource, int rowNum)
{
if(_isEditing)
{
_isEditing = false;
SetColumnValueAtRow(dataSource, rowNum, ColumnComboBox.Text);
}
return true;
}
protected override void ConcedeFocus()
{
Console.WriteLine("ConcedeFocus");
base.ConcedeFocus();
}
protected override object GetColumnValueAtRow(System.Windows.Forms.CurrencyManager source, int rowNum)
{
object s = base.GetColumnValueAtRow(source, rowNum);
DataView dv = (DataView)this.ColumnComboBox.DataSource;
int rowCount = dv.Count;
int i = 0;
//if things are slow, you could order your dataview
//& use binary search instead of this linear one
while (i < rowCount)
{
if( s.Equals( dv[i][this.ColumnComboBox.ValueMember]))
break;
++i;
}
if(i < rowCount)
return dv[i][this.ColumnComboBox.DisplayMember];
return DBNull.Value;
}
protected override void SetColumnValueAtRow(System.Windows.Forms.CurrencyManager source, int rowNum, object value)
{
object s = value;
DataView dv = (DataView)this.ColumnComboBox.DataSource;
int rowCount = dv.Count;
int i = 0;
//if things are slow, you could order your dataview
//& use binary search instead of this linear one
while (i < rowCount)
{
if( s.Equals( dv[i][this.ColumnComboBox.DisplayMember]))
break;
++i;
}
if(i < rowCount)
s = dv[i][this.ColumnComboBox.ValueMember];
else
s = DBNull.Value;
base.SetColumnValueAtRow(source, rowNum, s);
}
}
public class NoKeyUpCombo : ComboBox
{
private const int WM_KEYUP = 0x101;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if(m.Msg == WM_KEYUP)
{
//ignore keyup to avoid problem with tabbing & dropdownlist;
return;
}
base.WndProc(ref m);
}
}
}
b.DataGridButtonColumn
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace BookingCar.SubSystem
{
" 左面显示字段值,右面显示按钮"#region " 左面显示字段值,右面显示按钮"
public class DataGridTextButtonColumn : DataGridTextBoxColumn
{
public event DataGridCellButtonClickEventHandler CellButtonClicked;
private Bitmap _buttonFace;
private Bitmap _buttonFacePressed;
private int _columnNum;
private int _pressedRow;
public DataGridTextButtonColumn(int colNum)
{
_columnNum = colNum;
_pressedRow = -1;
try
{
System.IO.Stream strm = this.GetType().Assembly.GetManifestResourceStream("BookingCar.SubSystem.fullbuttonface.bmp");
_buttonFace = new Bitmap(strm);
strm = this.GetType().Assembly.GetManifestResourceStream("BookingCar.SubSystem.fullbuttonfacepressed.bmp");
_buttonFacePressed = new Bitmap(strm);
}
catch(Exception e)
{
string err=e.Message;
}
}
protected override void Edit(System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
{
// dont call the baseclass so no editing done
// base.Edit(source, rowNum, bounds, readOnly, instantText, cellIsVisible);
}
public void HandleMouseUp(object sender, MouseEventArgs e)
{
DataGrid dg = this.DataGridTableStyle.DataGrid;
DataGrid.HitTestInfo hti = dg.HitTest(new Point(e.X, e.Y));
bool isClickInCell = hti.Column == this._columnNum && hti.Row > -1;
_pressedRow = -1;
Rectangle rect = new Rectangle(0,0,0,0);
if(isClickInCell)
{
rect = dg.GetCellBounds(hti.Row, hti.Column);
isClickInCell = (e.X > rect.Right - this._buttonFace.Width);
}
if(isClickInCell)
{
Graphics g = Graphics.FromHwnd(dg.Handle);
g.DrawImage(this._buttonFace, rect.Right - this._buttonFace.Width, rect.Y);
g.Dispose();
if(CellButtonClicked != null)
CellButtonClicked(this, new DataGridCellButtonClickEventArgs(hti.Row, hti.Column));
}
}
public void HandleMouseDown(object sender, MouseEventArgs e)
{
DataGrid dg = this.DataGridTableStyle.DataGrid;
DataGrid.HitTestInfo hti = dg.HitTest(new Point(e.X, e.Y));
bool isClickInCell = hti.Column == this._columnNum && hti.Row > -1;
Rectangle rect = new Rectangle(0,0,0,0);
if(isClickInCell)
{
rect = dg.GetCellBounds(hti.Row, hti.Column);
isClickInCell = (e.X > rect.Right - this._buttonFace.Width);
}
if(isClickInCell)
{
//Console.WriteLine("HandleMouseDown " + hti.Row.ToString());
Graphics g = Graphics.FromHwnd(dg.Handle);
g.DrawImage(this._buttonFacePressed, rect.Right - this._buttonFacePressed.Width, rect.Y);
g.Dispose();
_pressedRow = hti.Row;
}
}
protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush foreBrush, bool alignToRight)
{
//base.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);
DataGrid parent = this.DataGridTableStyle.DataGrid;
bool current = parent.IsSelected(rowNum) ||
( parent.CurrentRowIndex == rowNum &&
parent.CurrentCell.ColumnNumber == this._columnNum);
Color BackColor = current ? parent.SelectionBackColor : parent.BackColor;
Color ForeColor = current ? parent.SelectionForeColor : parent.ForeColor;
//clear the cell
g.FillRectangle(new SolidBrush(BackColor), bounds);
//draw the value
string s = this.GetColumnValueAtRow(source, rowNum).ToString();//parent[rowNum, 0].ToString() + ((parent[rowNum, 1].ToString())+ " ").Substring(0,2);
//Font font = new Font("Arial", 8.25f);
//g.DrawString(s, font, new SolidBrush(Color.Black), bounds);
g.DrawString(s, parent.Font, new SolidBrush(ForeColor), bounds);
//draw the button
Bitmap bm = _pressedRow == rowNum ? this._buttonFacePressed : this._buttonFace;
g.DrawImage(bm, bounds.Right - bm.Width, bounds.Y);
//font.Dispose();
}
}
#endregion
GridCellButton click event#region GridCellButton click event
public delegate void DataGridCellButtonClickEventHandler(object sender, DataGridCellButtonClickEventArgs e);
public class DataGridCellButtonClickEventArgs : EventArgs
{
private int _row;
private int _col;
public DataGridCellButtonClickEventArgs(int row, int col)
{
_row = row;
_col = col;
}
public int RowIndex {get{return _row;}}
public int ColIndex {get{return _col;}}
}
#endregion
" 只显示按钮,且按钮大小随DataGrid的Cell变化"#region " 只显示按钮,且按钮大小随DataGrid的Cell变化"
public class DataGridButtonColumn : DataGridTextBoxColumn
{
public event DataGridCellButtonClickEventHandler CellButtonClicked;
private Bitmap _buttonFace;
private Bitmap _buttonFacePressed;
private int _columnNum;
private int _pressedRow;
public DataGridButtonColumn(int colNum)
{
_columnNum = colNum;
_pressedRow = -1;
try
{
System.IO.Stream strm = this.GetType().Assembly.GetManifestResourceStream("BookingCar.SubSystem.fullbuttonface.bmp");
_buttonFace = new Bitmap(strm);
strm = this.GetType().Assembly.GetManifestResourceStream("BookingCar.SubSystem.fullbuttonfacepressed.bmp");
_buttonFacePressed = new Bitmap(strm);
}
catch
{
}
}
protected override void Edit(System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
{
// dont call the baseclass so no editing done
// base.Edit(source, rowNum, bounds, readOnly, instantText, cellIsVisible);
}
private void DrawButton(Graphics g, Bitmap bm, Rectangle bounds, int row)
{
DataGrid dg = this.DataGridTableStyle.DataGrid;
string s = dg[row, this._columnNum].ToString();
SizeF sz = g.MeasureString(s, dg.Font, bounds.Width - 4, StringFormat.GenericTypographic);
int x = bounds.Left + Math.Max(0, (bounds.Width - (int)sz.Width)/2);
g.DrawImage(bm, bounds, 0, 0, bm.Width, bm.Height,GraphicsUnit.Pixel);
if(sz.Height < bounds.Height)
{
int y = bounds.Top + (bounds.Height - (int) sz.Height) / 2;
if(_buttonFacePressed == bm)
{
x++;
}
g.DrawString(s, dg.Font, new SolidBrush(dg.ForeColor), x, y);
}
}
public void HandleMouseUp(object sender, MouseEventArgs e)
{
DataGrid dg = this.DataGridTableStyle.DataGrid;
DataGrid.HitTestInfo hti = dg.HitTest(new Point(e.X, e.Y));
bool isClickInCell = (hti.Column == this._columnNum
&& hti.Row > -1);
_pressedRow = -1;
Rectangle rect = new Rectangle(0,0,0,0);
if(isClickInCell)
{
rect = dg.GetCellBounds(hti.Row, hti.Column);
isClickInCell = (e.X > rect.Right - this._buttonFace.Width);
}
if(isClickInCell)
{
Graphics g = Graphics.FromHwnd(dg.Handle);
// g.DrawImage(this._buttonFace, rect.Right - this._buttonFace.Width, rect.Y);
DrawButton(g, this._buttonFace, rect, hti.Row);
g.Dispose();
if(CellButtonClicked != null)
CellButtonClicked(this, new DataGridCellButtonClickEventArgs(hti.Row, hti.Column));
}
}
public void HandleMouseDown(object sender, MouseEventArgs e)
{
DataGrid dg = this.DataGridTableStyle.DataGrid;
DataGrid.HitTestInfo hti = dg.HitTest(new Point(e.X, e.Y));
bool isClickInCell = (hti.Column == this._columnNum
&& hti.Row > -1);
Rectangle rect = new Rectangle(0,0,0,0);
if(isClickInCell)
{
rect = dg.GetCellBounds(hti.Row, hti.Column);
isClickInCell = (e.X > rect.Right - this._buttonFace.Width);
}
if(isClickInCell)
{
//Console.WriteLine("HandleMouseDown " + hti.Row.ToString());
Graphics g = Graphics.FromHwnd(dg.Handle);
//g.DrawImage(this._buttonFacePressed, rect.Right - this._buttonFacePressed.Width, rect.Y);
DrawButton(g, _buttonFacePressed, rect, hti.Row);
g.Dispose();
_pressedRow = hti.Row;
}
}
protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle bounds, System.Windows.Forms.CurrencyManager source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush foreBrush, bool alignToRight)
{
//base.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);
DataGrid parent = this.DataGridTableStyle.DataGrid;
bool current = parent.IsSelected(rowNum) ||
( parent.CurrentRowIndex == rowNum &&
parent.CurrentCell.ColumnNumber == this._columnNum);
//draw the button
Bitmap bm = _pressedRow == rowNum ? this._buttonFacePressed : this._buttonFace;
this.DrawButton(g, bm, bounds, rowNum);
//font.Dispose();
}
}
#endregion
}
Part 2 添加上述b的代码时,需要添加两个bmp文件。如下,添加后要设置“生成操作”为“嵌入的资源”。
。
Part 3 使用上述两个类,在WinForm中添加一个DataGrid控件。
private void Form4_Load(object sender, System.EventArgs e)
{
DataSet dsOrder=Order.OrderForDisp("","","","","","");
DataSet dsOrderStatus=Order.QueryAllOrderStatus();
dataGrid1.DataSource=dsOrder.Tables[0];
DataGridTableStyle tableStyle = new DataGridTableStyle();
tableStyle.MappingName = dsOrder.Tables[0].TableName;
//第一列 订单号
DataGridTextBoxColumn TextCol = new DataGridTextBoxColumn();
TextCol.MappingName = "order_no"; //列名
TextCol.HeaderText = "订单号";
tableStyle.GridColumnStyles.Add(TextCol); //为TableStyle添加列
//第二列 订单状态
DataGridComboBoxColumn ComboTextCol = new DataGridComboBoxColumn();
ComboTextCol.MappingName = dsOrderStatus.Tables[0].TableName; //DataSet中的相应DataTable名称
ComboTextCol.HeaderText="订单状态";
ComboTextCol.Alignment=HorizontalAlignment.Center;
ComboTextCol.Width = 100;
ComboTextCol.ColumnComboBox.DataSource =dsOrderStatus.Tables[0].DefaultView;//必须用DataView
ComboTextCol.ColumnComboBox.DisplayMember = "status_descr";//要显示的字段名
ComboTextCol.ColumnComboBox.ValueMember = "status_id";//值的字段名
//tableStyle.PreferredRowHeight = ComboTextCol.ColumnComboBox.Height + 2;
tableStyle.GridColumnStyles.Add(ComboTextCol); //为TableStyle添加列
//第三列 提交按钮
DataGridButtonColumn textButtonColStyle = new DataGridButtonColumn(2); //参数指名列数,从0开始
textButtonColStyle.MappingName = "button"; //对应字段名称或别名
textButtonColStyle.HeaderText = "动作"; //列头名称
//与点击按钮后的事件关联
textButtonColStyle.CellButtonClicked +=
new DataGridCellButtonClickEventHandler(HandleCellButtonClick);
tableStyle.GridColumnStyles.Add(textButtonColStyle); //为TableStyle添加列
//添加鼠标事件,使得按钮可以被点击
dataGrid1.MouseDown += new MouseEventHandler(textButtonColStyle.HandleMouseDown);
dataGrid1.MouseUp += new MouseEventHandler(textButtonColStyle.HandleMouseUp);
//为DataGrid指定TableStyle
dataGrid1.TableStyles.Clear();
dataGrid1.TableStyles.Add(tableStyle);
}
//按钮事件处理函数:取出两列内容
private void HandleCellButtonClick(object sender, DataGridCellButtonClickEventArgs e)
{
string order_no=this.dataGrid1[e.RowIndex,0].ToString();
string order_status=this.dataGrid1[e.RowIndex,1].ToString();
MessageBox.Show("order_no:" + order_no + " order_status:" + order_status + ".");
}
Part 4 既然绑定按钮,意味着按钮上的标题是从数据库查询的,所以查询语句包括类似下面的内容:select ... '提交' as 'button' from ...