C# Winform DataGridView control and DataTable

Table of contents

I. Overview

Second, the usage of DataTable

1. Create tables and columns

2. Add row

3. Value and assignment

4. Delete row

5. Traverse the DataTable

6. Determine whether a value exists in the DataTable column

7. Set the primary key

8. Get the row number where the DataRow is located

9. Convert DataTable to List

10. Convert List to DataTable

3. Usage of DataGridView

1. Binding data

2. Get the bound data source

3. Get/set the data of the selected cell

4. Set the width and height of the cell

Finish


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

Guess you like

Origin blog.csdn.net/qq_38693757/article/details/131413486