具有持久列宽度和顺序的DataGridView






4.70/5 (26投票s)
一个演示如何使用Windows Forms应用程序设置功能,保存绑定到Access数据库的DataGridView控件的列宽、顺序和可见性信息的应用程序。

引言
这个示例程序演示了如何使用Windows Forms的应用程序设置功能来保存和恢复DataGridView
列的宽度、顺序和可见性。应用程序设置提供了一种处理持久化数据的简便方法。示例中包含一个Access数据库,其中包含DataGridView
控件显示的一些示例数据。
您将通过创建一个使用DataGridView
控件来显示、添加、更新和删除数据的应用程序来指导您完成整个过程,该应用程序使用一个示例数据库。
此示例是在Microsoft Visual C# 2005 Express Edition(免费下载)中开发的。示例数据库是使用Microsoft Access创建的。
创建数据库
使用Microsoft Access或Microsoft SQL Server 2005 Express Edition(免费下载)来创建数据库。为了简单起见,本例使用Access创建的数据库。本例中概述的步骤与使用SQL Server数据库所需的步骤类似。
本示例将使用一个建筑行业技工的数据库。下图显示了Microsoft Access表的定义。

创建C#项目
使用Windows应用程序模板创建一个新的C#项目。通过选择“项目”|“添加现有项”将数据库添加到项目中。将“文件类型”更改为“数据文件”,然后将您刚刚创建的数据库文件添加到项目中。当出现数据源配置向导时,选中“表”复选框以包含该表及其所有列。单击“完成”以接受选择并关闭向导。
通过选择“数据”|“显示数据源”来显示数据源。单击“数据源”窗格中的刷新图标,并确保“Contractors”表具有DataGridView
图标,如图所示。如果需要,请从下拉框中选择DataGridView
。

将“Contractors”表从“数据源”拖放到窗体上,以添加一个DataGridView
控件。您会注意到同时在窗体上添加了一个导航工具栏。根据您的喜好调整窗体和DataGridView
控件的大小。结果应与下图类似。

