Dynamically adding webparts to the dynamically added Catalog zone

Today we are going to discuss how to add webparts to a Catalog Zone dynamically in your webpage.

Sometimes, you may have quite a lot of different webparts which you don't want to add by default to any page. Instead, you want to design an interface where you have added everything into your catalog zone dynamically. This way, users have the option to simply populate those webparts which they like. It seems like there is no *easy* way to achieve this, so you have to plan accordingly to fulfill this requirement. Before I say anything else, let me point you to a link which will explain you quite a lot about webparts and no wonder I have derived some code directly from that link to make things easier.

Introducing the ASP.NET 2.0 Web Parts Framework.

A piece of advice, if time permits (and if you are not already comfortable with the webparts stuff), go through the above link and then proceed to the remaining part of this...

OK, cool... Let's begin...

Create a New Website in VS 2005. You will have a page called default.aspx. Lets delete it! We will add another page called Default.aspx, but ensure that there is no codebehind. You can do this by ensuring that when you are adding a new Web Form, the checkbox Place code in seperate file is UNCHECKED. Now, in the source view of the Default.aspx, delete everything and paste the following...

<%@ Page Language="vb" %>
<script runat="server">
Sub CustomizePage(ByVal s As Object, ByVal e As EventArgs)
WebPartManager1.DisplayMode = WebPartManager.CatalogDisplayMode
End Sub
Sub EditWebParts(ByVal s As Object, ByVal e As EventArgs)
WebPartManager1.DisplayMode = WebPartManager.EditDisplayMode
End Sub
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs)
Dim dynamicCatalog As New CatalogZone
dynamicCatalog.ZoneTemplate = New CustomZoneTemplate()
dynamicCatalog.ID = "DynamicCatalog"
Ph1.Controls.Add(dynamicCatalog)
End Sub
</script>
<html>
<head id="Head1" runat="server">
<title>Home Page</title>
</head>
<body bgcolor="gray">
<form id="form1" runat="server">
<asp:WebPartManager
ID="WebPartManager1"
Runat="Server" />
<table width="100%" Height="100%" cellpadding="5" cellspacing="10">
<tr height="50">
<td colspan="3" align="right" bgcolor="white" style="height: 50px">
<asp:LinkButton ID="LinkButton1"
Text="Customize Page"
OnClick="CustomizePage"
Runat="Server" />
|
<asp:LinkButton ID="LinkButton2"
Text="Edit Web Parts"
OnClick="EditWebParts"
Runat="Server" />
</td>
</tr>
<tr>
<td valign="top" bgcolor="white" width="40%">
<asp:WebPartZone
ID="WebPartZone1"
Width="100%"
HeaderStyle-BackColor="lightblue"
PartTitleStyle-BackColor="silver"
Runat="Server" >
<HeaderStyle BackColor="LightBlue" />
<PartTitleStyle BackColor="Silver" />
</asp:WebPartZone>
</td>
<td valign="top" bgcolor="white" width="40%">
<asp:WebPartZone
ID="WebPartZone2"
Width="100%"
HeaderStyle-BackColor="lightblue"
PartTitleStyle-BackColor="silver"
Runat="Server" >
<HeaderStyle BackColor="LightBlue" />
<PartTitleStyle BackColor="Silver" />
</asp:WebPartZone>
</td>
<td valign="top" width="20%" bgcolor="white">
<asp:PlaceHolder runat=server ID="Ph1"></asp:PlaceHolder>
</td>
</tr>
</table>
</form>
</body>
</html>

Add three new classes (in your App_code folder) called CustomProduct.vb, CustomWebPartTemplate.vb and CustomZoneTemplate.vb. Now, paste the following code accordingly.

CustomProduct.vb

