C#中的表格控件只有一个,那就是datagridview,不像QT中可以用QTableview,QTableWidget。新手拿到datagridview的第一个问题就是数据从哪里来?难道从设计器中一个个手动输入,到时候要变怎办?所以,我们这里说说DataGridView的手动操作。

一、手动操作DataGridView

这里我们是没有数据源的纯view控件的操作,后面第二部分我们再讲有数据源的操作。

1、初步尝试

下面的代码声明并初始化完成列DataGridViewColumn、行DataGridViewRow 、单元格DataGridViewCell 对象。
但这里需要注意的是,DataGridView必须先有列后有行,最后才是单元格cell,初始化完成后你就可以直接将他们加入DataGridView的实例中了,如下代码dataGridView1就是在设计器的工具箱中直接拖放到窗体中的DataGridView控件。

1
2
3
4
5
6
7
8
DataGridViewColumn col = new DataGridViewColumn();
DataGridViewRow row = new DataGridViewRow();
DataGridViewCell cell = new DataGridViewTextBoxCell();
cell.Value = "item";
col.CellTemplate = cell; //设置单元格格式模板
col.HeaderText = "column01";
dataGridView1.Columns.Add(col);

效果:

虽然,只有一行一列一个单元格,但如果我们搞懂了原理,那后面批量加入我们需要的行列和单元格就容易了。

这里了重点强调一下,加入的顺序应该是:

1、初始化列
2、初始化行
3、初始化单元格
4、将列column加入DataGridView
5、将行row加入列DataGridView
6、将单元格cell加入行row

注意,一个列必须设定它自己这一列的单元格格式母板,否则就会报错。如:

1
2
3
cell= new DataGridViewTextBoxCell();
col.CellTemplate = cell;

2、批量加入

批量加入无非就是加入了一些循环,过程和单个单元格的加入几乎没有差别。
需要注意的是每次加入的行或者列或者单元格都必须是一个新对象,也就是要new一个新的对象,否则就不能成功加入。

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
DataGridViewColumn col;
DataGridViewRow row;
DataGridViewCell cell= new DataGridViewTextBoxCell();

for (int i = 0; i < 6; i++)
{
col = new DataGridViewColumn();
col.HeaderText = "col" + i.ToString();
col.CellTemplate = cell;
dataGridView1.Columns.Add(col);
}

for (int i = 0; i <20; i++)
{
row = new DataGridViewRow();
for (int j = 0; j < 6; j++)
{
cell = new DataGridViewTextBoxCell();
cell.Value = "item" + i.ToString() + j.ToString();
row.Cells.Add(cell);
}
dataGridView1.Rows.Add(row);

}

运行的效果如下:

这里,我们将加入行和加入单元格同时进行的,你也可以加入行和加入列完成后,单独对单元格进行赋值

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

for (int i = 0; i < 20; i++)
{
row = new DataGridViewRow();
//for (int j = 0; j < 6; j++)
//{
// cell = new DataGridViewTextBoxCell();
// cell.Value = "item" + i.ToString() + j.ToString();
// row.Cells.Add(cell);
//}
dataGridView1.Rows.Add(row);
}

for (int i = 0; i < 6; i++)
for (int j = 0; j < 20; j++)
dataGridView1.Rows[j].Cells[i].Value = "item" + j.ToString() + i.ToString();

3、带数据的行的加入rows.Add

行的加入我们利用add方法来完成,它有三个重载,所以我们可以用多种方式加入,前面我们就已经使用过了它的最常见的重载,直接在add的参数中加入row
如:

1
2
dataGridView1.Rows.Add(row);

这里我们使用数组加入也很方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

//添加行
string[] row0 = { "Jack", "1880", "2022-12-5","12.5","true" };
string[] row1 = { "Smith", "2208", "2022-02-15", "538", "true" };
dataGridView1.Rows.Add(row0);
dataGridView1.Rows.Add(row1);
dataGridView1.Rows.Add(new string[] { "Tome", "1208", "2012-2-15", "1.2", "true" });
//list转数组后加入
List<string> values = new List<string>();
values.Add("Jone");
values.Add("1222");
values.Add("2022-05-12");
values.Add("23.2");
values.Add("false");
dataGridView1.Rows.Add(values.ToArray());

