DataGridView 将列顺序、宽度和可见性保存到 user.config






4.64/5 (18投票s)
增强的 DataGridView,可将列顺序、宽度和可见性保存到 user.config

引言
框架附带的 DataGridView
允许用户重新排序列,但没有任何机制可以持久化新的列顺序。
在本文中,我将展示一个增强的 DataGridView
,它可以保存
- 列顺序
- 列宽度
- 列可见性
到 user.config
,而无需在宿主窗体中编写任何代码。
背景
通常,应用程序和用户设置是通过 Visual Studio 中的设计器创建的。在后台,设计器会生成用于访问设置的代码。
对于此控件,用于访问设置的代码是手动生成的,因此可以使用比设计器中提供的几个原始数据类型更高级的数据类型。
由于客户端应用程序中可能存在多个 DGV,因此这些设置存储在使用字典中。字典的键是控件的名称。
使用二进制序列化,因为字典实现了 IDictionary 接口,因此无法使用 XML 序列化。但这无关紧要 - 结果是一样的。唯一的区别是 user.config 中的信息不如 XML 序列化那样易于阅读。
在 .NET 中,程序集被加载到 AppDomain 中并从那里执行。每个 AppDomain 都有一个配置文件(不一定),因此多个配置类的数据会被序列化到此配置文件中(或从中读取)。
使用控件
该控件的用法与 System.Windows.Form.DataGridView
没有区别。
控件的代码
该控件派生自 System.Windows.Form.DataGridView
。因此,DataGridView
提供的所有内容也可以由此控件提供。
类的属性
[Description("Extension of the System.Windows.Forms.DataGridView")]
[ToolboxBitmap(typeof(System.Windows.Forms.DataGridView))]
public class gfDataGridView : System.Windows.Forms.DataGridView
{
...
}
这些属性用于在工具箱中显示控件的位图和描述 - 就像通常的控件一样。
保存列顺序、宽度和可见性
这是在 Dispose
方法中完成的。为了存储数据,使用了 ColumnOrderItem
类(请参见本文稍后部分)。
protected override void Dispose(bool disposing)
{
SaveColumnOrder();
base.Dispose(disposing);
}
private void SaveColumnOrder()
{
if (this.AllowUserToOrderColumns)
{
List<ColumnOrderItem> columnOrder = new List<ColumnOrderItem>();
DataGridViewColumnCollection columns = this.Columns;
for (int i = 0; i < columns.Count; i++)
{
columnOrder.Add(new ColumnOrderItem
{
ColumnIndex = i,
DisplayIndex = columns[i].DisplayIndex,
Visible = columns[i].Visible,
Width = columns[i].Width
});
}
gfDataGridViewSetting.Default.ColumnOrder[this.Name] = columnOrder;
gfDataGridViewSetting.Default.Save();
}
}
第一步,检查是否启用了 AllowUserToOrderColumns
。如果未启用,则无需保存列顺序。如果要保存列的宽度等,则可以省略此步骤。
然后,使用应保存到 *user.config* 的值填充一个 List
,并将此列表添加或更新到字典,其中键是控件的名称。该字典被分配给属性设置并保存 - 就像“正常”设计器生成的设置一样。
恢复列顺序
在 OnCreateControl
方法中,列顺序被恢复。重要的是从第一个显示的列开始,以获得所需的结果。如果使用列索引来完成此操作,则就像将一列从一个位置拖动到另一个位置一样,这会重新排列顺序,并且结果是错误的。
protected override void OnCreateControl()
{
base.OnCreateControl();
SetColumnOrder();
}
private void SetColumnOrder()
{
if (!gfDataGridViewSetting.Default.ColumnOrder.ContainsKey(this.Name))
return;
List<ColumnOrderItem> columnOrder =
gfDataGridViewSetting.Default.ColumnOrder[this.Name];
if (columnOrder != null)
{
var sorted = columnOrder.OrderBy(i => i.DisplayIndex);
foreach (var item in sorted)
{
this.Columns[item.ColumnIndex].DisplayIndex =
item.DisplayIndex;
this.Columns[item.ColumnIndex].Visible = item.Visible;
this.Columns[item.ColumnIndex].Width = item.Width;
}
}
}
ColumnOrderItem
列表的项在此类中定义:
[Serializable]
public sealed class ColumnOrderItem
{
public int DisplayIndex { get; set; }
public int Width { get; set; }
public bool Visible { get; set; }
public int ColumnIndex { get; set; }
}
设置
如本文前面所述,设计器通常会生成设置类的代码。这里是手动完成的,为了存储列顺序,使用了 Dictionary<string, List<ColumnOrderItem>>
。此字典被序列化为二进制。
internal sealed class gfDataGridViewSetting : ApplicationSettingsBase
{
private static gfDataGridViewSetting _defaultInstace =
(gfDataGridViewSetting)ApplicationSettingsBase
.Synchronized(new gfDataGridViewSetting());
//---------------------------------------------------------------------
public static gfDataGridViewSetting Default
{
get { return _defaultInstace; }
}
//---------------------------------------------------------------------
// Because there can be more than one DGV in the user-application
// a dictionary is used to save the settings for this DGV.
// As key the name of the control is used.
[UserScopedSetting]
[SettingsSerializeAs(SettingsSerializeAs.Binary)]
[DefaultSettingValue("")]
public Dictionary<string, List<ColumnOrderItem>> ColumnOrder
{
get { return this["ColumnOrder"] as Dictionary<string,
List<ColumnOrderItem>>; }
set { this["ColumnOrder"] = value; }
}
}
上半部分只是设置类的单例实现。然后定义用于存储列顺序的字典。属性指定该属性
- 应存储到用户范围 (*user.config*)
- 序列化模式:二进制
- 默认值是一个空
string
,即一个空字典
这就是所需的一切。
历史
- 2009 年 7 月 29 日(版本 1.0.1.1)
更新了文章和代码。- 解决了客户端应用程序中存在多个 DGV 的问题(由于使用了字典)。
- DGV 可在多个容器中使用(由于在
OnCreateControl
方法中设置了 columnorder,并且由于在Dispose
方法中保存了 columnorder。
- 2009 年 6 月 8 日(版本 1.0.0.0)
初始发布。