I decided to create an HTML Edit FieldTemplate after the AJAX Control Toolkit HTML Editor was released and a post (Edit.aspx page hanging on text entry) on the ASP.Net Dynamic Data Forum was posted.
For this we will need two FieldTemplates:
- Html.ascx
- Html_Edit.ascx
The first of the two Html.ascx will display the HTML rendered correctly and the second will use the AJAX Control Toolkit HTML Editor.
The Normal FieldTemplate
<%@ Control Language="C#" Inherits="DD_HTMLEditor.Html_Field" Codebehind="Html.ascx.cs" %> <asp:Literal runat="server" ID="Literal1" Text="<%# FieldValueEditString %>" />
using System; using System.Web.UI; namespace DD_HTMLEditor { public partial class Html_Field : System.Web.DynamicData.FieldTemplateUserControl { public override Control DataControl { get { return Literal1; } } } }
As you can see this is a direct copy of the Text.ascx FieldTemplate the only change is to Literal1 in the ascx file instead of FieldValueString we are using FieldValueEditString.
Figure 1 – Description Field Showing HTML
The Edit FieldTemplate
<%@ Control Language="C#" Inherits="DD_HTMLEditor.Html_EditField" Codebehind="Html_Edit.ascx.cs" %> <%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit.HTMLEditor" TagPrefix="cc1" %> <cc1:Editor ID="Editor1" Content='<%# FieldValueEditString %>' runat="server" /> <asp:RequiredFieldValidator runat="server" ID="RequiredFieldValidator1" CssClass="droplist" ControlToValidate="Editor1" Display="Dynamic" Enabled="false" /> <asp:RegularExpressionValidator runat="server" ID="RegularExpressionValidator1" CssClass="droplist" ControlToValidate="Editor1" Display="Dynamic" Enabled="false" /> <asp:DynamicValidator runat="server" ID="DynamicValidator1" CssClass="droplist" ControlToValidate="Editor1" Display="Dynamic" />
Listing 3 – Html_Edit.ascx file
using System; using System.Collections.Specialized; using System.Web.UI; namespace DD_HTMLEditor { public partial class Html_EditField : System.Web.DynamicData.FieldTemplateUserControl { protected void Page_Load(object sender, EventArgs e) { SetUpValidator(RequiredFieldValidator1); RequiredFieldValidator1.Text = "*"; SetUpValidator(RegularExpressionValidator1); RegularExpressionValidator1.Text = "*"; SetUpValidator(DynamicValidator1); DynamicValidator1.Text = "*"; } protected override void ExtractValues(IOrderedDictionary dictionary) { dictionary[Column.Name] = ConvertEditedValue(Editor1.Content); } public override Control DataControl { get { return Editor1; } } } }
Listing 4 – Html_Edit.ascx.cs file
Here again it’s just the Text_Edit FieldTemplate with a few minor changes (shown in BOLD ITALIC). First we added the AJAC Control Toolkit HTML Editor control to replace the TextBox control and added a reference to the FieldTemplate.
You could also add a reference for the AJAX Control Toolkit to the web.config
<pages> <controls> <add tagPrefix="ajaxToolkit" namespace="AjaxControlToolkit" assembly="AjaxControlToolkit"/> </controls> </pages>
Figure 2 – Description Field in Edit mode
Next Steps
Next we need to add some of the configurability of the HTML Editor via a custom Attribute.using System; using System.Linq; using System.Web.DynamicData; using AjaxControlToolkit.HTMLEditor; namespace DD_HTMLEditor { /// <summary> /// Attribute to identify which column to use as a /// parent column for the child column to depend upon /// </summary> [AttributeUsage(AttributeTargets.Property)] public class HtmlEditorAttribute : Attribute { /// <summary> /// Default Contructor /// </summary> public HtmlEditorAttribute() { } /// <summary> /// Active editing panel (Design, Html, Preview) on control loaded /// </summary> public AjaxControlToolkit.HTMLEditor.ActiveModeType ActiveMode { get; set; } /// <summary> /// If true, editing panel is focused and cursor is set /// inside it ("Design" or "HTML text") on initial load /// or editing panel change /// </summary> public Boolean AutoFocus { get; set; } /// <summary> /// A css class override used to define a custom look /// and feel for the HTMLEditor. See the HTMLEditor /// Theming section for more details /// </summary> public String CssClass { get; set; } /// <summary> /// Sets the path of additional CSS file used for /// HTMLEditor's content rendering in "Design" panel. /// If not set, the default CSS file is used which is /// embedded as a WebResource and is a /// part of the Toolkit assembly /// </summary> public String DesignPanelCssPath { get; set; } /// <summary> /// Sets the path of CSS file used for HTMLEditor's /// content rendering in "Design" and "Preview" panels. /// If not set, the default CSS file is used which is /// embedded as a WebResource and is a part of the /// Toolkit assembly /// </summary> public String DocumentCssPath { get; set; } /// <summary> /// A css class override used to define a custom look for the /// HTMLEditor's "HTML text" mode panel. See the HTMLEditor /// Theming section for more details /// </summary> public String HtmlPanelCssClass { get; set; } /// <summary> /// If true, Tab key navigation is suppressed inside /// HTMLEditor control /// </summary> public Boolean IgnoreTab { get; set; } /// <summary> /// If true, HTMLEditor's content is cleaned up on /// initial load. MS Word specific tags are removed /// </summary> public Boolean InitialCleanUp { get; set; } /// <summary> /// If true, JavaScript code is suppressed /// in HTMLEditor's content /// </summary> public Boolean NoScript { get; set; } /// <summary> /// If true, all Unicode characters in /// HTML content are replaced with &#code; /// </summary> public Boolean NoUnicode { get; set; } /// <summary> /// The client-side script that executes after /// active mode (editing panel) changed /// </summary> public String OnClientActiveModeChanged { get; set; } /// <summary> /// The client-side script that executes before /// active mode (editing panel) changed /// </summary> public String OnClientBeforeActiveModeChanged { get; set; } /// <summary> /// If true, no white spaces inserted on Tab key /// press in Design mode. Default Tab key navigation /// is processing in this case /// </summary> public Boolean SuppressTabInDesignMode { get; set; } /// <summary> /// Sets the height of the body of the HTMLEditor /// </summary> public int Height { get; set; } /// <summary> /// Sets the width of the body of the HTMLEditor /// </summary> public int Width { get; set; } } public static partial class HelperExtansionMethods { /// <summary> /// Get the attribute or a default instance of the attribute /// if the Column attribute do not contain the attribute /// </summary> /// <typeparam name="T"> /// Attribute type /// </typeparam> /// <param name="table"> /// Column to search for the attribute on. /// </param> /// <returns> /// The found attribute or a default /// instance of the attribute of type T /// </returns> public static T GetAttributeOrDefault<T>(this MetaColumn column) where T : Attribute, new() { return column.Attributes.OfType<T>().DefaultIfEmpty(new T()).FirstOrDefault(); } } }
Listing 5 – HtmlEditorAttribute
var htmlAttr = Column.GetAttributeOrDefault<HtmlEditorAttribute>(); if (htmlAttr.ActiveMode != ActiveModeType.Design) Editor1.ActiveMode = htmlAttr.ActiveMode; if (htmlAttr.AutoFocus) Editor1.AutoFocus = true; if (htmlAttr.CssClass != null) Editor1.CssClass = htmlAttr.CssClass; if (htmlAttr.DesignPanelCssPath != null) Editor1.DesignPanelCssPath = htmlAttr.DesignPanelCssPath; if (htmlAttr.DocumentCssPath != null) Editor1.DocumentCssPath = htmlAttr.DocumentCssPath; if (htmlAttr.Height > 0) Editor1.Height = htmlAttr.Height; if (htmlAttr.HtmlPanelCssClass != null) Editor1.HtmlPanelCssClass = htmlAttr.HtmlPanelCssClass; if (htmlAttr.IgnoreTab) Editor1.IgnoreTab = true; if (htmlAttr.InitialCleanUp) Editor1.InitialCleanUp = true; if (htmlAttr.NoScript) Editor1.NoScript = true; if (htmlAttr.NoUnicode) Editor1.NoUnicode = true; if (htmlAttr.OnClientActiveModeChanged != null) Editor1.OnClientActiveModeChanged = htmlAttr.OnClientActiveModeChanged; if (htmlAttr.OnClientBeforeActiveModeChanged != null) Editor1.OnClientBeforeActiveModeChanged = htmlAttr.OnClientBeforeActiveModeChanged; if (htmlAttr.SuppressTabInDesignMode) Editor1.SuppressTabInDesignMode = true; if (htmlAttr.Width > 0) Editor1.Width = htmlAttr.Width;
Listing 6 – Attribute setting for Html_Edit.ascx
using System.ComponentModel; using System.ComponentModel.DataAnnotations; using AjaxControlToolkit.HTMLEditor; namespace DD_HTMLEditor.Models { [MetadataType(typeof(CategoryMD))] public partial class Category { public partial class CategoryMD { public object CategoryID {get;set;} public object CategoryName {get;set;} [UIHint("Html")] [HtmlEditor( ActiveMode=ActiveModeType.Preview, Width=200, Height=100 )] public object Description {get;set;} public object Picture {get;set;} public object Products {get;set;} } } }
Listing 7 – Metadata
Above we have the attribute Listing 5 and the code Listing 6 to set the properties of the Html Editor in the Html_Edit.ascx FieldTemplate’s Page_Load event, and finally Listing 7 sample metadata.
Figure 3 – Attribute from the Metadata applied
Not Rocket Science but a cool Html Editor (Thanks AJAX Toolkit Guys).