DataAnnotations attributes for DataGridView in Windows Forms
There is no built-in support for Data Annotation in Windows Forms, but
knowing how the attributes work and how windows forms work, we can
use them in windows forms.
Here in this post, I'll show an extension method for DataGridView
which binds an IList<T>
to DataGridView
and auto-generate columns based on the data annotations attributes, so you can get the following DataGridView
, by calling dataGridView1.Bind(list);
:
Look at the following items which are coming from data annotations attributes:
- Column visibility: Id column is invisible
- Column header texts: They are custom texts different from property names
- Order of columns: The order of columns is custom, different from property orders
- Tooltip: We have shown custom tooltip for columns.
- Format of data: We have used custom format for date.
And many more things still you can have using attributes.
While the model is like this:
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; }
}
Bind<T> Extension Method
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;
}
}
DataAnnotations Validation attributes for Windows Forms
Also for supporting data annotations validations you can implement IDataErrorInfo
interface using Validator
class, the same way that I've done it in DataAnnotations Validation attributes for Windows Forms.
Note
To enhance the answer, you may want to creating a type descriptor which cares about metadata attributes and then decorate the models with that type descriptor. You can start by using the code of AssociatedMetadataTypeTypeDescriptor
, MetadataPropertyDescriptorWrapper
, AssociatedMetadataTypeTypeDescriptionProvider
.
Also you can create a Metadata class and apply the effect of some attributes like Url
or DataType
on the metadata. Looking into this post will give you some idea: Combining multiple Attributes to a single Attribute - Merge Attributes.