Intranet Journal
The online resource for intranet professionals
Developing a Custom Web Part, Part 2
Paul Schaeflein
11/4/2005
This article is the second in a series that discusses developing a custom Web Part. Be sure to read Part 1 before continuing.
In Part 2, we will continue following the Web Part Development Process. The process is repeated here for review:
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. This countdown Web Part will provide a visual cue to an upcoming deadline — a very important task that all project managers strive to perform successfully.
|
Part 1 concluded with the sources of data. In Part 2, I will discuss the forms necessary for user input. Before creating the forms, however, I need to review how to save the data.
Web Part Property Storage
The Web Part framework provides storage of Web Part properties. Properties can be any data type, but the type must be serializable. The Web Part framework will convert the property data to XML and store it with the Web Part page. Web Part properties are added to the Web Part class just like any other properties of any other object. Attributes are then applied to the properties. These attributes are inspected by the Web Part framework and control how the properties are initialized, stored, and displayed.
Private Const _defaultText As String = ""
Dim _text As String = _defaultText
<Browsable(True), Category("Countdown"), DefaultValue(_defaultText), _
WebPartStorage(Storage.Shared), _
FriendlyName("Text"), Description("Text to describe the _
milestone. The text is displayed above the countdown timer.")> _
Property [Text]() As String
Get
Return _text
End Get
Set(ByVal Value As String)
_text = Value
End Set
End Property
The other Web Part properties are created in a similar manner. The image height and width can be specified as integers. I used a string type for the milestone date because it makes the storage (serialization) process much easier. The conversion from/to a date data type can occur during rendering.
Create Form(s) for User Input (if necessary)
The framework also provides for capturing user input and applying that input to Web Part properties. This is accomplished using the Tool Part class. The image below shows the Tool Pane open with the properties of the Site Image Web Part displayed. The Site Image Web Part has a Tool Part titled Image, which is at the top of the Tool Pane. At the bottom of the Tool Pane are buttons that the end-user can use to complete the changes.
Properties of Site Image Web Part.
The Tool Part is displayed in a manner similar to the Web Part — the Tool Part must render its output. At this point, we should prepare a mockup of the Tool Pane output. For the Milestone Countdown Web Part, I am creating two Tool Parts. The image attributes (URL, text, width, height) are optional, so I will separate those attributes into their own Tool Part.
HTML Mockup
I want my Tool Parts to look like the Microsoft-supplied ones. I do not want to confuse the end-users by having two different user interfaces. The easiest way to mimic the Microsoft formatting is to view the HTML source of an existing Tool Part. The HTML for my Image Properties Tool Part:
<DIV class=ms-TPBody>
<DIV class=UserGeneric>
<DIV class=UserSectionHead>Image Link</DIV>
<DIV class=UserSectionBody>
<DIV class=UserControlGroup>
<INPUT class=UserInput style="WIDTH: 175px" ms-TlPnWiden="true">
</DIV>
</DIV>
<DIV class=UserDottedLine style="WIDTH: 100%">>/DIV>
<DIV class=UserSectionHead>Alternate Text for image>/DIV>
<DIV class=UserSectionBody>
<DIV class=UserControlGroup>
<INPUT class=UserInput style="WIDTH: 175px" ms-TlPnWiden="true">
</DIV>
</DIV>
<DIV class=UserDottedLine style="WIDTH: 100%">>/DIV>
<DIV class=UserSectionHead>Image Width>/DIV>
<DIV class=UserSectionBody>
<DIV class=UserControlGroup>
<INPUT class=UserInput style="WIDTH: 50px" >
</DIV>
</DIV>
<DIV class=UserDottedLine style="WIDTH: 100%">>/DIV>
<DIV class=UserSectionHead>Image Height>/DIV>
<DIV class=UserSectionBody>
<DIV class=UserControlGroup>
<INPUT class=UserInput style="WIDTH: 50px">
</DIV>
</DIV>
</DIV>
</DIV>
The overall Tool Part structure can be summarized as follows:
I omitted some attributes from the HTML. The id and name attributes do not affect the display. However, the id attribute is required in the final code. The value will be determined at runtime.
Creating the Tool Part in Code
Using the Web Part templates for Visual Studio (available from MSDN), I added a Tool Part to the project. The template includes stub procedures for each event and method that a Tool Part needs to override.
In the constructor of the Tool Part class, I will set two properties. The Title property will identify this Tool Part as the Image properties, and the FrameState property will make the Tool Part display in minimized mode. Remember, in my Web Part the image properties are optional, so I do not want to clutter the Tool Pane with them.
Sub New() Me.Title = "Milestone Countdown Image" Me.FrameState = FrameState.Minimized End Sub
There are two methods that are used to output the Tool Part: RenderToolPart and CreateChildControls. The RenderToolPart method is passed a HtmlTextWriter object that can be used to write the HTML. My preference is to use the CreateChildControls method to build up the hierarchy of controls. Once the controls are created, they can be told to render themselves.
One more thing to consider — the current value of the properties need to be retrieved from the Web Part. Then the initial value of the input controls can be set as the property values.
Protected Overrides Sub CreateChildControls()
' 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
' Build up the controls
Dim div As HtmlControls.HtmlGenericControl
div = New HtmlControls.HtmlGenericControl("div")
div.Attributes.Add("class", "UserGeneric")
Dim sectionHead, sectionBody, As HtmlControls.HtmlGenericControl
Dim controlGroup, dottedLine As HtmlControls.HtmlGenericControl
'Image Link input
sectionHead = New HtmlControls.HtmlGenericControl("div")
sectionHead.Attributes.Add("class", "UserSectionHead")
sectionHead.InnerText = "Image Link"
div.Controls.Add(sectionHead)
sectionBody = New HtmlControls.HtmlGenericControl("div")
sectionBody.Attributes.Add("class", "UserSectionBody")
controlGroup = New HtmlControls.HtmlGenericControl("div")
controlGroup.Attributes.Add("class", "UserControlGroup")
Dim imageLink As TextBox = New TextBox
imageLink.ID = "imageLink"
imageLink.CssClass = "UserInput"
imageLink.Attributes.Add("style", "WIDTH: 175px;")
imageLink.Attributes.Add("ms-TlPnWiden", "true")
imageLink.Text = _imageLink
controlGroup.Controls.Add(imageLink)
sectionBody.Controls.Add(controlGroup)
div.Controls.Add(sectionBody)
'output the dotted line separator
dottedLine = New HtmlControls.HtmlGenericControl("div")
dottedLine.Attributes.Add("class", "UserDottedLine")
dottedLine.Attributes.Add("style", "WIDTH: 100%")
div.Controls.Add(dottedLine)
' repeat the above for the other properties…
' the height and width property should have a style attribute
' that set the input box width to 50px.
' the toolpart is wrapped in a higher-level div
Dim containerDiv As HtmlControls.HtmlGenericControl
containerDiv = New HtmlControls.HtmlGenericControl("div")
containerDiv.Attributes.Add("class", "ms-TPBody")
containerDiv.ID = "ImageToolPart" + Me.UniqueID.Replace(":", "_")
containerDiv.Controls.Add(div)
Me.Controls.Add(containerDiv)
End Sub
Protected Overrides Sub RenderToolPart(ByVal output As _
System.Web.UI.HtmlTextWriter)
MyBase.EnsureChildControls()
MyBase.RenderToolPart(output)
End Sub
The HTML mock up and rendering code for the other Tool Part follow the same structure. The other Tool Part is used for the main Web Part properties: text, milestone date, and time display depth.
|
When the end-user chooses to modify a Web Part, the framework will call the GetToolParts method of the Web Part class. By overriding this method, I can control the order and appearance of the Tool Parts.
Public Overrides Function _
GetToolParts() As ToolPart()
Dim toolParts(3) As ToolPart
Dim wptp As WebPartToolPart
wptp = New WebPartToolPart
Dim cdtp As MilestoneCountdownTP
cdtp = New MilestoneCountdownTP
cdtp.Title = "Milestone Countdown"
Dim itp As MilestoneCountdownImageTP
itp = New MilestoneCountdownImageTP
itp.Title = _
"Milestone Countdown Image"
itp.FrameState = FrameState.Minimized
toolParts(0) = cdtp
toolParts(1) = itp
toolParts(2) = wptp
Return toolParts
End Function
The GetToolParts method returns an array of ToolParts. The Tool Parts are displayed in the Tool Pane in the same order as they exist in the array. I put the standard countdown properties (text, date, display) first followed by the image properties. The image property Tool Part is initially minimized. The built-in properties (appearance, Layout, Advanced) are at the bottom.
Summary
The next article in the series will cover the steps required show the Tool Parts in the Tool Pane, how to update the Web Part properties from the Tool Parts, as well as performing the actual Web Part rendering.
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/.
Intranet Journal's Tutorials |
|
Managing Editor |