One of the biggest advantages of ASP.NET Server Controls is that you can package a lot of functionality into a Server Control and reuse it in the UI layer. The .NET Framework ships with a wide range of .NET Server Controls that come in handy for almost everything that you usually do in a typical Web implementation scenario. In this article we're going to build a text box Server Control that works like a Word document and can be used to format the text without knowing any HTML! This is very useful because this Server Control will simplify life when you need to publish well-formatted content! As you would imagine, this does a lot of things with client-side technologies such as JavaScript and DHTML, so I assume you have an in-depth knowledge of DHTML and .NET Server Controls.
With this background, let's take a look at how to build a Rich Text Editor .NET Server Control that can be used to publish rich content. The language I'm using is VB.NET.
Rich Text Editor Design
As I mentioned earlier, my aim is to design a Rich Text Editor Server Control. To achieve this functionality, here is what we need to incorporate in a Server Control:
- Ability to edit/enter the content (could be plain text or some rich content)
- Ability to format the content
- Ability to extract the HTML from the rich content
At the end, when it is used on a Web Form (ASPX page), the Server Control should look like Figure 1.
Now the goal is clear. Before we jump into the VB.NET coding specifics for the Server Control, here is how we will achieve these design requirements.
1. Ability to Edit/Enter the Content
We are going to use the iFrame element from DHTML to enable the control's users to edit the rich text. An iFrame element creates inline-floating frames within an HTML document. But the cool thing about iFrames is that you can programmatically set the HTML Document contained in the iFrame element to design mode, which means you can edit the HTML document sitting inside the iFrame element! This will enable the user to edit and enter the "rich" content. I know that you might be thinking: "Okay, if this is going to use the DHTML iFrame element, then does this control work for Netscape browsers and IE browsers with versions earlier than 5.0?". You are correct; this server control does not work for the browsers mentioned above. So we need to provide a mechanism to decide the browser version when the control is loaded and then decide whether or not to render the control. We will see how to handle this problem later on in this article.
2. Ability to Format the Content
Content formatting is also implemented easily using DHTML and JavaScript on the client side. The rich formatting can be done by calling the execCommand function on the inner HTML document of the iFrame element contained in the Server Control. For example, if you select some content in the Rich Text Editor and you want to make it look bold, the command to do that would be:
varIframe.document.execCommand
('bold');
Of course, you can also use CTRL + B to achieve the same result.
3. Ability to Extract the HTML from the Rich Content
Finally, you need to extract the HTML from the Rich Text Document contained in the iFrame element so that you can process it according to your needs. For example, if you're publishing content, you might want to save the HTML of the rich formatted content in a database so that you can display it later. Since there is no direct mapping between a .NET Web Control type and an iFrame element, you cannot really extract the HTML from the iFrame element on the server side, so you have to do it on client side. Here's how to implement it:
1. Declare a hidden field (of type input) in the Rich Editor Server Control along with the iFrame element.
2. Add "OnBlur" event to the iFrame element so that you can copy the iFrame inner HTML document's HTML to the hidden field that you have declared in the above step.
3. Now, since the HTML string is available in the hidden field, you can access it on the server side (in the Rich Edit Control) to extract the HTML.
With this background, let's dig into some coding specifics.
Developing the Rich Text Editor Server Control
The Server Control is inherited from the System.Web.UI.Control base class and implements InamingContainer and IPostBackDataHandler interfaces. The InamingContainer interface identifies a container control that creates a new ID namespace within a Page object's control hierarchy. This is a marker interface only, which means there are no methods to implement when you implement this interface. The IpostBackDataHandler defines methods that an ASP.NET Server control must implement to automatically load post-back data. We need this interface since we need to extract the HTML string from the Rich Text Formatted content. The definition of our Server Control class will look like this:
Public Class RTFEditor
Inherits System.Web.UI.Control
Implements INamingContainer, IPostBackDataHandler
I'm going to discuss only the most important functions of this class, but you can download it from the support material (the class is named RTFEditor.VB) for a look at the full class (the source code for this article is available below).
This class defines several Public Properties, such as Width, Height, and so on. But the properties that are important in this context are RichHTML and RichText.
The RichHTML property is a ReadOnly Public Property that returns a string - the HTML string for the Rich Formatted Text entered. If you want to extract the HTML string from the rich content that you have entered, this is the property to use. It is defined below:
Public ReadOnly Property RichHtml() As String
Get
Return CType
(ViewState.Item
("_text2html"), String)
End Get
End Property
The RichText property is a Public Property that takes in an HTML string and sets the Rich Text Content to the control. If you want to set some Rich Text to the Server Control to display, this is the property that you should use:
Public Property RichText() As String
Get
Dim text As String = CType(ViewState.Item
("_Html2Text"), _String)
If IsNothing(text) Then
text = String.Empty
End If
Return text
End Get
Set(ByVal Value As String)
ViewState.Item("_Html2Text") = Value
End Set
End Property
Next, you should look at the CreateChildControls. We're going to override this method to provide the child controls that are required for the Rich Text Server Control, such as the buttons that can be used for formatting the text, the iFrame element, and the hidden input element to hold the HTML string. The method implementation is partially shown in Listing 1.
The PrepareLinkControl method actually creates the image buttons and adds the "OnClick" attribute to call executeCommand to format the text.
The next method we'll look at is PrepareBrowserMsgJs. This function checks the browser version to see whether the Rich Text Control will work. The browser details are obtained from the HTTP Request context as shown below:
Dim hbc As New
HttpBrowserCapabilities()
hbc = HttpContext.Current.Request.Browser
Then we need to check for the version of the browser to see if this Rich Text control will work (see Listing 2)
Finally, let's look at the method, LoadPostData, responsible for capturing the HTML that is copied from the iFrame element to the hidden field upon submitting the Web form. The LoadPostData method is one of the methods you have to implement when you implement the interface IpostBackDataHandler. The method's implementation is shown below:
Public Function LoadPostData(ByVal postDataKey As String,
_ ByVal values As NameValueCollection) _
As Boolean Implements
IPostBackDataHandler.LoadPostData
Dim htmlstring As String = values(MyBase.ClientID & "_hidden")
If htmlstring <> String.Empty
Then
ViewState.Add("_text2html",htmlstring)
Return True
End If
Return False
End Function
As you can see, the hidden field is accessed in the control to extract the HTML string. This completes the development of the Rich Text Editor Control. Now let's move to actually using this control in an ASPX page.
Using the Rich Text Editor Control
Using the Rich Text Editor Control is fairly simple. The first step is to register the control on top of the page, as shown below:
<%@ Register TagPrefix="eSynaps" Namespace="RTFEditor"
Assembly ="RTFEditor" %>
And then add the actual control itself:
<eSynaps:RTFEditor id="myeditor" runat="server" height="300"
width="600"></eSynaps:RTFEditor>
To test this, let's add a button to post the form back and a <div> element to display the HTML for the formatted rich content.
<asp:Button ID="mybutton" Runat="server" Text="Get the HTML"
Width="600px"></asp:Button>
. . .
<div id="myhtml" runat="server" width="600">
</div>
Upon formatting some rich text content when you post back the Web Form, the Button Click event will set the HTML to the <div> elements innerHTML property, as shown below:
Private Sub mybutton_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles mybutton.Click
myhtml.InnerHtml = Server.HtmlEncode(myeditor.RichHtml)
End Sub
Figure 2 shows how the Rich Content Editor works. You can see the HTML for the Rich Text that I have formatted in the Rich Text Control displayed in the bottom of the form.
Summary
As you've seen in this article, by combining the DHTML/Java Script and ASP.NET Server controls, you can create some powerful Server Controls. Although this control, works only with IE browsers, it is a good idea to target a variety of browsers in your design. Finally, you can extend this server control by adding more functionality to format the content.
Happy .NET 'ing!
Author Bio
Chandu Thota works as a technical lead for a leading channel management company in Chicago. He is the coauthor of Understanding The .NET Framework and ASP .NET Intranet Programming (WROX) and is also the founder of www.eSynaps.com, an online .NET XML Web services portal.
csthota@att.net
Listing 1
Protected Overrides Sub CreateChildControls()
Dim t As New Table()
Dim tr As New TableRow()
Dim tc As New TableCell()
'Add a table entry with Bold link
tc.Attributes.Add("align", "center")
tc.Width = Unit.Pixel(10)
tc.Attributes.Add("align", "center")
tc.HorizontalAlign = HorizontalAlign.Center
tc.Controls.Add(PrepareLinkControl _
(HttpContext.Current.Server.MapPath
("~/images/circle_b.gif"), _"Bold", "Bold"))
tr.Cells.Add(tc)
. . .
. . .
'Add the IFrame element
Dim hg As New HtmlGenericControl()
hg.TagName = "iframe"
hg.ID = Me.ClientID + "eSynaps_RTE"
hg.Attributes.Add("width", "100%")
hg.Attributes.Add("Height", "100%")
hg.Attributes.Add("OnBlur", String.Concat("PostIt",_
Me.ClientID, "();"))
tc.Controls.Add(hg)
tc.Width = Unit.Percentage(100)
tr.Cells.Add(tc)
t.Rows.Add(tr)
. . .
. . .
Listing 2
If ((hbc.MajorVersion < 5) Or (hbc.Browser <> "IE") Or _
((hbc.Platform <> "Win95" And hbc.Platform <> "Win98" And _
hbc.Platform <> "WinNT"))) Then
'Display a message that this Rich Text Box does not work with this 'Browser
ELSE
'Do the processing to register the JavaScript that we have generated in this control
to copy the IFRame's HTML to the hidden field.
END IF
. . .
All Rights Reserved
Copyright © 2004 SYS-CON Media, Inc.
E-mail:
info@sys-con.com