DataGridView的CellFormatting事件和CellPainting事件
1、CellFormatting事件,一般重绘单元格属性。 private Bitmap highPriImage;
private Bitmap mediumPriImage;
private Bitmap lowPriImage;
private void dataGridView1_CellFormatting(object sender,
System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
{
// Set the background to red for negative values in the Balance column.
if (dataGridView1.Columns[e.ColumnIndex].Name.Equals("Balance"))
{
Int32 intValue;
if (Int32.TryParse((String)e.Value, out intValue) &&
(intValue < 0))
{
e.CellStyle.BackColor = Color.Red;
e.CellStyle.SelectionBackColor = Color.DarkRed;
}
}
// Replace string values in the Priority column with images.
if (dataGridView1.Columns[e.ColumnIndex].Name.Equals("Priority"))
{
// Ensure that the value is a string.
String stringValue = e.Value as string;
if (stringValue == null) return;
// Set the cell ToolTip to the text value.
DataGridViewCell cell = dataGridView1[e.ColumnIndex, e.RowIndex];
cell.ToolTipText = stringValue;
// Replace the string value with the image value.
switch (stringValue)
{
case "high":
e.Value = highPriImage;
break;
case "medium":
e.Value = mediumPriImage;
break;
case "low":
e.Value = lowPriImage;
break;
}
}
}
2、CellPainting事件,一般用于合并单元格用Windows Forms DataGridView 没有提供合并单元格的功能,要实现合并单元格的功能就要在CellPainting事件中使用Graphics.DrawLine和 Graphics.DrawString 自己来“画”。下面的代码可以对DataGridView第1列内容相同的单元格进行合并: #region"合并单元格的测试"
private int? nextrow = null;
private int? nextcol = null;
private void dataGridView1_CellFormatting(object sender, System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
{
if (this.dataGridView1.Columns["description"].Index == e.ColumnIndex && e.RowIndex >= 0)
{
if (this.nextcol != null & e.ColumnIndex == this.nextcol)
{
e.CellStyle.BackColor = Color.LightBlue;
this.nextcol = null;
}
if (this.nextrow != null & e.RowIndex == nextrow)
{
e.CellStyle.BackColor = Color.LightPink;
this.nextrow = null;
}
if (e.RowIndex != this.dataGridView1.RowCount - 1)
{
if (e.Value.ToString() == this.dataGridView1.Rows[e.RowIndex + 1].Cells[e.ColumnIndex].Value.ToString())
{
e.CellStyle.BackColor = Color.LightPink;
nextrow = e.RowIndex + 1;
}
}
}
if (this.dataGridView1.Columns["name"].Index == e.ColumnIndex && e.RowIndex >= 0)
{
if (e.Value.ToString() == this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].Value.ToString())
{
e.CellStyle.BackColor = Color.LightBlue;
nextcol = e.ColumnIndex + 1;
}
}
}
//==========================
//绘制单元格private void dataGridView1_CellPainting(object sender, System.Windows.Forms.DataGridViewCellPaintingEventArgs e)
{
//纵向合并 if (this.dataGridView1.Columns["description"].Index == e.ColumnIndex && e.RowIndex >= 0)
{
using (
Brush gridBrush = new SolidBrush(this.dataGridView1.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor))
{
using (Pen gridLinePen = new Pen(gridBrush))
{
// 擦除原单元格背景 e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
////绘制线条,这些线条是单元格相互间隔的区分线条,
////因为我们只对列name做处理,所以datagridview自己会处理左侧和上边缘的线条 if (e.RowIndex != this.dataGridView1.RowCount - 1)
{
if (e.Value.ToString() != this.dataGridView1.Rows[e.RowIndex + 1].Cells[e.ColumnIndex].Value.ToString())
{
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1,
e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);//下边缘的线 //绘制值 if (e.Value != null)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font,
Brushes.Crimson, e.CellBounds.X + 2,
e.CellBounds.Y + 2, StringFormat.GenericDefault);
}
}
}
else
{
e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1,
e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);//下边缘的线 //绘制值 if (e.Value != null)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font,
Brushes.Crimson, e.CellBounds.X + 2,
e.CellBounds.Y + 2, StringFormat.GenericDefault);
}
}
//右侧的线 e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1,
e.CellBounds.Top, e.CellBounds.Right - 1,
e.CellBounds.Bottom - 1);
e.Handled = true;
}
}
}
//横向合并 if (this.dataGridView1.Columns["name"].Index == e.ColumnIndex && e.RowIndex >= 0)
{
using (
Brush gridBrush = new SolidBrush(this.dataGridView1.GridColor),
backColorBrush = new SolidBrush(e.CellStyle.BackColor))
{
using (Pen gridLinePen = new Pen(gridBrush))
{
// 擦除原单元格背景 e.Graphics.FillRectangle(backColorBrush, e.CellBounds);
if (e.Value.ToString() != this.dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex + 1].Value.ToString())
{
//右侧的线 e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1, e.CellBounds.Top,
e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
//绘制值 if (e.Value != null)
{
e.Graphics.DrawString((String)e.Value, e.CellStyle.Font,
Brushes.Crimson, e.CellBounds.X + 2,
e.CellBounds.Y + 2, StringFormat.GenericDefault);
}
}
//下边缘的线 e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1,
e.CellBounds.Right - 1, e.CellBounds.Bottom - 1);
e.Handled = true;
}
}
}
}
#endregion
本文转自 qianshao 51CTO博客,原文链接:http://blog.51cto.com/qianshao/201801,如需转载请自行联系原作者
DataGridView使用方法汇总
DataGridView控件
DataGridView是用于Windows Froms 2.0的新网格控件。它能够代替先前版本号中DataGrid控件,它易于使用并高度可定制,支持许多我们的用户须要的特性。
关于本文档:
本文档不准备面面俱到地介绍DataGridView,而是着眼于深入地介绍一些技术点的高级特性。
本文档按逻辑分为5个章节,首先是结构和特性的概览,其次是内置的列/单元格类型的介绍,再次是数据操作相关的内容,然后是主要特性的综述,最后是最佳实践。
大部分章节含有一个“Q & A”部分,来回答该章节相关的一些常见问题。注意,某些问题会因为知识点的关联性反复出如今多个章节。这些问题、答案及其附带的演示例子代码都包含在本文档的附录部分。
内容
1 何为DataGridView.. 4
1.1 DataGridView和DataGrid 之间的差别... 4
1.2 DataGridView的亮点... 5
2 DataGridView的结构... 6
2.1 结构元素... 6
2.2 单元格和组... 6
2.3 DataGridView的单元格... 6
2.3.1 DataGridViewCell的工作机制... 7
2.4 DataGridView的列... 9
2.5 DataGridView的编辑控件... 9
2.6 DataGridView的行... 10
3 列/单元格类型揭密... 11
3.1 DataGridViewTextBoxColumn. 11
3.2 DataGridViewCheckBoxColumn. 12
3.3 DataGridViewImageColumn. 12
3.4 DataGridViewButtonColumn. 13
3.5 DataGridViewComboBoxColumn. 13
3.5.1 DataError与ComboBox列... 13
3.6 DataGridViewLinkColumn. 14
4 操作数据... 15
4.1 数据输入和验证的相关事件... 15
4.1.1 数据验证相关事件的顺序... 15
4.1.2 验证数据... 15
4.1.3 在新行中的数据输入... 16
4.2 关于Null值... 19
4.2.1 NullValue属性... 19
4.2.2 DataSourceNullValue属性... 19
4.3 DataError事件... 20
4.4 数据绑定模式... 21
4.4.1 非绑定模式... 21
4.4.2 绑定模式... 21
4.4.3 虚拟模式... 22
4.4.4 混合模式... 22
5 Overview of features. 24
5.1 Styling. 24
5.1.1 The DataGridViewCellStyle Class. 24
5.1.2 Using DataGridViewCellStyle Objects. 24
5.1.3 Style Inheritance. 25
5.1.4 Setting Styles Dynamically. 28
5.2 Custom painting. 28
5.2.1 Paint Parts. 28
5.2.2 Row Pre Paint and Post Paint 29
5.3 Autosizing. 30
5.3.1 Sizing Options in the Windows Forms DataGridView Control 30
5.3.2 Resizing with the Mouse. 31
5.3.3 Automatic Sizing. 32
5.3.4 Programmatic Resizing. 33
5.3.5 Customizing Content-based Sizing Behavior. 34
5.3.6 Content-based Sizing Options. 34
5.4 Selection modes. 34
5.4.1 Programmatic Selection. 35
5.5 Scrolling. 35
5.5.1 Scroll event 35
5.5.2 Scroll bars. 35
5.5.3 Scrolling Properties. 36
5.6 Sorting. 36
5.6.1 Programmatic Sorting. 37
5.6.2 Custom Sorting. 38
5.7 Border styles. 39
5.7.1 Standard Border Styles. 39
5.7.2 Advanced Border Styles. 39
5.8 Enter-Edit modes. 40
5.9 Clipboard copy modes. 40
5.10 Frozen columns/rows. 41
5.11 Implementing Custom cells and editing controls/cells. 41
5.11.1 IDataGridViewEditingControl 42
5.11.2 IDataGridViewEditingCell 42
5.12 Virtual mode. 42
5.12.1 Bound Mode and Virtual Mode. 42
5.12.2 Supplementing Bound Mode. 42
5.12.3 Replacing Bound Mode. 43
5.12.4 Virtual-Mode Events. 43
5.12.5 Best Practices in Virtual Mode. 44
5.13 Capacity. 44
6 Best Practices. 45
6.1 Using Cell Styles Efficiently. 45
6.2 Using Shortcut Menus Efficiently. 45
6.3 Using Automatic Resizing Efficiently. 45
6.4 Using the Selected Cells, Rows, and Columns Collections Efficiently. 46
6.5 Using Shared Rows. 46
6.6 Preventing Rows from Becoming Unshared. 47
附录 A – 常见问题:... 49
怎样使指定的单元格不可编辑?. 49
怎样让一个单元格不可用?. 49
怎样避免用户将焦点设置到指定的单元格?... 51
怎样使全部单元格总是显示控件(不论它是否处于编辑状态)?. 51
Why does the cell text show up with “square” characters where they should be new lines?. 51
怎样在单元格内同一时候显示图标和文本?... 51
怎样隐藏一列?... 53
怎样避免用户对列排序?... 53
怎样针对多个列排序?. 54
怎样为编辑控件增加事件处理函数?. 58
应在何时移除编辑控件的事件处理函数?. 58
怎样处理ComboBox列中ComboBox控件的SelectIndexChanged事件?. 58
怎样通过拖放调整行的顺序?... 59
怎样调整最后一列的宽度使其占领网格的剩余客户区?... 60
怎样让TextBox类型的单元格支持换行?. 60
怎样使Image列不显示不论什么图像(字段值为null时)?. 61
怎样能够在ComboBox类型的单元格中输入数据?. 61
How do I have a combo box column display a sub set of data based upon the value of a different combo box column? 61
怎样在用户编辑控件的时候(而不是在验证时)就显示错误图标?. 62
怎样同一时候显示绑定数据和非绑定数据?... 65
How do I show data that comes from two tables?. 66
怎样显示主从表?... 66
怎样在同一DataGridView中显示主从表?... 68
怎样避免用户对列排序?. 68
怎样在点击工具栏button的时候将数据提交到数据库?... 68
怎样在用户删除记录时显示确认对话框?... 68
1 何为DataGridView通过DataGridView控件,能够显示和编辑表格式的数据,而这些数据能够取自多种不同类型的数据源。
DataGridView控件具有很高的的可配置性和可扩展性,提供了大量的属性、解决方案和事件,能够用来对该控件的外观和行为进行自己定义。当你须要在WinForm应用程序中显示表格式数据时,能够优先考虑DataGridView(相比于DataGrid等其它控件)。假设你要在小型网格中显示仅仅读数据,或者同意用户编辑数以百万计的记录,DataGridView将为你提供一个易于编程和良好性能的解决方案。
DataGridView 用来替换先前版本号中的DataGrid,拥有较DataGrid许多其他的功能;但DataGrid仍然得到保留,以备向后兼容和将来使用。假设你要在两者中选择,能够参考下面给出的DataGrid 和DataGridView之间差别的细节信息。
1.1 DataGridView和DataGrid 之间的差别DataGridView提供了大量的DataGrid所不具备的基本功能和高级功能。此外,DataGridView 的结构使得它较之DataGrid控件更容易扩展和自己定义。
下表描述了DataGridView提供而DataGrid未提供的几个主要功能。
DataGridView功能
描述
多种列类型
与DataGrid相比,DataGridView 提供了许多其他的内置列类型。这些列类型能够满足大部分常见须要,而且比DataGrid中的列类型易于扩展或替换。
多种数据显示方式
DataGrid仅限于显示外部数据源的数据。而DataGridView则能够显示非绑定的数据,绑定的数据源,或者同一时候显示绑定和非绑定的数据。你也能够在DataGridView中实现virtual mode,实现自己定义的数据管理。
用于自己定义数据显示的多种方式
DataGridView提供了许多属性和事件,用于数据的格式化和显示。比方,你能够依据单元格、行和列的内容改变其外观,或者使用一种类型的数据替代还有一种类型的数据。
用于更改单元格、行、列、表头外观和行为的多个选项
DataGridView使你能够以多种方式操作单个网格组件。比方,你能够冻结行和列,避免它们因滚动而不可见;隐藏行、列、表头;改变行、列、表头尺寸的调整方式;为单个的单元格、行和列提供工具提示(ToolTip)和快捷菜单。
唯一的一个DataGrid提供而DataGridView未提供的特性是两个相关表中数据的分层次显示(比方常见的主从表显示)。你必须使用两个DataGridView来显示具有主从关系的两个表的数据。
1.2 DataGridView的亮点下表着重显示了DataGridView的主要特性,稍后会介绍它们的具体信息。
DataGridView控件特性
描述
多种列类型
DataGridView提供有TextBox、CheckBox、Image、Button、ComboBox和Link类型的列及对应的单元格类型。
多种数据显示方式
DataGrid仅限于显示外部数据源的数据。而DataGridView则能够显示非绑定的数据,绑定的数据源,或者同一时候显示绑定和非绑定的数据。你也能够在DataGridView中实现virtual mode,实现自己定义的数据管理。
自己定义数据的显示和操作的多种方式
DataGridView提供了许多属性和事件,用于数据的格式化和显示。
此外,DataGridView提供了操作数据的多种方式,比方,你能够:
对数据排序,并显示对应的排序符号(带方向的箭头表示升降序)对行、列和单元格的多种选择模式;多项选择和单项选择以多种格式将数据拷贝到剪贴板,包含text,CSV (以逗号隔开的值) 和 HTML改变用户编辑单元格内容的方式用于更改单元格、行、列、表头外观和行为的多个选项
DataGridView使你能够以多种方式操作单个网格组件。比方,你能够:
冻结行和列,避免它们因滚动而不可见;隐藏行、列、表头;改变行、列、表头尺寸的调整方式;改变用户对行、列、单元格的选择模式;为单个的单元格、行和列提供工具提示(ToolTip)和快捷菜单。自己定义单元格、行和列的边框样式。提供丰富的可扩展性的支持
DataGridView提供易于对网格进行扩展和自己定义的基础结构,比方:
处理自己定义的绘制事件能够为单元格、列和行提供自己定义的观感;继承一个内置的单元格类型以为其提供许多其他的行为;实现自己定义的接口以提供新的编辑体验。2 DataGridView的结构DataGridView及其相关类被设计为用于显示和编辑表格数据式数据的灵活的、可扩展的体系。这些类都位于system.Windows.Forms命名空间,它们的名称也都有共同的前缀"DataGridView"。
2.1 结构元素(Architecture Elements)主要的DataGridView相关类继承自DataGridViewElement类。
DataGridViewElement类有两个属性,一是DataGridView,该属性提供了对其所属的DataGridView的引用;二是State,该属性表示当前的状态,其值为DataGridViewElementStates枚举,该枚举支持位运算,这意味着能够设置组合状态。
2.2 单元格和组(Cells and Bands)DataGridView由两种主要的对象组成:单元格(cell)和组(band)。全部的单元格都继承自DataGridViewCell基类。 两种类型的组(或称集合)DataGridViewColumn和DataGridViewRow都继承自DataGridViewBand 基类,表示一组结合在一起的单元格。
DataGridView会与一些类进行互操作,但最常打交道的则是例如以下三个:DataGridViewCell, DataGridViewColumn,DataGridViewRow。
2.3 DataGridView的单元格 (DataGridViewCell)单元格(cell)是操作DataGridView的基本单位。Display is centered on cells, and data entry is often performed through cells。能够通过DataGridViewRow 类的Cells 集合属性访问一行包含的单元格,通过DataGridView的SelectedCells集合属性访问当前选中的单元格,通过DataGridView的CurrentCell属性访问当前的单元格。
DataGridViewCell 类图
Cell 相关类和属性
DataGridViewCell是一个抽象基类,全部的单元格类型都继承于此。DataGridViewCell及其继承类型并非Windows Forms控件,但当中一些宿主于Windows Forms控件。单元格支持的编辑功能通常都由其宿主控件来处理。
DataGridViewCell对象不会像Windows Forms控件那样控制自己的外观和绘制(painting)特征,相反的,DataGridView会负责其包含的单元格的外观。通过DataGridView 控件的属性和事件,你能够深刻地影响单元格的外观和行为。假设你对单元格定制有特殊要求,超出了DataGridView提供的功能,能够继承DataGridViewCell或者它的某个子类来满足这些要求。
2.3.1 DataGridViewCell的工作机制
理解DataGridView结构的一个重要部分是理解DataGridViewCell的工作机制:
单元格的值(A Cell’s Value)
单元格的值是其根本所在。假设单元格所在列不是绑定列,并且所在的DataGridView也不是Virtual Mode,那么它的值就由它本身所持有并维护。对于那些由绑定产生的单元格,它们压根儿就不“知道”该持有什么值,当然也就不会去维护了;当DataGridView须要单元格的值的时候,它会到数据源中查询该单元格应当显示的值。在Virtual Mode下,除了会触发CellValueNeeded事件以获取对应单元格的值外,与数据绑定方式很相似。在单元格级,全部这些由DataGridViewCell.GetValue() 解决方案来控制。
默认情况下,单元格的值的类型为object。当一个列被绑定后,会设置它的ValueType属性,它包含的单元格的ValueType也随之更新。而单元格的ValueType对于下一步的格式化很重要。
格式化显示(Formatting for Display)
注意:当DataGridView须要了解“怎样显示这个单元格”时,它须要的是单元格的FormattedValue ,而不是Value。这是一个复杂的过程,因为格式化屏幕上的一些内容通常须要将它转换为字符串。比如,尽管你将单元格的值(Value)设置为整型值155,在显示它的时候仍须要将其格式化。单元格和其所在的列的FormattedValueType 属性决定了显示它时所用的类型。多数列使用字符串类型,而Image和CheckBox类型的单元格/列则使用其它类型。Image类型的单元格和列使用Image作为默认的FormattedValueType,它的内置实现了解怎样去显示一个Image。CheckBox类型的单元格/列的FormattedValueType属性则取决于属性ThreeState的值。在单元格级,全部这些由DataGridViewCell.GetFormattedValue()控制。
默认情况下,DataGridView使用TypeConverter将单元格的值(Value)转换为格式化的值(FormattedValue)。DataGridView会基于单元格的ValueType和FormattedValueType属性来获取合时的TypeConverter。
对于一个单元格,FormattedValue会得到多次请求(即会在多个地方用到):绘制单元格的时候,所在列依据单元格内容自己主动调整大小的时候,甚至是在推断鼠标是否经过单元格内容时。每次须要FormattedValue的时候,DataGridView会触发CellFormatting事件,这时你就有机会改动单元格的格式化显示了。
假设单元格不能获取它的格式化值,它会触发DataError事件。
格式化显示单元格还包含以怎样的首选尺寸显示它。这个首选尺寸是由单元格的FormattedValue,填充区域(padding),附加显示和边框合并而成。
绘制单元格的显示(Painting the Display)
在获得FormattedValue 后,单元格将负责绘制它的内容。单元格决定了绘制过程所使用的正确样式(参见本文档第五章的样式部分)并进行绘制。记住:假设单元格不去绘制自己,那么该单元格将不会有不论什么内容得到绘制(即单元格的绘制仅仅由它自己负责),行、列不会负责绘制不论什么内容,因此要确保至少要绘制单元格的背景(background),否则单元格所在的矩形区域仍然是无效的(即未经绘制)。
解析单元格的显示(Parsing the Display)
用户开始与单元格交互后,可能会编辑单元格的值。有一件事要记住,用户编辑的实际上是单元格的FormattedValue。用户提交所编辑的值时,FormattedValue须要转换回单元格的值(Value),这个过程称为解析(parsing)。在单元格级上,全部这些工作由单元格的DataGridViewCell.ParseFormattedValue(int rowIndex)解决方案控制。
默认情况下,会再次使用TypeConverter来将FormattedValue解析为单元格的真实值,这时会触发DataGridView的CellParsing事件,这时你就有机会改动单元格的解析方式了。.
假设单元格不能得到正确地解析,会触发DataError事件。
2.3.2 常见问题
1) 怎样使指定的单元格不可编辑?
2) 怎样让一个单元格不可用(disable)?
3) 怎样避免用户将焦点设置到指定的单元格?
4) 怎样使全部单元格总是显示控件(不论它们是否处于编辑状态)?
5) Why does the cell text show up with “square” characters where they should be new lines?
6) 怎样在单元格内同一时候显示图标和文本?
2.4 DataGridView的列(DataGridViewColumn)DataGridView所附带的数据(这些数据能够通过绑定或非绑定方式附加到控件)的结构表现为DataGridView的列。你能够使用DataGridView的Columns集合属性访问DataGridView所包含的列,使用SelectedColumns 集合属性访问当前选中的列。
DataGridViewColumn 类图
Column 相关类和属性
一些主要的单元格类型拥有对应的列类型,这些列类型继承自DataGridViewColumn基类。
常见问题:
1) 怎样隐藏一列?
2) 怎样避免用户对列排序?
3) 怎样针对多个列排序?
2.5 DataGridView的编辑控件(Editing Controls)支持高级编辑功能的单元格一般都使用一个继承自Windows Forms控件的宿主控件,这些控件同一时候也实现了IDataGridViewEditingControl接口。
DataGridView Editing Control Class diagram
Classes that implement Editing Controls
下表说明了单元格类型、列类型、编辑控件间的关系:
单元格类型
宿主控件
列类型
DataGridViewButtonCell
n/a
DataGridViewButtonColumn
DataGridViewCheckBoxCell
n/a
DataGridViewCheckBoxColumn
DataGridViewComboBoxCell
DataGridViewComboBoxEditingControl
DataGridViewComboBoxColumn
DataGridViewImageCell
n/a
DataGridViewImageColumn
DataGridViewLinkCell
n/a
DataGridViewLinkColumn
DataGridViewTextBoxCell
DataGridViewTextBoxEditingControl
DataGridViewTextBoxColumn
常见问题(FAQ)
1) 怎样为编辑控件增加事件处理函数?
2) 应在何时移除编辑控件的事件处理函数?
3) 怎样处理ComboBox列中Combox控件的SelectIndexChanged事件?
4) 怎样使全部单元格总是显示控件(不论它是否处于编辑状态)?
2.6 DataGridViewRowDataGridViewRow类用于显示数据源的一行数据。能够通过DataGridView控件的Rows集合属性来访问其包含的行,通过SelectedRows集合属性访问当前选中的行。
DataGridViewRow类图
Row相关的类和属性
你能够继承DataGridViewRow类来实现自己的行类型,尽管多数情况下这并不必要。DataGridView 有几个行相关的事件和属性,用以自己定义其包含的DataGridViewRow对象的行为。
假设你将DataGridView的AllowUserToAddRows属性设为true,一个专用于增加新行的特殊行会出如今最后一行的位置上,这一行也属于Rows集合,但它有一些须要你提起注意的特殊功能,要获得这方面的许多其他信息,请参看4.1.3节。
2.6.1 常见问题
1) 怎样通过拖放调整行的顺序?
3 列/单元格类型揭密(column/cell types)DataGridView控件提供了几种列类型用以显示数据,并同意用户改动和增加数据。
当你对DataGridView进行了绑定,并将它的AutoGenerateColumns属性设置为true,它会依据数据源中列的数据类型自己主动生成列,这些列都使用对应的默认类型(与数据源列数据类型相适应)。
你也能够自行创建列的实例,将它们添加DataGridView的Columns集合中,这些列可用作非绑定列,也能够以手动方式让它们用于绑定数据。手动绑定的列很实用,比方,自己主动生成的列都采用与数据源的列对应的默认类型,而你不想用默认列类型。
下表描述了DataGridView 的各种列对应的类:
列类型
描述
DataGridViewTextBoxColumn
用于基于文本的值。绑定到数字和字符串值时会自己主动生成这种类型的列。
DataGridViewCheckBoxColumn
用于显示Boolean和CheckState类型的值,绑定到上述类型值时会自己主动生成这种类型的列。
DataGridViewImageColumn
用于显示图像。绑定到byte数组,Image对象,图标对象时会自己主动生成这种类型的列。
DataGridViewButtonColumn
用于在单元格内显示button。在绑定时不会自己主动生成,一般用于非绑定列。
DataGridViewComboBoxColumn
用于在单元格内显示下拉列表。在绑定时不会自己主动生成,一般地须要手工绑定。
DataGridViewLinkColumn
用于在单元格内显示链接。在绑定时不会自己主动生成,一般地须要手工绑定。
自己定义列类型
通过继承DataGridViewColumn 类或其子类,你能够创建自己的列类型,以提供自己定义的外观、行为和宿主控件。
常见问题(FAQ)
1) 怎样隐藏一列?
2) 怎样使特定的单元格不可编辑?
3) 怎样避免用户将焦点设置到指定的单元格?
4) 怎样调整最后一列的宽度使其占领网格的剩余客户区?
3.1 DataGridViewTextBoxColumnDataGridViewTextBoxColumn是一种通用的列类型,用于表示基于文本的值,比方数字和字符串。在编辑模式下,会有一个TextBox控件出如今当前活动单元格,用户能够改动单元格的值。
单元格的值在显示时会自己主动转换为字符串。用户输入或改动的值在提交时则被自己主动解析为合适的数据类型以创建一个单元格的值。通过处理CellFoamatting和CellParsing事件,你能够自己定义这些转换的方式。比方将数据源的日期字段以特定的形式显示,对某些特殊单元格作出特殊的标记。
对一列来说,它包含的单元格值的数据类型由该列的ValueType属性指定。
3.1.1 常见问题
1) 怎样让TextBox类型的单元格支持换行?
2) Why does the cell text show up with “square” characters where they should be new lines?
3) 怎样在单元格内同一时候显示图标和文本?
4) 怎样避免用户将焦点设置到指定的单元格?
3.2 DataGridViewCheckBoxColumnDataGridViewCheckBoxColumn用于显示Boolean或CheckState类型的值。Boolean 值显示为二元(two-state)或三元 (three-state) 的CheckBox,而这取决于该列的ThreeState 属性的值。假设该类型的列绑定到CheckState类型的值,ThreeState属性的默认值为true。
普通情况下,CheckBox类型的单元格要么用于存储数据,就像其它类型的数据一样,要么用于进行一些重要操作。用户点击CheckBox单元格时,假设你希望对此马上做出反应,能够处理CellClick事件,但该事件发生在单元格的值更新之前。假设点击之时就希望获得新值,一种选择是依据当前值计算点击后的值;还有一种解决方案是马上提交值的变化,然后在CellValueChanged事件处理函数中对此作出反应,而要在用户点击单元格时马上提交值的变化,你必须处理CurrentCellDirtyStateChanged事件,在这里,调用CommitEnd解决方案提交新值。
3.3 DataGridViewImageColumnDataGridViewImageColumn 类型的列用于显示图像。这种类型的列有三种解决方案生成:绑定到数据源时自己主动生成;为非绑定列手动生成;在CellFormatting事件处理函数(该事件发生在单元格显示前)中动态生成。
绑定到数据源时自己主动生成Image列的解决方案适用于大量的图像格式,包含.NET中Image类支持的各种格式,还有Access数据库及Northwind范例数据库使用的OLE图片格式。
假设你想提供DataGridViewButtonColumn列的功能,又希望显示自己定义的外观,手动生成Image列会很实用。在显示后,你能够处理CellClick事件以处理用户对单元格的点击(模拟button列)。
假设你要为计算值或非图片的值提供图片显示,在CellFormatting事件处理函数中动态生成Image列的解决方案会很实用。比方,你有一个表示风险值的列,它的值可能是”high”、”middle”或”low”,能够为它们显示不同的图标作为警示;或者你有一个名为”Image”的列,它的值时图片文件的位置而不是真实的图片内容,也能够用这种解决方案。
3.3.1 常见问题
1) 怎样使Image列不显示不论什么图像(字段值为null时)?
3.4 DataGridViewButtonColumn使用DataGridViewButtonColumn 列,能够在单元格内显示button。假设你要为用户操作特定行提供一种简单的方式,Button列会很实用,比方排序或在还有一个窗口中显示子表记录。
在对DataGridView进行数据绑定时不会自己主动生成Button列,所以你必须手动创建它们,然后把它们增加到DataGridView控件的Columns集合中。
你能够处理CellClick事件以响应用户的点击动作。
3.5 DataGridViewComboBoxColumn在DataGridViewComboBoxColumn类型的列中,你能够显示包含下拉列表的单元格。这在仅同意用户输入一些特定值的时候显得很实用,比方在SQL Server演示例子数据库Northwind中Products表的Category列,它表示产品的种类,这个应仅仅同意选择现有的产品种类,此时就能够使用ComboBox列。
假设你了解怎样为ComboBox控件生成下拉列表,就能够用相同的方式为ComboBox列中的全部单元格生成下拉列表。要么通过列的Items集合手动增加,要么通过DataSource,DisplayMember 和ValueMember属性绑定到一个数据源。要了解当中的许多其他信息,能够参考WinForms中ComboBox空间的使用方法。
你能够将ComboBox列的单元格的实际值绑定到DataGridView控件本身的数据源(注意不是ComboBox列的数据源),这须要设置该列的DataPropertyName属性(设置某个列的名称)。
ComboBox列不会在数据绑定时自己主动生成,所以你必须手动创建它们,然后将其增加到Columns集合属性中。另外,你也能够使用设计器,在设计时设置对应的属性,这个过程相似于在设计器中ComboBox控件的使用。
3.5.1 DataError事件和ComboBox列
在使用DataGridViewComboBoxColumn 时,有时会改动单元格的值或启动ComboBox控件的Items集合,这样可能会引发DataError事件。这是ComboBox列的设计使然,ComboBox列的单元格会进行数据验证。在ComboBox列的单元格尝试绘制包含的内容时,它须要将包含的值进行格式化(见第二章第三节),在此转换过程中,它会在ComboBox的Items集合中查找对应的值,假设查找失败,就会引发DataError事件。忽略了DataError事件可能会使单元格不能进行正确的格式化。
3.5.2 常见问题
1) 怎样能够在ComboBox类型的单元格中输入数据?
2) How do I handle the SelectedIndexChanged event?
3) How do I have a combo box column display a sub set of data based upon the value of a different combo box column?
本文转自博客园知识天地的博客,原文链接:DataGridView使用方法汇总 需转载请自行联系原博主。
近期开发项目中用到的编码小技巧汇总说明
1.默认EF生成的连接字符串比较的长和怪异,若想使用普通的连接字符串来连接EF,则可以通过创建分部类,并重写一个构造函数,在构造函数中通过动态拼接EntityConnectionString得到EF所需的连接字符串,具代实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public partial class DataEntities
{
private static ConcurrentDictionary<string, string> entityConnStrings = new ConcurrentDictionary<string, string>();
public DataEntities(string connName)
: base(BuildEntityConnectionString(connName))
{
}
private static string BuildEntityConnectionString(string connName)
{
if (!entityConnStrings.ContainsKey(connName))
{
var connStrSetting = System.Configuration.ConfigurationManager.ConnectionStrings[connName];
EntityConnectionStringBuilder entityConnStrBuilder = new EntityConnectionStringBuilder();
entityConnStrBuilder.Provider = connStrSetting.ProviderName;
entityConnStrBuilder.ProviderConnectionString = EncryptUtility.DesDecrypt("XXXXX", connStrSetting.ConnectionString);
entityConnStrBuilder.Metadata = "res://*/Data.csdl|res://*/Data.ssdl|res://*/Data.msl";
string entityConnString = entityConnStrBuilder.ToString();
entityConnStrings.AddOrUpdate(connName, entityConnString, (key, value) => entityConnString);
}
return entityConnStrings[connName];
}
}
注意上面的类是一个分部类:partial,同时BuildEntityConnectionString方法是一个静态方法,在BuildEntityConnectionString方法中ProviderConnectionString = EncryptUtility.DesDecrypt("XXXXX", connStrSetting.ConnectionString);是关键,我这里是对config中的连接字符串 也都进行了加密,故此处我需要解密,若无这个需求可以直接:ProviderConnectionString =connStrSetting.ConnectionString即可。后续实例化EF上下文对象时,请使用:DataEntities(string connName)这个构造涵数即可,DataEntities是具体的EF上下文对象,大家的EF上下文类名均可能不相同。
2.支持一个通用对象的XML序列化(即:一个类中有可变类型属性成员,需要不同的序列结果及生成不同的序列元素名称),具体实现代码如下:
一个需要被序列化成XML的类:其中要求生成的XML元素detail必需有子元素,且子元素名称及子元素内部属性根据类型的不同而不同(即:detail元素下的子元素是可变的)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[XmlRootAttribute("master")]
public class DemoMaster<T> where T : class
{
[XmlElement("attr")]
public string DemoAttr { get; set; }
[XmlElement("detail")]
public DemoDetail<T> DemoDetail { get; set; } //关键点在这里,该属性元素为:detail,但其子元素根据T不同而不同
}
public class DemoDetail<T> : IXmlSerializable where T : class
{
public T body { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
string bodyStr = reader.ReadInnerXml();
this.body = XmlHelper.XmlDeserialize<T>(bodyStr, Encoding.UTF8);
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteRaw(XmlHelper.XmlSerialize(this.body, Encoding.UTF8, true));
}
}
[XmlTypeAttribute("list-a", AnonymousType = false)]
public class DemoDetailA
{
public string Apro1 { get; set; }
public string Apro2 { get; set; }
public string Apro3 { get; set; }
}
[XmlTypeAttribute("list-b", AnonymousType = false)]
public class DemoDetailB
{
public string Bpro1 { get; set; }
public string Bpro2 { get; set; }
public string Bpro3 { get; set; }
}
[XmlTypeAttribute("list-c", AnonymousType = false)]
public class DemoDetailC
{
public string Cpro1 { get; set; }
public string Cpro2 { get; set; }
public string Cpro3 { get; set; }
}
注意上面代码中,需要关注:DemoDetail属性及DemoDetail<T>类,DemoDetail属性仅是为了生成detail元素节点,而子节点则由DemoDetail<T>类来进行生成,DemoDetail<T>是实现了IXmlSerializable接口,在XML序列化时,DemoDetail<T>类仅将body属性对应的T类型实例内容进行序列化(WriteRaw),而反序列化时,则先反序列化body属性对应的T类型实例,然后赋值给body属性,这也是巧妙之处,DemoDetail<T>类本身并没有真正参与到序列化中,故序列化的字符串也看不到DemoDetail<T>类相关的元素,DemoDetail<T>类仅仅是一个XML序列化格式生成的中介。序列化的XML结果如下:
序列化代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var demo1 = new DemoMaster<DemoDetailA>()
{
DemoAttr = "demo1",
DemoDetail = new DemoDetail<DemoDetailA>() { body = new DemoDetailA() { Apro1 = "demoA1", Apro2 = "demoA2", Apro3 = "demoA3" } }
};
var demo2 = new DemoMaster<DemoDetailB>()
{
DemoAttr = "demo2",
DemoDetail = new DemoDetail<DemoDetailB>() { body = new DemoDetailB() { Bpro1 = "demoB1", Bpro2 = "demoB2", Bpro3 = "demoB3" } }
};
var demo3 = new DemoMaster<DemoDetailC>()
{
DemoAttr = "demo3",
DemoDetail = new DemoDetail<DemoDetailC>() { body = new DemoDetailC() { Cpro1 = "demoC1", Cpro2 = "demoC2", Cpro3 = "demoC3" } }
};
textBox1.Text = XmlHelper.XmlSerialize(demo1, Encoding.UTF8);
textBox1.Text += "\r\n" + XmlHelper.XmlSerialize(demo2, Encoding.UTF8);
textBox1.Text += "\r\n" + XmlHelper.XmlSerialize(demo3, Encoding.UTF8);
序列化的XML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<master>
<attr>demo1</attr>
<detail><list-a>
<Apro1>demoA1</Apro1>
<Apro2>demoA2</Apro2>
<Apro3>demoA3</Apro3>
</list-a></detail>
</master>
<?xml version="1.0" encoding="utf-8"?>
<master>
<attr>demo2</attr>
<detail><list-b>
<Bpro1>demoB1</Bpro1>
<Bpro2>demoB2</Bpro2>
<Bpro3>demoB3</Bpro3>
</list-b></detail>
</master>
<?xml version="1.0" encoding="utf-8"?>
<master>
<attr>demo3</attr>
<detail><list-c>
<Cpro1>demoC1</Cpro1>
<Cpro2>demoC2</Cpro2>
<Cpro3>demoC3</Cpro3>
</list-c></detail>
</master>
3.winform DataGridView 实现指定列采取密码框模式显示与编辑,以及列绑定到复合属性(即:绑定到多层次属性),具体实现代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
dataGridView1.CellFormatting += new DataGridViewCellFormattingEventHandler(dataGridView1_CellFormatting);
dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);
public string EvaluateValue(object obj, string property)
{
string retValue = string.Empty;
string[] names = property.Split('.');
for (int i = 0; i < names.Count(); i++)
{
try
{
var prop = obj.GetType().GetProperty(names[i]);
var result = prop.GetValue(obj, null);
if (result != null)
{
obj = result;
retValue = result.ToString();
}
else
{
break;
}
}
catch (Exception)
{
throw;
}
}
return retValue;
}
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].DataPropertyName.Contains("."))
{
e.Value = EvaluateValue(dataGridView1.Rows[e.RowIndex].DataBoundItem, dataGridView1.Columns[e.ColumnIndex].DataPropertyName);
}
if (dataGridView1.Columns[e.ColumnIndex].Name == "KeyCode")
{
if (e.Value != null && e.Value.ToString().Length > 0)
{
e.Value = new string('*', e.Value.ToString().Length);
}
}
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
int i = this.dataGridView1.CurrentCell.ColumnIndex;
bool usePassword = false;
if (dataGridView1.Columns[i].Name == "KeyCode")
{
usePassword = true;
}
TextBox txt = e.Control as TextBox;
if (txt != null)
{
txt.UseSystemPasswordChar = usePassword;
}
}
//示例:绑定的源数据类定义
public class DemoBindClass
{
public string Attr { get; set; }
public string KeyCode { get; set; }
public DemoDetailA Detail { get; set; }
}
public class DemoDetailA
{
public string Apro1 { get; set; }
public string Apro2 { get; set; }
public string Apro3 { get; set; }
public DemoDetailB DetailChild { get; set; }
}
public class DemoDetailB
{
public string Bpro1 { get; set; }
public string Bpro2 { get; set; }
public string Bpro3 { get; set; }
}
绑定到数据源:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var demo = new[] {
new DemoBindClass()
{
Attr = "demo",
KeyCode="a123456789b",
Detail = new DemoDetailA()
{
Apro1 = "demoA1",
Apro2 = "demoA2",
Apro3 = "demoA3",
DetailChild = new DemoDetailB()
{
Bpro1 = "demoB1",
Bpro2 = "demoB2",
Bpro3 = "demoB3"
}
}
}
};
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = demo;
实现指定列采取密码框模式显示与编辑,以及列绑定到复合属性均需要订阅DataGridView的CellFormatting及EditingControlShowing事件,并在其中写转换当前Cell的Value,实现列绑定到复合属性,关键点在:EvaluateValue方法,该方法逻辑很简单,就是根据绑定的属性层级(.分隔)层层遍历获取属性的值,直到遍历完或为空时停止,最后得到的结果即是绑定的属性的值。最终实现的效果如下图示:
4.利用BCP(sqlbulkcopy)来实现两个不同数据库之间进行数据差异传输(即:数据同步)
TransferBulkCopy作用:实现两个不同数据库之间进行数据差异传输,BuildInsertOrUpdateToDestTableSql作用:根据目的表及临时表生成更新与插入记录的SQL语句,以此实现:若同步的数据已存在,则更新,不存在,则插入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/// <summary>
/// 通用数据传输方法(采用SqlBulkCopy快速批量插入,然后再进行处理)
/// </summary>
/// <param name="sourceSelectSql"></param>
/// <param name="sourceConn"></param>
/// <param name="destTableName"></param>
/// <param name="destConn"></param>
/// <param name="colMapFunc"></param>
/// <param name="lastSaveAction"></param>
public void TransferBulkCopy(string sourceSelectSql, SqlConnection sourceConn, string destTableName, SqlConnection destConn, Func<DataTable, Dictionary<string, string>> colMapFunc,
Func<string, DataTable, SqlConnection, SqlConnection, bool> lastSaveAction, bool closeConnection = true)
{
DataTable srcTable = new DataTable();
SqlDataAdapter srcAdapter = new SqlDataAdapter(sourceSelectSql, sourceConn);
srcAdapter.AcceptChangesDuringUpdate = false;
SqlCommandBuilder srcCmdBuilder = new SqlCommandBuilder(srcAdapter);
srcAdapter.Fill(srcTable);
if (srcTable != null && srcTable.Rows.Count > 0)
{
string tempDestTableName = "#temp_" + destTableName;
ClsDatabase.gExecCommand(destConn, string.Format("select top 0 * into {0} from {1}", tempDestTableName, destTableName), false);
List<string> mapDestColNameList = new List<string>();
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(destConn))
{
sqlBulkCopy.DestinationTableName = tempDestTableName;
foreach (var map in colMapFunc(srcTable))
{
sqlBulkCopy.ColumnMappings.Add(map.Key, map.Value);
mapDestColNameList.Add(map.Value);
}
sqlBulkCopy.WriteToServer(srcTable);
}
srcTable.ExtendedProperties.Add(MapDestColNames_String, mapDestColNameList);
bool needUpdate = lastSaveAction(tempDestTableName, srcTable, destConn, sourceConn);
if (needUpdate)
{
if (srcTable.Columns.Contains("TranFlag"))
{
foreach (DataRow row in srcTable.Rows)
{
row["TranFlag"] = true;
}
}
srcAdapter.Update(srcTable);
}
}
if (closeConnection)
{
DisposeConnections(sourceConn, destConn);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/// <summary>
/// 生成同步插入及更新目的表SQL语句
/// </summary>
/// <param name="destTableName"></param>
/// <param name="tempdestTableName"></param>
/// <param name="pkWhereColNames"></param>
/// <param name="mapDestColNames"></param>
/// <param name="sqlType">0=生成INSERT与UPDATE;1=生成UPDATE语句;2=生成INSERT语句</param>
/// <returns></returns>
public string BuildInsertOrUpdateToDestTableSql(string destTableName, string tempdestTableName, string[] pkWhereColNames, object mapDestColNames, int sqlType = 0)
{
var mapDestColNameList = mapDestColNames as List<string>;
string updateColNames = null;
foreach (string col in mapDestColNameList)
{
if (!pkWhereColNames.Contains(col, StringComparer.OrdinalIgnoreCase))
{
updateColNames += string.Format(",{0}=tnew.{0}", col);
}
}
updateColNames = updateColNames.Substring(1);
string insertColNames = string.Join(",", mapDestColNameList);
string pkWhereSql = null;
foreach (string col in pkWhereColNames)
{
pkWhereSql += string.Format(" and told.{0}=tnew.{0} ", col);
}
pkWhereSql = pkWhereSql.Trim().Substring(3);
StringBuilder sqlBuilder = new StringBuilder();
if (sqlType == 0 || sqlType == 1)
{
sqlBuilder.AppendFormat("UPDATE {0} SET {1} FROM {0} told INNER JOIN {2} tnew ON {3} " + Environment.NewLine,
destTableName, updateColNames, tempdestTableName, pkWhereSql);
}
if (sqlType == 0 || sqlType == 2)
{
sqlBuilder.AppendFormat("INSERT INTO {0}({1}) SELECT {1} FROM {2} tnew WHERE NOT EXISTS(SELECT 1 FROM {0} told WHERE {3}) " + Environment.NewLine,
destTableName, insertColNames, tempdestTableName, pkWhereSql);
}
return sqlBuilder.ToString();
}
使用示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public void SendData_CustomerAuthorization()
{
try
{
SqlConnection obConnLMS1 = new SqlConnection(master.connLMSStr);
SqlConnection obConnWEB1 = new SqlConnection(master.connWEBStr);
string selectSql = @"SELECT TOP {0} Id,Phone,Mac,IsSet,LastLoginTime,PCName,TranFlag FROM TWEB_CustomerAuthorization WHERE TranFlag=0 ORDER BY Id ";
selectSql = string.Format(selectSql, master.batchSize);
master.TransferBulkCopy(selectSql, obConnWEB1,
"TB_CustomerAuthorization", obConnLMS1,
(stable) =>
{
var colMaps = new Dictionary<string, string>();
foreach (DataColumn col in stable.Columns)
{
if (!col.ColumnName.Equals("TranFlag", StringComparison.OrdinalIgnoreCase))
{
colMaps.Add(col.ColumnName, col.ColumnName);
}
}
return colMaps;
},
(tempTableName, stable, destConn, srcConn) =>
{
StringBuilder saveSqlBuilder = new StringBuilder("begin tran" + Environment.NewLine);
string IUSql = master.BuildInsertOrUpdateToDestTableSql("TB_CustomerAuthorization", tempTableName, new[] { "Id" }, stable.ExtendedProperties[master.MapDestColNames_String]);
saveSqlBuilder.Append(IUSql);
saveSqlBuilder.AppendLine("commit");
ClsDatabase.gExecCommand(destConn, saveSqlBuilder.ToString());
master.WriteMsg(master.lstSended, string.Format("上传时间:{0:yyyy-MM-dd HH:mm}\t SendData_CustomerAuthorization \t Succeed:{1}", DateTime.Now, stable.Rows.Count));
return true;
});
}
catch (Exception ex)
{
master.WriteMsg(master.lstErrorInfo, DateTime.Now.ToString("yyyy-MM-dd HH:mm") + "\t" + "SendData_CustomerAuthorization" + "\t" + ex.Message.ToString());
}
}
同步原理如下:
4.1.定义好查询源服务器的需要同步的表(一般表中我们定义一个用于是否同步的标识字段,如:TranFlag Bit类型,0表示新数据,未同步,1表示已同步);
4.2.查询源服务器的需要同步的表的记录(一般是TranFlag=0的记录),利用SqlDataAdapter+SqlCommandBuilder 装载Dataset,目的是后续可以利用SqlDataAdapter直接生成更新命令并执行;
4.3.利用insert into从目的服务器的将被同步的表复制结构产生一个临时表,表名一般是:#temp_目的服务器的将被同步表名 ,这样临时表与实体表的结构完全一致;
4.4.实例化一个SqlBulkCopy,并建立源服务器的需要同步的表字段与目的临时表字段的映射,然后执行跨服务器传输;
4.5.利用 BuildInsertOrUpdateToDestTableSql 方法 ,生成 目的服务器的将被同步的表 与 临时表的插入与更新SQL语句(现在在同一个库了,想怎么用SQL语句均可)
4.6.为确保一致性,故外层还需包裹事务SQL语句,若还需加入其它处理SQL,可以加在begin tran ... commit代码块中即可,最后执行SQL语句:gExecCommand(ClsDatabase.gExecCommand是一个SQLDB HELPER 类的执行SQL命令的方法)
5.实现同一个WINDOWS SERVICE程序 COPY多份,然后通过更改自定义的服务ID(ServiceID)配置项来实现:同一个服务程序安装成多个不同的WINDOWS服务进程:
5.1.创建一个WINDOWS服务项目,在ProjectInstaller设计器界面通过右键弹出菜单选择安装程序(serviceProcessInstaller1、serviceInstaller1)、并设置好ServiceName、DisplayName、Description、Account等,如下图示:
5.2.在ProjectInstaller构造函数中增加从CONFIG文件中读取自定义的服务ID(ServiceID)配置项的值,然后将ServiceID拼加到预设的ServiceName后面,以便实际根据ServiceID能够安装成不同ServiceID后缀的服务进程,关键点在于改变ServiceName,另一个关键点是从CONFIG文件中获取ServiceID,由于安装时,传统的方式无法正常读取到CONFIG,只能通过Assembly.GetExecutingAssembly().Location 来获取当前执行的程序集的路径再拼成CONFIG文件路径,最后读出ServiceID的值,示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
string assyLocation = System.Reflection.Assembly.GetExecutingAssembly().Location;
string assyCfgPath = assyLocation + ".config";
string installServiceLogPath = Path.Combine(Path.GetDirectoryName(assyLocation), "InstallServiceLog.log");
string serviceID = ConfigUtil.GetAppSettingValueForConfigPath("ServiceID", assyCfgPath);
System.IO.File.AppendAllText(installServiceLogPath, string.Format("[{0:yyyy-MM-dd HH:mm:ss}] ServiceAssembly ConfigPath:{1};\r\n", DateTime.Now, assyCfgPath));
if (!string.IsNullOrWhiteSpace(serviceID))
{
this.serviceInstaller1.DisplayName = "TestService_" + serviceID;
this.serviceInstaller1.ServiceName = "TestService_" + serviceID;
}
System.IO.File.AppendAllText(installServiceLogPath, string.Format("[{0:yyyy-MM-dd HH:mm:ss}] ProjectInstaller.ProjectInstaller() ->ServiceID:{1},ServiceName:{2}; \r\n", DateTime.Now, serviceID, this.serviceInstaller1.ServiceName));
}
}
5.3.在服务类的构造函数中同样增加从CONFIG中读取自定义的服务ID(ServiceID)配置项的值,然后将ServiceID拼加到预设的ServiceName后面(注意应与上述ProjectInstaller中指定的ServiceName相同),示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
public partial class TestService: ServiceBase
{
public TestService()
{
serviceID = ConfigUtil.GetAppSettingValue("ServiceID");
if (!string.IsNullOrWhiteSpace(serviceID))
{
this.ServiceName = "TestService_" + serviceID;
}
}
}
上述三步就完成了同一个服务程序安装成多个不同的WINDOWS服务进程,这个还是比较实用的哦!上述ConfigUtil是封装的一个配置文件读写帮助类,之前文章有介绍,后面也会发布一个更完整的ConfigUtil类。
本文转自 梦在旅途 博客园博客,原文链接: http://www.cnblogs.com/zuowj/p/6264711.html ,如需转载请自行联系原作者
DataGridView 单元格表示值的自定义
通过CellFormatting事件,可以自定义单元格的表示值。(比如:值为Error的时候,单元格被设定为红色)下面的示例:将“Colmn1”列的值改为大写。
[VB.NET]'CellFormatting 事件处理方法Private Sub DataGridView1_CellFormatting(ByVal sender As Object, _
ByVal e As DataGridViewCellFormattingEventArgs) _
Handles DataGridView1.CellFormatting
Dim dgv As DataGridView = CType(sender, DataGridView)
' 如果单元格是“Column1”列的单元格 If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _
TypeOf e.Value Is String Then
' 将单元格值改为大写 Dim str As String = e.Value.ToString()
e.Value = str.ToUpper()
' 应用该Format,Format完毕。 e.FormattingApplied = True
End IfEnd Sub
[C#]//CellFormatting 事件处理方法private void DataGridView1_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
// 如果单元格是“Column1”列的单元格 if (dgv.Columns[e.ColumnIndex].Name == "Column1" && e.Value is string)
{
// 将单元格值改为大写 string str = e.Value.ToString();
e.Value = str.ToUpper();
// 应用该Format,Format完毕。 e.FormattingApplied = true;
}
}
CellFormatting事件的DataGridViewCellFormattingEventArgs对象的Value属性一开始保存着未被格式化的值。当Value属性被设定表示用的文本之后,把FormattingApplied属性做为True,告知DataGridView文本已经格式化完毕。如果不这样做的话,DataGridView会根据已经设定的Format,NullValue,DataSourceNullValue,FormatProvider属性会将Value属性会被重新格式化一遍。
本文转自 qianshao 51CTO博客,原文链接:http://blog.51cto.com/qianshao/201795,如需转载请自行联系原作者
c#DataGridView数据绑定示例——格式化单元格的内容
c#DataGridView数据绑定示例 格式化单元格的内容
在使用DataGridView显示数据库中的数据时,我们需要对某列的数据显示格式进行格式化。
这里使用实时构建的数据,如下图:
在显示时对第三列的数据进行格式化,如下图:
测试数据构建及数据绑定:
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Id"));
dt.Columns.Add(new DataColumn("Name"));
dt.Columns.Add(new DataColumn("Bit"));
dt.Rows.Add(new object[] { "1", "abcd", "0"});
dt.Rows.Add(new object[] { "2", "abcd", "1" });
dt.Rows.Add(new object[] { "3", "abcd", "0" });
dt.Rows.Add(new object[] { "4", "abcd", "1" });
dt.Rows.Add(new object[] { "5", "abcd", "1" });
dt.Rows.Add(new object[] { "6", "abcd", "0" });
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = dt;
}单元格数据格式化:private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (Column_bit.Index == e.ColumnIndex)
{
if (e.Value == null)
{
return;
}
if (e.Value.Equals("0"))
{
e.Value = "否";
}
else
{
e.Value = "是";
}
}
}
源码下载:c#DataGridView数据绑定示例 格式化单元格的内容源码
【Winform】单元格的Formatted值的类型错误
最近在做一个C# winform应用程序,第一次接触C# winform开发,觉得还真不习惯,很多东西不知如何着手,与asp.net相差还是比较大的。就如今天遇到的一个问题,想将DataGridView的某一列格式化一下,就出现问题了:
DataGridView中发生以下异常:
System.FormatException:单元格的Formatted值的类型错误。
要替换此默认对话框,请处理DataError事件。
最后经查找将代码更正后即没事了:
private void gvList_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (gvList.Rows[e.RowIndex].IsNewRow)
return;
if (gvList.Columns[e.ColumnIndex].Name == "StreetID")
{
if (e.Value == null)
e.Value = string.Empty;
else {
//e.Value = "本街道"; int streedId = Utils.ConvertToInt32(e.Value.ToString());
if (streedId > 0)
{
Street streetModel = Utils.GetStreetModel(streedId);
if (streetModel != null)
e.Value = streetModel.Name;
}
}
}
if (e.ColumnIndex == 0)
{
e.Value = e.RowIndex + 1; //DataGridView行号,序号
}
//if (e.ColumnIndex == 2) {
// //e.FormattingApplied = true;
// DataGridViewRow row =gvList.Rows[e.RowIndex];
// if(row!=null){
// if (row.Cells[2].Value != null && row.Cells[3].Value.ToString() == "2")
// {
// e.Value = string.Format("{0}",
// "好啊");
// }
// }
//} }
转载请注明出处[http://samlin.cnblogs.com/]
作者赞赏
当当计算书籍 5-8折
刚做的招标网:八爪鱼招标网 请大家多意见
分类: .net,C#小技巧,代码片断
标签: winform
本文转自Sam Lin博客博客园博客,原文链接:http://www.cnblogs.com/samlin/archive/2012/03/28/FormatException.html,如需转载请自行联系原作者
DataGridView使用小结
1).右键点击行时选中行,并弹出操作菜单1). 添加一个快捷菜单contextMenuStrip1;2). 给dataGridView1的CellMouseDown事件添加处理程序: private void dataGridView1_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e) { if (e.Button == MouseButtons.Right) { //过滤有可能右键点击的行标题和空白列头。 if (e.RowIndex >= 0 && e.ColumnIndex>=0) { //若行已是选中状态就不再进行设置 if (dataGridView1.Rows[e.RowIndex].Selected == false) { dataGridView1.ClearSelection(); dataGridView1.Rows[e.RowIndex].Selected = true; } //只选中一行时设置活动单元格 if (dataGridView1.SelectedRows.Count == 1) { dataGridView1.CurrentCell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]; } //弹出操作菜单 contextMenuStrip1.Show(MousePosition.X, MousePosition.Y); } } }
效果图:2).复制选中单元格的内容到剪贴板Clipboard.SetDataObject(dataGridView1.GetClipboardContent());3).只显示自定义列dataGridView1.AutoGenerateColumns = false;//必须在代码中设置4).显示图片通常,我们将图片路径保存在数据库中,但在dataGridView1中要显示图片,可以进行如下操作:①.添加一个DataGridViewTextBoxColumn类型的列,Name=Path,DataPropertyName=Pic,Visible=False;②.添加一个DataGridViewImageColumn类型的列,Name=Pic;③.dataGridView1控件DataBindingComplete事件处理程序如下:private void DataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e){ Image image1 = null; Image image2 = null; string path = string.Empty; for (int i = 0; i < dataGridView1.Rows.Count; i++) { path = @"F:\" + dataGridView1.Rows[i].Cells["Path"].Value; if (File.Exists(path)) { image1 = Image.FromFile(path); image2 = new Bitmap(image1, 120, 120);//重设大小 dataGridView1.Rows[i].Cells["Pic"].Value = image2; //((DataGridViewImageCell)dataGridView1.Rows[i].Cells["Pic"]).Value = image2; } }}5).当网格未填充满控件时,画线来填充空白区域/// <summary>/// 绘制网格填充空白区域/// </summary>/// <param name="sender"></param>/// <param name="e"></param>public void CellPainting(object sender, DataGridViewCellPaintingEventArgs e){ DataGridView myDataGridView = (DataGridView)sender; if (myDataGridView.Rows.Count > 0) { int i = myDataGridView.ColumnHeadersHeight;//标题行高 int j = myDataGridView.Rows.GetRowsHeight(DataGridViewElementStates.Visible); //所有可见行总高 int k = myDataGridView.Height; //控件高度 int l = myDataGridView.Rows.GetLastRow(DataGridViewElementStates.Visible);//最后一行索引 int count = myDataGridView.Columns.Count;//列总数 int width = 0; //当网格未充满控件时才画线 if (i + j < k) { using (Brush gridBrush = new SolidBrush(myDataGridView.GridColor)) { using (Pen gridLinePen = new Pen(gridBrush)) { //处理标题列 if (myDataGridView.RowHeadersVisible) { width = myDataGridView.RowHeadersWidth; e.Graphics.DrawLine(gridLinePen, width, i + j, width, k); } else { width = 1; } //处理正常列 for (int index = 0; index < count; index++) { if (myDataGridView.Columns[index].Visible) { width += myDataGridView.Columns[index].Width; e.Graphics.DrawLine(gridLinePen, width, i + j, width, k); } } } } } }}6).自定义列宽手动添加列,再在编辑列界面中逐个设置宽度。注意AutoSizeColumnsMode的值必须为DataGridViewAutoSizeColumnsMode.None,否则自定义宽度不能生效!7).单元格内容格式化private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e){ DataGridView myDataGridView = (DataGridView)sender; if (myDataGridView.Columns["ID"].Index == e.ColumnIndex) { if(e.Value != null && !string.IsNullOrEmpty(e.Value.ToString())) e.Value = "BH" + string.Format("{0:D8}", int.Parse(e.Value.ToString())); }}8).打造一个漂亮的DataGridView//样式dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;//列宽不自动调整,手工添加列dataGridView1.RowHeadersWidth = 12;//行标题宽度固定12dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing;//不能用鼠标调整列标头宽度dataGridView1.AlternatingRowsDefaultCellStyle.BackColor = Color.LemonChiffon;//奇数行背景色dataGridView1.BackgroundColor = Color.White;//控件背景色dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;//列标题居中显示dataGridView1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;//单元格内容居中显示//行为dataGridView1.AutoGenerateColumns = false;//不自动创建列dataGridView1.AllowUserToAddRows = false;//不启用添加dataGridView1.ReadOnly = true;//不启用编辑dataGridView1.AllowUserToDeleteRows = false;//不启用删除dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;//单击单元格选中整行dataGridView1.MultiSelect = false;//不能多选9).判断有无滚动条//垂直滚动条if (dataGridView1.Rows.GetRowsHeight(DataGridViewElementStates.None) > dataGridView1.Height) MessageBox.Show("有");else MessageBox.Show("无");//水平滚动条if(dataGridView1.Columns.GetColumnsWidth(DataGridViewElementStates.None) > dataGridView1.Width) MessageBox.Show("有");else MessageBox.Show("无");10).为什么列标题总不居中?已经将列标题默认对齐方式设置为居中:dataGridView1.ColumnHeadersDefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;//列标题居中显示但实际的效果总是偏左了一点,原因是列可以进行排序,排序标志符号在列标题上占了空间。逐列按下边设置可去掉:dataGridView1.Columns[i].SortMode = DataGridViewColumnSortMode.NotSortable;
关键字: datagridview 属性 说明
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chinahuyong/article/details/4245827
关键字: datagridview 属性 说明
① 取得或者修改当前单元格的内容 ② 设定单元格只读 ③ 不显示最下面的新行 ④ 判断新增行 ⑤ 行的用户删除操作的自定义 ⑥ 行、列的隐藏和删除 ⑦ 禁止列或者行的Resize ⑧ 列宽和行高以及列头的高度和行头的宽度的自动调整 ⑨ 冻结列或行 ⑩ 列顺序的调整 ⑪ 行头列头的单元格 ⑫ 剪切板的操作 ⑬ 单元格的ToolTip的设置 ⑭ 右键菜单(ContextMenuStrip)的设置 ⑮ 单元格的边框、 网格线样式的设定 ⑯ 单元格表示值的设定 ⑰ 用户输入时,单元格输入值的设定 ⑱ 设定新加行的默认值 ① DataGridView 取得或者修改当前单元格的内容: GO TO TOP 当前单元格指的是 DataGridView 焦点所在的单元格,它可以通过 DataGridView 对象的 CurrentCell 属性取得。如果当前单元格不存在的时候,返回Nothing(C#是null) [VB.NET] ' 取得当前单元格内容 Console.WriteLine(DataGridView1.CurrentCell.Value) ' 取得当前单元格的列 Index Console.WriteLine(DataGridView1.CurrentCell.ColumnIndex) ' 取得当前单元格的行 Index Console.WriteLine(DataGridView1.CurrentCell.RowIndex) [C#] // 取得当前单元格内容 Console.WriteLine(DataGridView1.CurrentCell.Value); // 取得当前单元格的列 Index Console.WriteLine(DataGridView1.CurrentCell.ColumnIndex); // 取得当前单元格的行 Index Console.WriteLine(DataGridView1.CurrentCell.RowIndex); 另外,使用 DataGridView.CurrentCellAddress 属性(而不是直接访问单元格)来确定单元格所在的行:DataGridView.CurrentCellAddress.Y 和列: DataGridView.CurrentCellAddress.X 。这对于避免取消共享行的共享非常有用。 当前的单元格可以通过设定 DataGridView 对象的 CurrentCell 来改变。可以通过 CurrentCell 来设定 DataGridView 的激活单元格。将 CurrentCell 设为 Nothing(null) 可以取消激活的单元格。 [VB.NET] ' 设定 (0, 0) 为当前单元格 DataGridView1.CurrentCell = DataGridView1(0, 0) [C#] // 设定 (0, 0) 为当前单元格 DataGridView1.CurrentCell = DataGridView1[0, 0]; 在整行选中模式开启时,你也可以通过 CurrentCell 来设定选定行。 /**//// <summary> /// 向下遍历 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button4_Click(object sender, EventArgs e) ...{ int row = this.dataGridView1.CurrentRow.Index + 1; if (row > this.dataGridView1.RowCount - 1) row = 0; this.dataGridView1.CurrentCell = this.dataGridView1[0, row]; } /**//// <summary> /// 向上遍历 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button5_Click(object sender, EventArgs e) ...{ int row = this.dataGridView1.CurrentRow.Index - 1; if (row < 0) row = this.dataGridView1.RowCount - 1; this.dataGridView1.CurrentCell = this.dataGridView1[0, row]; } * 注意: this.dataGridView 的索引器的参数是: columnIndex, rowIndex 或是 columnName, rowIndex 这与习惯不同。 -------------------------------------------------------------------------------- ② DataGridView 设定单元格只读: GO TO TOP 1) 使用 ReadOnly 属性 ⇒ 如果希望,DataGridView 内所有单元格都不可编辑, 那么只要: [VB.NET] ' 设置 DataGridView1 为只读 DataGridView1.ReadOnly = True [C#] // 设置 DataGridView1 为只读 DataGridView1.ReadOnly = true;此时,用户的新增行操作和删除行操作也被屏蔽了。 ⇒ 如果希望,DataGridView 内某个单元格不可编辑, 那么只要: [VB.NET] ' 设置 DataGridView1 的第2列整列单元格为只读 DataGridView1.Columns(1).ReadOnly = True ' 设置 DataGridView1 的第3行整行单元格为只读 DataGridView1.Rows(2).ReadOnly = True ' 设置 DataGridView1 的[0,0]单元格为只读 DataGridView1(0, 0).ReadOnly = True [C#] // 设置 DataGridView1 的第2列整列单元格为只读 DataGridView1.Columns[1].ReadOnly = true; // 设置 DataGridView1 的第3行整行单元格为只读 DataGridView1.Rows[2].ReadOnly = true; // 设置 DataGridView1 的[0,0]单元格为只读 DataGridView1[0, 0].ReadOnly = true; 2) 使用 EditMode 属性 DataGridView.EditMode 属性被设置为 DataGridViewEditMode.EditProgrammatically 时,用户就不能手动编辑单元格的内容了。但是可以通过程序,调用 DataGridView.BeginEdit 方法,使单元格进入编辑模式进行编辑。 [VB.NET] DataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically [C#] DataGridView1.EditMode = DataGridViewEditMode.EditProgrammatically; 3) 根据条件设定单元格的不可编辑状态 当一个一个的通过单元格坐标设定单元格 ReadOnly 属性的方法太麻烦的时候,你可以通过 CellBeginEdit 事件来取消单元格的编辑。 [VB.NET] 'CellBeginEdit 事件处理方法 Private Sub DataGridView1_CellBeginEdit(ByVal sender As Object, _ ByVal e As DataGridViewCellCancelEventArgs) _ Handles DataGridView1.CellBeginEdit Dim dgv As DataGridView = CType(sender, DataGridView) ' 是否可以进行编辑的条件检查 If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _ Not CBool(dgv("Column2", e.RowIndex).Value) Then ' 取消编辑 e.Cancel = True End If End Sub [C#] // CellBeginEdit 事件处理方法 private void DataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { DataGridView dgv = (DataGridView)sender; //是否可以进行编辑的条件检查 if (dgv.Columns[e.ColumnIndex].Name == "Column1" && !(bool)dgv["Column2", e.RowIndex].Value) { // 取消编辑 e.Cancel = true; } } -------------------------------------------------------------------------------- ③ DataGridView 不显示最下面的新行: GO TO TOP 通常 DataGridView 的最下面一行是用户新追加的行(行头显示 * )。如果不想让用户新追加行即不想显示该新行,可以将 DataGridView 对象的 AllowUserToAddRows 属性设置为 False。 [VB.NET] ' 设置用户不能手动给 DataGridView1 添加新行 DataGridView1.AllowUserToAddRows = False [C#] // 设置用户不能手动给 DataGridView1 添加新行 DataGridView1.AllowUserToAddRows = false; 但是,可以通过程序: DataGridViewRowCollection.Add 为 DataGridView 追加新行。 补足: 如果 DataGridView 的 DataSource 绑定的是 DataView, 还可以通过设置 DataView.AllowAdd 属性为 False 来达到同样的效果。 -------------------------------------------------------------------------------- ④ DataGridView 判断新增行: GO TO TOP DataGridView的AllowUserToAddRows属性为True时也就是允许用户追加新行的场合下,DataGridView的最后一行就是新追加的行(*行)。使用 DataGridViewRow.IsNewRow 属性可以判断哪一行是新追加的行。另外,通过DataGridView.NewRowIndex 可以获取新行的行序列号。在没有新行的时候,NewRowIndex = -1。 [VB.NET] If DataGridView1.CurrentRow.IsNewRow Then Console.WriteLine("当前行为新追加行。") Else Console.WriteLine("当前行不是新追加行。") End If -------------------------------------------------------------------------------- ⑤ DataGridView 行的用户删除操作的自定义: GO TO TOP 1) 无条件的限制行删除操作。 默认时,DataGridView 是允许用户进行行的删除操作的。如果设置 DataGridView对象的AllowUserToDeleteRows属性为 False 时, 用户的行删除操作就被禁止了。 [VB.NET] ' 禁止DataGridView1的行删除操作。 DataGridView1.AllowUserToDeleteRows = False [C#] // 禁止DataGridView1的行删除操作。 DataGridView1.AllowUserToDeleteRows = false; 但是,通过 DataGridViewRowCollection.Remove 还是可以进行行的删除。 补足: 如果 DataGridView 绑定的是 DataView 的话,通过 DataView.AllowDelete 也可以控制行的删除。 2) 行删除时的条件判断处理。 用户在删除行的时候,将会引发 DataGridView.UserDeletingRow 事件。 在这个事件里,可以判断条件并取消删除操作。 [VB.NET] ' DataGridView1 的 UserDeletingRow 事件 Private Sub DataGridView1_UserDeletingRow(ByVal sender As Object, _ ByVal e As DataGridViewRowCancelEventArgs) _ Handles DataGridView1.UserDeletingRow ' 删除前的用户确认。 If MessageBox.Show("确认要删除该行数据吗?", "删除确认", _ MessageBoxButtons.OKCancel, MessageBoxIcon.Question) <> _ Windows.Forms.DialogResult.OK Then ' 如果不是 OK,则取消。 e.Cancel = True End If End Sub [C#] // DataGridView1 的 UserDeletingRow 事件 private void DataGridView1_UserDeletingRow( object sender, DataGridViewRowCancelEventArgs e) { // 删除前的用户确认。 if (MessageBox.Show("确认要删除该行数据吗?", "删除确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) != DialogResult.OK) { // 如果不是 OK,则取消。 e.Cancel = true; } } -------------------------------------------------------------------------------- ⑥ DataGridView 行、列的隐藏和删除: GO TO TOP 1) 行、列的隐藏 [VB.NET] ' DataGridView1的第一列隐藏 DataGridView1.Columns(0).Visible = False ' DataGridView1的第一行隐藏 DataGridView1.Rows(0).Visible = False [C#] // DataGridView1的第一列隐藏 DataGridView1.Columns[0].Visible = false; // DataGridView1的第一行隐藏 DataGridView1.Rows[0].Visible = false; 2) 行头、列头的隐藏 [VB.NET] ' 列头隐藏 DataGridView1.ColumnHeadersVisible = False ' 行头隐藏 DataGridView1.RowHeadersVisible = False [C#] // 列头隐藏 DataGridView1.ColumnHeadersVisible = false; // 行头隐藏 DataGridView1.RowHeadersVisible = false; 3) 行和列的删除 [VB.NET] ' 删除名为"Column1"的列 DataGridView1.Columns.Remove("Column1") ' 删除第一列 DataGridView1.Columns.RemoveAt(0) ' 删除第一行 DataGridView1.Rows.RemoveAt(0) [C#] ' 删除名为"Column1"的列 DataGridView1.Columns.Remove("Column1"); ' 删除第一列 DataGridView1.Columns.RemoveAt(0); ' 删除第一行 DataGridView1.Rows.RemoveAt(0); 4) 删除选中行 [VB.NET] For Each r As DataGridViewRow In DataGridView1.SelectedRows If Not r.IsNewRow Then DataGridView1.Rows.Remove(r) End If Next [C#] foreach (DataGridViewRow r in DataGridView1.SelectedRows) { if (!r.IsNewRow) { DataGridView1.Rows.Remove(r); } } -------------------------------------------------------------------------------- ⑦ DataGridView 禁止列或者行的Resize: GO TO TOP 1) 禁止所有的列或者行的Resize [VB.NET] ' 禁止用户改变DataGridView1的所有列的列宽 DataGridView1.AllowUserToResizeColumns = False '禁止用户改变DataGridView1の所有行的行高 DataGridView1.AllowUserToResizeRows = False [C#] // 禁止用户改变DataGridView1的所有列的列宽 DataGridView1.AllowUserToResizeColumns = false; //禁止用户改变DataGridView1の所有行的行高 DataGridView1.AllowUserToResizeRows = false; 但是可以通过 DataGridViewColumn.Width 或者 DataGridViewRow.Height 属性设定列宽和行高。 2) 禁止指定行或者列的Resize [VB.NET] ' 禁止用户改变DataGridView1的第一列的列宽 DataGridView1.Columns(0).Resizable = DataGridViewTriState.False ' 禁止用户改变DataGridView1的第一列的行宽 DataGridView1.Rows(0).Resizable = DataGridViewTriState.False [C#] // 禁止用户改变DataGridView1的第一列的列宽 DataGridView1.Columns[0].Resizable = DataGridViewTriState.False; // 禁止用户改变DataGridView1的第一列的行宽 DataGridView1.Rows[0].Resizable = DataGridViewTriState.False; ⇒ 关于 NoSet 当 Resizable 属性设为 DataGridViewTriState.NotSet 时, 实际上会默认以 DataGridView 的 AllowUserToResizeColumns 和 AllowUserToResizeRows 的属性值进行设定。比如: DataGridView.AllowUserToResizeColumns = False 且 Resizable 是 NoSet 设定时,Resizable = False 。 判断 Resizable 是否是继承设定了 DataGridView 的 AllowUserToResizeColumns 和 AllowUserToResizeRows 的属性值, 可以根据 State 属性判断。如果 State 属性含有 ResizableSet,那么说明没有继承设定。 3) 列宽和行高的最小值的设定 [VB.NET] ' 第一列的最小列宽设定为 100 DataGridView1.Columns(0).MinimumWidth = 100 ' 第一行的最小行高设定为 50 DataGridView1.Rows(0).MinimumHeight = 50 [C#] // 第一列的最小列宽设定为 100 DataGridView1.Columns[0].MinimumWidth = 100; // 第一行的最小行高设定为 50 DataGridView1.Rows[0].MinimumHeight = 50; 4) 禁止用户改变行头的宽度以及列头的高度 [VB.NET] ' 禁止用户改变列头的高度 DataGridView1.ColumnHeadersHeightSizeMode = _ DataGridViewColumnHeadersHeightSizeMode.DisableResizing ' 禁止用户改变行头的宽度 DataGridView1.RowHeadersWidthSizeMode = _ DataGridViewRowHeadersWidthSizeMode.EnableResizing [C#] // 禁止用户改变列头的高度 DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; // 禁止用户改变行头的宽度 DataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing; -------------------------------------------------------------------------------- ⑧ DataGridView 列宽和行高自动调整的设定: GO TO TOP 1) 设定行高和列宽自动调整 [VB.NET] ' 设定包括Header和所有单元格的列宽自动调整 DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells ' 设定包括Header和所有单元格的行高自动调整 DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells [C#] // 设定包括Header和所有单元格的列宽自动调整 DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; // 设定包括Header和所有单元格的行高自动调整 DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells; AutoSizeColumnsMode 属性的设定值枚举请参照 msdn 的 DataGridViewAutoSizeRowsMode 说明。 2)指定列或行自动调整 [VB.NET] ' 第一列自动调整 DataGridView1.Columns(0).AutoSizeMode = _ DataGridViewAutoSizeColumnMode.DisplayedCells [C#] // 第一列自动调整 DataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.DisplayedCells; AutoSizeMode 设定为 NotSet 时, 默认继承的是 DataGridView.AutoSizeColumnsMode 属性。 3) 设定列头的高度和行头的宽度自动调整 [VB.NET] ' 设定列头的宽度可以自由调整 DataGridView1.ColumnHeadersHeightSizeMode = _ DataGridViewColumnHeadersHeightSizeMode.AutoSize ' 设定行头的宽度可以自由调整 DataGridView1.RowHeadersWidthSizeMode = _ DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders [C#] // 设定列头的宽度可以自由调整 DataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; // 设定行头的宽度可以自由调整 DataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders; 4) 随时自动调整 a, 临时的,让列宽自动调整,这和指定AutoSizeColumnsMode属性一样。 [VB.NET] ' 让 DataGridView1 的所有列宽自动调整一下。 DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells) ' 让 DataGridView1 的第一列的列宽自动调整一下。 DataGridView1.AutoResizeColumn(0, DataGridViewAutoSizeColumnMode.AllCells) [C#] // 让 DataGridView1 的所有列宽自动调整一下。 DataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); // 让 DataGridView1 的第一列的列宽自动调整一下。 DataGridView1.AutoResizeColumn(0, DataGridViewAutoSizeColumnMode.AllCells);上面调用的 AutoResizeColumns 和 AutoResizeColumn 当指定的是DataGridViewAutoSizeColumnMode.AllCells 的时候, 参数可以省略。即: DataGridView1.AutoResizeColumn(0) 和 DataGridView1.AutoResizeColumns() b,临时的,让行高自动调整 [VB.NET] ' 让 DataGridView1 的所有行高自动调整一下。 DataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells) ' 让 DataGridView1 的第一行的行高自动调整一下。 DataGridView1.AutoResizeRow(0, DataGridViewAutoSizeRowMode.AllCells) [C#] // 让 DataGridView1 的所有行高自动调整一下。 DataGridView1.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells); //让 DataGridView1 的第一行的行高自动调整一下。 DataGridView1.AutoResizeRow(0, DataGridViewAutoSizeRowMode.AllCells);上面调用的 AutoResizeRows 和 AutoResizeRow 当指定的是DataGridViewAutoSizeRowMode.AllCells 的时候, 参数可以省略。即:DataGridView1.AutoResizeRow (0) 和 DataGridView1.AutoResizeRows() c,临时的,让行头和列头自动调整 [VB.NET] ' 列头高度自动调整 DataGridView1.AutoResizeColumnHeadersHeight() ' 行头宽度自动调整 DataGridView1.AutoResizeRowHeadersWidth( _ DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders) [C#] // 列头高度自动调整 DataGridView1.AutoResizeColumnHeadersHeight(); // 行头宽度自动调整 DataGridView1.AutoResizeRowHeadersWidth( DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders); 关于性能: 通过 AutoSizeColumnsMode 或者 AutoSizeRowsMode 属性所指定的单元格进行自动调整时,如果调整次数过于多那么将可能导致性能下降,尤其是在行和列数比较多的情况下。在这时用 DisplayedCells 代替 AllCells 能减少非所见的单元格的调整,从而提高性能。 -------------------------------------------------------------------------------- ⑨ DataGridView 冻结列或行 GO TO TOP 1) 列冻结 DataGridViewColumn.Frozen 属性为 True 时, 该列左侧的所有列被固定, 横向滚动时固定列不随滚动条滚动而左右移动。这对于重要列固定显示很有用。 [VB.NET] ' DataGridView1的左侧2列固定 DataGridView1.Columns(1).Frozen = True [C#] // DataGridView1的左侧2列固定 DataGridView1.Columns[1].Frozen = true; 但是,DataGridView.AllowUserToOrderColumns = True 时,固定列不能移动到非固定列, 反之亦然。 2) 行冻结 DataGridViewRow.Frozen 属性为 True 时, 该行上面的所有行被固定, 纵向滚动时固定行不随滚动条滚动而上下移动。 [VB.NET] ' DataGridView1 的上3行固定 DataGridView1.Rows(2).Frozen = True [C#] // DataGridView1 的上3行固定 DataGridView1.Rows[2].Frozen = true; -------------------------------------------------------------------------------- ⑩ DataGridView 列顺序的调整 GO TO TOP 设定 DataGridView 的 AllowUserToOrderColumns 为 True 的时候, 用户可以自由调整列的顺序。 当用户改变列的顺序的时候,其本身的 Index 不会改变,但是 DisplayIndex 改变了。你也可以通过程序改变 DisplayIndex 来改变列的顺序。 列顺序发生改变时会引发 ColumnDisplayIndexChanged 事件: [VB.NET] ' DataGridView1的ColumnDisplayIndexChanged事件处理方法 Private Sub DataGridView1_ColumnDisplayIndexChanged(ByVal sender As Object, _ ByVal e As DataGridViewColumnEventArgs) _ Handles DataGridView1.ColumnDisplayIndexChanged Console.WriteLine("{0} 的位置改变到 {1} 。", _ e.Column.Name, e.Column.DisplayIndex) End Sub [C#] // DataGridView1的ColumnDisplayIndexChanged事件处理方法 private void DataGridView1_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e) { Console.WriteLine("{0} 的位置改变到 {1} ", e.Column.Name, e.Column.DisplayIndex); } -------------------------------------------------------------------------------- ⑪ DataGridView 行头列头的单元格 GO TO TOP [VB.NET] ' DataGridView1的第一列列头内容 DataGridView1.Columns(0).HeaderCell.Value = "第一列" ' DataGridView1的第一行行头内容 DataGridView1.Rows(0).HeaderCell.Value = "第一行" ' DataGridView1的左上头部单元内容 DataGridView1.TopLeftHeaderCell.Value = "左上" [C#] // 改变DataGridView1的第一列列头内容 DataGridView1.Columns[0].HeaderCell.Value = "第一列"; // 改变DataGridView1的第一行行头内容 DataGridView1.Rows[0].HeaderCell.Value = "第一行"; // 改变DataGridView1的左上头部单元内容 DataGridView1.TopLeftHeaderCell.Value = "左上"; 另外你也可以通过 HeaderText 来改变他们的内容。 [VB.NET] ' 改变DataGridView1的第一列列头内容 DataGridView1.Columns(0).HeaderText = "第一列" [C#] // 改变DataGridView1的第一列列头内容 DataGridView1.Columns[0].HeaderText = "第一列"; -------------------------------------------------------------------------------- ⑫ DataGridView 剪切板的操作 GO TO TOP DataGridView.ClipboardCopyMode 属性被设定为 DataGridViewClipboardCopyMode.Disable 以外的情况时,「Ctrl + C」 按下的时候,被选择的单元格的内容会拷贝到系统剪切板内。格式有: Text, UnicodeText,Html, CommaSeparatedValue。可以直接粘贴到 Excel 内。 ClipboardCopyMode 还可以设定 Header部分是否拷贝: EnableAlwaysIncludeHeaderText 拷贝Header部分、EnableWithoutHeaderText 则不拷贝。默认是 EnableWithAutoHeaderText , Header 如果选择了的话,就拷贝。 1) 编程方式实现剪切板的拷贝 Clipboard.SetDataObject(DataGridView1.GetClipboardContent()) 2) DataGridView 的数据粘贴 实现剪切板的拷贝比较容易,但是实现 DataGridView 的直接粘贴就比较难了。「Ctrl + V」按下进行粘贴时,DataGridView 没有提供方法,只能自己实现。 以下,是粘贴时简单的事例代码,将拷贝数据粘贴到以选择单元格开始的区域内。 [VB.NET] ' 当前单元格是否选择的判断 If DataGridView1.CurrentCell Is Nothing Then Return End If Dim insertRowIndex As Integer = DataGridView1.CurrentCell.RowIndex ' 获取剪切板的内容,并按行分割 Dim pasteText As String = Clipboard.GetText() If String.IsNullOrEmpty(pasteText) Then Return End If pasteText = pasteText.Replace(vbCrLf, vbLf) pasteText = pasteText.Replace(vbCr, vbLf) pasteText.TrimEnd(New Char() {vbLf}) Dim lines As String() = pasteText.Split(vbLf) Dim isHeader As Boolean = True For Each line As String In lines ' 是否是列头 If isHeader Then isHeader = False Else ' 按 Tab 分割数据 Dim vals As String() = line.Split(ControlChars.Tab) ' 判断列数是否统一 If vals.Length - 1 <> DataGridView1.ColumnCount Then Throw New ApplicationException("粘贴的列数不正确。") End If Dim row As DataGridViewRow = DataGridView1.Rows(insertRowIndex) ' 行头设定 row.HeaderCell.Value = vals(0) ' 单元格内容设定 Dim i As Integer For i = 0 To row.Cells.Count - 1 row.Cells(i).Value = vals((i + 1)) Next i ' DataGridView的行索引+1 insertRowIndex += 1 End If Next line [C#] //当前单元格是否选择的判断 if (DataGridView1.CurrentCell == null) return; int insertRowIndex = DataGridView1.CurrentCell.RowIndex; // 获取剪切板的内容,并按行分割 string pasteText = Clipboard.GetText(); if (string.IsNullOrEmpty(pasteText)) return; pasteText = pasteText.Replace(" ", " "); pasteText = pasteText.Replace(' ', ' '); pasteText.TrimEnd(new char[] { ' ' }); string[] lines = pasteText.Split(' '); bool isHeader = true; foreach (string line in lines) { // 是否是列头 if (isHeader) { isHeader = false; continue; } // 按 Tab 分割数据 string[] vals = line.Split(' '); // 判断列数是否统一 if (vals.Length - 1 != DataGridView1.ColumnCount) throw new ApplicationException("粘贴的列数不正确。"); DataGridViewRow row = DataGridView1.Rows[insertRowIndex]; // 行头设定 row.HeaderCell.Value = vals[0]; // 单元格内容设定 for (int i = 0; i < row.Cells.Count; i++) { row.Cells[i].Value = vals[i + 1]; } // DataGridView的行索引+1 insertRowIndex++; } -------------------------------------------------------------------------------- ⑬ DataGridView 单元格的ToolTip的设置 GO TO TOP DataGridView.ShowCellToolTips = True 的情况下, 单元格的 ToolTip 可以表示出来。对于单元格窄小,无法完全显示的单元格, ToolTip 可以显示必要的信息。 1) 设定单元格的ToolTip内容 [VB.NET] ' 设定单元格的ToolTip内容 DataGridView1(0, 0).ToolTipText = "该单元格的内容不能修改" ' 设定列头的单元格的ToolTip内容 DataGridView1.Columns(0).ToolTipText = "该列只能输入数字" ' 设定行头的单元格的ToolTip内容 DataGridView1.Rows(0).HeaderCell.ToolTipText = "该行单元格内容不能修改" [C#] // 设定单元格的ToolTip内容 DataGridView1[0, 0].ToolTipText = "该单元格的内容不能修改"; // 设定列头的单元格的ToolTip内容 DataGridView1.Columns[0].ToolTipText = "该列只能输入数字"; // 设定行头的单元格的ToolTip内容 DataGridView1.Rows[0].HeaderCell.ToolTipText = "该行单元格内容不能修改"; 2) CellToolTipTextNeeded 事件 在批量的单元格的 ToolTip 设定的时候,一个一个指定那么设定的效率比较低, 这时候可以利用 CellToolTipTextNeeded 事件。当单元格的 ToolTipText 变化的时候也会引发该事件。但是,当DataGridView的DataSource被指定且VirualMode=True的时候,该事件不会被引发。 [VB.NET] ' CellToolTipTextNeeded事件处理方法 Private Sub DataGridView1_CellToolTipTextNeeded(ByVal sender As Object, _ ByVal e As DataGridViewCellToolTipTextNeededEventArgs) _ Handles DataGridView1.CellToolTipTextNeeded e.ToolTipText = e.ColumnIndex.ToString() + ", " + e.RowIndex.ToString() End Sub [C#] // CellToolTipTextNeeded事件处理方法 private void DataGridView1_CellToolTipTextNeeded(object sender, DataGridViewCellToolTipTextNeededEventArgs e) { e.ToolTipText = e.ColumnIndex.ToString() + ", " + e.RowIndex.ToString(); } -------------------------------------------------------------------------------- ⑭ DataGridView 的右键菜单(ContextMenuStrip) GO TO TOP DataGridView, DataGridViewColumn, DataGridViewRow, DataGridViewCell 有 ContextMenuStrip 属性。可以通过设定 ContextMenuStrip 对象来控制 DataGridView 的右键菜单的显示。 DataGridViewColumn 的 ContextMenuStrip 属性设定了 除了列头以外的单元格的右键菜单。 DataGridViewRow 的 ContextMenuStrip 属性设定了除了行头以外的单元格的右键菜单。DataGridViewCell 的 ContextMenuStrip 属性设定了指定单元格的右键菜单。 [VB.NET] ' DataGridView 的 ContextMenuStrip 设定 DataGridView1.ContextMenuStrip = Me.ContextMenuStrip1 ' 列的 ContextMenuStrip 设定 DataGridView1.Columns(0).ContextMenuStrip = Me.ContextMenuStrip2 ' 列头的 ContextMenuStrip 设定 DataGridView1.Columns(0).HeaderCell.ContextMenuStrip = Me.ContextMenuStrip2 ' 行的 ContextMenuStrip 设定 DataGridView1.Rows(0).ContextMenuStrip = Me.ContextMenuStrip3 ' 单元格的 ContextMenuStrip 设定 DataGridView1(0, 0).ContextMenuStrip = Me.ContextMenuStrip4 [C#] // DataGridView 的 ContextMenuStrip 设定 DataGridView1.ContextMenuStrip = this.ContextMenuStrip1; // 列的 ContextMenuStrip 设定 DataGridView1.Columns[0].ContextMenuStrip = this.ContextMenuStrip2; // 列头的 ContextMenuStrip 设定 DataGridView1.Columns[0].HeaderCell.ContextMenuStrip = this.ContextMenuStrip2; // 行的 ContextMenuStrip 设定 DataGridView1.Rows[0].ContextMenuStrip = this.ContextMenuStrip3; // 单元格的 ContextMenuStrip 设定 DataGridView1[0, 0].ContextMenuStrip = this.ContextMenuStrip4; 对于单元格上的右键菜单的设定,优先顺序是: Cell > Row > Column > DataGridView ⇒ CellContextMenuStripNeeded、RowContextMenuStripNeeded 事件 利用 CellContextMenuStripNeeded 事件可以设定单元格的右键菜单,尤其但需要右键菜单根据单元格值的变化而变化的时候。比起使用循环遍历,使用该事件来设定右键菜单的效率更高。但是,在DataGridView使用了DataSource绑定而且是VirtualMode的时候,该事件将不被引发。 [VB.NET] ' CellContextMenuStripNeeded事件处理方法 Private Sub DataGridView1_CellContextMenuStripNeeded( _ ByVal sender As Object, _ ByVal e As DataGridViewCellContextMenuStripNeededEventArgs) _ Handles DataGridView1.CellContextMenuStripNeeded Dim dgv As DataGridView = CType(sender, DataGridView) If e.RowIndex < 0 Then ' 列头的ContextMenuStrip设定 e.ContextMenuStrip = Me.ContextMenuStrip1 ElseIf e.ColumnIndex < 0 Then ' 行头的ContextMenuStrip设定 e.ContextMenuStrip = Me.ContextMenuStrip2 ElseIf TypeOf (dgv(e.ColumnIndex, e.RowIndex).Value) Is Integer Then ' 如果单元格值是整数时 e.ContextMenuStrip = Me.ContextMenuStrip3 End If End Sub [C#] // CellContextMenuStripNeeded事件处理方法 private void DataGridView1_CellContextMenuStripNeeded(object sender, DataGridViewCellContextMenuStripNeededEventArgs e) { DataGridView dgv = (DataGridView)sender; if (e.RowIndex < 0) { // 列头的ContextMenuStrip设定 e.ContextMenuStrip = this.ContextMenuStrip1; } else if (e.ColumnIndex < 0) { // 行头的ContextMenuStrip设定 e.ContextMenuStrip = this.ContextMenuStrip2; } else if (dgv[e.ColumnIndex, e.RowIndex].Value is int) { // 如果单元格值是整数时 e.ContextMenuStrip = this.ContextMenuStrip3; } } 同样,可以通过 RowContextMenuStripNeeded 事件来设定行的右键菜单。 [VB.NET] ' RowContextMenuStripNeeded事件处理方法 Private Sub DataGridView1_RowContextMenuStripNeeded( _ ByVal sender As Object, _ ByVal e As DataGridViewRowContextMenuStripNeededEventArgs) _ Handles DataGridView1.RowContextMenuStripNeeded Dim dgv As DataGridView = CType(sender, DataGridView) ' 当"Column1"列是Bool型且为True时、设定其的ContextMenuStrip Dim boolVal As Object = dgv("Column1", e.RowIndex).Value Console.WriteLine(boolVal) If TypeOf boolVal Is Boolean AndAlso CBool(boolVal) Then e.ContextMenuStrip = Me.ContextMenuStrip1 End If End Sub [C#] // RowContextMenuStripNeeded事件处理方法 private void DataGridView1_RowContextMenuStripNeeded(object sender, DataGridViewRowContextMenuStripNeededEventArgs e) { DataGridView dgv = (DataGridView)sender; // 当"Column1"列是Bool型且为True时、设定其的ContextMenuStrip object boolVal = dgv["Column1", e.RowIndex].Value; Console.WriteLine(boolVal); if (boolVal is bool && (bool)boolVal) { e.ContextMenuStrip = this.ContextMenuStrip1; } } CellContextMenuStripNeeded 事件处理方法的参数中、「e.ColumnIndex=-1」表示行头、「e.RowIndex=-1」表示列头。RowContextMenuStripNeeded则不存在「e.RowIndex=-1」的情况。 -------------------------------------------------------------------------------- ⑮ DataGridView 的单元格的边框、 网格线样式的设定 GO TO TOP 1) DataGridView 的边框线样式的设定 DataGridView 的边框线的样式是通过 DataGridView.BorderStyle 属性来设定的。 BorderStyle 属性设定值是一个 BorderStyle 枚举: FixedSingle(单线,默认)、Fixed3D、None。 2) 单元格的边框线样式的设定 单元格的边框线的样式是通过 DataGridView.CellBorderStyle 属性来设定的。 CellBorderStyle 属性设定值是 DataGridViewCellBorderStyle 枚举。(详细参见 MSDN) 另外,通过 DataGridView.ColumnHeadersBorderStyle 和 RowHeadersBorderStyle 属性可以修改 DataGridView 的头部的单元格边框线样式。 属性设定值是 DataGridViewHeaderBorderStyle 枚举。(详细参见 MSDN) 3) 单元格的边框颜色的设定 单元格的边框线的颜色可以通过 DataGridView.GridColor 属性来设定的。默认是 ControlDarkDark 。但是只有在 CellBorderStyle 被设定为 Single、SingleHorizontal、SingleVertical 的条件下才能改变其边框线的颜色。同样,ColumnHeadersBorderStyle 以及 RowHeadersBorderStyle 只有在被设定为 Single 时,才能改变颜色。 4) 单元格的上下左右的边框线式样的单独设定 CellBorderStyle只能设定单元格全部边框线的式样。要单独改变单元格某一边边框式样的话,需要用到DataGridView.AdvancedCellBorderStyle属性。如示例: [VB.NET] ' 单元格的上边和左边线设为二重线 ' 单元格的下边和右边线设为单重线 DataGridView1.AdvancedCellBorderStyle.Top = _ DataGridViewAdvancedCellBorderStyle.InsetDouble DataGridView1.AdvancedCellBorderStyle.Right = _ DataGridViewAdvancedCellBorderStyle.Inset DataGridView1.AdvancedCellBorderStyle.Bottom = _ DataGridViewAdvancedCellBorderStyle.Inset DataGridView1.AdvancedCellBorderStyle.Left = _ DataGridViewAdvancedCellBorderStyle.InsetDouble 同样,设定行头单元格的属性是: AdvancedRowHeadersBorderStyle, 设定列头单元格属性是:AdvancedColumnHeadersBorderStyle。 -------------------------------------------------------------------------------- ⑯ DataGridView 单元格表示值的自定义 GO TO TOP 通过CellFormatting事件,可以自定义单元格的表示值。(比如:值为Error的时候,单元格被设定为红色) 下面的示例:将“Colmn1”列的值改为大写。 [VB.NET] 'CellFormatting 事件处理方法 Private Sub DataGridView1_CellFormatting(ByVal sender As Object, _ ByVal e As DataGridViewCellFormattingEventArgs) _ Handles DataGridView1.CellFormatting Dim dgv As DataGridView = CType(sender, DataGridView) ' 如果单元格是“Column1”列的单元格 If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _ TypeOf e.Value Is String Then ' 将单元格值改为大写 Dim str As String = e.Value.ToString() e.Value = str.ToUpper() ' 应用该Format,Format完毕。 e.FormattingApplied = True End If End Sub [C#] //CellFormatting 事件处理方法 private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { DataGridView dgv = (DataGridView)sender; // 如果单元格是“Column1”列的单元格 if (dgv.Columns[e.ColumnIndex].Name == "Column1" && e.Value is string) { // 将单元格值改为大写 string str = e.Value.ToString(); e.Value = str.ToUpper(); // 应用该Format,Format完毕。 e.FormattingApplied = true; } } CellFormatting事件的DataGridViewCellFormattingEventArgs对象的Value属性一开始保存着未被格式化的值。当Value属性被设定表示用的文本之后,把FormattingApplied属性做为True,告知DataGridView文本已经格式化完毕。如果不这样做的话,DataGridView会根据已经设定的Format,NullValue,DataSourceNullValue,FormatProvider属性会将Value属性会被重新格式化一遍。 -------------------------------------------------------------------------------- ⑰ DataGridView 用户输入时,单元格输入值的设定 GO TO TOP 通过 DataGridView.CellParsing 事件可以设定用户输入的值。下面的示例:当输入英文文本内容的时候,立即被改变为大写。 [VB.NET] 'CellParsing 事件处理方法 Private Sub DataGridView1_CellParsing(ByVal sender As Object, _ ByVal e As DataGridViewCellParsingEventArgs) _ Handles DataGridView1.CellParsing Dim dgv As DataGridView = CType(sender, DataGridView) ' 单元格列为“Column1”时 If dgv.Columns(e.ColumnIndex).Name = "Column1" AndAlso _ e.DesiredType Is GetType(String) Then ' 将单元格值设为大写 e.Value = e.Value.ToString().ToUpper() ' 解析完毕 e.ParsingApplied = True End If End Sub [C#] //CellParsing 事件处理方法 private void DataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e) { DataGridView dgv = (DataGridView)sender; //单元格列为“Column1”时 if (dgv.Columns[e.ColumnIndex].Name == "Column1" && e.DesiredType == typeof(string)) { //将单元格值设为大写 e.Value = e.Value.ToString().ToUpper(); //解析完毕 e.ParsingApplied = true; } } -------------------------------------------------------------------------------- ⑱ DataGridView 新加行的默认值的设定 GO TO TOP 需要指定新加行的默认值的时候,可以在DataGridView.DefaultValuesNeeded事件里处理。在该事件中处理除了可以设定默认值以外,还可以指定某些特定的单元格的ReadOnly属性等。 [VB.NET] ' DefaultValuesNeeded 事件处理方法 Private Sub DataGridView1_DefaultValuesNeeded(ByVal sender As Object, _ ByVal e As DataGridViewRowEventArgs) _ Handles DataGridView1.DefaultValuesNeeded ' 设定单元格默认值 e.Row.Cells("Column1").Value = 0 e.Row.Cells("Column2").Value = "-" End Sub [C#] // DefaultValuesNeeded 事件处理方法 private void DataGridView1_DefaultValuesNeeded(object sender, DataGridViewRowEventArgs e) { // 设定单元格的默认值 e.Row.Cells["Column1"].Value = 0; e.Row.Cells["Column2"].Value = "-"; }