运行效果:

还有一个重载是add(int ),这个专门从来加入空行,比如加入1000个空行,那就直接在参数中输入1000:

1
2
dataGridView1.Rows.Add(1000);

二、数据来源DataSource

数据来源可以是自己从数据库中获取,也可以自己构建一个DataTable,也可以读入字符流或者字符列表等。这里分别演示。
DataSource它的特点是:任何实现IListSource接口的类都可以作为它的右值。

1、来自列表List

我们将列表中装入一个对象,当然,这个对象有多少特征,我们就可以显示在表格中显示多少列

1
2
3
4
5
6
7
List<Student> students = new List<Student>()
{
new Student() {Name="John", Gender=true, Birthday=new DateTime(2012, 12, 4),Age= 20, Hight=15},
new Student() {Name="Jack", Gender=true, Birthday=new DateTime(2022, 10, 12), Age=10, Hight=125}
};
dataGridView1.DataSource = students.Select(x => new { x.Name, x.Gender, x.Birthday, x.Age, x.Hight }).ToList();

运行效果:

2、来自自定义DataTable

既然是我们手动自定义的一个表,那么我们就必须给它定义行列和单元格内容。这的Datatable只是提供数据,与视图View无关,那么它的责任就是组织好数据给视图来显示,这在MVC中就属于model层。
下面的代码我们初始化了一个DataTable对象后就可以利用columns.add增加列了,增加完列我们用DataTable的newRow()方法直接增加行,没有它法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    DataTable dt = new DataTable();
dt.Columns.Add("col1", typeof(System.String));
dt.Columns.Add("col2", typeof(System.String));
dt.Columns.Add("col3", typeof(System.String));
dt.Columns.Add("col4", typeof(System.String));
dt.Columns.Add("col5", typeof(System.String));
dt.Columns.Add("col6", typeof(System.String));

for(int i = 0; i < 10; i++)
{
dt.Rows.Add(dt.NewRow());
for(int j = 0; j < 6; j++)
dt.Rows[i][j]="item" + j.ToString() + i.ToString();
}
dataGridView1.DataSource =dt;


我们上面所有的行,我们使用的格式都是String的,便于统一用循环添加,我们我们想要添加其他的格式的数据可以这样添加:

1
2
3
4
5
6
7
8
9
DataTable dt = new DataTable();

dt.Columns.Add("col1", typeof(System.Int32));
dt.Columns.Add("col2", typeof(System.String));
dt.Columns.Add("col3", typeof(System.DateTime));
dt.Columns.Add("col4", typeof(System.Boolean));
dt.Columns.Add("col5", typeof(System.Int16));
dt.Columns.Add("col6", typeof(System.Decimal));

关于赋值,使用二维数组的方式直接给单元格赋值即可:

1
2
dt.Rows[i][j]="item" + j.ToString() + i.ToString();

最后,我们给DataGridView实例指定数据源DataSource 属性即可,这里我们指定为我们刚刚手动建立的DataTable。

运行效果:

看起来,和前面我们直接对DataGridView手动操作得到的表格没有什么两样,但实际我们此时已经使用了MVC的概念了,一个负责的是视图一个负责的是数据

3、动态建立表格

  • 我们首先定义两个List分别存放表格的字段类型和值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//定义一个表格的字段类型
List<string> typeDef = new List<string>();
typeDef.Add("System.Int32");
typeDef.Add("System.String");
typeDef.Add("System.DateTime");
typeDef.Add("System.Decimal");
typeDef.Add("System.Boolean");

//表格字段内容
List<string> values = new List<string>();
values.Add("1222");
values.Add("Jone");
values.Add("2022-05-12");
values.Add("23.2");
values.Add("false");
dataGridView1.DataSource = initialDataTable(typeDef,values);

  • 接下来,我们定义一个函数,专门来建立一个表格
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
DataTable initialDataTable(List<String> strlist, List<String> vluelist)
{

DataTable dt = new DataTable();

DataColumn col = new DataColumn();
for (int i = 0; i < strlist.Count; i++)
{
col = new DataColumn();
col.DataType = System.Type.GetType(strlist[i]);
dt.Columns.Add(col);
}

for (int i = 0; i < 10; i++)
{
dt.Rows.Add(dt.NewRow());
for (int j = 0; j < strlist.Count; j++)
dt.Rows[i][j] = vluelist[j];
}

return dt;

}
}