Imports System.Collections
Imports System.Data
Imports System.Data.SqlClient
Imports System.Web.UI
Imports System.Web.UI.WebControls.WebParts
Public Class CustomProduct
Inherits WebPart
Const connectionString As String = _
"Server=localhost;Trusted_Connection=True;Database=Northwind"
Const selectString As String = "SELECT * FROM Products " & _
"JOIN Categories ON Products.CategoryID=Categories.CategoryID"
Private _categoryName As String = "Beverages"
Public Sub New()
MyBase.Title = "Custom Product"
End Sub
Public Overrides ReadOnly Property Verbs() As WebPartVerbCollection
Get
' Create Beverages verb
Dim verb1 As New WebPartVerb("verb1", New _
WebPartEventHandler(AddressOf ChangeCategory))
verb1.Text = "Beverages"
verb1.Description = "Displays Beverages Products"
' Create Seafood verb
Dim verb2 As New WebPartVerb("verb2", New _
WebPartEventHandler(AddressOf ChangeCategory))
verb2.Text = "Seafood"
verb2.Description = "Displays Seafood Products"
' Create collection of verbs
Dim newVerbs() As WebPartVerb = {verb1, verb2}
' Return WebPartVerbCollection including base verbs
Return New WebPartVerbCollection(newVerbs)
End Get
End Property
Public Sub ChangeCategory(ByVal s As Object, ByVal e As WebPartEventArgs)
Dim newCategory As String = s.Text
Me.CategoryName = newCategory
Me.Title = String.Format("Featured Product - {0}", newCategory)
End Sub
<Personalizable(), WebBrowsable()> _
Public Property CategoryName() As String
Get
Return _categoryName
End Get
Set(ByVal value As String)
_categoryName = value
End Set
End Property
Protected Overrides Sub RenderContents(ByVal writer _
As HtmlTextWriter)
' Load Products into DataTable
Dim productTable As New DataTable()
Dim dad As New SqlDataAdapter(selectString, _
connectionString)
dad.Fill(productTable)
' Filter the DataTable with a Category
Dim productView As DataView = productTable.DefaultView
productView.RowFilter = "CategoryName='" & _categoryName & "'"
If productView.Count = 0 Then
Return
End If
' Randomly select a row
Dim rnd As New Random()
Dim row As DataRowView = _
productView(rnd.Next(productView.Count))
' Render the row
writer.Write(row("ProductName").ToString())
writer.Write(String.Format("- {0:c}", row("UnitPrice")))
End Sub
End Class

CustomWebPartTemplate.vb

Public Class CustomWebPartTemplate
Implements ITemplate
Dim Product1 As CustomProduct
Dim Product2 As CustomProduct
Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) _
Implements System.Web.UI.ITemplate.InstantiateIn
'
Product1 = New CustomProduct
Product1.ID = "CustomProduct1"
Product1.Title = "Custom Product 1"
container.Controls.Add(Product1)
Product2 = New CustomProduct
Product2.ID = "CustomProduct2"
Product2.Title = "Custom Product 2"
container.Controls.Add(Product2)
End Sub
End Class

CustomZoneTemplate.vb

Public Class CustomZoneTemplate
Inherits WebPart
Implements ITemplate
Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) _
    Implements System.Web.UI.ITemplate.InstantiateIn
'
Dim DeclCatalogPart As New DeclarativeCatalogPart
Dim PgCatalogPart As New PageCatalogPart
PgCatalogPart.ID = "MyPageCatalog"
PgCatalogPart.Title = "My Page Catalog Title"
DeclCatalogPart.WebPartsTemplate = New CustomWebPartTemplate()
DeclCatalogPart.ID = "MyDeclarativeCatalog"
DeclCatalogPart.Title = "My Declarative Catalog Title"
container.Controls.Add(PgCatalogPart)
container.Controls.Add(DeclCatalogPart)
End Sub
End Class

If you switch to the design view of default.aspx you will see that there are two Zones created at design time and in the third column you will see a simple Placeholder. This is where our Catalogzone will get created and loaded at runtime. Once you run the project you will see something like this...

Now, click on "Customize Page" link and you should be able to see the dynamically added webparts with appropriate titles like the following...

Happy Programming :o)

-Rahul Soni

HomePage.GIF