Developing a Custom Web Part, Part 3
Paul Schaeflein
12/5/2005
Printer Friendly Version
This article is the third in series that discusses developing a custom Web Part. Be sure to read Part 1 and Part 2 before continuing.
In Part 3, we will complete the Web Part Development Process. The process is repeated here for review:
- Define requirements
- Create an HTML mockup of the output
- Identify sources of data
- Create form(s) for user input (if necessary)
- Create data access code (if necessary)
- Create output code
Milestone Countdown Web Part, Continued
Our custom Web Part project is to develop a part that outputs a countdown timer to a project milestone, or some other event. Part 1 concluded with the sources of data. Part 2 concluded with the user input forms. In Part 3, I will discuss how to save the data entered on the form and then how to render the output of the Web Part.
Create Data Access Code (If Necessary)
Our Milestone Countdown Web Part has very minimal data requirements. All of the data required for our part is entered in the Tool Pane using our custom Tool Parts. In the previous article I showed how to create the hierarchy of controls in the Tool Part. At the beginning of the CreateChildControls method, the Tool Part retrieves the data from the Web Part storage.
The Tool Part class has a property named ParentToolPane that contains a reference to the Tool Pane that contains the Tool Part. The Tool Pane in turn has a property named SelectedWebPart that contains a reference to the Web Part being edited. Once we have the reference to the Web Part, we can access its properties. In my Tool Part code, I copy the property values to local variables for processing.
' Retrieve the current values from the web part
Dim wp As MilestoneCountdownWP
wp = CType(Me.ParentToolPane.SelectedWebPart, MilestoneCountdownWP)
_imageLink = wp.ImageLink
_altText = wp.AlternateText
_imageWidth = wp.ImageWidth
_imageHeight = wp.ImageHeight
Conversely, when the Tool Pane is submitted, the values need to be stored in the Web Part properties. The Web Part framework will call a method in the Tool Part named ApplyChanges. In this method, we need to store the values entered by the user using the same technique.
ASP.NET Web forms use a hierarchical naming convention for controls (text boxes, buttons, etc.). Inside SharePoint, this hierarchy can be several layers deep. In addition, the controls that we are creating in our CreateChildControls method are associated with a Web Part — and the Web Part gets an ID assigned to it by the framework. When the ApplyChanges method is called, we do not know all of the information necessary to access the Request.Form object.
Fortunately, the ASP.Net framework has a solution to this problem. Since the ToolPart class derives from Web.UI.Control, it contains a method named FindControl that will return the control with a specific name. In the CreateChildControls method, all of the input controls were assigned an ID. Using this ID, we can retrieve the control (and its value) in the ApplyChanges method.
Public Overrides Sub ApplyChanges()
' pull the values from the form
Dim input As TextBox
input = CType(Me.FindControl("imageLink"), TextBox)
_imageLink = input.Text
input = CType(Me.FindControl("alternateText"), TextBox)
_altText = input.Text
input = CType(Me.FindControl("imageWidth"), TextBox)
If input.Text = "" Then
_imageWidth = -1
Else
_imageWidth = Integer.Parse(input.Text)
End If
input = CType(Me.FindControl("imageHeight"), TextBox)
If input.Text = "" Then
_imageHeight = -1
Else
_imageHeight = Integer.Parse(input.Text)
End If
' Put the new values in the web part
Dim wp As MilestoneCountdownWP
wp = CType(Me.ParentToolPane.SelectedWebPart, MilestoneCountdownWP)
wp.ImageLink = _imageLink
wp.AlternateText = _altText
wp.ImageWidth = _imageWidth
wp.ImageHeight = _imageHeight
End Sub
Create Output Code
We are now ready to create the code to output the Web Part. I use the same technique as in the Tool Part: CreateChildControls. The mock up of the output from Part 1 shows how the image and text should be arranged. However, there is still the matter of the actual countdown clock.
To render the countdown, I am going to borrow a technique from an article written back in March. In that article, I used client-side script to format the current date and output it inside a DIV tag. Client-side script is the best choice for the countdown because the client-side script environment provides a timer. The last requirement from Part 1 states that the countdown timer has to display down to the second. Having the page connect to the server every second to update the display is not a good idea.
Accordingly, I need to update my mockup. In this revision, I am not including the HTML, HEAD and BODY tags, since they are not required inside a Web Part. The SCRIPT tag will be generated in the CreateChildControls method, where I can insert the milestone date and display depth properties.
<P align="center">
<img alt="New building" src="/images/building.jpg"
width="100" height="150">
</P>
<H3 align="center">Move to new building<BR>
<SPAN id="countdownClock_WPQ_">CLOCK DISPLAYS HERE</SPAN></H3>
<script language="Javascript">
updateCountdown("[id of element to update]","[milestone date]", _
"[display depth]");
</script>
There is another noteworthy item in the above HTML. The tag that will contain the clock has an ID with a token (_WPQ_) appended to it. The Web Part framework has several of these tokens that are used when the same client-side script may be output multiple times. By using this token, and a related line of code, I can put the Web Part on the page multiple times, each with a different milestone date.
The CreateChildControls method:
Protected Overrides Sub RenderWebPart(ByVal output As _
System.Web.UI.HtmlTextWriter)
MyBase.EnsureChildControls()
MyBase.RenderWebPart(output)
End Sub
Protected Overrides Sub CreateChildControls()
If Me.ImageLink <> "" Then
Dim p As HtmlControls.HtmlGenericControl
p = New HtmlControls.HtmlGenericControl("P")
p.Attributes.Add("align", "center")
Dim i As HtmlControls.HtmlImage = New HtmlControls.HtmlImage
i.Src = Me.ImageLink
i.Alt = Me.AlternateText
If Me.ImageHeight <> -1 Then i.Height = Me.ImageHeight
If Me.ImageWidth <> -1 Then i.Width = Me.ImageWidth
p.Controls.Add(i)
Controls.Add(p)
End If
Dim t As HtmlControls.HtmlGenericControl
t = New HtmlControls.HtmlGenericControl("H3")
t.Attributes.Add("align", "center")
t.InnerHtml = Me.Text
Controls.Add(t)
Dim s As HtmlControls.HtmlGenericControl
s = New HtmlControls.HtmlGenericControl("script")
s.Attributes.Add("language", "javascript")
Dim milestone As Date = Date.Parse(Me.MilestoneDate)
s.InnerText = String.Format("updateCountdown('{0}', '{1}', '{2}');", _
clientID, milestone.ToString("r"), Me.DisplayDepth)
Controls.Add(s)
End Sub
The updateCountdown function is a client-side javascript routine that will calculate the time remaining until the milestone and formats it based on the timer depth property. This javascript is output to the web page using the standard ASP.NET method named RegisterClientScriptBlock. This can be seen in the full download.
Web Part Download
The complete source code and a CAB file for deployment can be found on my Web log at http://www.schaeflein.net/blog/2005/11/29/MilestoneCountdownWebPart.aspx. Please post questions and comments about the web part on the Intranet Journal Discussion Forum.
Deploy the Web Part
Once the Web Part has been completely developed, it needs to be deployed to the SharePoint server. There are many different ways to deploy a Web Part, and the procedure differs based on the desired availability of the Web Part. A future article will discuss these options. The download for this article contains a CAB file for deployment using STSADM.
Summary
This three-part article on provides a proven process to create SharePoint Web Parts. While there are many other articles that cover Web Part development, I believe that developers can learn something from each different article or approach. I encourage your feedback and questions on the Intranet Journal Discussion Board.
About this series
This series of articles on SharePoint is intended to help you understand the capabilities of the product, as well as provide tips and tricks, development ideas, information from Microsoft, information from the community, and perhaps some samples. Like many other series on IntranetJournal.com, I plan to include how-to articles that can help you with your deployments — ways to customize a page; deployment scenarios; content management; etc. With such a diverse product, there is no lack of topics for this series of articles. What would you like to read?
About the author
Paul Schaeflein is a developer with more than 20 years experience. Paul has been developing dynamic and interactive Web sites since 1996. Paul has worked on all of the versions of SharePoint and has worked with the .NET framework since its debut. You can reach Paul through his blog at http://www.schaeflein.net/blog/.
Printer Friendly Version