我想在Windows窗体应用程序中的类和实体上使用数据注释。我使用Windows DataGridViews和Infragistics UltraGrids。我之前已成功使用[DisplayName("Name to Display")]
属性在DataGridView / UltraGrid上设置列标题文本。
这非常有用,因为我可能有几个显示此类的网格,而不是配置每个网格以显示相应的标题文本,我只需设置一个数据注释。
我也想使用以下数据注释:
示例
给出以下带注释的数据类:
public class Item
{
//Specifies that the column should not be displayed
[Display(AutoGenerateField = false)]
public int ItemID { get; set; }
//Specifies that the column should be the 1st column in the datagridview
[Display(Order = 1)]
public int Name { get; set; }
//Specifies that the column should be the 3rd column in the datagridview
//Specifies that the column header text should display "Cost" instead of "Price"
[Display(Order = 3, Name="Cost")]
//Specifies that the column should be rendered using the default local currency format string
[DataType(DataType.Currency)]
public int Price { get; set; }
//Specifies that the column should be the 4th column in the datagridview
[Display(Order = 4)]
//specifies that the column should be rendered using the datetime format string "M/d/yy h:mm tt"
[DisplayFormat(DataFormatString = "{0:M/d/yy h:mm tt")]
public DateTime ExpirationDate { get; set; }
//Specifies that the column should be the 2nd column in the datagridview
[Display(Order = 2)]
public ItemCategory Category { get; set; }
}
//Specifies that the Name column should be displayed, if referenced in a containing object
[DisplayColumn("Name")]
public class ItemCategory
{
public int CategoryID { get; set; }
public string Name { get; set; }
}
我希望DataGridView像这样渲染:
+-------+---------------+--------+-----------------+
| Name | Category | Cost | ExpirationDate |
+-------+---------------+--------+-----------------+
| Item1 | Category1Name | $30.45 | 7/23/17 5:22 PM |
+-------+---------------+--------+-----------------+
| Item2 | Category1Name | $45.05 | 8/24/17 6:22 PM |
+-------+---------------+--------+-----------------+
| Item3 | Category2Name | $35.50 | 9/25/17 7:22 PM |
+-------+---------------+--------+-----------------+
然而,在.Net 4.5.2 WinForms中使用DataGridViews的实践中,datagrid实际上显示如下:
+----+-------+-------+----------------+--------------------+
| ID | Name | Price | ExpirationDate | Category |
+----+-------+-------+----------------+--------------------+
| 1 | Item1 | 30.45 | 7/23/17 | Namespace.Category |
+----+-------+-------+----------------+--------------------+
| 2 | Item2 | 45.05 | 8/24/17 | Namespace.Category |
+----+-------+-------+----------------+--------------------+
| 3 | Item3 | 35.50 | 9/25/17 | Namespace.Category |
+----+-------+-------+----------------+--------------------+
文档
该文档声明它在ASP.NET和ASP.NET MVC中受支持。
System.ComponentModel.DataAnnotations Namespace
System.ComponentModel.DataAnnotations命名空间提供了用于为ASP.NET MVC和ASP.NET数据控件定义元数据的属性类。
问题
似乎这些类在Windows窗体环境中尚未被采用/支持。这是真的吗?
是否有一种简单的方法可以在WinForms中实现对数据注释的支持?
是否有一种简单的方法来注释可用于格式化DataGridView和/或UltraGrid显示的类/实体?
答案 0 :(得分:7)
Windows窗体中没有对数据注释的内置支持,但是 了解属性如何工作以及Windows窗体如何工作,我们可以 在Windows窗体中使用它们。
在本文中,我将展示DataGridView
的扩展方法,该方法将IList<T>
绑定到DataGridView
并根据数据注释属性自动生成列,因此您可以通过调用DataGridView
获得以下dataGridView1.Bind(list);
:
查看来自数据注释属性的以下各项:
使用属性还有更多的东西。
虽然模型是这样的:
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
[TypeDescriptionProvider(typeof(MetadataTypeTypeDescriptionProvider))]
public class Person
{
[Display(Name = "Id")]
[Browsable(false)]
public int? Id { get; set; }
[Display(Name = "First Name", Description = "First name.", Order = 1)]
public string FirstName { get; set; }
[Display(Name = "Last Name", Description = "Last name", Order = 2)]
public string LastName { get; set; }
[Display(Name = "Birth Date", Description = "Date of birth.", Order = 4)]
[DisplayFormat(DataFormatString = "yyyy-MM-dd")]
public DateTime BirthDate { get; set; }
[Display(Name = "Homepage", Description = "Url of homepage.", Order = 5)]
public string Url { get; set; }
[Display(Name = "Member", Description = "Is member?", Order = 3)]
public bool IsMember { get; set; }
}
绑定
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows.Forms;
public static class DataGridViewExtensions
{
public static void Bind<T>(this DataGridView grid, IList<T> data,
bool autoGenerateColumns = true)
{
if (autoGenerateColumns)
{
var properties = TypeDescriptor.GetProperties(typeof(T));
var metedata = properties.Cast<PropertyDescriptor>().Select(p => new
{
Name = p.Name,
HeaderText = p.Attributes.OfType<DisplayAttribute>()
.FirstOrDefault()?.Name ?? p.DisplayName,
ToolTipText = p.Attributes.OfType<DisplayAttribute>()
.FirstOrDefault()?.GetDescription() ?? p.Description,
Order = p.Attributes.OfType<DisplayAttribute>()
.FirstOrDefault()?.GetOrder() ?? int.MaxValue,
Visible = p.IsBrowsable,
ReadOnly = p.IsReadOnly,
Format = p.Attributes.OfType<DisplayFormatAttribute>()
.FirstOrDefault()?.DataFormatString,
Type = p.PropertyType
});
var columns = metedata.OrderBy(m => m.Order).Select(m =>
{
DataGridViewColumn c;
if (m.Type == typeof(bool)) {
c = new DataGridViewCheckBoxColumn(false); }
else if (m.Type == typeof(bool?)) {
c = new DataGridViewCheckBoxColumn(true); }
else { c = new DataGridViewTextBoxColumn(); }
c.DataPropertyName = m.Name;
c.Name = m.Name;
c.HeaderText = m.HeaderText;
c.ToolTipText = m.ToolTipText;
c.DefaultCellStyle.Format = m.Format;
c.ReadOnly = m.ReadOnly;
c.Visible = m.Visible;
return c;
});
grid.Columns.Clear();
grid.Columns.AddRange(columns.ToArray());
}
grid.DataSource = data;
}
}
Windows窗体的另外,为了支持数据注释验证,您可以使用IDataErrorInfo
类来实现Validator
接口,就像在DataAnnotations Validation attributes for Windows Forms中一样。
注意
要增强答案,您可能需要创建一个关心元数据属性的类型描述符,然后用该类型描述符装饰模型。您可以使用AssociatedMetadataTypeTypeDescriptor
,MetadataPropertyDescriptorWrapper
,AssociatedMetadataTypeTypeDescriptionProvider
的代码开始。
您还可以创建一个元数据类,并在元数据上应用某些属性,例如Url
或DataType
。查看这篇文章将给您一些想法:Combining multiple Attributes to a single Attribute - Merge Attributes。
答案 1 :(得分:2)
Infragistics UltraGrid和Windows DataGridView都不支持这种方式的数据注释。 DevExpress从15.1开始,在其数据布局控件https://community.devexpress.com/blogs/thinking/archive/2015/06/08/winforms-data-layout-control-data-annotation-attributes.aspx中有一些有限的WinForms数据注释支持。
我发现这个链接,有人通过查看元数据询问有关如何在Infragistics Grid中抑制列的类似问题:http://www.infragistics.com/community/forums/t/91864.aspx