The challenge: Allow users to define the columns shown and order for datagrid displays in ASP .NET webpages. Here is my first stab at a solution.
I'm going to create a class object called Employer, with some text fields, a true/false to be displayed as a checkbox, a hyperlink on the company name, and an image path (just so we can cover several different types of columns in one example). I am not going to post the class layout, just note that the properties in the class are as follows:
- Type
- CompanyName (hyperlink)
- Length
- Position
- Phone
- Supervisor
- ImagePath (image)
- IsChecked (checkbox)
So the first thing I did was write an xml file that would specificy the order of the columns, and have attributes defining what property on the employer object belongs in each column. (This will be generated through a config interface in the future, but for now I wrote it by hand)
<?
xml version="1.0" encoding="utf-8" ?>
<
Columns>
<Column headerText="Type" type="Label" bindTo="Type"/>
<Column headerText="CompanyName" type="HyperLink" linkText="CompanyName" navURL="editPage" target="_blank"/>
<Column headerText="Length" type="Label" bindTo="Length"/>
<Column headerText="Position" type="Label" bindTo="Position"/>
<Column headerText="Main Phone" type="Label" bindTo="MainPhone"/>
<Column headerText="Supervisor" type="Label" bindTo="Supervisor"/>
<Column headerText="Image" type="Image" bindTo="ImagePath"/>
<Column headerText="Check" type="CheckBox" bindTo="isChecked"/>
</
Columns>
So now in my .aspx page I'm going to instantiate my employer object, read the xml layout file, build the datagrid programatically from the xml layout, add it to the page, and bind it. (For the purposes of this example I put default values in my employer object and just added a few of them to an arraylist and bound the arraylist to the grid). Here is the .aspx code:
Protected
emp As New Employer
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim dgr As New System.Web.UI.WebControls.DataGrid
Dim doc As New System.Xml.XmlDocument
doc.Load("C:\Dev\StreamLend.Net\CoreGUI\XMLFiles\XMLFile1.xml")
Dim columnNodeList As System.Xml.XmlNodeList = doc.SelectNodes("//Columns/Column")
Dim columnNode As System.Xml.XmlNode
For Each columnNode In columnNodeList
Dim dgrCol As System.Web.UI.WebControls.DataGridColumn
Select Case (columnNode.Attributes.GetNamedItem("type").Value.ToUpper)
Case "LABEL"
Dim bCol As New System.Web.UI.WebControls.BoundColumn
bCol.DataField = columnNode.Attributes.GetNamedItem("bindTo").Value
dgrCol = bCol
Case "HYPERLINK"
Dim hCol As New System.Web.UI.WebControls.HyperLinkColumn
hCol.DataTextField = columnNode.Attributes.GetNamedItem("linkText").Value
hCol.NavigateUrl = columnNode.Attributes.GetNamedItem("navURL").Value
hCol.Target = columnNode.Attributes.GetNamedItem("target").Value
dgrCol = hCol
Case "CHECKBOX"
Dim tCol As New System.Web.UI.WebControls.TemplateColumn
tCol.ItemTemplate =
New DataGridCheckBoxColumn(emp)
dgrCol = tCol
Case "IMAGE"
Dim tCol As New System.Web.UI.WebControls.TemplateColumn
tCol.ItemTemplate =
New DataGridImageColumn(emp)
dgrCol = tCol
End Select
dgrCol.HeaderText = columnNode.Attributes.GetNamedItem("headerText").Value
dgr.Columns.Add(dgrCol)
Next
'Build Arraylist and bind grid
emp =
New Employer
Dim employers As New ArrayList
employers.Add(emp)
employers.Add(emp)
employers.Add(emp)
employers.Add(emp)
dgr.AutoGenerateColumns =
False
dgr.Width = Unit.Percentage(100)
dgr.DataSource = employers
dgr.DataBind()
page.Controls.Add(
dgr)
End Sub
Public Class DataGridCheckBoxColumn
Implements System.web.UI.ITemplate
Dim mContainer As Object
Dim mBindTo As String
Public Sub New(ByVal Container As Object)
mContainer = Container
End Sub
Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn
Dim chkbox As New System.Web.UI.WebControls.CheckBox
chkbox.Checked = DataBinder.Eval(mContainer, "isChecked")
chkbox.ID = "chk1"
container.Controls.Add(chkbox)
End Sub
End Class
Public Class DataGridImageColumn
Implements System.web.UI.ITemplate
Dim mContainer As Object
Public Sub New(ByVal Container As Object)
mContainer = Container
End Sub
Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn
Dim img As New System.Web.UI.WebControls.Image
img.ImageUrl = "Images/" & DataBinder.Eval(mContainer, "ImagePath")
img.ID = "img1"
container.Controls.Add(img)
End Sub
End Class
Feedback and questions welcome!