一、效果图
实现功能:
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;
}
完
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/FlashElf/archive/2005/02/02/277121.aspx