显示DataGridView中的导航属性的属性(二级属性) [英] Show Properties of a Navigation Property in DataGridView (Second Level Properties)

查看:86
本文介绍了显示DataGridView中的导航属性的属性(二级属性)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在一个 DataGridView





以下是加载数据的代码

  try 
{
_context.OrderSheets.Include(o => o.OrderSheetItems.Select(i =&i; .Product))。Load();
orderSheetBindingSource.DataSource = _context.OrderSheets.Local.ToBindingList();
}
catch(Exception ex)...

ProductId在一个单独的列仅用于实验,那将是组合框。
那么有没有办法将其他列绑定到OrderSheetItem的产品导航属性中的数据,或者我必须处理产品ID上的CellValueChanged以物理地设置其他列中的数据?如果有办法绑定列,那么是通过OnLoad中的代码还是网格视图列设计器中的某个位置?



TIA,Mike

解决方案

您可以使用以下选项之一:


  1. code> DataGridViewComboBoxColumn

  2. 向子实体部分类添加相应的属性

  3. 将查询的形状包含在导航属性使用 Linq

  4. 使用 CellFormatting 事件获取子属性的值有限列

  5. 使用自定义的 TypeDescriptor 启用数据绑定到子属性。

  6. 显示字符串表示的对象通过覆盖 ToString()

选项1 - 使用DataGridViewComboBoxColumn



在这种方法中,您可以使用 DataGridViewComboBoxColumn 来显示navigationn属性的任何字段。要在网格中显示导航属性的多个字段子属性,请使用多个 DataGridViewComboBoxColumn 绑定到不同的 DisplayMember



