DataGridView是一个强大而灵活的数据显示编辑控件.网上流传着大量简单而且实用的于DataGridView有关的开发技巧.不过,要从纷繁杂乱的网络资源中筛选出自己真正需要的也并不是一件省心省力的事.因此,这里将平时常用的几个DataGridView技巧整理出来,供有需要的朋友参考.
一,数据列计数与汇总的计算
还是先看一段代码再来说事吧:
/// <summary>
/// 计算各种状态的数量及总金额
/// </summary>
/// <returns></returns>
private void SetItemCount()
{
int refilling = 0, success = 0, failed = 0, totalcount = 0;
decimal TotalRefillMoney = 0, TotalCharge = 0;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
int state = Convert.ToInt16(dataGridView1["stateCodeDataGridViewTextBoxColumn", i].Value);
decimal RefillMoney = Convert.ToDecimal(dataGridView1["refillMoneyDataGridViewTextBoxColumn", i].Value);
decimal Charge = Convert.ToDecimal(dataGridView1["chargeDataGridViewTextBoxColumn", i].Value);
switch (state)
{
case 3:
failed++;
break;
case 2:
success++;
break;
case 0:
case 1:
default:
refilling++;
break;
}
totalcount++;
TotalRefillMoney += RefillMoney;
TotalCharge += Charge;
}
if (totalcount == dataGridView1.Rows.Count)
{
lbRefilling.Text = string.Format(" {0}", refilling);
lbSuccess.Text = string.Format(" {0}", success);
lbFailed.Text = string.Format(" {0}", failed);
lbTotal.Text = string.Format("Total: Charge/RefillMoney = {1}/{0}", TotalRefillMoney, TotalCharge);
}
}
这段代码是一个私有的方法,它根据StateCode列的值,分别计算种状态(成功,失败和正在执行)的数量,同时计算金额列的总和.然后在标签控件中显示出来.我们只需要在刷新或检索数据的之后,调用该方法就可以了.当然,有朋友可能会觉得在DataGridView本身的事件RowPrePaint或CellPrePaint中进行计算会更好一些.这当然也是一种不错的选择,但是,这些事件在第次重绘的时候都会执行.而事实上大多数时候的重绘并不是因为数据发生了改变,这时原本是不需要重新计算数量和汇总的,因此大增加了系统的运算量,在数据量大的时候它的弊端就更加明显了.把计算放在方法中,可以在需要的时候才调用,比如重新检索了数据,修改了数据或增加删除了行.
二,添加图片列和替换单元格内容
图片的使用会使原本显得有些枯燥无味的纯数据罗列变得生动形象了不少.因此,很多人都想在自己的DataGridView中添加上适当的图片,以达到更好的显示效果.
我们可以在"编辑列"中添加一个图片列,命名为"Image",然后在CellFormatting事件中根据不同的单元格数据显示不同的图片.代码示例如下:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if(dataGridView1.Columns[e.ColumnIndex].Name)=="Image")
{
switch (Convert.ToInt16((dataGridView1["stateCodeDataGridViewTextBoxColumn", e.RowIndex].Value)))
{
case 2:
e.Value = imageList1.Images["TrayXP_green.ico"];
break;
case 3:
e.Value = imageList1.Images["TrayXP_red.ico"];
break;
case 0:
case 1:
default:
e.Value = imageList1.Images["TrayXP_purple.ico"];
break;
}
}
}
细心的朋友可能会发现,在这个代码段中,我们用到了一个名为imageList1的ImageList控件,事先给它添加好了几个ICO图片.值得一提是这里用到的CellFormatting事件,这是一个非常重要的DataGridView事件,很多预显示的内容都可以在这里完成,比如单元格内容的替换,背景色的更改等.将上面的文字稍微改一下就可以了:
if(dataGridView1.Columns[e.ColumnIndex].Name)=="stateCodeDataGridViewTextBoxColumn")
{
switch(Convert.ToInt16(e.Value))
{
case 2:
e.CellStyle.BackColor = Color.LightGreen;
e.Value = "Success";
break;
case 3:
e.CellStyle.BackColor = Color.LightPink;
e.Value = "Failed";
break;
case 0:
case 1:
default:
e.Value = "Refilling";
break;
}
}
三,灵活查询DataGridView数据
当DataGridView控件的数据源绑定到DataAdapter时,我们通常使用DataAdapter的SelectCommand对象中的CommandText字符串语句来做为从数据库读取数据的Select语句.当我们在设计器界面通过DataGridView控件的"添加查询"功能来增加一种新的查询方式的时候,其实就是为与它绑定DataAdapter添加一个SelectCommand对象,通过设定新对象的CommandText语句,来使用新参数完成新的查询功能.这种方式简单易用,但却不够灵活,也不够强大.最灵活强大的方式莫过于是自己生成Select语句的Where条件部分,然后用新SQL语句替换现有的SelectCommand对象中的CommandText部分.示例如下:
private void ToolBarQuery_Click(object sender, EventArgs e)
{
string QueryString = tx_QueryString.Text.Trim();//这就是自定义的Where部分.
if (QueryString.Length > 0)
{
string oldsql = string.Empty;
string newsql = string.Empty;
try
{
oldsql = this.accountTableAdapter.Adapter.SelectCommand.CommandText;
string ClearSql = oldsql.Replace(" TOP 100 ", " ").Replace("ORDER BY ID DESC", "");
newsql = ClearSql + " " + QueryString + " ORDER BY ID DESC";
this.accountTableAdapter.Adapter.SelectCommand.CommandText = newsql;
this.accountTableAdapter.Fill(this.refillingDataSet.Account);
}
catch (Exception)
{
MessageBox.Show("Select Command Error:/r/n" + newsql, Text);
}
finally
{
this.accountTableAdapter.Adapter.SelectCommand.CommandText = oldsql;
}
}
else
{
this.accountTableAdapter.Fill(this.refillingDataSet.Account);
}
}
需要提醒的是:一定要先保存原SQL语句,使用完新的Select语句后,再替换回去.要不然替换几次下来就不知道会变得什么样子啦.而且,当新的SQL语句有错的时候,应该及时提醒用户,并替换回原语句.
四,DataGridView中显示下拉列表框
这里将介绍两种情况下的下拉列表框,一种是下拉列表框关联DataSet中的一个表,即下拉列表框数据来自与表.另一种是下拉列表框数据预定义好的几个值.
前一种比较简单,只需要点几下鼠标就可以完成了:编辑列时,将要显示成下拉列表框的列的ColumnType设置为DataGridViewComboBoxColumn,然后在该列的DataSource属性中为它指定或新建一个BindingSource,最后再为它指定要显示的字段和数据字段就可以了.解释一下:显示字段(DisplayMember)就是界面上我们看到的文字对应的列,而数据字段(ValueMember)就是该列真正的值,这个值和数据库中的值是一致的.
后一种方法在设置列为DataGridViewComboBoxColumn后,还需要自己写代码来声明一个DataTable.然后定义它的列,再加DataTable中添加数据,最后将它绑定到需要显示成下拉框的列中,并指定其DisplayMember和ValueMember所对应的DataTable列.如:
private System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("Level", System.Type.GetType("System.String"));
dt.Rows.Add("1");
dt.Rows.Add("2");
dt.Rows.Add("3");
this.PowerLevel.DataSource = this.dt;//其中的PowerLevel是DataGridView中的列名
this.PowerLevel.DisplayMember = "Level";
this.PowerLevel.ValueMember = "Level";
这里dt只添加了一列,并将显示字段和数据字段都设成了这一列.
五,DataGridView中显示密码字符
关于在DataGridView中显示密码字符,网上有多种方法,如将真正的密码列隐藏,添加一个"影子"列来显示几个星号等等.这些都不是真正的我们想要的样子(我们希望能像文本框中的密码编辑那样可以方便的输入,修改密码,只是不显示文字内容).今天这里介绍一种真正的密码框的设计方法,请看代码:
private void TheDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (TheTableName == "User")
{
//密码显示:
if (TheDataGridView.Columns[e.ColumnIndex].Name == "Password" && e.Value != null && e.Value.ToString().Length > 0)
{
e.Value = new string('*', e.Value.ToString().Length);
}
}
}
private void TheDataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (TheTableName == "User")
{
//密码编辑:
TextBox t = e.Control as TextBox;
if (t != null)
{
for (int i = 0; i < TheDataGridView.Columns.Count; i++)
{
if (this.TheDataGridView.Columns[i].Name == "Password")
t.PasswordChar = '*';
else
t.PasswordChar = new char();
}
}
}
}
其实很简单,就是在CellFormatting事件中将原密码内容替换成星号(呵呵,上面讲过的技巧这里又用到了),在EditingControlShowing事件中编辑密码.这里的一个关键是"TextBox t = e.Control as TextBox;",这使得当前单元格有了文本框的特性.这样我们编辑起来就和在文本框中编辑密码一样简单方面了.而且这样做的一个非常直观的好处就是:可以直接更新单元格中的数据,而不需要做任何额外的处理.
六,给新增列指定默认值
一个用户友好的程序,往往会为用户操作指定合适的默认值,这样可以在一定程序上减少用户的操作,提高操作效率.在DataGridView的操作中,这一点显示尤其重要.因为一些列是不能为空的.如果用户忘记输入数据,就会弹出错误提示.因此,为新增行的各列指定合适的默认值是很有必要的.那么我们需要用到DefaultValuesNeeded事件.
private void TheDataGridView_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e)
{
e.Row.Cells["UserName"].Value = "User";
e.Row.Cells["Password"].Value = "8888";
e.Row.Cells["PowerLevel"].Value = "2";
e.Row.Cells["Remark"].Value = "Default Password is '8888'.The user can change it by himself.";
}