运行效果:

4、类和BindingList

类的特征属性直接显示在表格里可以通过BindingList来实现

1
2
3
4
5
6
BindingList<Student> list2 = new BindingList<Student>();
list2.Add(new Student("John", true, new DateTime(2012, 12, 4), 20, 15));
list2.Add(new Student("Jack", true, new DateTime(2022, 10, 12), 10, 125));
list2.Add(new Student("Tomy", true, new DateTime(1992, 3, 5), 30, 5));
dataGridView1.DataSource= list2;

运行效果:

5、来自文件字符流

有了上面的基础后,我们就可以建立一个导入文本文件的表格,并且可以自动识别文本文件中的字段类型。

我们首先来看看效果:

导入文本表格要做好文本字段之间的分割Split,这里不详说了,首先要从读入的文本流中取出表格的各列的名称和类型,然后再取出内容,然后分别形成数组

关键代码:

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
StreamReader sr = new StreamReader(filepath, Encoding.UTF8);
typetext = sr.ReadLine();
headtext = sr.ReadLine();
string[] typer = typetext.Split(',');
ArrayList content = new ArrayList();
//开始读文本中的每条记录的内容
while ((str=sr.ReadLine()) != null)
{
content.Add(str);
Console.WriteLine(str);
}
//定义一个表格的字段类型
List<string> typeDef = new List<string>();
for (int i = 0; i < typer.Length; i++)
{
typeDef.Add("System." + typer[i].ToString());
}

//表格字段内容
ArrayList head = new ArrayList();
string[] header = headtext.Split(',');
for (int i = 0; i < header.Length; i++)
{
head.Add( header[i].ToString());
}

将上述代码得到的三个列表传入下面的DataTable处理函数中即可得到DataGridView的DataSource需要的DataTable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
DataTable initialDataTable(List<String> typelist, ArrayList headerlist,ArrayList contentarry)
{

DataTable dt = new DataTable();
DataColumn col = new DataColumn();
for (int i = 0; i < headerlist.Count; i++)
{
col = new DataColumn();
col.ColumnName = headerlist[i].ToString();
col.DataType = System.Type.GetType(typelist[i]);
dt.Columns.Add(col);
}
// 加入内容
for (int i = 0; i < contentarry.Count; i++)
{
dt.Rows.Add(contentarry[i].ToString().Split(','));
}
return dt;
}

可以参考的文本:

1
2
3
4
5
6
7
8
String,Boolean,Int32,DateTime,Int32,Int32
Name,Gender,ID,Birthday,Score1,Score2
John, true,1908, 2012-12-4, 20, 16
Jack, false2015, 2022-10-12, 10, 125
Tomy, true, 2047,1992-3-5, 30, 15,
Mophy, true, 1147,2014-6-3, 40, 24
Tollor, false,2347,2102-2-15, 50, 55

6、来自数据库

如果有数据库,那是最好不过的啦,直接将查询所得的表赋值给DataGridView的DataSource即可。
这里我们使用sqlite,事先要安装上sqlite,到Nuget中最快方式获得。

有了sqlite的环境,我们可以开始组织数据库读取了。这里我们调用的句子非常少,其实这是直接通过SQLiteDataAdapter 填充了一个新建的DataTable而已。

1
2
3
4
5
6
7
8
9
//指定数据库地址(我这里就放在debug目录下)
string constr = "Data Source=tbdb.db;";
//设置SQL查询语句
string sql = "select * from TestTab";
SQLiteDataAdapter mAdapter = new SQLiteDataAdapter(sql, constr);
DataTable dt = new DataTable();
mAdapter.Fill(dt);
dataGridView1.DataSource = dt;

数据库中的表:

运行效果:

7、用到的student类

