一、效果图
实现功能:
n 码名转换[输入编码焦点离开后显示名称]。
n 下拉出带有DataGrid 的选取窗口。
n 背景窗口不失去焦点
二、 开发背景
看到N 多程序里都有这种类是功能、如PB 的下拉数据窗口、Delphi 也有同类的Grid
而 DotNet 的Grid 控件却没有这种功能、两个字“郁闷”、配合上一文中的一些经验和知识
很轻易的就可以搞出 类是的功能、在发文档回报csdn 的各位同僚、数行代码寥表我心
如果要转载文章情通知本人
QQ:65323574 Email:FlashElf@163.com
三、程序实现代码解析
说明:本文使用的 SystemShell 和 NoActForm 类在上一篇文章
“dotNet 桌面程序改造计划.下拉框篇.类似Word的颜色下拉框”中以有讲解这里不再重复。
地址:http://blog.csdn.net/flashelf/archive/2005/01/30/273954.aspx
3.1 DataGridVNTextColumnStyle 类
本文的最基础类[具有 码、名 转换功能]
using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Data; using System.Diagnostics;
namespace MagicLink.FlashElf.Windows.Controls.WinDataGrid.ColumnStyle { /// <summary> /// 以[码|名]方式显示的 DataGridColumnStyle /// 如: /// 输入 1 显示 男 /// 输入 2 显示 女 /// </summary> public class DataGridVNTextColumnStyle:DataGridTextBoxColumn { /// <summary> /// (1)控件像绑定的数据对象 提交数据是使用的 delegate /// </summary> public delegate void DelegateCommit( object ActData, string TextBoxText, ref bool Abort);
/// <summary> ///(2)控件向绑定的数据对象提交数据时发生 /// </summary> public event DelegateCommit DataCommit; private string _DisplayMember; private string _ValueMember; private DataView _dv; private DataTable _dt; private bool isEdit=false; private bool isCommit = false;
public DataGridVNTextColumnStyle():base() { //映射基类中的 TextBox 的key KeyPress 用于获得编辑状态 base.TextBox.KeyPress+=new KeyPressEventHandler(TextBox_KeyPress);
base.Disposed+=new EventHandler(DataGridVNTextColumnStyle_Disposed); // // TODO: 在此处添加构造函数逻辑 // } /// <summary> /// 基类 TextBox KeyPress /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void TextBox_KeyPress(object sender, KeyPressEventArgs e) { //Debug.WriteLine("TextBox_KeyPress"); isEdit=true; }
/// <summary> /// 显示的数据列 /// </summary> public string DisplayMember { get { return _DisplayMember; } set { _DisplayMember =value; } } /// <summary> /// 实现[码|名] 方式显示的数据 /// </summary> public DataTable DataSource { get { return _dt; } set { if (_dt==null) { _dt =value;
_dv= new DataView(); _dv.Table=_dt; } } } /// <summary> /// 写入的数据列 /// </summary> public string ValueMember { get { return _ValueMember; } set { _ValueMember=value; } }
/// <summary> ///(3) 重写基类 Commit /// </summary> /// <param name="dataSource"></param> /// <param name="rowNum"></param> /// <returns></returns> protected override bool Commit(CurrencyManager dataSource, int rowNum) { //如果不是在编辑状态[这里代表用户没有在 textBox 输入数据时] if (!isEdit) return base.Commit(dataSource, rowNum); //如果上一个 Commit 没处理完 if (isCommit) return false; try { isCommit=true; //通过 GetColumnValueAtRow 取得当前单元格数据 object ActData = GetColumnValueAtRow(dataSource,rowNum); //当前 TextBox 中的数据 string TextBoxText = TextBox.Text; bool isAbort=false; if (DataCommit!=null) { try { //触发事件[这样使使用本类时容易控制用户的输入]
//事件中可以使用异常 使 DataGrid 停止提交并弹出提示 DataCommit(ActData,TextBoxText,ref isAbort); } catch(Exception ex) {
throw ex; } }
if (isAbort) { Abort(rowNum); return false;
}
_dv.Sort= _ValueMember; int index= 0;
try {
if ( TextBox.Text!="" && TextBox.Text!=NullText ) { object oDate = TextBox.Text; //判断数据在 DataView 中的第己行 如果不存在返回 -1 index = _dv.Find(oDate); } else { //如果是空的就设置为 DBNull base.SetColumnValueAtRow(dataSource,rowNum,System.DBNull.Value); }
} catch(FormatException Fex) { Fex.GetHashCode(); //输入的不是期待的类型 index=-1; } catch(Exception ex) { //其他异常 throw ex; }
if (index < 0) {
//如果不是期待的数据 throw new ApplicationException("输入了不正确的数据!"); };
try { return base.Commit(dataSource, rowNum); } catch(Exception ex) { throw ex; } } finally { //还原开关变量 isCommit=false; isEdit =false; } } /// <summary> /// (4)费编辑状态 绘制图像或文本到 Grid 的单元格中 /// 重写本函数为了实现 [名称] 的显示 /// </summary> /// <param name="g"></param> /// <param name="bounds"></param> /// <param name="source"></param> /// <param name="rowNum"></param> /// <param name="backBrush"></param> /// <param name="foreBrush"></param> /// <param name="alignToRight"></param> protected override void Paint( Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight) {
object sDate=GetColumnValueAtRow(source, rowNum); if (System.Convert.IsDBNull(sDate)) { //如果数据是空 调用基类的绘制函数
base.Paint (g, bounds, source, rowNum,backBrush,foreBrush,alignToRight); } else { //sDate = DBNull.Value; _dv.Sort= _ValueMember; int index = _dv.Find(sDate);
//判断是否是期待的数据 if (index != -1) sDate = _dv[index][_DisplayMember]; else sDate = DBNull.Value;
Rectangle rect = bounds; g.FillRectangle(backBrush,rect);
rect.Offset(0, 2); rect.Height -= 2; StringFormat Sf =new StringFormat();
if (alignToRight) Sf.Alignment=StringAlignment.Far;
g.DrawString(sDate.ToString(), this.TextBox.Font, foreBrush, rect,Sf); Sf.Dispose();
}
} 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) { Paint( g,bounds, source, rowNum, Brushes.Red, Brushes.Blue, alignToRight); }
private void DataGridVNTextColumnStyle_Disposed(object sender, EventArgs e) { if (_dv!=null) { _dv.Dispose(); } } } } |
3.2 DataGridVNButtonColumnStyle 类
继承 上一个 DataGridVNTextColumnStyle 多加了一个 button
using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Windows.Forms;
namespace MagicLink.FlashElf.Windows.Controls.WinDataGrid.ColumnStyle { /// <summary> ///继承 DataGridVNTextColumnStyle 并在右面加入一个 button ///为了以后扩展用 /// </summary> public class DataGridVNButtonColumnStyle:DataGridVNTextColumnStyle { protected System.Windows.Forms.ImageList _imageList; private System.ComponentModel.IContainer components; protected System.Windows.Forms.Button _button;
private void InitializeComponent() {
this.components = new System.ComponentModel.Container(); System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(DataGridVNButtonColumnStyle)); this._button = new System.Windows.Forms.Button(); this._imageList = new System.Windows.Forms.ImageList(this.components); // // _button // this._button.BackColor = System.Drawing.SystemColors.ActiveCaptionText; this._button.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this._button.ImageIndex = 0; this._button.ImageList = this._imageList; this._button.Location = new System.Drawing.Point(0, 0); this._button.Name = "_button"; this._button.TabIndex = 0; // // _imageList // this._imageList.ImageSize = new System.Drawing.Size(16, 16); this._imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("_imageList.ImageStream"))); this._imageList.TransparentColor = System.Drawing.Color.Transparent;
}
public DataGridVNButtonColumnStyle():base() { InitializeComponent(); base.Disposed+=new EventHandler(DataGridVNButtonColumnStyle_Disposed); _button.Dock=DockStyle.Right; _button.Size=new Size(16,16); base.TextBox.Controls.Add(_button);
_button.GotFocus+=new EventHandler(_button_GotFocus); _button.Visible=true; // // TODO: 在此处添加构造函数逻辑 // } /// <summary> /// 如果鼠标点击 使 TextBox 获得焦点 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void _button_GotFocus(object sender, EventArgs e) { _button.Parent.Focus(); } public Button @Button { get { return _button; }
}
private void DataGridVNButtonColumnStyle_Disposed(object sender, EventArgs e) { if (_button!=null) { _button.Dispose(); }
if(_imageList!=null) { _imageList.Dispose(); } } } }
|
3.2 DataGridVMShowGridColumnStyle 类
实现下拉 DataGrid
using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; using System.Data; using System.Diagnostics;
namespace MagicLink.FlashElf.Windows.Controls.WinDataGrid.ColumnStyle { /// <summary> /// 以[码|名]方式显示带下拉 /// DataGrid 列表的 DataGridColumnStyle /// </summary> public class DataGridVMShowGridColumnStyle:DataGridVNButtonColumnStyle {
DataView _dv=new DataView(); /// <summary> /// 下拉的窗口 上面就一个DataGrid /// </summary> GridForm _gf = new GridForm(); private CurrencyManager _mc; private int _Rownum;
public DataGridVMShowGridColumnStyle():base() {
//映射一些事件 base.Button.Click+=new EventHandler(_button_Click); _gf.MouseDown+=new MouseEventHandler(Gf_MouseDown); _gf.MouseMove+=new MouseEventHandler(Gf_MouseMove); this.Disposed+=new EventHandler(DataGridVMShowGridColumnStyle_Disposed); }
//(1)重写基类 edit 得到 CurrencyManager,rowNum /// <summary> /// 重写基类 edit /// </summary> /// <param name="source"></param> /// <param name="rowNum"></param> /// <param name="bounds"></param> /// <param name="readOnly"></param> /// <param name="instantText"></param> /// <param name="cellIsVisible"></param> protected override void Edit(CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) {
_mc=source; _Rownum = rowNum; base.Edit (source, rowNum, bounds, readOnly, instantText, cellIsVisible); }
/// <summary> /// 鼠标单机按钮 show 出大有 DataGrid 的窗口 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void _button_Click(object sender, EventArgs e) { if (_dv.Table ==null) { _dv.Table = base.DataSource; _gf.dataGrid1.DataSource=_dv; _dv.Sort = ValueMember; }
if (_gf.Owner==null) { _gf.Owner = this._button.TopLevelControl as Form; } //调用 NoActForm 的 show _gf.Show(TextBox); //捕获鼠标 _gf.Capture=true; //得到当前行在DataView里的位置 int selectIndex = _dv.Find(GetColumnValueAtRow(_mc,_Rownum));
if (selectIndex==-1) selectIndex =0;
//不只到如何清除 DataGrid 的多选 就这么写了 for(int i = 0 ;i< _gf.dataGrid1.VisibleRowCount;i++) { _gf.dataGrid1.UnSelect(i); } //选择 TextBox 里面的编码对应show出来的 DataGrid里的 行 _gf.dataGrid1.Select(selectIndex); _gf.BindingContext[_dv].Position=selectIndex;
}
/// <summary> /// 下拉窗口的 MouseMove 捕捉鼠标所以可以取到 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Gf_MouseMove(object sender, MouseEventArgs e) { DataGrid Grid = _gf.dataGrid1; System.Windows.Forms.DataGrid.HitTestInfo hti; //通过坐标取得 HitTestInfo 对象 hti = Grid.HitTest(e.X, e.Y); //如果鼠标的位置在 单元格 或 行表头上 if (hti.Type == System.Windows.Forms.DataGrid.HitTestType.Cell || hti.Type == System.Windows.Forms.DataGrid.HitTestType.RowHeader) { int index = hti.Row;
if (index==-1 )index=0;
//不只到如何清除 DataGrid 的多选 就这么写了 for(int i = 0 ;i< Grid.VisibleRowCount;i++) { Grid.UnSelect(i); }
_gf.BindingContext[_dv].Position=index; //选择鼠标下的行 Grid.Select(index); }
} /// <summary> /// 下拉窗口鼠标按下 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Gf_MouseDown(object sender, MouseEventArgs e) { _gf.Capture=false;
Point pt = Control.MousePosition; //如果是在下拉窗口 窗口范围内 if(!(pt.X> _gf.Right || pt.X < _gf.Left|| pt.Y>_gf.Bottom || pt.Y< _gf.Top)) { System.Windows.Forms.DataGrid.HitTestInfo hti; hti = _gf.dataGrid1.HitTest(e.X, e.Y); //鼠标下的行 int index = hti.Row; //如果没有就当第一行处理 if (index==-1 )index=0;
object oDate = _dv[index][base.ValueMember];
object oldDate = base.GetColumnValueAtRow(_mc,_Rownum); //如果下拉窗口选择的数据行和和原始数据不同 if (!oldDate.Equals(oDate)) { //设置当前单元格数据 SetColumnValueAtRow(_mc,_Rownum,oDate);
ColumnStartedEditing(base.TextBox);
TextBox.Text=oDate.ToString();
}
} //隐藏下拉窗口 _gf.Hide();
}
/// <summary> /// 清理战场 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DataGridVMShowGridColumnStyle_Disposed(object sender, EventArgs e) { if (_dv!=null) { _dv.Dispose(); }
if(_gf!=null) { _gf.Dispose(); } } } }
|
3.2 如何使用
和一般的 DataGridColumnStyle 查不多
private void Form1_Load(object sender, System.EventArgs e) { //准备 DataGrid 的数据 _dv.Table = GetMainTable(); //准备下拉窗口的数据 DataTable SexDt =GetShowGridTable();
DataGridTableStyle gts; gts=new DataGridTableStyle();
DataGridVMShowGridColumnStyle Glc= new DataGridVMShowGridColumnStyle();
gts.MappingName=_dv.Table.TableName;
Glc.HeaderText="性别"; Glc.MappingName ="Sex";
Glc.DataSource = SexDt; Glc.DisplayMember="Txt"; Glc.ValueMember="Id";
gts.GridColumnStyles.Add(Glc);
dataGrid1.TableStyles.Add(gts);
//添加一个一般的列 DataGridColumnStyle dgcolStyle; dgcolStyle= new DataGridTextBoxColumn(); dgcolStyle.MappingName ="id"; dgcolStyle.HeaderText = "编号"; gts.GridColumnStyles.Add(dgcolStyle);
Glc.DataCommit+=new DataGridVNTextColumnStyle.DelegateCommit(Glc_DataCommit);
dataGrid1.DataSource=_dv;
}
private void Glc_DataCommit(object ActData, string TextBoxText, ref bool Abort) { //如果认为数据不符合要求 Abort = true 即可 Console.WriteLine("1:::{0},{1},{2}",ActData,TextBoxText,Abort);
} private DataTable GetMainTable() { DataTable dt =new DataTable("Test"); dt.Columns.Add("id",typeof(int)); dt.Columns.Add("birthday",typeof(DateTime)); dt.Columns.Add("Sex",typeof(int));
dt.Rows.Add(new object[]{1,DateTime.Now,1});
return dt;
} private DataTable GetShowGridTable() { DataTable SexDt =new DataTable("SexTable"); SexDt.Columns.Add("Id",typeof(int)); SexDt.Columns.Add("Txt",typeof(String)); SexDt.Rows.Add(new object[]{1,"男"}); SexDt.Rows.Add(new object[]{2,"女"});
return SexDt;
} |
完