Your message has been sent.
This article has been saved to your account.
Go to my account
This article has been emailed to your Kindle.
Send this article
Complete the form below to send this article, Adding Web Controls to Custom Modules in DotNetNuke, to a friend (or to yourself). We will never share your details (or your friend's) with anyone. For more information, read our Privacy Policy.
In the previous article, Web Controls in DotNetNuke, we took a look at the Web Controls in DotNetNuke.
In this article by John K. Murphy, author of DotNetNuke 5.4 Cookbook, we will cover the following topics:
- Showing data in a Treeview
- Using a Tabstrip to separate content
- Using a CAPTCHA control for security
- Creating a multi-state checkbox
DotNetNuke 5.4 Cookbook
(For more resources on DotNetNuke, see here.)
Showing data in a Treeview
A Treeview control is used when you have information arranged in a hierarchy like the organizational chart of a company. The Treeview control will show each level in the hierarchy with an icon to drill-down or expand to the next level.
Getting ready
To follow along with this recipe you must have completed the following recipes:
- Deploying a module as a standalone package
- Displaying a Datagrid with filter controls
- Adding web controls to your Toolbox
The Treeview control requires that the employees in the Employee table have been assigned to managers. Here is the data that was used in this recipe:

In this example, the employees are arranged in a simple two-level hierarchy. If your ManagerNo is 0 it means you are a manager. Otherwise the manager number on your record is the ItemID of your manager. So John Smith is a manager (his ManagerNo=0) and he manages Kevin Jones and Amy Roe (as their ManagerNo is John Smith's ItemID).
How to do it...
- Launch the Development Tool and load the Employee project.
- In the Solution Explorer, look under the references and make sure your project includes a reference to DotNetNuke.WebUtility.dll.
- Double-click to open the ViewEmployee.ascx file.
- Start by adding a new register directive at the top of the file:
<%@ Register tagprefix="DNN" assembly="DotNetNuke.WebControls"
namespace="DotNetNuke.UI.WebControls" %> - Next, we'll create a simple tree control by placing the following code at the bottom of the file, right after the paging control:
<dnn:PagingControl ID="ctlPagingControl" runat="server">
</dnn:PagingControl>
<br />
<DNN:DnnTree ID="treeManager" runat="server"
CollapsedNodeImage="~\images\plus.gif"
ExpandedNodeImage="~\images\minus.gif">
</DNN:DnnTree> - Next, open the ViewEmployee.ascx.vb file.
- Look at the top of the file and make sure the following imports are there:
Imports System.Data.SqlClient
Imports DotNetNuke.UI.WebControls - We must create a procedure to populate the tree control with records from the database. Find the Private Methods region at the top of the file and add the following new procedures:
#Region "Private Methods"
Private Sub PopulateTreeControl()
' set the images to use for the nodes
treeManager.ImageList.Add("..\images\icon_hostusers_16px.gif")
treeManager.ImageList.Add("..\images\icon_users_16px.gif")
' reset the tree control
treeManager.TreeNodes.Clear()
Dim objParentNode As TreeNode
' get the list of all managers and create a parent node for each
one
Dim objEmployeeController As New EmployeeController
Dim drMgr As SqlDataReader
drMgr = objEmployeeController.GetManagersDR(ModuleId)
If drMgr.HasRows Then
Do While drMgr.Read()
objParentNode = New TreeNode()
objParentNode.Text = drMgr("EmpLastName") + ", " +
drMgr("EmpFirstName")
objParentNode.ImageIndex = 0 ' manager image
objParentNode.ClickAction = eClickAction.Expand ' when click
on a manager, expand
objParentNode.HasNodes = True
treeManager.TreeNodes.Add(objParentNode)
PopulateEmployeeNodes(objParentNode, drMgr("ItemId"))
Loop
End If
drMgr.Close()
End Sub
Private Sub PopulateEmployeeNodes(ByRef objParentNode As TreeNode,
ByVal ParentItemId As Integer)
Dim objChildNode As TreeNode
' get the list of all employee with the given manager
Dim objEmployeeController As New EmployeeController
Dim colEmployees As ArrayList
Dim objEmployeeInfo As EmployeeInfo
Dim TotalRecords As Integer
colEmployees = objEmployeeController.GetEmployeesByFilter
(ModuleId, ParentItemId, -1, 0, 1000, TotalRecords)
If colEmployees.Count > 0 Then
' add a node to the parent that was passed
For intEmp = 0 To colEmployees.Count - 1
objEmployeeInfo = CType(colEmployees(intEmp), EmployeeInfo)
objChildNode = New TreeNode(objEmployeeInfo.EmpLastName + ", "
+ objEmployeeInfo.EmpFirstName)
objChildNode.ImageIndex = 1 ' employee image
objParentNode.TreeNodes.Add(objChildNode)
Next intEmp
End If
End Sub
#End Region - What we are doing here is calling a new GetManagersDR function for the first level of the tree, then calling the GetEmployeesByFilter function to get the list of employees for each manager.
- Next, we need to call these new procedures when the page loads, so scroll down to the Page_Load procedure and add the following code inside the IsPostBack check:
If Page.IsPostBack = False Then
If Not Request.QueryString("PageRecords") Is Nothing Then
ddlRecordsPerPage.SelectedValue =
Request.QueryString("PageRecords")
End If
BindManagerDropDown()
BindSalaryDropDown()
BindData()
PopulateTreeControl()
End If - Next, open the EmployeeController.vb file.
- The last step is to create the new GetManagersDR function. This is just like the GetManagers function, but this the function returns the list of managers as a DataReader. Add the following code to the bottom of the Public Methods region:
Public Function GetManagersDR(ByVal ModuleId As Integer) As
SqlDataReader
Return DataProvider.Instance().GetManagers(ModuleId)
End Function
#End Region - Select Save All from the File menu.
- To check the results, build and deploy the module to a development portal for testing.
- Go to the ACME Employee page to see the list of employees in a tree control.

How it works...
In this recipe we saw the tasks to organize database records in a hierarchy tree control:
- We placed the control in the .ascx file
- We defined the images to use for the expand and collapse indicators
- In the code behind file we changed the Page_Load procedure to populate the tree
- We created a PopulateTreeControl procedure with two parts:
- Query the database for the employee managers
- For each manager add them to the tree and query the database for the employees they manage
Using a TabStrip to separate content
There are many times when you have a lot of information to display, but not enough space on the page. The TabStrip control maximizes the available space by separating the content into tabs and displaying one tab at a time.
To demonstrate this control we're going to take the five fields of the Edit Employee page and split them onto two different tabs.
Getting ready
To follow along with this recipe you must have completed the following recipes:
- Adding web controls to your Toolbox
- Deploying a module as a standalone package
How to do it...
- Launch the Development Tool and load the Employee project.
- In the Solution Explorer, look under the references and make sure your project includes a reference to DotNetNuke.WebUtility.dll.
- Double-click to open the EditEmployee.ascx file.
- Make sure the following register directive is at the top of the file:
<%@ Register tagprefix="DNN" assembly="DotNetNuke.WebControls"
namespace="DotNetNuke.UI.WebControls" %> - We will replace the existing HTML table containing the employee fields with a TabStrip control table holding the name fields under the first tab and the information fields under the second tab. Replace the existing HTML table with the following highlighted code:
<%@ Control language="vb" Inherits="ACME.Modules.Employee.EditEmployee" AutoEventWireup="false
Explicit="True" Codebehind="EditEmployee.ascx.vb" %>
<%@ Register TagPrefix="dnn" TagName="Label"
Src="~/controls/LabelControl.ascx" %>
<%@ Register TagPrefix="dnn" TagName="TextEditor"
Src="~/controls/TextEditor.ascx"%>
<%@ Register TagPrefix="dnn" TagName="Audit"
Src="~/controls/ModuleAuditControl.ascx" %>
<%@ Register tagprefix="DNN" assembly="DotNetNuke.WebControls"
namespace="DotNetNuke.UI.WebControls" %>
<DNN:DNNTabStrip
ID="tsEmployee"
runat="server"
TabRenderMode="All"
CssTabContainer="LoginTabGroup"
CssContentContainer="LoginContainerGroup"
DefaultContainerCssClass="LoginContainer"
DefaultLabel-CssClass="LoginTab"
DefaultLabel-CssClassHover="LoginTabHover"
DefaultLabel-CssClassSelected="LoginTabSelected"
visible="true" >
<dnn:DNNTab Label-Text="Employee Name" ID="tab1">
<table width="650" cellspacing="0" cellpadding="0" border="0"
summary="Edit Table">
<tr valign="top">
<td class="SubHead" width="125"><dnn:label
id="lblEmpFirstName" runat="server"
controlname="lblEmpFirstName" suffix=":">
</dnn:label>
</td>
<td>
<asp:TextBox ID="txtEmpFirstName" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="valEmpFirstName"
resourcekey="valEmpFirstName.ErrorMessage"
ControlToValidate="txtEmpFirstName"
CssClass="NormalRed" Display="Dynamic"
ErrorMessage="<br>EmpFirstName is required"
Runat="server" />
</td>
</tr>
<tr valign="top">
<td class="SubHead" width="125"><dnn:label
id="lblEmpLastName" runat="server"
controlname="lblEmpLastName" suffix=":">
</dnn:label>
</td>
<td>
<asp:TextBox ID="txtEmpLastName" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="valEmpLastName"
resourcekey="valEmpLastName.ErrorMessage"
ControlToValidate="txtEmpLastName"
CssClass="NormalRed" Display="Dynamic"
ErrorMessage="<br>EmpLastName is required"
Runat="server" />
</td>
</tr>
</table>
</dnn:DNNTab>
<dnn:DNNTab Label-Text="Information" ID="tab2">
<table width="650" cellspacing="0" cellpadding="0" border="0"
summary="Edit Table">
<tr valign="top">
<td class="SubHead" width="125"><dnn:label
id="lblManagerNo" runat="server"
controlname="lblManagerNo" suffix=":">
</dnn:label>
</td>
<td>
<asp:TextBox ID="txtManagerNo" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="valManagerNo"
resourcekey="valManagerNo.ErrorMessage"
ControlToValidate="txtManagerNo"
CssClass="NormalRed" Display="Dynamic"
ErrorMessage="<br>ManagerNo is required"
Runat="server" />
</td>
</tr>
<tr valign="top">
<td class="SubHead" width="125"><dnn:label
id="lblHireDate" runat="server"
controlname="lblHireDate" suffix=":">
</dnn:label>
</td>
<td>
<asp:TextBox ID="txtHireDate" runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator ID="valHireDate"
resourcekey="valHireDate.ErrorMessage"
ControlToValidate="txtHireDate"
CssClass="NormalRed" Display="Dynamic"
ErrorMessage="<br>HireDate is required"
Runat="server" />
</td>
</tr>
<tr valign="top">
<td class="SubHead" width="125"><dnn:label id="lblSalary"
runat="server" controlname="lblSalary" suffix=":">
</dnn:label>
</td>
<td>
<asp:TextBox ID="txtSalary" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="valSalary"
resourcekey="valSalary.ErrorMessage"
ControlToValidate="txtSalary"
CssClass="NormalRed" Display="Dynamic"
ErrorMessage="<br>Salary is required" Runat="server" />
</td>
</tr>
</table>
</dnn:DNNTab>
</dnn:DNNTabStrip>
<br /><br />
<p>
<asp:linkbutton cssclass="CommandButton" id="cmdUpdate"
resourcekey="cmdUpdate" runat="server"
borderstyle="none" text="Update">
</asp:linkbutton>
<asp:linkbutton cssclass="CommandButton" id="cmdCancel"
resourcekey="cmdCancel" runat="server"
borderstyle="none" text="Cancel"
causesvalidation="False">
</asp:linkbutton>
<asp:linkbutton cssclass="CommandButton" id="cmdDelete"
resourcekey="cmdDelete" runat="server"
borderstyle="none" text="Delete"
causesvalidation="False">
</asp:linkbutton>
</p>
<dnn:audit id="ctlAudit" runat="server" /> - Select Save All from the File menu.
- To check the results, build and deploy the module to a development portal for testing.
- Go to the ACME Employee page and click on the edit icon (the little pencil) next to an employee to display the Edit Employee page.
- When you edit the employee record you will see the fields have been separated into two separate tabs. Clicking on Employee Name displays the first tab with the name fields:

- Clicking on Information reveals the remaining fields:

The appearance of the tab strip is controlled by the styles we apply to it (CssTabContainer, CssContentContainer, DefaultLabel-CssClass, DefaultLabel-CssClassHover, and DefaultLabel-CssClassSelected). In this example we used the same styles as the DNN Login page so we have a similar look and feel. The styles are defined in the /portals/_default/default.css by default.
How it works...
In this recipe we saw the tasks to use a TabStrip control:
- We placed the control in the .ascx file
- We separated the existing content onto separate tabs
(For more resources on DotNetNuke, see here.)
Using a CAPTCHA control for security
CAPTCHA is a technique for detecting when a real person is typing at the keyboard. It works by presenting a word or phrase in an image that has been scrambled enough that a computer cannot read it but a person can.
Older DNN versions had bugs in the CAPTCHA control. To follow along with this recipe you should make sure your DNN version is 5.1 or later.
In this recipe we will show how to add a CAPTCHA control to a data entry form that will block automated processes from updating a record.
CAPTCHA is an acronym that stands for "Completely Automated Public Turing test to tell Computers and Humans Apart". You can learn more about CAPTCHA at http://www.captcha.net.
Getting ready
To follow along with this recipe you must have completed the following recipes:
- Adding web controls to your Toolbox
- Deploying a module as a standalone package
How to do it...
- Launch the Development Tool and load the Employee project.
- In the Solution Explorer, look under the references and make sure your project includes a reference to DotNetNuke.WebUtility.dll.
- Double-click to open the EditEmployee.ascx file.
- Make sure the following register directive is at the top of the file:
<%@ Register tagprefix="DNN" assembly="DotNetNuke.WebControls"
namespace="DotNetNuke.UI.WebControls" %> - Scroll down to the bottom of the file and note where the table holding the edit controls ends and the links to save, cancel, or delete are shown:
</table>
<p>
<asp:linkbutton cssclass="CommandButton" id="cmdUpdate"
resourcekey="cmdUpdate" runat="server"
borderstyle="none" text="Update">
</asp:linkbutton>
<asp:linkbutton cssclass="CommandButton" id="cmdCancel"
resourcekey="cmdCancel" runat="server"
borderstyle="none" text="Cancel"
causesvalidation="False">
</asp:linkbutton>
<asp:linkbutton cssclass="CommandButton" id="cmdDelete"
resourcekey="cmdDelete" runat="server"
borderstyle="none" text="Delete"
causesvalidation="False">
</asp:linkbutton>
</p> - Put the following code just after the HTML table and before the links:
</table>
<p>
<dnn:CaptchaControl ID="btnCaptcha" CaptchaHeight="40"
CaptchaWidth="150"
ErrorStyle-CssClass="NormalRed" cssclass="Normal" runat="server"
resourcekey="Captcha"
ErrorMessage="The typed code is case sensitive, must match the
image and cannot be left blank. Please try again./>
</p>
<p>
<asp:linkbutton cssclass="CommandButton" id="cmdUpdate"
resourcekey="cmdUpdate" runat="server"
borderstyle="none" text="Update">
</asp:linkbutton>
<asp:linkbutton cssclass="CommandButton" id="cmdCancel"
resourcekey="cmdCancel" runat="server"
borderstyle="none" text="Cancel"
causesvalidation="False">
</asp:linkbutton>
<asp:linkbutton cssclass="CommandButton" id="cmdDelete"
resourcekey="cmdDelete" runat="server"
borderstyle="none" text="Delete"
causesvalidation="False">
</asp:linkbutton>
</p> - Next, open the EditEmployee.ascx.vb file.
- As the CAPTCHA control validates before allowing changes, we need to modify the update process to check if the CAPTCHA value has been given before performing the update. Scroll down to the cmdUpdate_Click procedure.
- At the top of the procedure add the first part of an IF statement: and place the rest at the bottom of the procedure. The entire procedure should now look like this:
Private Sub cmdUpdate_Click(ByVal sender As Object,
ByVal e As EventArgs) Handles cmdUpdate.Click
Try
If btnCaptcha.IsValid Then
Dim objEmployees As New EmployeeController
Dim objEmployee As EmployeeInfo = New
EmployeeInfo
objEmployee.ModuleId = ModuleId
objEmployee.ItemId = ItemId
objEmployee.EmpFirstName = txtEmpFirstName.Text
objEmployee.EmpLastName = txtEmpLastName.Text
objEmployee.ManagerNo = txtManagerNo.Text
objEmployee.HireDate = txtHireDate.Text
objEmployee.Salary = txtSalary.Text
objEmployee.CreatedByUser = Me.UserId
If Common.Utilities.Null.IsNull(ItemId) Then
' add the content within the Employee table
objEmployees.AddEmployee(objEmployee)
Else
' update the content within the Employee
table
objEmployees.UpdateEmployee(objEmployee)
End If
' Redirect back to the portal home page
Response.Redirect(NavigateURL(), True)
End If
Catch exc As Exception 'Module failed to load
ProcessModuleLoadException(Me, exc)
End Try
End Sub - Select Save All from the File menu.
- To check the results, build and deploy the module to a development portal for testing.
- Go to the ACME Employee page and click on the edit icon (the little pencil) next to an employee to display the Edit Employee page. At the bottom of the page the CAPTCHA control will appear.

- When you click on the Update link to save any changes to the record it will check that you have filled in the correct CAPTCHA value. If the value doesn't match the image an error message is displayed and the record is not saved.
How it works...
In this recipe we saw the tasks to use a CAPTCHA control:
- We placed the control in the .ascx file and set the properties
- We modified the normal update procedure to check the CAPTCHA control and only save if the correct value was entered
See also
Other control properties you can set:
| Property | Meaning |
| CaptchaChars | The set of characters that could be used to create the CAPTCHA. |
| CaptchaHeight | The height of the CAPTCHA image. |
| CaptchaLength | Total maximum number of characters to use in the CAPTCHA. |
| CaptchaWidth | The width of the CAPTCHA image. |
| CssClass | The CSS class for the control. |
| Text | The prompt Text that is used. |
Creating a multi-state checkbox
A checkbox control normally has two possible values (or states): checked and unchecked. The DNN Multi-State checkbox control is used in situations when you want to show a visual indicator for the state of the control but you need more then checked and unchecked.
You can see an example of this with the DNN page security where you grant, deny, or ignore access to a DNN page:

In this recipe we will add a four-state checkbox to the Edit Employee page representing the Bonus Level of the employee (None, Small, Medium, and Large) represented by color-coded star icons.
Getting ready
To follow along with this recipe you must have completed the following recipes:
- Adding web controls to your Toolbox
- Deploying a module as a standalone package
How to do it...
- Launch the Development Tool and load the Employee project.
- In the Solution Explorer, look under the references and make sure your project includes a reference to DotNetNuke.WebUtility.dll.
- Double-click to open the EditEmployee.ascx file.
- Make sure the following register directive is at the top of the file:
<%@ Register tagprefix="DNN" assembly="DotNetNuke.WebControls"
namespace="DotNetNuke.UI.WebControls" %> - Scroll down to the bottom of the file and locate the table holding the edit controls. Add a new table row by inserting the following code:
<tr valign="top">
<td class="SubHead" width="125"><dnn:label id="lblSalary"
runat="server" controlname="lblSalary" suffix=":">
</dnn:label>
</td>
<td>
<asp:TextBox ID="txtSalary" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="valSalary"
resourcekey="valSalary.ErrorMessage"
ControlToValidate="txtSalary"
CssClass="NormalRed" Display="Dynamic" ErrorMessage=
"<br>Salary is required" Runat="server" />
</td>
<tr valign="top">
<td class="SubHead" width="125"><dnn:label id="lblBonus"
runat="server" controlname="msbBonus" suffix=":">
</dnn:label>
</td>
<td>
<dnn:DNNMultiStateBox ID="msbBonus" runat="server"
ImagePath="~/images/">
<States>
<dnn:DNNMultiState Key="1" ImageUrl="unchecked.gif"
DisabledImageUrl="lock.gif" />
<dnn:DNNMultiState Key="2" ImageUrl="ratingminus.gif"
DisabledImageUrl=”lock.gif" />
<dnn:DNNMultiState Key="3" ImageUrl="ratingzero.gif"
DisabledImageUrl="lock.gif" />
<dnn:DNNMultiState Key="4" ImageUrl="ratingplus.gif"
DisabledImageUrl="lock.gif" />
</States>
</dnn:DNNMultiStateBox>
</td>
</tr>
</table> - Next, open the EditEmployee.ascx.vb file.
- Check the top of the file and make sure it has the following imports:
Imports DotNetNuke.UI.WebControls
- To set the checkbox when the employee information is displayed, scroll down to the Page_Load procedure and add the following code after the existing set values code:
txtHireDate.Text = objEmployee.HireDate
txtSalary.Text = objEmployee.Salary
msbBonus.SelectedStateKey = objEmployee.BonusLevel - Next, scroll down a little more to the cmdUpdate_Click procedure and add the following line of code:
objEmployee.HireDate = txtHireDate.Text
objEmployee.Salary = txtSalary.Text
objEmployee.BonusLevel = msbBonus.SelectedState.Key
objEmployee.CreatedByUser = Me.UserId
If Common.Utilities.Null.IsNull(ItemId) Then - Lastly, we need to create a new property that will convert the salary of the employee to a bonus level. Open the EmployeeInfo.vb file and add the following code:
' public properties
Public Property BonusLevel() As Integer
Get
' use integer division to get 0,1,2,3...
Return (_Salary \ 30000)
End Get
Set(ByVal Value As Integer)
_Salary = Value * 30000
End Set
End Property - As we included a new label control with our new multi-state checkbox, open the ViewEmployee.ascx.resx file (under /App_LocalResources) and set the label text and Help prompt:
lblBonus.Text: Bonus Level
lblBonus.Help: Click on the icon to set the salary bonus level.

- Select Save All from the File menu.
- To check the results, build and deploy the module to a development portal for testing.
- Go to the ACME Employee page and click on the edit icon (the little pencil) next to an employee to display the Edit Employee page. The Bonus Level will appear at the bottom.

- Clicking on the Bonus Level star icon will change the bonus level which will raise or lower the salary when you update the employee record.
How it works...
In this recipe we saw the tasks to use a multi-state checkbox:
- We placed the control in the .ascx file and defined how many states it has
- For each state we picked an image
- On the page load we set the current state
- When a record was updated we saved the state to the database
There's more...
In this example we used existing images from the DNN site, but you are free to upload and use custom images as well.
See also
Other control properties you can set:
| Property | Meaning |
| ImagePath | The path on the server to the folder containing the images for the different checkbox states. |
| ImageUrl | The name of the image file to display for the state. |
| Text | A text message to display next to image. |
| ToolTip | A message displayed when you hover over the image. |
Summary
In this article we took a look at the following recipes:
- Showing data in a Treeview
- Using a Tabstrip to separate content
- Using a CAPTCHA control for security
- Creating a multi-state checkbox
Further resources on this subject:
- Creating a Simple Skin using DotNetNuke [Article]
- Deploying and Exploring Skin Objects using DotNetNuke [Article]
- Creating and Styling Container Images using DotNetNuke [Article]
- Web Controls in DotNetNuke [Article]
About the Author :
John K Murphy
John K Murphy is a software industry veteran with more than 25 years experience as a programmer and database administrator. A graduate of the University of West Virginia he began writing computer games in the 1980's before pursuing a career as a computer consultant. Over the years, John has enjoyed developing software in most major programming languages while striving to keep current with new technologies.
In his spare time, John enjoys scuba diving, skydiving and piloting small planes. He lives with his wife and two children in Pittsburgh, Pennsylvania.



Post new comment