您可以使用以下任一选项:
- 使用
DataGridViewComboBoxColumn
- 为子实体部分类添加相应的属性
- 使用
Linq 调整查询以包含导航属性的属性
- 使用
CellFormatting 事件获取子属性有界列的值
- 通过覆盖
ToString()显示对象的字符串表示
- 使用自定义
TypeDescriptor 启用与子属性的数据绑定。
选项 1 - 使用 DataGridViewComboBoxColumn
用法:这种方法在您希望保持控件可编辑的情况下特别有用。
在这种方法中,您可以使用DataGridViewComboBoxColumn 来显示navigationn 属性的任何字段。要在网格中显示导航属性的多个字段子属性,请使用多个DataGridViewComboBoxColumn 绑定到具有不同DisplayMember 的相同导航属性
在这种方法中,除了您的 ProductId 列之外,将更多 DataGridViewComboBoxColumn 添加到网格中,然后对所有其他组合列执行这些设置:
- 将其中的
DataPropertyName 设置为ProductId
- 将它们的
DataSource 属性设置为与您用于主ProductId 列的数据源完全相同的数据源,例如productBindingSource
- 将其中的
ValueMember 设置为您为产品id 列设置的相同值成员,它是产品表的键列。(ProductId)
- 将它们每个的
DisplayMember 设置为您要显示的列,例如,将其中一个设置为名称。一到价格,一到尺寸,...。这样您就可以显示相关的实体字段。
- 将它们的
ReadOnly 属性设置为true。它使单元格只读。
- 如果要使列只读,请将它们的
DisplayStyle 属性设置为Nothing。它删除了下拉样式。
如果您想保持ProductId 可编辑,请将其DisplayStyle 保留为DropDownButton。这样,当您使用组合框更改ProductId 列的值时,当您离开该行并移至下一行时,您将看到该行的其他单元格,显示所选产品的其他属性。此外,由于其他组合框列是只读的并且没有组合框样式,因此用户无法更改它们的值,它们的行为就像只读文本框列一样,显示来自相关实体的其他属性。
选项 2 - 为子实体部分类添加相应的属性
用法:当您不需要编辑值时,这种方法会很有用。
在这种方法中,您可以在子实体部分类中定义属性,返回父实体对应属性的值。例如商品名称,在订单商品分部类中定义该属性:
public string ProductName
{
get
{
if (this.Product != null)
return this.Product.Name;
else
return string.Empty;
}
}
然后您可以在选择订单项时简单地包含产品,并将网格列绑定到订单项的相应属性。
选项 3 - 调整查询以包含导航属性的属性
用法:当您不需要编辑值时,这种方法会很有用。
您可以调整查询以包含导航属性的属性。您可以简单地使用匿名对象或查看模式,例如:
var list = db.OrderDetails.Include("Products").Where(x=>x.OrderId==1)
.Select(x=> new OrderDetailVM() {
Id = x.Id,
ProductId = x.ProductId,
ProductName = x.Product.Name,
Price = x.Product.Price
}).ToList();
选项 4 - 使用 CellFormatting 事件获取子属性有界列的值
用法:当您不需要编辑值时,这种方法会很有用。
在这种方法中,您可以使用DataGridView 的CellFormatting 事件。您可以根据列索引简单地设置e.Value。例如:
void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
//I Suppose you want to show product name in column at index 3
if(e.RowIndex>=0 && e.ColumnIndex==3)
{
var orderLineItem= (OrderLineItem)(this.dataGridView1.Rows[e.RowIndex]
.DataBoundItem);
if (order!= null && orderLineItem.Product != null)
e.Value = orderLineItem.Product.Name);
}
}
您可以使用不同的条件来处理不同的列并显示不同的子属性。
您还可以使用反射使其更具动态性和可重用性。您可以使用反射提取导航属性的子属性的值。为此,您应该创建列并将DataPropertyName 设置为Product.Name 等子属性,然后在CellFormatting 事件中,使用反射获取列的值。这是 Antonio Bello 关于这种方法的一篇好文章:
选项 5 - 通过覆盖 ToString() 来显示对象的字符串表示形式
用法:当您不需要编辑值时,这种方法会很有用。
如果您只想显示导航属性的单列,您可以简单地覆盖导航属性类的ToString() 方法并返回合适的值。这样,当在网格中显示该类型的属性时,您将看到一个友好的文本。比如Product的部分类,可以这样写:
public override string ToString()
{
return this.Name;
}
选项 6 - 使用自定义 TypeDescriptor 启用与子属性的数据绑定
用法:当您不需要编辑值时,这种方法会很有用。
在这种方法中,您可以创建一个自定义 TypeDescriptor,使您能够对二级属性执行数据绑定。这是 Linda Liu 关于这种方法的一篇好文章: