65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.70/5 (26投票s)

2007年10月6日

CPOL

9分钟阅读

viewsIcon

161106

downloadIcon

4245

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

Screenshot - Demo Application.png

引言

这个示例程序演示了如何使用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表的定义。

Contractor's database table

创建C#项目

使用Windows应用程序模板创建一个新的C#项目。通过选择“项目”|“添加现有项”将数据库添加到项目中。将“文件类型”更改为“数据文件”,然后将您刚刚创建的数据库文件添加到项目中。当出现数据源配置向导时,选中“表”复选框以包含该表及其所有列。单击“完成”以接受选择并关闭向导。

通过选择“数据”|“显示数据源”来显示数据源。单击“数据源”窗格中的刷新图标,并确保“Contractors”表具有DataGridView图标,如图所示。如果需要,请从下拉框中选择DataGridView

Data Sources pane

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

Data Sources pane

现在构建并运行应用程序。请注意,如果调整窗口大小,DataGridView控件不会随之改变。另请注意,您可以更改列宽,但不能重新排列列。关闭应用程序,我们将解决这些问题。

右键单击DataGridView控件,然后选择“属性”。找到AllowUserToOrderColumns属性并将其设置为True。现在找到Anchor属性并选择“底部”和“右侧”。请注意,“顶部”和“左侧”应该已经选中。

添加数据库条目

重新构建并启动应用程序。确保DataGridView控件在窗口调整大小时会随之改变大小。同时检查列是否可以拖动到新的位置。

NameTradePhoneComments列中输入条目。如果愿意,可以添加多行。完成后,单击导航工具栏中的保存(软盘)图标以保存更改。现在退出并重新启动应用程序。您刚才输入的 डेटा 哪里去了?

默认情况下,Visual Studio会复制数据库并将其放在bin\Debug目录中。应用程序启动时,您对数据库所做的任何更改都会被覆盖。要更改此行为,请首先在解决方案资源管理器窗格中右键单击数据库(Contractors.mdb),然后选择“属性”。将“复制到输出目录”属性更改为“不复制”。现在使用Windows资源管理器复制数据库,并将其粘贴到bin\Debug目录中。

启动应用程序并再次添加一些条目。确保在退出前单击保存图标,以便保存更改。现在退出并重新启动以验证条目是否已保存。

应用程序设置文件

通过选择“视图”|“解决方案资源管理器”来显示“解决方案资源管理器”窗格。创建项目时,会自动将一个Settings.settings文件添加到项目中。展开解决方案资源管理器窗格中的“属性”文件夹,然后双击Settings.settings。当我们向项目中添加Contractors数据源时,数据库连接字符串会自动添加到应用程序设置中。您将在应用程序设置编辑器中看到它作为第一条条目。

持久化数据在应用程序关闭时保存在应用程序设置文件中,并在应用程序启动时恢复。我们将保存应用程序框架的大小和位置,以及DataViewGrid控件的列的显示索引、宽度、可见性和列索引。

需要在应用程序设置文件中添加三个条目,以便保存这些信息。我们将把框架的位置保存到DataViewGridFormLocation,所以在“名称”列中输入它。现在在“类型”列中选择System.Drawing.Point

根据约定,应用程序范围内的值是只读的,而用户范围内的值是读写的。由于我们将在每次应用程序关闭时保存持久化值,因此我们的所有条目都将在用户范围内。

现在,在用户范围内添加类型为System.Drawing.PointDataViewGridFormSize,以及类型为System.Collections.Specialized.StringCollectionDataViewGridFormColumns。将这三个新条目的“值”列留空。保存并关闭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,因为这些值是空的。

在成功读取locationsize值(不会引发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属性设置为TrueFalse来选择显示哪些列。

在应用程序开发过程中,很可能会向DataGridView控件添加或删除列。进行此类更改后,用于恢复列状态的for循环将生成一个异常。添加代码以检查此条件。

如果持久化数据的格式发生更改或损坏,则在for循环中调用Parse时很可能会引发异常。您可能希望添加代码来处理此问题。

历史

1.0.0.0 (2007年10月)

  • 首次发布

1.1.0.0 (2009年3月)

  • 根据Kevin Van Puyvelde和krt12的报告,修正了代码以解决列顺序问题。
  • 更新了文章,解释了解决列顺序问题的代码。
  • 指出了Vista下user.config文件的位置。
© . All rights reserved.