上面用到的student类,这里列出来省得大家重新编写:

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
class Student
{
string _name = "";
bool _gender =false;
DateTime _birthday;
int _age;
decimal _hight;
public string School;

public Student() {

School = "";
}

public Student(string name, bool gender, DateTime birthday, int age, decimal hight)
{
Name = name;
Gender = gender;
Birthday = birthday;
Age = age;
Hight = hight;
School = "";
}

public string Name{get { return _name; }set { _name = value; }}
public bool Gender{get { return _gender; } set { _gender = value; }}
public DateTime Birthday{ get { return _birthday; } set { _birthday = value; } }
public int Age { get { return _age; } set { _age = value; } }
public decimal Hight { get { return _hight; } set { _hight = value; } }
public List<int> Scores { get; set; }
}

最后

其实关于DataGridView的操作还有很多,控件中最复杂的就属它了,所以如果说你要重新编写一个自定义控件,它也是最复杂的,这里我们只是讲了表格的数据填充,后面一篇我们会讲到样式设置和编辑,有时间我们还可以讲讲自定义DataGridView的编写。感兴趣的童鞋可以继续关注。

其他补充

datagridview默认选中第一行

设置datagridview在加载时默认选中第一行:
在需要为datagridview加载数据的地方添加代码:

1
2
this.dataGridView1.Rows[0].Selected = true;

例如:

1
2
3
4
5
6
7
8
9
private void deplane_Load(object sender, EventArgs e)
{

// TODO: 这行代码将数据加载到表“charge_sysDataSet.OnLine_Info”中。您可以根据需要移动或删除它。
this.onLine_InfoTableAdapter.Fill(this.charge_sysDataSet.OnLine_Info);
dataGridView1.AllowUserToAddRows = false; //去除空白行
dataGridView1.Rows[0].Selected = true;//默认选中第一行
}在这里插入代码片

C# 向datagridview添加一行,并使他位于第一行

1
datagridview.Rows.Insert(0, row);

点击DataGridView时获取当前单元格信息(这个也很有用!)

在使用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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Test_DataGridView
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = Source();
}

//数据表资源
private DataTable Source()
{
DataTable mydt = new DataTable();
mydt.Columns.Add("姓名");
mydt.Columns.Add("年龄");
mydt.Columns.Add("分数");
String[,] str = new String[,] { { "张三", "21", "90" }, { "李四", "22", "93" }, { "王五", "23", "99" } };

for (int i = 0; i < 3; i++)
{
DataRow dr = mydt.NewRow();
dr[0] = str[i, 0];
dr[1] = str[i, 1];
dr[2] = str[i, 2];
mydt.Rows.Add(dr);
}
return mydt;

}

//获取单元格信息
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
//获取单元格坐标
int col = dataGridView1.CurrentCellAddress.X + 1;
int row = dataGridView1.CurrentCellAddress.Y + 1;

//获取单元格内容
String content = dataGridView1.CurrentCell.Value.ToString();

MessageBox.Show("行:" + row.ToString() + " 列:" + col.ToString()+" 内容:"+content);

}


}
}

在C#中将datagridview中的数据与图表绑定

我正在创建一个应用程序,它用于确定原始数据,并将这些原始数据值导入到datagridview中。
现在,我需要在图形表示中生成原始数据值。我有一个有多列的datgridview,我想用c#中的datagridview列值绘制图形/图表。

通过DataGridview对图表使用以下代码(未验证过,不知是否行)

1
2
3
4
5
6
7
8
9
10
foreach (DataGridViewRow row in datagridview.Rows)
{

//chartBpComplaince.Series.Clear();
Series S = chartBpComplaince.Series.Add(row.Cells[2].Value.ToString());

S.Points.AddXY(row.Cells[4].Value.ToString(), row.Cells[3].Value.ToString());
S.ChartType = SeriesChartType.Column;
S.IsValueShownAsLabel = true;
}

相关链接(侵删)

  1. C#手动操作DataGridView之——使用各种数据源填充表格实例
  2. datagridview默认选中第一行方法
  3. 【C#语言】DataGridView获取当前单元格信息
  4. 如何在C#中将datagridview中的数据与图表绑定?

=================我是分割线=================

欢迎到公众号来唠嗑: