Feed Subscribe
Exception has been thrown by the target of an invocation.

How to specify UIHint template only for specific mode in ASP.NET Dynamic Data

by ondrejsv 8. October 2009 16:58

If you want to display a data field in your custom template instead of the default one coming with ASP.NET Dynamic Data, you can by decorating your metadata with the UIHint attribute:

[UIHint("Attributes")] public EntityCollection<Attribute> Attributes

In this case, Attributes collection will be displayed using Attributes.ascx template. Dynamic Date is clever enough to use Attributes_Edit.ascx if you happen to edit the collection. If Attributes_Edit.ascx does not exist, Dynamic Date will use the default template.

However, if you have a template that you want to use only for editing (or inserting) and use the default template otherwise (for read only), you cannot. If you supply the UIHint, you are required to have also a read-only template – in our case, you must have Attributes_Edit.ascx together with Attributes.ascx. You end up copying the content of the default template and renaming it (to Attributes.ascx and so on). As we know that copy-paste is a bad programmer’s friend which promotes low code maintainability and readability, we must come up with another solution.

Dynamic Data delegates deciding which template to use for which field to an instance of the FieldTemplateFactory class. In particular, we are interested in its GetFieldTemplateVirtualPath method which eats a column to get the template for, mode (ReadOnly, Edit, Insert) and UIHint value. We can, of course, extend the default factory to process UIHints in the form realUIHint|mode (e.g. “Attributes|Edit” which means use the Attributes_Edit.ascx for editing but the default template for anything else). The actual code is simple:

public class MyFieldTemplateFactory : FieldTemplateFactory { private const char HintSeparator = '|'; public override string GetFieldTemplateVirtualPath(MetaColumn column, System.Web.UI.WebControls.DataBoundControlMode mode, string uiHint) { if (!string.IsNullOrEmpty(uiHint) && uiHint.IndexOf(HintSeparator) > 0) { string[] sArr = uiHint.Split(HintSeparator); string hint = sArr[0]; string forMode = sArr[1]; // If current mode is the one specified in the UiHint // use it, otherwise fall back to the base implemenation. if (mode.ToString() == forMode) uiHint = hint; else uiHint = ""; } var temp = base.GetFieldTemplateVirtualPath(column, mode, uiHint); return base.GetFieldTemplateVirtualPath(column, mode, uiHint); } }

Associate your custom template factory with the model in the RegisterRoutes method inside the Global.asax:

model.FieldTemplateFactory = new MyFieldTemplateFactory();
Done! :-)
kick it on DotNetKicks.com [digg]

Tags: ,