This is really just an addition to Matt Berseth's article Dynamic Data And Custom Metadata Providers from August 24, 2008, all I wanted to do was add the same features to the Table/Class not just the Columns/Properties. So you can see the full explanation over at Matt Berseth's blog. So here are the listings:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Web; public class DefaultAttributesTypeDescriptionProvider : System.ComponentModel.TypeDescriptionProvider { private Type Type { get; set; } public DefaultAttributesTypeDescriptionProvider(Type type) : this(type, TypeDescriptor.GetProvider(type)) { this.Type = type; } public DefaultAttributesTypeDescriptionProvider(Type type, TypeDescriptionProvider parentProvider) : base(parentProvider) { this.Type = type; } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { return new DefaultAttributesTypeDescriptor(base.GetTypeDescriptor(objectType, instance), this.Type); } }
Listing 1 – TypeDescriptorProvider
No change in Listing 1 from what Matt has already done just some renaming to make it a bit clearer to me what's going on.
using System; using System.Linq; using System.Text; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Reflection; public class DefaultAttributesTypeDescriptor : CustomTypeDescriptor { private Type Type { get; set; } public DefaultAttributesTypeDescriptor(ICustomTypeDescriptor parent, Type type) : base(parent) { this.Type = type; } /// <summary> /// Returns the collection of attributes for a given table /// </summary> /// <returns>AttributeCollection</returns> public override AttributeCollection GetAttributes() { AttributeCollection baseAttributes = base.GetAttributes(); if (baseAttributes.OfType<DisplayNameAttribute>().FirstOrDefault() == null) { List<Attribute> extraAttributes = new List<Attribute>(); // generate the display name String friendlyDisplayName = base.GetClassName().ToTitleFromPascal(); // add it to the list extraAttributes.Add(new DisplayNameAttribute(friendlyDisplayName)); // only create a new collection if it is necessary return AttributeCollection.FromExisting(baseAttributes, extraAttributes.ToArray()); } else { return baseAttributes; } } /// <summary> /// Returns a collection of properties (columns) for the type, /// each with attributes for that table /// </summary> /// <returns>PropertyDescriptorCollection</returns> public override PropertyDescriptorCollection GetProperties() { List<PropertyDescriptor> propertyDescriptors = new List<PropertyDescriptor>(); foreach (PropertyDescriptor propDescriptor in base.GetProperties()) { List<Attribute> newAttributes = new List<Attribute>(); // Display Name Rules ... // If the property doesn't already have a DisplayNameAttribute defined // go ahead and auto-generate one based on the property name if (!propDescriptor.HasAttribute<DisplayNameAttribute>()) { // generate the display name String friendlyDisplayName = propDescriptor.Name.ToTitleFromPascal(); // add it to the list newAttributes.Add(new DisplayNameAttribute(friendlyDisplayName)); } // Display Format Rules ... // If the property doesn't already have a DisplayFormatAttribute defined // go ahead and auto-generate one based on the property type if (!propDescriptor.HasAttribute<DisplayFormatAttribute>()) { // get the default format for the property type String displayFormat = propDescriptor.PropertyType.GetDisplayFormat(); // add it to the list newAttributes.Add(new DisplayFormatAttribute() { DataFormatString = displayFormat }); } propertyDescriptors.Add(new WrappedPropertyDescriptor(propDescriptor, newAttributes.ToArray())); } // return the descriptor collection return new PropertyDescriptorCollection(propertyDescriptors.ToArray(), true); } private class WrappedPropertyDescriptor : PropertyDescriptor { private PropertyDescriptor _wrappedPropertyDescriptor; public WrappedPropertyDescriptor(PropertyDescriptor wrappedPropertyDescriptor, Attribute[] attributes) : base(wrappedPropertyDescriptor, attributes) { _wrappedPropertyDescriptor = wrappedPropertyDescriptor; } public override bool CanResetValue(object component) { return _wrappedPropertyDescriptor.CanResetValue(component); } public override Type ComponentType { get { return _wrappedPropertyDescriptor.ComponentType; } } public override object GetValue(object component) { return _wrappedPropertyDescriptor.GetValue(component); } public override bool IsReadOnly { get { return _wrappedPropertyDescriptor.IsReadOnly; } } public override Type PropertyType { get { return _wrappedPropertyDescriptor.PropertyType; } } public override void ResetValue(object component) { _wrappedPropertyDescriptor.ResetValue(component); } public override void SetValue(object component, object value) { _wrappedPropertyDescriptor.SetValue(component, value); } public override bool ShouldSerializeValue(object component) { return _wrappedPropertyDescriptor.ShouldSerializeValue(component); } } }
Listing 2 – CustomTypeDescriptor
Here all I’ve done is again some renaming and add a GetAttributes method which returns the attributes on the class/table. The section is marked in BOLD ITALIC for emphasis. What it does is check to see if the DisplayNameAttriburte is set and if not then auto generates it.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Web; using System.Web.DynamicData; using Microsoft.Web.DynamicData; public static class HelperExtansionMethods { public static ColumnOrderAttribute ColumnOrdering(this MetaColumn column) { return column.Attributes.OfType<ColumnOrderAttribute>().DefaultIfEmpty(ColumnOrderAttribute.Default).First(); } public static Boolean IsHidden(this MetaColumn column, PageTemplate currentPage) { var hideIn = column.Attributes.OfType<HideColumnInAttribute>().DefaultIfEmpty(new HideColumnInAttribute()).First() as HideColumnInAttribute; return hideIn.PageTemplates.Contains(currentPage); } /// <summary> /// Converts a Pascal type Name to Title /// i.e. MyEmployees becomes My Employees /// OrderID becomes Order ID etc /// </summary> /// <param name="s">String to convert</param> /// <returns>Title String</returns> public static String ToTitleFromPascal(this String s) { // remove name space String s0 = Regex.Replace(s, "(.*\\.)(.*)", "$2");Listing 3 – Helper extension methods
// add space before Capital letter String s1 = Regex.Replace(s0, "[A-Z]", " $&"); // replace '_' with space String s2 = Regex.Replace(s1, "[_]", " "); // replace double space with single space String s3 = Regex.Replace(s2, " ", " "); // remove and double capitals with inserted space String s4 = Regex.Replace(s3, "(?<before>[A-Z])\\s(?<after>[A-Z])", "${before}${after}"); // remove and double capitals with inserted space String sf = Regex.Replace(s4, "^\\s", ""); // force first character to upper case return sf.ToTitleCase(); } public static String ToTitleCase(this String text) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < text.Length; i++) { if (i > 0) { if (text.Substring(i - 1, 1) == " " || text.Substring(i - 1, 1) == "\t" || text.Substring(i - 1, 1) == "/") sb.Append(text.Substring(i, 1).ToString().ToUpper()); else sb.Append(text.Substring(i, 1).ToString().ToLower()); } else sb.Append(text.Substring(i, 1).ToString().ToUpper()); } return sb.ToString(); } public static Boolean HasAttribute<T>(this PropertyDescriptor descriptor) where T : Attribute { Boolean value = false; for (int i = 0; i < descriptor.Attributes.Count && !value; i++) { value = (descriptor.Attributes[i] is T); } return value; } public static String GetDisplayFormat(this Type type) { string defaultFormat = "{0}"; if (type == typeof(DateTime) || type == typeof(Nullable<DateTime>)) { defaultFormat = "{0:d}"; } else if (type == typeof(decimal) || type == typeof(Nullable<decimal>)) { defaultFormat = "{0:c}"; } return defaultFormat; } }
EntitiesModel.MyEntity
or
tbl_name_of_table
I’ve moved my helper extension methods out of the class and rewritten the ToHumanFromPascal as ToTitleFromPascal and used Regex to do my converting.
I hope Matt doesn't mind. ![]()