Every time i got DNN project, this scenario always happened :
You know, every page of DNN consist one or more modules. Deleting 3 or more modules are painful. You have to click in every action menu in every module, and click Delete. After click Delete link, a confirmation window trigger and you have to click OK button again. There are many click you have to do.
It's time to develop custom module to create a short-way. This is the prototype that i have created 4 months ago (yes, it quite long, wasn't it ? :) ) But i believe it will usefull for DNN lovers. :)
First, just create UI like screenshot above. Very simple, only have 4 controls, btnDelete, btnShowModules, listTabs, and gridModules.
What we will cover is :
- How to load DNN menu (or tabs) and bind it in a bindable control
- How to use DNN ClientAPI to inject confirmation window to a button control (or whatever web control you like)
- How to load DNN modules and bind it in a bindable control
- How to delete module
- How to clear DNN site cache
First, make sure you add your namespace reference :
Let's code !
1. Suppose that i have a dropdown list control (eg. listTabs). I will bind DNN tabs into my dropdownlist control using this code :
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim objTabs As New TabController
Dim arTabs As ArrayList = objTabs.GetTabs(PortalSettings.PortalId)
listTabs.Items.Insert(0, New ListItem("--- Select Tabs ---", "0"))
For Each tab As TabInfo In arTabs
If Not (tab.IsAdminTab Or tab.IsSuperTab) Then
If tab.IsVisible Then
Dim item As New ListItem
item.Text = tab.TabName
item.Value = tab.TabID.ToString()
You see a method called IsAdminTab, isSuperTab, and IsVisible. We have to extract tabs first because we do not want Admin and Host module to be deleted, right ? :) So IsAdminTab and IsSuperTab will filter those things. And what is the isVisible ? You know, when you click on Admin --> Pages, you will see Search Result page which is not visible from user perspective, but shown on Pages administration menu. We have to filter it too. Since users can have more than one non-visible menu (even the name is non-visible, but it still can accessed from you DNN framework or your code).
Then I create two methods to wrap LoadTabModules functionality. I will explain each of them.
' This method used to load tab modules based on TabID/menuID. It returns as ArrayList.
Private Function LoadTabModules(ByVal TabID As Integer) As ArrayList
Dim objModules As New ModuleController
Dim arrModules As New ArrayList
For Each kvp As KeyValuePair(Of Integer, ModuleInfo) In objModules.GetTabModules(TabID)
Dim objModule As ModuleInfo = kvp.Value
If PortalSecurity.IsInRoles(objModule.AuthorizedEditRoles) = True And objModule.IsDeleted = False And objModule.AllTabs = False Then
You see that objModules.GetTabModules(TabID) **IS A NEW** method to replace GetModules method. It will return KeyValuePair object, then you put it's value into ModuleInfo object. You have to check it first, does it in AuthorizedEditRoles role ? This should checked because your code have to make sure that only appropriate user can delete/add/edit modules. You also have to check, doest it in IsDeleted state ? You can see the deleted module in Admin --> Recycled Bin. It's no use to show them in your custom module. :) The last it, you have to check doest it in AllTabs mode ? AllTabs means that your module will be visible in ALL PAGES in your site. AllTabs is a little bit complicated since it can has more than one behavior. For example, you can have one module that shown on all pages with the same content AND WITH THE SAME ModuleID (meaning that, your other modules is only references from the original one. Change content from original module content will automatically reflected to others). You also can have on module that shown on all pages with the same content BUT different ModuleID (meaning that you don't have a reference to original module). That's why i said that AllTabs should check first because we have to do different behavior for it.
' This is only private method to show grid modules
Private Sub ShowGridModules()
gridModules.DataSource = LoadTabModules(Integer.Parse(listTabs.SelectedItem.Value))
This is simple method. Just call LoadTabModules with listTabs.SelectedItem.Value as a parameter and bind it to gridModules object.
2. Using ClientAPI to inject delete button (the ID is btnDelete), so i'm using code like this :
Protected Sub btnShowModules_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnShowModules.Click
DotNetNuke.UI.Utilities.ClientAPI.AddButtonConfirm(btnDelete, "Do you want to delete selected item(s) ?")
Please remind that i put ClientAPI.AddButtonConfirm into btnShowModules_Click event. Every time click event fired in this button, it will automatically inject confirmation window into btnDelete control. So whenever you click Delete button, it will show you confirmation button before triggered btnDelete_Click method. Nice ClientAPI ! DNN also has many useful ClientAPI that will help you to work with your project. :)
3, 4, 5 will become one. This code will do the rest :
Protected Sub btnDelete_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDelete.Click
Dim objModules As New ModuleController
For Each item As GridViewRow In gridModules.Rows
Dim chk As CheckBox = CType(item.FindControl("chkSelect"), CheckBox)
If chk.Checked Then
If you see this line --> objModules.DeleteModule(Integer.Parse(item.Cells(1).Text))
Cells with index number 1 is the ModuleID. Look at the screenshot above. I use custom column that bind like this :
1st column --> Template Column, fill with CheckBox web control. Assign it with chkSelect as ID.
2nd column --> Bound Field, fill your Header Text with "ModuleID" and Data Field with "ModuleID"
3rd column --> Bound Field, fill your header text with "Title" and DataField with "ModuleTitle"
4th column --> Bound Field, fill your header text with "ModuleName" and DataField with "FriendlyName"
5th column --> Bound Field, fill your header text with "Pane Name" and DataField with "PaneName"
Do not forget to uncheck the Auto Generate Columns (or change AutoGenerateColumns value to False from your Property Window).
If you see this line --> DataCache.ClearHostCache(True)
It will clear your host cache, so cache will be invalidated in order to show up the newest request. This line should be used because DNN using cache method that define in Host --> Host Settings --> Performance Settings option. Sometimes, when you delete a module from code in your custom module, it's not really reflected into your site. So you have to clearing up the cache.
You see that DNN provide many functionality that usually happened in your ASP .NET development project. DNN not only has very useful ClientAPI, but also DNN WebControls that you can start with (eg. DNNLabelEdit, DNNTextSuggest, DNNTabStrips, DNNMenu, DNNTreeview, and will grown up in the next release of DotNetNuke)
That's all folks !
See you next time in my DNN development tutorial !