Implementing a ViewAsText property for a WebControl at design time
Sometimes all you want is a little change. Something simple like “View as Text” in design view.
There are starting to be a reasonable number of articles about Design-Time Support for Web Forms , there is Nikhil Kothari’s book, and Scott Mitchell has begun to write about them. When I started working on designers there were a lot fewer resources, but I learned some interesting stuff along the way.
This is my first blog about design time, and it is a simple article. I’m going to take two controls and give each of them a new property called ViewAsText.
I will use this property to decide if the control will display normaly or if it will display the html found in the html view.
The two controls are CustomLabel which inherits Label and CustomDropDownList which inherits DropDownList. Both controls have a view as text property, the label’s defaults to true, the dropdown's to false.
Each control has an associated designer. It is in the designers that we do something different, we override GetDesignTimeHtml so that we can return custom markup. The trick here is to get the html; I use the designer’s DesignTimeElement and cast it as an mshtml.IHTMLElement. From this element I get the innerHTML or outerHTML and procede to display it.
//The Controls
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using AndrewSeven.Samples.Design;
[assembly:TagPrefix("AndrewSeven.Samples", "AndrewSeven")]
namespace AndrewSeven.Samples
{
[Designer(typeof(CustomLabelDesigner),typeof(IDesigner))]
public class CustomLabel : Label
{
private bool viewAsText = true;
[DefaultValue(true)]
public bool ViewAsText
{
get{return viewAsText;}
set{viewAsText = value;}
}
}
[Designer(typeof(CustomDropDownListDesigner),typeof(IDesigner))]
public class CustomDropDownList : DropDownList
{
private bool viewAsText = false;
[DefaultValue(false)]
public bool ViewAsText
{
get{return viewAsText;}
set{viewAsText = value;}
}
}
}
//The designers
using System;
using System.IO;
using System.Xml;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.Web.UI.Design.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Caching;
using System.ComponentModel;
using System.Globalization;
using System.Configuration;
using System.ComponentModel.Design;
using System.Collections;
using System.Reflection;
using System.Diagnostics;
using System.Threading;
using System.Text;
using UITemplates;
using mshtml;
[assembly:TagPrefix("AndrewSeven.Samples", "UITemplates")]
//using System.Windows.Forms;
namespace AndrewSeven.Samples.Design
{
public class CustomLabelDesigner : LabelDesigner
{
DesignerVerb viewAsTextVerb ;
DesignerVerb viewNormalVerb ;
CustomLabel _targetControl;
public CustomLabelDesigner():base()
{
BuildVerbs();
}
private void BuildVerbs()
{
viewAsTextVerb = new DesignerVerb("View as Text" ,new EventHandler(this.OnViewAsText));
viewNormalVerb = new DesignerVerb("View Normal" ,new EventHandler(this.OnViewNormal));
Verbs.Add(viewAsTextVerb);
Verbs.Add(viewNormalVerb);
}
private CustomLabel TargetControl
{
get
{
if(_targetControl==null)
{
_targetControl = this.Component as CustomLabel;
}
return _targetControl;
}
}
private void SetViewAsText(bool newValue)
{
if(TargetControl.ViewAsText!=newValue)
{
TargetControl.ViewAsText=newValue;
this.RaiseComponentChanged(null,"","");
}
viewAsTextVerb.Enabled = !newValue;
viewNormalVerb.Enabled = newValue;
}
private void OnViewAsText(object sender, EventArgs e)
{
SetViewAsText(true);
}
private void OnViewNormal(object sender, EventArgs e)
{
SetViewAsText(false);
}
public override string GetDesignTimeHtml()
{
SetViewAsText(TargetControl.ViewAsText);
string baseGetDesignTimeHtml = base.GetDesignTimeHtml();
if( TargetControl.ViewAsText)
{
IHTMLElement copy = ((mshtml.IHTMLElement)this.DesignTimeElement);
string dtHTML = (string)copy.outerHTML;
if(dtHTML ==null)
{
dtHTML = " ";
}
if(dtHTML.Length > 0 && dtHTML.IndexOf("<") > -1)
{
dtHTML = dtHTML.Replace("<","<");
}
return "<table border=1 width='99%'><tr><td><pre>" + dtHTML +"</pre></td></tr></table>";
}
else
{
return baseGetDesignTimeHtml;
}
}
}
public class CustomDropDownListDesigner : ListControlDesigner
{
DesignerVerb viewAsTextVerb ;
DesignerVerb viewNormalVerb ;
CustomDropDownList _targetControl;
public CustomDropDownListDesigner():base()
{
BuildVerbs(false);
}
private void BuildVerbs(bool viewAsTextVisible)
{
viewAsTextVerb = new DesignerVerb("View as Text" ,new EventHandler(this.OnViewAsText));
viewNormalVerb = new DesignerVerb("View Normal" ,new EventHandler(this.OnViewNormal));
Verbs.Add(viewAsTextVerb);
Verbs.Add(viewNormalVerb);
}
private CustomDropDownList TargetControl
{
get
{
if(_targetControl==null)
{
_targetControl = this.Component as CustomDropDownList;
}
return _targetControl;
}
}
private void SetViewAsText(bool newValue)
{
if(TargetControl.ViewAsText!=newValue)
{
TargetControl.ViewAsText=newValue;
this.RaiseComponentChanged(null,"","");
}
viewAsTextVerb.Enabled = !newValue;
viewNormalVerb.Enabled = newValue;
}
private void OnViewAsText(object sender, EventArgs e)
{
SetViewAsText(true);
}
private void OnViewNormal(object sender, EventArgs e)
{
SetViewAsText(false);
}
public override string GetDesignTimeHtml()
{
try
{
SetViewAsText(TargetControl.ViewAsText);
string baseGetDesignTimeHtml = base.GetDesignTimeHtml();
//baseGetDesignTimeHtml will have the rendered select tag with options...
if( TargetControl.ViewAsText)
{
IHTMLElement copy = ((mshtml.IHTMLElement)this.DesignTimeElement);
string dtHTML = (string)copy.innerHTML;
if(dtHTML ==null)
{
dtHTML = " ";
}
if(dtHTML.Length > 0 && dtHTML.IndexOf("<") > -1)
{
dtHTML = dtHTML.Replace("<","<");
}
return "<table border=1 width='99%'><tr><td><pre>" + dtHTML +"</pre></td></tr></table>";
}
else
{
return baseGetDesignTimeHtml;
}
}
catch (Exception ex)
{
return ex.ToString();
}
}
}
}
And an aspx page from my sample
<%@ Register TagPrefix="AndrewSeven" Namespace="AndrewSeven.Samples" Assembly="TemplatedSampleSite" %>
<%@ Page language="c#" Codebehind="DesignTimeHtmlView.aspx.cs" AutoEventWireup="false" Inherits="TemplatedSampleSite.examples.DesignTimeHtmlView" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body>
<form id="DesignTimeHtmlView" method="post" runat="server">
<P>
<hr>
<AndrewSeven:CustomLabel id="DesignViewHtmlControl1s" runat="server">
[HERE ]
<TITLE>Design Time Html Views</TITLE>
<META content="MainTemplate.aspx" name="Template Source">
</AndrewSeven:CustomLabel>
<hr>
<AndrewSeven:CustomDropDownList id="CustomDropDownList1" runat="server" ViewAsText="True">
<asp:ListItem Value="0000000000000">0000000000000</asp:ListItem>
<asp:ListItem Value="111111111111">111111111111</asp:ListItem>
<asp:ListItem Value="2222222222">2222222222</asp:ListItem>
</AndrewSeven:CustomDropDownList>
<hr>
<AndrewSeven:CustomLabel id="Customlabel1" runat="server" Text='<%# "BoundValue" %>' >
</AndrewSeven:CustomLabel>
<HR>
</form>
</body>
</HTML>