In answer to a post on the ASP.Net Dynamic Data Forum from Luigi here I though I should post my solution. The basic issue was dealt with here by Rick Anderson I decided to implement a version that used Attributes and a simple extension method to apply the attribute values:
Firstly here is the attribute, it just handles one class name.
/// <summary> /// Used to apply css classes to the cell /// that encloses a field template. /// </summary> [AttributeUsage(AttributeTargets.Property)] public class CssAttribute : Attribute { public String Class { get; private set; } public CssAttribute() { } public CssAttribute(String css) { Class = css; } }
Listing 1 – CSS Attribute
There are two extension methods I use to implement the CssAttribute, the first Listing 2 is used in the Field Template is a helper that I use in many other places; I use it to get the first parent control of a Type DetailsView GridView etc. here I’m use it to get the parent DataControlFieldCell or TD/cell of the table, obviously if you are using FormView or ListView you will need to specify the relevant container control.
/// <summary> /// Gets the container control. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="control">The control.</param> /// <returns></returns> public static T GetContainerControl<T>(this Control control) where T : Control { // get current parent var parentControl = control.Parent; while (parentControl != null) { var p = parentControl as T; if (p != null) { // return found control return p; } else { // get next parent parentControl = parentControl.Parent; } } // if no control found return null return null; }
Listing 2 – GetContainerControl
The next Listing 3 actually applies the attribute by first calling the GetParentControl helper to get the containing cell/TD then extracts the class attribute and applies the new class either by appending or assigning.
/// <summary> /// Applies the CSS. /// </summary> /// <param name="control">The control.</param> /// <param name="Column">The column.</param> public static void ApplyCss(this FieldTemplateUserControl control, MetaColumn Column) { // get the attribute var css = Column.GetAttribute<CssAttribute>(); // get parent control var parentCell = control.GetContainerControl<DataControlFieldCell>(); // make sure we have the attribute and parent control if (css != null && parentCell != null) { // test for the presence of a class attribute on the cell var cssClass = parentCell.Attributes["class"]; if (cssClass != null) { // add the extra class cssClass += " " + css.Class; } else { // assign the class parentCell.Attributes.Add("class", css.Class); } } }
Listing 3 – ApplyCss method
You will also notice the GetAttribute extension method which I wont go into as you can find details on this site here Writing Attributes and Extension Methods for Dynamic Data
Some sample Metadata showing adding cantering to a single column:
[MetadataType(typeof(CategoryMetadata))] public partial class Category { internal class CategoryMetadata { public Object CategoryID { get; set; } [Css("CenterCell")] public Object CategoryName { get; set; } public Object Description { get; set; } public Object Picture { get; set; } // Entity Set public Object Products { get; set; } } }
Listing 4 – CssAttribute applied
Figure 1 – applied CSS attribute
Download
Happy coding
2 comments:
Why would you ever want to mix up presentation logic with your domain logic?
Simply put because people ask for it and it keeps the model DRY as you are not putting this setting in many different places, you could concivable have two buddy classes one for domain logic and one for presentation logic, but the benfit it you are not adding this to many pages/templates.
Steve
Post a Comment