现在构建并运行应用程序。请注意,如果调整窗口大小,DataGridView
控件不会随之改变。另请注意,您可以更改列宽,但不能重新排列列。关闭应用程序,我们将解决这些问题。
右键单击DataGridView
控件,然后选择“属性”。找到AllowUserToOrderColumns
属性并将其设置为True
。现在找到Anchor
属性并选择“底部”和“右侧”。请注意,“顶部”和“左侧”应该已经选中。
添加数据库条目
重新构建并启动应用程序。确保DataGridView
控件在窗口调整大小时会随之改变大小。同时检查列是否可以拖动到新的位置。
在Name
、Trade
、Phone
和Comments
列中输入条目。如果愿意,可以添加多行。完成后,单击导航工具栏中的保存(软盘)图标以保存更改。现在退出并重新启动应用程序。您刚才输入的 डेटा 哪里去了?
默认情况下,Visual Studio会复制数据库并将其放在bin\Debug目录中。应用程序启动时,您对数据库所做的任何更改都会被覆盖。要更改此行为,请首先在解决方案资源管理器窗格中右键单击数据库(Contractors.mdb),然后选择“属性”。将“复制到输出目录”属性更改为“不复制”。现在使用Windows资源管理器复制数据库,并将其粘贴到bin\Debug目录中。
启动应用程序并再次添加一些条目。确保在退出前单击保存图标,以便保存更改。现在退出并重新启动以验证条目是否已保存。
应用程序设置文件
通过选择“视图”|“解决方案资源管理器”来显示“解决方案资源管理器”窗格。创建项目时,会自动将一个Settings.settings文件添加到项目中。展开解决方案资源管理器窗格中的“属性”文件夹,然后双击Settings.settings。当我们向项目中添加Contractors
数据源时,数据库连接字符串会自动添加到应用程序设置中。您将在应用程序设置编辑器中看到它作为第一条条目。
持久化数据在应用程序关闭时保存在应用程序设置文件中,并在应用程序启动时恢复。我们将保存应用程序框架的大小和位置,以及DataViewGrid
控件的列的显示索引、宽度、可见性和列索引。
需要在应用程序设置文件中添加三个条目,以便保存这些信息。我们将把框架的位置保存到DataViewGridFormLocation
,所以在“名称”列中输入它。现在在“类型”列中选择System.Drawing.Point
。
根据约定,应用程序范围内的值是只读的,而用户范围内的值是读写的。由于我们将在每次应用程序关闭时保存持久化值,因此我们的所有条目都将在用户范围内。
现在,在用户范围内添加类型为System.Drawing.Point
的DataViewGridFormSize
,以及类型为System.Collections.Specialized.StringCollection
的DataViewGridFormColumns
。将这三个新条目的“值”列留空。保存并关闭Settings.settings文件。
保存持久化数据
在不编写一行代码的情况下,我们已经有了一个可以显示数据库数据并能够添加、更新和删除条目的应用程序。这还不错。现在是时候写一些代码了。
单击应用程序的窗体,然后选择“视图”|“属性窗口”来查看其属性。通过单击“属性”窗格中的闪电图标来显示窗体的事件。现在双击FormClosing
属性以自动命名并添加一个事件处理程序。当用户关闭窗体(通常是在应用程序退出时)时,将执行PersistentDataGridViewForm_FormClosing
事件处理程序。
要保存持久化数据,请将以下代码添加到您刚刚创建的事件处理程序中。
private void PersistentDataGridViewForm_FormClosing
(object sender, FormClosingEventArgs e) {
// Save column state data
// including order, column width and whether or not the column is visible
StringCollection stringCollection = new StringCollection();
int i = 0;
foreach(DataGridViewColumn column in this.contractorsDataGridView.Columns) {
stringCollection.Add(string.Format(
"{0},{1},{2},{3}",
column.DisplayIndex.ToString("D2"),
column.Width,
column.Visible,
i++));
}
Properties.Settings.Default.DataGridViewFormColumns = stringCollection;
// Save location and size data
// RestoreBounds remembers normal position if minimized or maximized
if(this.WindowState == FormWindowState.Normal) {
Properties.Settings.Default.DataGridViewFormLocation = this.Location;
Properties.Settings.Default.DataGridViewFormSize = this.Size;
}
else {
Properties.Settings.Default.DataGridViewFormLocation =
this.RestoreBounds.Location;
Properties.Settings.Default.DataGridViewFormSize = this.RestoreBounds.Size;
}
// Save the data
Properties.Settings.Default.Save();
}
您还需要在文件开头添加以下using
语句。需要using
语句才能访问string
集合类。
using System.Collections.Specialized;
您会记得,我们在Settings.settings文件中添加了一个类型为stringCollection
的条目,用于保存DataGridView
列的状态信息。列的状态由四个逗号分隔的值表示,这些逗号分隔值的集合用于保存所有列的数据。代码为DataGridView
控件的每一列添加一个string
到集合中。典型的列数据如下:01,100,True,0
。
接下来,窗体的位置和大小将被写入持久化存储。如果窗体处于最小化或最大化状态,则必须从RestoreBounds
属性读取位置和大小。
数据被写入一个文件,以便在下次启动应用程序时可用,这是事件处理程序中的最后一行代码。
现在应用程序退出时会保存状态信息,我们需要读取这些数据,以便下次应用程序启动时将窗体初始化为其之前的状态。
将恢复应用程序状态的代码放在窗体的构造函数中,如下所示。请注意,代码放置在对InitializeComponent
的调用之后。
public PersistentDataGridViewForm() {
InitializeComponent();
// Restore state data
try {
Point location = Properties.Settings.Default.DataGridViewFormLocation;
Size size = Properties.Settings.Default.DataGridViewFormSize;
// Set StartPosition to manual
// after being sure there are no null values
this.StartPosition = FormStartPosition.Manual;
this.Location = location;
this.Size = size;
// Restore the columns' state
StringCollection cols = Properties.Settings.Default.DataGridViewFormColumns;
string[] colsArray = new string[cols.Count];
cols.CopyTo(colsArray, 0);
Array.Sort(colsarray);
for(int i = 0; i < colsArray.Length; ++i) {
string[] a = colsArray[i].Split(',');
int index = int.Parse(a[3]);
this.contractorsDataGridView.Columns[index].DisplayIndex = Int16.Parse(a[0]);
this.contractorsDataGridView.Columns[index].Width = Int16.Parse(a[1]);
this.contractorsDataGridView.Columns[index].Visible = bool.Parse(a[2]);
}
}
catch(NullReferenceException) {
// This happens when settings values are empty
}
}
请记住,我们在Settings.settings中添加的条目的值列留空了。首次运行应用程序时,会生成一个NullReferenceException
,因为这些值是空的。
在成功读取location
和size
值(不会引发NullReferenceException
)后,通过将StartPosition
属性设置为Manual
来通知窗体它将手动定位。
接下来,将列值的每一行拆分为四个string
,并保存在一个string
数组中。然后解析每个值并将其分配给指定的列。
首先必须按显示索引顺序对列数据进行排序。在某些情况下,如果未按升序分配列的DisplayIndex
属性,则列顺序将不会按预期显示。这是因为显示索引被重新编号以避免任何间隙(例如,0, 1, 3, 4 将被重新编号为 0, 1, 2, 3)。请注意,由于使用了简单的string
排序,因此需要前导零,以便DisplayIndex
数字的string
表示具有相同的长度(例如,01, 02, 03, ... 而不是 1, 10, 2, 3, ...)。
应用程序还需要进行一项更改。ID列显示的是数据库自动生成的数字,我们不太关心它。在DataGridView
控件的“属性”窗格中,找到“列”属性。单击值列。现在单击出现的椭圆按钮,以编辑列的属性。在“编辑列”对话框中,选择ID
列,并将其Visible
属性设置为False
。单击“确定”以接受更改并关闭“编辑列”对话框。
启动应用程序并更改其位置和大小。接下来,重新排列列并更改一些列的大小。现在退出并重新启动应用程序,以验证其先前的状态是否已恢复。
持久化数据存储在哪里?在Windows XP下,它保存在\Documents and Settings\user_name\Local Settings\Application Data\company_name\mangled_program_name\version_number中的user.config文件中。位置可能会因操作系统而异。例如,在Vista下,文件保存在\Users\user_name\AppData\Local\company_name\mangled_program_name\
version_number中。在开发过程中,可能会创建多个user.config文件,这可能导致一些混淆。请注意,在Settings.settings
编辑器中,屏幕左上角有一个名为“同步”的按钮。单击此按钮可删除所有user.config副本。好处是会列出user.config可能存在的位置。保存持久化数据后,找到并检查一个user.config文件,看看保存的数据是什么样的。
下一步?
我已经演示了如何保存和恢复窗体和列的状态信息;然而,我才刚刚触及表面。您可能希望参考Microsoft文档以获取有关应用程序设置的更多信息。
以下任务留给读者作为练习。
向DataGridView
控件添加一个上下文菜单,通过将Visible
属性设置为True
或False
来选择显示哪些列。
在应用程序开发过程中,很可能会向DataGridView
控件添加或删除列。进行此类更改后,用于恢复列状态的for
循环将生成一个异常。添加代码以检查此条件。
如果持久化数据的格式发生更改或损坏,则在for
循环中调用Parse
时很可能会引发异常。您可能希望添加代码来处理此问题。
历史
1.0.0.0 (2007年10月)
- 首次发布
1.1.0.0 (2009年3月)
- 根据Kevin Van Puyvelde和krt12的报告,修正了代码以解决列顺序问题。
- 更新了文章,解释了解决列顺序问题的代码。
- 指出了Vista下user.config文件的位置。