【问题标题】:Is it possible to bind complex type properties to a datagrid?是否可以将复杂类型属性绑定到数据网格?
【发布时间】:2008-09-23 14:18:48
【问题描述】:

我将如何将以下对象 Car 绑定到网格视图?

公共级汽车 { 长 ID {get;放;} 制造商 制造商 {get;放;} } 公共类 制造商 { 长 ID {get;放;} 字符串名称 {get;放;} }

原始类型很容易绑定,但我发现无法为 Maker 显示任何内容。我希望它显示制造商名称。甚至可能吗?

有什么方法可以做到这一点?我是否也必须将 ManufacturerId 存储在 Car 中,然后设置一个带有制造商列表的 lookupEditRepository?

【问题讨论】:

    标签: c# .net data-binding


    【解决方案1】:

    好的,伙计们...这个问题已经发布了,但我刚刚找到了一种相当不错且简单的方法,方法是在 cell_formatting 事件中使用反射来检索嵌套属性。

    是这样的:

        private void Grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
    
            DataGridView grid = (DataGridView)sender;
            DataGridViewRow row = grid.Rows[e.RowIndex];
            DataGridViewColumn col = grid.Columns[e.ColumnIndex];
            if (row.DataBoundItem != null && col.DataPropertyName.Contains("."))
            {
                string[] props = col.DataPropertyName.Split('.');
                PropertyInfo propInfo = row.DataBoundItem.GetType().GetProperty(props[0]);
                object val = propInfo.GetValue(row.DataBoundItem, null);
                for (int i = 1; i < props.Length; i++)
                {
                    propInfo = val.GetType().GetProperty(props[i]);
                    val = propInfo.GetValue(val, null);
                }
                e.Value = val;
            }
        }
    

    就是这样!您现在可以在列的 DataPropertyName 中使用熟悉的语法“ParentProp.ChildProp.GrandChildProp”。

    【讨论】:

    • 效果很好!感谢分享。
    • 这值得更多的支持!根本不知道发生了什么,但它有效,哈哈。谢谢分享!!!
    【解决方案2】:

    是的,您可以创建一个 TypeDescriptionProvider 来完成嵌套绑定。这是来自 MSDN 博客的详细示例:

    http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx

    【讨论】:

    • 实现这一目标的复杂程度相当高。我是否应该有另一组可绑定类,我可以将我的业务对象转换为?
    • 这是一个设计决定。要么你必须创建一堆新的类只是为了绑定的目的,要么使用我帖子中提供的配方。就个人而言,我讨厌用“帮助者”来混淆我的类层次结构,所以我会选择后者。
    【解决方案3】:

    我在最近的一个应用程序中处理此问题的方法是创建我自己的 DataGridViewColumn 和 DataGridViewCell 类,继承自 DataGridViewTextBoxColumn 和 DataGridViewTextBoxCell 等现有类之一。

    根据您想要的单元格类型,您可以使用其他类型,例如 Button、Checkbox、ComboBox 等。看看 System.Windows.Forms 中可用的类型。

    单元格将其值作为对象处理,因此您可以将 Car 类传递给单元格的值。

    重写 SetValue 和 GetValue 将允许您拥有处理值所需的任何其他逻辑。

    例如:

    public class CarCell : System.Windows.Forms.DataGridViewTextBoxCell
    {
        protected override object GetValue(int rowIndex)
        {
            Car car = base.GetValue(rowIndex) as Car;
            if (car != null)
            {
                return car.Maker.Name;
            }
            else
            {
                return "";
            }
        }
    }
    

    在列类上,您需要做的主要事情是将 CellTemplate 设置为您的自定义单元格类。

    public class CarColumn : System.Windows.Forms.DataGridViewTextBoxColumn
    {
        public CarColumn(): base()
        {
            CarCell c = new CarCell();
            base.CellTemplate = c;
        }
    }
    

    通过在 DataGridView 上使用这些自定义列/单元格,它允许您向 DataGridView 添加许多额外的功能。

    我使用它们来更改显示的格式,方法是覆盖 GetFormattedValue 以将自定义格式应用于字符串值。

    我还对 Paint 进行了覆盖,以便我可以根据值条件进行自定义单元格突出显示,根据值将单元格 Style.BackColor 更改为我想要的。

    【讨论】:

      【解决方案4】:
          public class Manufacturer
          {
             long Id {get; set;}
             String Name {get; set;}
      
             public override string ToString()
             {
                return Name;
             }
          }
      

      重写 to 字符串方法。

      【讨论】:

      • 只需要一个属性是可以的,但它不适用于您想要该对象的多个属性。
      【解决方案5】:

      只需使用列表并将 DataMember 设置为字符串“Maker.Name”,如果您希望 DataKeyField 使用汽车 ID,只需将其设置为“ID” .

      dataGrid.DataSource = carList;
      dataGrid.DataMember = "Maker.Name";
      dataGrid.DataKeyField = "ID";
      dataGrid.DataBind();
      

      我知道这在转发器控件中有效,至少......

      【讨论】:

        【解决方案6】:

        如果您想将特定的嵌套属性公开为绑定目标,那么 Ben Hoffstein 的回答 (http://blogs.msdn.com/msdnts/archive/2007/01/19/how-to-bind-a-datagridview-column-to-a-second-level-property-of-a-data-source.aspx) 非常好。引用的文章有点迟钝,但确实有效。

        如果您只想将列绑定到复杂属性(例如制造商)并覆盖呈现逻辑,那么要么执行 ManiacXZ 推荐的操作,要么仅将 BoundField 子类化并提供 FormatDataValue() 的自定义实现。这类似于覆盖 ToString();你得到一个对象引用,然后返回你想要在网格中显示的字符串。

        类似这样的:

        public class ManufacturerField : BoundField
        {
            protected override string FormatDataValue(object dataValue, bool encode)
            {
                var mfr = dataValue as Manufacturer;
        
                if (mfr != null)
                {
                    return mfr.Name + " (ID " + mfr.Id + ")";
                }
                else
                {
                    return base.FormatDataValue(dataValue, encode);
                }
            }
        }
        

        只需将 ManufacturerField 添加到您的网格,将“Manufacturer”指定为数据字段,您就可以开始了。

        【讨论】:

          【解决方案7】:

          这是我工作的另一个选择:

          <asp:TemplateColumn
              HeaderText="Maker">
              <ItemTemplate>
                    <%#Eval("Maker.Name")%>
              </ItemTemplate>
          </asp:TemplateColumn>
          

          可能是 ASP.NET 4.0 特有的,但它的工作原理就像一个魅力!

          【讨论】:

            【解决方案8】:

            我假设您可以执行以下操作:

            public class Car
            {
                public long Id {get; set;}
                public Manufacturer Maker {private get; set;}
            
                public string ManufacturerName
                {
                   get { return Maker != null ? Maker.Name : ""; }
                }
            }
            
            public class Manufacturer
            {
               long Id {get; set;}
               String Name {get; set;}
            }
            

            【讨论】:

            • 不是人们通常想做的事,但它似乎更符合得墨忒耳法则。
            猜你喜欢
            • 2015-01-23
            • 1970-01-01
            • 2013-01-30
            • 2010-10-15
            • 2011-08-22
            • 2019-05-12
            • 1970-01-01
            • 1970-01-01
            • 2011-07-27
            相关资源
            最近更新 更多