在这种方法中,除了 ProductId 列之外,添加更多 DataGridViewComboBoxColumn 到网格,然后对所有其他组合列执行这些设置:




  • 设置 DataPropertyName ProductId

  • 设置 DataSource 属性它们与您用于主要 ProductId 列的完全相同的数据源,例如 productBindingSource

  • ValueMember 设置为您为产品ID列设置的相同值成员,它是您的产品表的关键列( ProductId

  • DisplayMember 设置为要显示的列,例如,设置一个m命名。一个价格,一个到大小,...。 c code ReadOnly 的属性设置为 true 。它使单元格只读。

  • 如果要使列成为只读设置将 DisplayStyle 属性设置为没有什么。它可以删除下拉样式。



如果要保持 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事件获取子属性有界列的值



在这种方法中,您可以使用 CellFormatting 事件 DataGridView 。您可以根据列索引设置 e.Value 。例如:

  void dataGridView1_CellFormatting(object sender,DataGridViewCellFormattingEventArgs e)
{
//我假设你要在索引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关于这种方法的一篇很好的文章:




  • DataGridView:如何绑定嵌套对象



    • 选项5 - 使用自定义TypeDescriptor启用数据绑定到子属性



      这种方法可以创建一个自定义的TypeDescriptor,使您能够执行数据绑定到二级属性。这是Linda Liu关于这种方法的一篇很好的文章:





      选项6 - 显示字符串表示的对象通过覆盖 ToString()



      如果您只想显示一个列的导航属性,您可以简单地覆盖导航属性类的 ToString()方法,并返回合适的值。这样,当在网格中显示该类型的属性时,您将看到一个友好的文本。例如,在 Product 的部分类别中,您可以写:

        public重写字符串ToString()
      {
      return this.Name;
      }


      I'm trying to display several properties from a related entity on a DataGridView in a app. It seems pretty ordinary to me but I'm having trouble finding examples. It's an order entry operation. OrderSheet data, the ID and the pickup date for the order, then the line items (OrderSheetItems in the model below) in the grid. The order lineitems have a navigation property, Product, based on the ProductId. I can use a DataGridViewComboBoxColumn with ProductId as ValueMember and another field as DisplayMember. But I want to include more data in other columns, size, color, material, etc.

      Here's the code for loading the data

      try
      {
          _context.OrderSheets.Include(o => o.OrderSheetItems.Select(i => i.Product)).Load();
          orderSheetBindingSource.DataSource = _context.OrderSheets.Local.ToBindingList();
      }
      catch (Exception ex)...
      

      The ProductId is in a separate column just for experimenting, that will be the combobox later. So is there a way to bind the other columns to the data in Product navigation property of the OrderSheetItem or do I have to handle CellValueChanged on the product id to physically set the data in the other columns? If there's a way to bind the columns then would that be via code in OnLoad or somewhere in the grid view columns designer?

      TIA, Mike

      解决方案

      You can use either of these options:

      1. Use DataGridViewComboBoxColumn
      2. Add corresponding properties to child entity partial class
      3. Shape the query to include properties of navigation property using Linq
      4. Use CellFormatting event to get value for sub property bounded columns
      5. Use a custom TypeDescriptor to enable data binding to sub properties.
      6. Show string representation of object by overriding ToString()

      Option 1 - Use DataGridViewComboBoxColumn

      In this approach you can use DataGridViewComboBoxColumn to show any field of navigationn property. To show multiple field sub properties of navigation property in grid, use multiple DataGridViewComboBoxColumn bound to same navigation property with different DisplayMember

      In this approach, additional to your ProductId column, add more DataGridViewComboBoxColumn to the grid and then perform these settings for all additional combo columns:

      • Set DataPropertyName of them to ProductId
      • Set the DataSource property of them, to exactly the same data source you used for main ProductId column, for example productBindingSource
      • Set ValueMember of them to the same value member you set for product id column, it's the key column of your product table.(ProductId)
      • Set DisplayMember for each of them to a column that you want to show, for example, set one of them to Name. one to Price, one to Size, ... . This way you can show related entity fields.
      • Set ReadOnly property of them to true. It makes the cell read only.
      • If you want to make columns readonly Set DisplayStyle property of them to Nothing. It removes dropdown style.

      If you want to keep ProductId editable, keep the DisplayStyle of it to DropDownButton. This way when you change the value of ProductId column using combobox, when you leave the row and moved to next row, you will see other cells of row, shows other properties of the selected product. Also since the other combobox columns are read only and have no combobox style, the user can not change the value of them and they act only like a read only text box column that show other properties from related entity.

      Option 2 - Add corresponding properties to child entity partial class

      In this approach, You can define properties in child entity partial class return value of corresponding property of parent entity. For example for product name, define this property in order item partial class:

      public string ProductName
      {
          get
          {
              if (this.Product != null)
                  return this.Product.Name;
              else 
                  return string.Empty;
          }
      }
      

      Then you can simply include products when selecting order items and bind the grid column to corresponding properties of order item.

      Option 3 - Shape the query to include properties of navigation property

      You can shape the query to include properties of navigation property. You can use an anonymous object or a View Mode simply, for example:

      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();       
      

      Option 4 - Use CellFormatting event to get value for sub property bounded columns

      In this approach you can use CellFormatting event of DataGridView. You can simply set e.Value based on column index. For example:

      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);
          }
      }
      

      You can use different criteria to handle different columns and show different sub properties.

      Also you can make it more dynamic and reusable using reflection. You can extract the value of sub property of navigation property using reflection. To do so you should create column and set DataPropertyName to sub properties like Product.Name then in CellFormatting event, using reflection, get the value for column. Here is a good article by Antonio Bello about this approach:

      Option 5 - Use a custom TypeDescriptor to enable data binding to sub properties

      In this approach you can create a custom TypeDescriptor that enables you to perform data binding to second-level properties. Here is a good article by Linda Liu about this approach:

      Option 6 - Show string representation of object by overriding ToString()

      If you want to show only a single column of navigation property, you can simply override ToString() method of navigation property class and return suitable value. This way, when showing a property of that type in grid, you will see a friendly text. For example in partial class of Product, you can write:

      public override string ToString()
      {
          return this.Name;
      }
      

      这篇关于显示DataGridView中的导航属性的属性(二级属性)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