Table of contents
Second, the usage of DataTable
6. Determine whether a value exists in the DataTable column
8. Get the row number where the DataRow is located
3. Get/set the data of the selected cell
4. Set the width and height of the cell
I. Overview
The DataGridView control provides a customizable table for displaying data. Class DataGridView allows customization of cell, row, column, and GridColor borders by using properties such as DefaultCellStyle, ColumnHeaders, DefaultCellStyle, and CellBorderStyle. For more information, see Basic Formatting and Styling in the Microsoft DataGridView Control.
Data can be displayed with or without an underlying data source using the DataGridView control. If you don't specify a data source, you can create columns and rows containing data and add them directly to the DataGridView using Rows and Columns properties. You can also use the Rows collection to access the DataGridViewRow object and the DataGridViewRow.Cells property to read or write cell values directly. Indexer Item[] also provides direct access to cells.
As an alternative to manually populating the control, you can set the DataSource property DataMember to bind to the DataGridView data source and populate the data automatically. For more information, see Displaying Data in the Microsoft DataGridView Control.
When dealing with large amounts of data, the property can be set to VirtualModetrue to display a subset of the available data. Virtual mode requires implementing a data cache in which to populate the DataGridView control.
Second, the usage of DataTable
1. Create tables and columns
Use new DataTable() to create a DataTable table, the table can be created with or without the table name
DataTable dt = new DataTable();
DataTable dt1 = new DataTable("Datas");
The DataTable table is the same as our commonly used Excel, as shown in the figure below, the columns are A, B, C, D.... and the rows are 1, 2, 3, 4.....
It's just that after the DataTable is created, it is empty, and there are neither automatically created columns nor automatically created rows. These are all implemented by us through code.
Create a column by instantiating the DataColumn class and adding the DataColumn class to DataTable.Columns to add a column.
DataTable dt = new DataTable("Datas");
DataColumn dc1 = new DataColumn("商品编号");
DataColumn dc2 = new DataColumn("商品名称");
DataColumn dc3 = new DataColumn("商品重量");
DataColumn dc4 = new DataColumn("商品价格");
DataColumn dc5 = new DataColumn("购买数量");
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
dt.Columns.Add(dc3);
dt.Columns.Add(dc4);
dt.Columns.Add(dc5);
While adding a column, you can add some settings to the column
DataTable dt = new DataTable("Datas");
DataColumn dc1 = new DataColumn("商品编号");
DataColumn dc2 = new DataColumn("商品名称");
DataColumn dc3 = new DataColumn("商品重量");
DataColumn dc4 = new DataColumn("商品价格");
DataColumn dc5 = new DataColumn("购买数量");
dc1.AutoIncrement = true;//自动增加
dc1.AutoIncrementSeed = 1;//起始为1
dc1.AutoIncrementStep = 1;//步长为1
dc1.AllowDBNull = false;//是否允许空值
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
dt.Columns.Add(dc3);
dt.Columns.Add(dc4);
dt.Columns.Add(dc5);
It's just that it's cumbersome to do so, so it's not recommended.
It is recommended to add columns in the following way
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
dataGridView1.DataSource = dt;
Running effect in Winform
At this time, the row of the table has no data yet, let's see how to add row data
2. Add row
Rows are added by adding the DataRow class, as follows:
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
DataRow newRow = dt.NewRow();
newRow["姓名"] = "1号";
newRow["年龄"] = "17";
newRow["身高"] = "155";
newRow["体重"] = "220";
dt.Rows.Add(newRow);
dataGridView1.DataSource = dt;
run:
Although it is possible to add lines in this way, it is very cumbersome to use, and of course there is a concise way of writing
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("2号", 12, 220, 300);
dataGridView1.DataSource = dt;
run:
The way of adding lines here can also be replaced with the following way of writing, the effect is the same
dt.Rows.Add(new object[] { "2号", 12, 220, 300 });
3. Value and assignment
Before getting and setting these data, add some data
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dc = dt.Columns.Add("姓名", typeof(string));
dc = dt.Columns.Add("年龄", typeof(int));
dc = dt.Columns.Add("身高", typeof(float));
dc = dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
dataGridView1.DataSource = dt;
run:
1) assignment
Assignment by index number
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
dataGridView1.DataSource = dt;
//1)赋值
dt.Rows[0][0] = "张三";
run:
Note that here, dt.Rows[0] refers to which row, and the second 0 refers to which column. If dt.Rows[0] is changed to dt.Rows[1], the effect is as follows:
Assignment by column name
The definition of the row number in dt.Rows[0] can only be defined by numbers, but the following columns can be obtained by column names
dt.Rows[0]["姓名"] = "张三";
Effect:
2) Value
The usage of getting value and getting value is similar to the usage of variables, except that the returned type is object type, just do some conversion
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
dataGridView1.DataSource = dt;
//2)取值
object name = dt.Rows[0]["姓名"];
object age = dt.Rows[0][1];
Console.WriteLine(name);
Console.WriteLine(age);
run:
4. Delete row
There are many ways to delete rows, you can use dt.Rows.Remove(dt.Rows[0]);
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
//删除行
dt.Rows.Remove(dt.Rows[0]);
dataGridView1.DataSource = dt;
You can also use dt.Rows.RemoveAt(0) The effect is the same
dt.Rows.RemoveAt(0);
run:
5. Traverse the DataTable
The column name is separate from the content traversal of the table
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
//打印所有列名
string columnName = string.Empty;
for (int i = 0; i < dt.Columns.Count; i++)
{
columnName += string.Format("{0}({1}) | ", dt.Columns[i].ColumnName, i);
}
Console.WriteLine(columnName);
//打印每一行的数据
foreach (DataRow row in dt.Rows)
{
string columnStr = string.Empty;
foreach (DataColumn column in dt.Columns)
{
columnStr += row[column] + " | ";
}
Console.WriteLine(columnStr);
}
dataGridView1.DataSource = dt;
Print the data of each line, do not want to use foreach, it is also possible to use for loop.
for (int i = 0; i < dt.Rows.Count; i++)
{
string columnStr = string.Empty;
for (int j = 0; j < dt.Columns.Count; j++)
{
columnStr += dt.Rows[i][j] + " | ";
}
Console.WriteLine(columnStr);
}
Running effect, Winform and console:
6. Determine whether a value exists in the DataTable column
Use DataTable.Select to query the data in the table
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
//判断 DataTable 列中是否存在某个值
DataRow[] seleRes = dt.Select(string.Format("{0}='{1}'", "姓名", "2号"));
Console.WriteLine("寻找结果:{0}", seleRes.Length > 0);
run:
Make some changes to the code
DataRow[] seleRes = dt.Select(string.Format("{0}='{1}'", "姓名", "2"));
Console.WriteLine("寻找结果:{0}", seleRes.Length > 0);
run:
7. Set the primary key
A table's primary key must be unique to identify records in the table. Tables with primary keys consisting of two or more columns can also be used. This happens when a single column cannot contain enough unique values. For example, a two-column primary key might contain "OrderNumber" and "ProductID" columns. Because a primary key can consist of multiple columns, the PrimaryKey property consists of an array of DataColumn objects.
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
//设置主键
DataColumn[] PrimaryKeyColumns = new DataColumn[2];
//添加主键,必须是已经在DataTable里有的列名
PrimaryKeyColumns[0] = dt.Columns["姓名"];
PrimaryKeyColumns[1] = dt.Columns["年龄"];
//配置主键
dt.PrimaryKey = PrimaryKeyColumns;
8. Get the row number where the DataRow is located
How to get a primary key
DataTable dt = new DataTable("Datas");
DataColumn dc = new DataColumn();
dc.AutoIncrement = true;//自动增加
dc.AutoIncrementSeed = 1;//起始为1
dc.AutoIncrementStep = 1;//步长为1
dc.AllowDBNull = false;//是否允许空值
//添加列
dt.Columns.Add("姓名", typeof(string));
dt.Columns.Add("年龄", typeof(int));
dt.Columns.Add("身高", typeof(float));
dt.Columns.Add("体重", typeof(float));
//添加行
dt.Rows.Add("1号", 17, 155, 220);
dt.Rows.Add("2号", 12, 220, 300);
dt.Rows.Add("3号", 45, 170, 132);
//设置主键
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
//添加主键,必须是已经在DataTable里有的列名
PrimaryKeyColumns[0] = dt.Columns["姓名"];
//配置主键
dt.PrimaryKey = PrimaryKeyColumns;
//获取行号
DataRow dataRow = dt.Rows.Find("3号");
int index = dataRow.Table.Rows.IndexOf(dataRow);
Console.WriteLine("行号:{0}", index);
run:
If it is two primary keys, write like this
//设置主键
DataColumn[] PrimaryKeyColumns = new DataColumn[2];
//添加主键,必须是已经在DataTable里有的列名
PrimaryKeyColumns[0] = dt.Columns["姓名"];
PrimaryKeyColumns[1] = dt.Columns["年龄"];
//配置主键
dt.PrimaryKey = PrimaryKeyColumns;
//获取行号
DataRow dataRow = dt.Rows.Find(new object[] { "3号", 45 });
int index = dataRow.Table.Rows.IndexOf(dataRow);
Console.WriteLine("行号:{0}", index);
The result of the operation is still: 2
Note that the name and age must match here. If you make a mistake, for example, change 45 to 46, the code will also report an error
9. Convert DataTable to List<T>
the code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Reflection;
/// <summary>
/// 将DataTable数据源转换成实体类
/// </summary>
public static class ConvertTool
{
/// <summary>
/// DataTable转换成实体类
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="dt"></param>
/// <returns></returns>
public static List<T> TableToEntity<T>(DataTable dt) where T : class, new()
{
List<T> list = new List<T>();
try
{
foreach (DataRow row in dt.Rows)
{
T entity = new T();
PropertyInfo[] pArray = entity.GetType().GetProperties();
foreach (PropertyInfo p in pArray)
{
if (dt.Columns.Contains(p.Name))
{
if (!p.CanWrite) continue;
var value = row[p.Name];
if (value != DBNull.Value)
{
Type targetType = p.PropertyType;
Type convertType = targetType;
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
//可空类型
NullableConverter nullableConverter = new NullableConverter(targetType);
convertType = nullableConverter.UnderlyingType;
}
if (!string.IsNullOrEmpty(convertType.FullName) && !string.IsNullOrEmpty(value.ToString()))
{
value = Convert.ChangeType(value, convertType);
}
switch (convertType.FullName)
{
case "System.Decimal":
p.SetValue(entity, Convert.ToDecimal(value), null);
break;
case "System.String":
p.SetValue(entity, Convert.ToString(value), null);
break;
case "System.Int32":
p.SetValue(entity, Convert.ToInt32(value), null);
break;
case "System.Int64":
p.SetValue(entity, Convert.ToInt64(value), null);
break;
case "System.Int16":
p.SetValue(entity, Convert.ToInt16(value), null);
break;
case "System.Double":
p.SetValue(entity, Convert.ToDouble(value), null);
break;
case "System.DateTime":
p.SetValue(entity, Convert.ToDateTime(value), null);
break;
default:
p.SetValue(entity, value, null);
break;
}
}
}
}
list.Add(entity);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
if(list.Count > 0)
return list;
else
return null;
}
}
10. Convert List<T> to DataTable
Here is whether to convert the title or convert the title. Let’s take a look at the direct conversion of List<T> to DataTable. If the entity class field of T is in English, then the column names of DataTable will also be displayed in English.
/// <summary>
/// 将 List 转换成 DataTable (不转换标题)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
public static DataTable ToDataTable<T>(List<T> data)
{
if(data == null || data.Count == 0) return null;
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
DataTable dt = new DataTable();
for (int i = 0; i < properties.Count; i++)
{
PropertyDescriptor property = properties[i];
dt.Columns.Add(property.Name, property.PropertyType);
}
object[] values = new object[properties.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = properties[i].GetValue(item);
}
dt.Rows.Add(values);
}
return dt;
}
Converting English fields to Chinese column names requires some conversion. I created a custom feature UserAttribute, as follows
using System;
//自定义特性类
[AttributeUsage(AttributeTargets.Property)]
internal class UserAttribute : Attribute
{
public string ChineseName { get; set; }
public UserAttribute(string chineseName)
{
ChineseName = chineseName;
}
}
The field that will be converted to Chinese, add the Chinese name to the feature
internal class UserInfo
{
[User("用户名")]
public string UserName { get; set; }
[User("地址")]
public string Address { get; set; }
[User("年龄")]
public int Age { get; set; }
[User("重量")]
public int Weight { get; set; }
}
Conversion method:
/// <summary>
/// 将 List 转换为 DataTable (转换标题)
/// </summary>
/// <param name="list">数据实体</param>
/// <returns></returns>
public static DataTable ListToDataTable<T>(List<T> list)
{
if (list == null || list.Count == 0) return null;
//创建一个名为"tableName"的空表
DataTable dt = new DataTable("tableName");
//key 中文名, value 英文名
Dictionary<string, string> dic = new Dictionary<string, string>();
//创建传入对象名称的列
foreach (var item in list.FirstOrDefault().GetType().GetProperties())
{
object[] attrs = item.GetCustomAttributes(true);
if (attrs.Length > 0 && attrs[0] is UserAttribute)
{
UserAttribute user = attrs[0] as UserAttribute;
dt.Columns.Add(user.ChineseName);
dic.Add(user.ChineseName, item.Name);
}
else
dt.Columns.Add(item.Name);
}
//循环存储
foreach (var item in list)
{
//新加行
DataRow value = dt.NewRow();
//根据DataTable中的值,进行对应的赋值
foreach (DataColumn dtColumn in dt.Columns)
{
int i = dt.Columns.IndexOf(dtColumn);
string cloumnName = dtColumn.ColumnName;
if (dic.ContainsKey(cloumnName))
{
cloumnName = dic[cloumnName];
}
//基元元素,直接复制,对象类型等,进行序列化
if (value.GetType().IsPrimitive)
{
value[i] = item.GetType().GetProperty(cloumnName).GetValue(item);
}
else
{
value[i] = JsonConvert.SerializeObject(item.GetType().GetProperty(cloumnName).GetValue(item));
}
}
dt.Rows.Add(value);
}
return dt;
}
3. Usage of DataGridView
1. Binding data
Binding data has been used many times in the above case, just one sentence, just bind the DataSource of the control to the DataTable.
dataGridView1.DataSource = dt;
Not only the DataTable type can be bound here, DataSet, DataView, ArrayList, Dictionary, and List are all possible, so I won’t show them one by one here.
2. Get the bound data source
The bound data can be converted to the type before binding, as follows
DataTable dataTable = (dataGridView1.DataSource as DataTable);
Currently testing the DataTable type is no problem
3. Get/set the data of the selected cell
First add an event CellClick to the dataGridView1 control
the code
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
//当前的行数
int selectRowIndex = dataGridView1.CurrentRow.Index;
//当前的列数
int selectColumnIndex = dataGridView1.CurrentCell.ColumnIndex;
DataTable dataTable = (dataGridView1.DataSource as DataTable);
int rowLen = dataTable.Rows.Count;
if (selectRowIndex >= rowLen) return;
Console.WriteLine("当前选中行:{0},选中的列:{1}", selectRowIndex, selectColumnIndex);
}
After running, click on the last row, last column
console output
After the data is bound, a row will be added automatically. If you click on a blank row here, the number of rows in the DataTable will be exceeded. If you do not make a judgment, an error will be reported. You need to pay attention here.
With the index of row and column, it is relatively simple to get the value, just get the value of DataTable directly
object obj = dataTable.Rows[selectRowIndex][selectColumnIndex];
Console.WriteLine("value:{0}", obj);
It is also common sense to set its value.
4. Set the width and height of the cell
Adaptive width and height
//根据数据内容自动调整列宽
dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader;
//根据数据内容自动调整行高
dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCellsExceptHeaders;
According to the example in Chapter 2, the effect
The system automatically removes the blank part, which looks particularly crowded, it is better to manually set the width.
How to manually set the column width, where 0, 1, 2, and 3 are the index of the column
dataGridView1.Columns[0].Width = 100;
dataGridView1.Columns[1].Width = 100;
dataGridView1.Columns[2].Width = 200;
dataGridView1.Columns[3].Width = 150;
Finish
If this post is helpful to you, please follow + like + leave a message, thank you!
end