用于域对象的网格






4.25/5 (5投票s)
一个实用的领域对象网格,用于 WinForms 系统。
引言
使用 Windows Forms 应用程序的一个优点是可以直接将领域对象包含到 UI 组件中,例如在下拉列表和列表框中。在 UI 组件中,表格网格非常有用,因为它们从信息角度提供了广泛的视图,并且在 CRUD 窗口中被广泛使用。
假设需要构建一个包含一些相关信息的类别网格系统。已经有一个 `Category` 类,它被声明为一个 POCO 类,具有以下 C# 代码:
using System;
namespace DomainObjects
{
public class Category
{
private long _id;
public virtual long Id
{
get { return this._id; }
set { this._id = value; }
}
private string _categoryName;
public virtual string CategoryName
{
get { return this._categoryName; }
set { this._categoryName = value; }
}
private string _description;
public virtual void SetDescription(string description)
{
this._description = description;
}
public virtual string GetDescription()
{
return this._description;
}
}
}
为此,在 .NET 框架中,我们可以找到 `DataGrid`。为了在 `DataGrid` 中显示对象数据,`DataSource` 属性必须接收这些对象的集合。
IList<category> lstCategories = PopulateCategoriesList(lstCategories);
this.dataGridView1.DataSource = lstCategories;
作为 Categories 列表的结果,得到了以下网格:
请注意,`DataGrid` 组件只能看到 `Id` 和 `CategoryName` 属性,并将它们的内容显示为列。
当与对象集合一起使用时,`DataGrid` 会出现以下缺点:
- 它在反射映射方面非常受限,因为它只能将公共属性视为网格中的列,这使得它在多种对象场景中无法使用;
- 配置诸如标题和宽度之类的列功能不是一项直观的任务;
- 无法遍历对象关联以显示更深层次的另一个对象的数据;
为了克服这些缺点,本文提出了一种用于领域对象的网格,该网格能够将字段和对象之间的关联映射到网格表中的列,称为 `ObjectGrid`。
示例用法
要使用 `ObjectListGrid`,首先,您应该将组件拖到您的窗口上,并将其重命名为 `gridResults`。将上面的网格替换为名为 `gridResults` 的 `ObjectGrid` 后,必须在接收对象项之前对其进行配置。
// Domain Grid Mappings for Category Class ( or any class with the members below )
this.gridResults.AddColumn(new string[] {"CategoryName"},"Name",80);
this.gridResults.AddColumn(new string[] {"GetDescription"}, "Description", 200);
// Domain Grid receives collection of Categories as a Datasource
this.gridResults.DataSource = PopulateCategoriesList();
下面是生成的网格:
将对象图转换为网格表
`ObjectGrid` 是一个 .NET 用户组件,它包装了一个 `DataGrid`。它具有描述列特性的方法,并且必须接收一个对象集合作为 DataSource。
这些列通过一系列成员名称映射为值,组件使用这些成员名称遍历对象图,从集合中的对象开始,通过反射获取链中最终对象的特定数据。
由于它使用成员名称的反射信息,因此同一个 `ObjectGrid` 可以用来显示不同类型的对象,前提是它们包含这些成员的名称。
另一种用法
例如,考虑下面的 UML 中的供应商网格:
在这个网格中,需要显示供应商的以下数据:公司名称、电话、街道、城市、州和国家。
在 Windows Forms 应用程序中使用此组件需要四个步骤:
- 将组件拖到 Windows 窗体上的所需位置。
- 添加描述标题、长度和对象成员的列。
- 将对象集合设置到组件中。每个对象都必须实现映射的成员。
this.gridResults.AddColumn(new string[]{"CompanyName"},"Name",80);
this.gridResults.AddColumn(new string[]{"ContactName"},"Contact",90);
this.gridResults.AddColumn(new string[]{"Phone"},"Phone",50);
this.gridResults.AddColumn(new string[]{"HomePage"},"Home Page",110);
this.gridResults.AddColumn(new string[]{"Street","Name"},"Street",50);
this.gridResults.AddColumn(new string[]{"Street","City","Name"},"City",50);
this.gridResults.AddColumn(new string[]{"Street","City","State","Name"},"State", 50);
this.gridResults.AddColumn(new string[]{"Street","City", "State","Country",
"Name"},"Country",50);
如果您知道此网格仅用于供应商,则可以在窗体初始化时将列添加到网格中。
第一个参数是成员名称数组(可以是方法、属性或字段)。第二个是列标题,第三个是列宽度。第一个参数也是此网格的关键方面。`map` 方法负责通过在内存中导航领域网格列来映射它们。
例如,为了获取供应商的城市名称,需要执行 `supplier.Street.City.Name`。因此,`Street` 列映射为 {“Street”, “City”, “Name”}。
理论上,`ObjectGrid` 能够导航 N 级对象关联,为避免此组件出现异常的唯一要求是对象必须实现映射的成员名称,并且成员返回值实现前向成员名称,依此类推。
this.olstgResults.DataSource = PopulateSuppliersList();
向网格添加、更新和删除对象
为了修改网格显示的数据,可以通过 `Item` 属性向网格添加或删除新对象。
// Adding new element to the grid
this.gridResults.Items.Add(category);
// Removing element from the grid
this.gridResults.Items.Remove(category);
当列表中的对象被更改时,必须使用 `UpdateView` 方法通知网格。
// Refreshing grid
category.SetDescription("New description");
this.gridResults.Refresh();
恢复选定对象
除了易于配置以查看数据外,使用 `ObjectGrid` 的另一个优点是可以将代表选定行的对象恢复到应用程序中。
选择网格行后,例如:
可以使用 `CurrentObject` 属性恢复选定对象:
object selectedObject = this.gridResults.CurrentObject;