Working in investment banking, I often get asked to create semi-functional prototypes of user interfaces, where the development methodology is all about speed and not about code-quality.
Often these projects will be centred around the Silverlight DataGrid, and I want to get it up and running fast with whatever data object that needs to be used (the DataGrid will need to be bound to a collection of such objects).
By default, a DataGrid for Silverlight will automatically generate columns, which is a great little feature in these scenarios, which is a great time saver – especially when the underlying object that your rows are binding to is in a state of flux.
However, when automatically generating columns for your data, the column header is just set to the name of the property – which isn't going to impress the audience when you show off your prototype.
A great solution I put together, is to use the ‘DescriptionAttribute’ on your data object’s properties, and have the DataGrid automatically pick that up.
To Illustrate this, please find below the ‘before’ and ‘after’ code and screenshots.
1) Before
public class Person
{
public string Name { get; set; }
public DateTime Dob { get; set; }
public int EmployeeId { get; set; }
public double Salary { get; set; }
}
<UserControl.Resources>
<AttributesConverter:PersonCollection x:Key="PersonCollectionDS"
d:IsDataSource="True"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<data:DataGrid Name="PersonGrid" HorizontalAlignment="Left"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource PersonCollectionDS}}" />
</Grid>
2) After
public class Person
{
[Description("Employee Name")]
public string Name { get; set; }
[Description("Date Of Birth")]
public DateTime Dob { get; set; }
[Description("Employee Id")]
public int EmployeeId { get; set; }
[Description("Salary Amount")]
public double Salary { get; set; }
}
<UserControl.Resources>
<AttributesConverter:PersonCollection x:Key="PersonCollectionDS"
d:IsDataSource="True"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<data:DataGrid Name="PersonGrid" HorizontalAlignment="Left"
ItemsSource="{Binding Mode=OneWay, Source={StaticResource PersonCollectionDS}}"
AutoGeneratingColumn="ColumnGenerate" />
</Grid>
private void ColumnGenerate(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
var attrib = gridDataType.GetProperty(e.PropertyName).GetCustomAttributes(
typeof (DescriptionAttribute), true);
e.Column.Header = attrib == null ?
e.PropertyName :
((DescriptionAttribute)attrib[0]).Description;
}
As you can see, the second screenshot has user-friendly headings.
The code differences between before and after are summarised below:
- In the ‘After’ code, our ‘Person’ data object has its properties decorated with the DescriptionAttribute attribute – this is where we set our user-friendly descriptions.
- In the ‘After’ code, our DataGrid sets a handler for the ‘AutoGeneratingColumn’ event.
- In the ‘After’ code, our code-behind handles the above event, and sets the column headers to match the property description custom attribute.
Pretty simple really, and a great productivity boon during prototype development. Simply setup your grid, and as your domain object changes so does your grid – automatically.
I hope this little tips helps anyone else out in this scenario.
If anyone has any further comments, please let me know.
Dean