本文主要介绍如何在DataGridView的基础上,自定义DataGridView,实现列的顺序、宽度、显示名等信息的保存与读取,实现用户的个性化需求。
1. 需求说明
虽说在文章简介中大致说明了要实现的功能是什么,但是这里还是举个例子说明一下:
假设现有一张学生表,表头如下:
每个用户对于每张表的关注点不同,假设我比较关注学校和年级这些信息,那么我想要把学校和年级放在姓名的前面(如果一些表很复杂,列很多,学校和年级导致在后面,需要拉动滑动条才能看见,这是很麻烦的):
如果我退出系统后,下一次再打开系统,发现学校和年级又跑到后面去了,不得不再次拖动相关的列,这对于用户来说是一件很麻烦的事。
所以,我们需要保存DataGridView中的列信息,使得用户下次打开系统时,列的顺序仍然和上次退出时的一样:
这就是本文要介绍的内容。
2. 实现
主要新建一个组件类,然后将父类Component
改为DataGridView
,MyDataGridView.cs
部分代码如下:
public partial class MyDataGridView : DataGridView
{
private DataTable dataTable; //列样式数据表
private string path; //XML文件路径
public MyDataGridView()
{
InitializeComponent();
}
public MyDataGridView(IContainer container)
{
container.Add(this);
InitializeComponent();
}
public void InitAfterConstructor()
{
path = Application.StartupPath + @"\User\"
+ this.Name + ".xml";
//列样式数据表
dataTable = new DataTable();
dataTable.TableName = this.Name; //表名
dataTable.Columns.Add("Name"); // 列名
dataTable.Columns.Add("HeaderText"); // 显示的名字
dataTable.Columns.Add("DisplayIndex"); // 显示顺序
dataTable.Columns.Add("Width"); // 列宽度
dataTable.Columns.Add("DataPropertyName"); // 绑定的数据项名
dataTable.Columns.Add("Visible"); // 是否可见
// 加载列样式
BindColumnStyle();
}
/// <summary>
/// 绑定列样式
/// </summary>
private void BindColumnStyle()
{
try
{
//如果不存在则保存列样式
if (!File.Exists(path))
{
SaveColumnStyle();
return;
}
//加载列样式
dataTable.ReadXml(path);
foreach (DataRow row in dataTable.Rows)
{
if (Columns.Contains(row["Name"].ToString().Trim()))
{
Columns[row["Name"].ToString()].HeaderText = row["HeaderText"].ToString();
Columns[row["Name"].ToString()].DisplayIndex =
int.Parse(row["DisplayIndex"].ToString());
Columns[row["Name"].ToString()].Width = int.Parse(row["Width"].ToString());
Columns[row["Name"].ToString()].DataPropertyName =
row["DataPropertyName"].ToString();
Columns[row["Name"].ToString()].Visible = bool.Parse(row["Visible"].ToString());
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/// <summary>
/// 保存列样式
/// </summary>
private void SaveColumnStyle()
{
try
{
//如果目录不存在则创建
var dir = path.Substring(0, path.LastIndexOf('\\'));
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
//读取列样式
dataTable.Rows.Clear();
foreach (DataGridViewColumn column in this.Columns)
{
var newRow = dataTable.NewRow();
newRow["Name"] = column.Name;
newRow["HeaderText"] = column.HeaderText;
newRow["DisplayIndex"] = column.DisplayIndex;
newRow["Width"] = column.Width;
newRow["DataPropertyName"] = column.DataPropertyName;
newRow["Visible"] = column.Visible;
dataTable.Rows.Add(newRow);
}
// 保存列样式到XML文件中
dataTable.WriteXml(path);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
MyDataGridView.designer.cs
部分的代码如下,最主要的是在Dispose()
方法中添加保存列样式的方法,注意顺序:
partial class MyDataGridView
{
......
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
// 关闭保存列样式,注意要先保存列样式,再调用父类的Dispose()
SaveColumnStyle();
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
......
}
3. 使用方式
当编写好自定义的DataGridView后,编译一下项目,这样我们就可以在工具箱中看到自定义的控件了。
然后新建一个界面Form,将自定义的MyDataGridView
拖进界面,并设置启用列重新排序,然后添加三列:
在Form的构造方法中添加MyDataGridView
的初始化方法(注意:该步骤需要手动添加!):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myDataGridView1.InitAfterConstructor();
}
}
启动项目,改变列的排序,页面如下:
然后关闭页面,再次启动项目,列顺序如之前的一样。
在项目的xxx\bin\Debug\User
下,有XML文件记录着列的排序、宽度等信息:
<?xml version="1.0" standalone="yes"?>
<DocumentElement>
<myDataGridView1>
<Name>Column1</Name>
<HeaderText>Column1</HeaderText>
<DisplayIndex>2</DisplayIndex>
<Width>72</Width>
<DataPropertyName />
<Visible>True</Visible>
</myDataGridView1>
<myDataGridView1>
<Name>Column2</Name>
<HeaderText>Column2</HeaderText>
<DisplayIndex>0</DisplayIndex>
<Width>72</Width>
<DataPropertyName />
<Visible>True</Visible>
</myDataGridView1>
<myDataGridView1>
<Name>Column3</Name>
<HeaderText>Column3</HeaderText>
<DisplayIndex>1</DisplayIndex>
<Width>72</Width>
<DataPropertyName />
<Visible>True</Visible>
</myDataGridView1>
</DocumentElement>
整个自定义的MyDataGridView
逻辑如下:
- 在父页面(Form)加载完控件后,调用
InitAfterConstructor()
方法,加载之前保存的列顺序、宽度等信息; - 在页面关闭时,保存列顺序、宽度等信息;
参考资料
[1] https://www.cnblogs.com/atomy/p/11852072.html