ITemplate - Dynamic ImageButton in BindLabelColumn for DataList

E

Erik

Good Morning,
I am trying to dynamically generate an ImageButton in a datalist label
column. When I have a static reference to the image 'image/plus.gif', the
image is displayed in the label column.

However, when I try to adapt the html code to be dynamically defined in the
binding of the label column, the image is not displayed. Below is the sub
BindParentLabelColumn where the label text is assigned.
Any insight on the issue is greatly appreciated - I am stumped.
Thank you, Erik

Public Sub BindParentLabelColumn(ByVal sender As Object, ByVal e As EventArgs)
Dim lbl As Label = CType(sender, Label)
Dim strvals As String
Dim container As DataListItem = CType(lbl.NamingContainer,
DataListItem)
Dim dt As DataTable = Session("DataList_ParentDetailControls")
Dim dc As DataColumn
Dim sColumnValue As String
Dim sColumnName As String

strvals = "<tr>"

For Each dc In dt.Columns
sColumnName = dc.ColumnName
sColumnValue =
Convert.ToString(DataBinder.Eval(CType(container, DataListItem).DataItem,
dc.ColumnName))

strvals &= "<TD align='center' width='10'><asp:ImageButton
ID='Expand" + sColumnName + "' runat='server' CommandName='Select" +
sColumnName + "' ImageUrl='images/plus.gif'></asp:ImageButton></TD>" & _
"<TD align='center' width='80'>" + sColumnValue +
"</TD>"
End If
Next

strvals &= "</tr>"

lbl.Text = strvals
End Sub 'BindParentLabelColumn
 
P

Phillip Williams

Hi Erik,

Good morning to you too and welcome back to the newsgroup. Regarding your
code:
1- Server control markup renders into HTML markup when it is processed by
the ASP.NET engine. But when you placed it inside the label text, the label
control will assume that is a regular HTML markup and would not translate it
from being server control markup to HTML
2- The BindParentLabelColumn would not execute unless you add an event
hanlder to the lable.databinding event. You could have also wrote the logic
within the DataList.ItemDataBound event to achieve the same outcome.
3- If you want your page to handle the click events of the dynamically
created image buttons you should databind the list during the Page.Init stage.

Here is how I would modify your code:

'starting during the initialization phase of the page's lifecycle
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Init
InitializeComponent()
'Dynamically created controls should be created during the
'page initializtion stage for the control to maintain their viewstate
BindControls()
End Sub

Private Sub BindControls()
'Explicity cast the session variable to its appropriate type before
using it
datalist1.DataSource =
CType(Session("DataList_ParentDetailControls"), DataTable)
datalist1.DataBind()

End Sub

Private Sub DataList1_ItemCreated(ByVal sender As Object, ByVal e As
DataListItemEventArgs) Handles datalist1.ItemCreated
Dim myLabel As Label = e.Item.FindControl("Label1")
'this step wires up the label databinding event to a method
AddHandler myLabel.DataBinding, AddressOf BindParentLabelColumn

End Sub

Public Sub BindParentLabelColumn(ByVal sender As Object, ByVal e As
EventArgs)
Dim lbl As Label = CType(sender, Label)
Dim container As DataListItem = CType(lbl.NamingContainer,
DataListItem)
'the datalistitem has a pointer to the DataItem (which is datarowview)
'of your datatable. Therefore you do not need to retrieve the
datatable
'from the session
Dim drv As DataRowView = container.DataItem
Dim dt As DataTable = drv.Row.Table
Dim dc As DataColumn
Dim sColumnValue As String
Dim sColumnName As String


For Each dc In dt.Columns
'you have to add the imagebutton control as a control object to
the
'controls collection of the label so that it would be rendered
by the
'asp.net engine as a server control
Dim btnImg As New ImageButton
sColumnName = dc.ColumnName
sColumnValue = drv(sColumnName)
btnImg.ID = "Expand" + sColumnName
btnImg.CommandName = "Select" + sColumnName
btnImg.ImageUrl = "images/plus.gif"
lbl.Controls.Add(btnImg)
'add the description beside the image button also as a label
control
'to the original label's controls collection
Dim UrlLabel As New Label
UrlLabel.Text = sColumnValue
lbl.Controls.Add(UrlLabel)

Next

End Sub
Private Sub DataList1_ItemCommand(ByVal sender As Object, ByVal e As
DataListCommandEventArgs) Handles datalist1.ItemCommand
'This is the method that would handle the click event of the
dynamically created imagebuttons
End Sub
 
E

Erik

Hi Phillip,
Good to hear from you also.
I am encountering an error (Object reference not set to an instance of an
object.) on line dlstParent1.DataBind after populating the Parent_Data_Table
with the SQL string defined from the user's parameter selection. Do I have
some redundant code which is causing a conflict?

dlstParent1.HeaderTemplate =
New DatalistParentLabelColumn(ListItemType.Header)
dlstParent1.ItemTemplate =
New DatalistParentLabelColumn(ListItemType.Item)

Try
dvwSelect = New DataView(Parent_Data_Table(sCmd))
If dvwSelect.Table.Rows.Count <> 0 Then
dlstParent1.DataSource = dvwSelect
dlstParent1.DataBind()
Else
Session("DataList_ParentDetailControls") = Nothing
pnlDetail.Visible = False
End If
Catch ex As SqlException
lblErrorMsg.Text = ex.message.ToString
Catch ex As Exception
lblErrorMsg.Text = ex.Message.ToString
Finally
dvwSelect.Dispose()
End Try
 
P

Phillip Williams

Hi Erik,

Using VS.Net debugger, set up break points within the methods that are
triggered upon databinding (of both the datalist and the label) and step
through them. Somewhere in the code that you did not post, you will find the
line that threw that exception.
 
E

Erik

Hi Phillip,
It appears the following is causing the error, with an itemtype = 'header'.
Should there be code added to verify the itemtype = 'item'. Thanks, Erik

Private Sub dlstParent1_ItemCreated(ByVal sender As Object, ByVal e As
DataListItemEventArgs) Handles dlstParent1.ItemCreated
Dim myLabel As Label = e.Item.FindControl("Label1")
'this step wires up the label databinding event to a method
AddHandler myLabel.DataBinding, AddressOf BindParentLabelColumn
End Sub
 
P

Phillip Williams

Hi Erik,

Yes, of course. I exptected you to fill in those tiny details :) but here
is a checked code:

Private Sub DataList1_ItemCreated(ByVal sender As Object, ByVal e As
DataListItemEventArgs) Handles datalist1.ItemCreated
If e.Item.ItemType = ListItemType.Item And e.Item.ItemType =
ListItemType.AlternatingItem Then
Dim myLabel As Label = e.Item.FindControl("Label1")
If Not myLabel Is Nothing Then
'this step wires up the label databinding event to a method
AddHandler myLabel.DataBinding, AddressOf
BindParentLabelColumn
End If
End If
End Sub
 
P

Phillip Williams

Correction; the condition should be:

If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType =
ListItemType.AlternatingItem Then
'....
End IF
 
E

Erik

Hi Phillip,
The error is still occurring in
Dim myLabel As Label = e.Item.FindControl("Label1")
AddHandler myLabel.DataBinding, AddressOf BindParentLabelColumn
with the addition below. The ID for the item is Nothing. I can't figure
out what the control 'Label1' refers to since the controls are being created
for the DataList. I apologize for my confusion, but this is new territory
for me again.
Thanks, Erik
 
P

Phillip Williams

Hi Erik,

That's alright. Label1 is the id of the label that I placed within the
DataList markup. You have to give the label an Id to be able to identify it
using the FindControl method in the Codebehind.

<asp:DataList ID="datalist1" Runat='server' >
<ItemTemplate>
<asp:Label ID="Label1" Runat="server"></asp:Label>"
</ItemTemplate>
</asp:DataList>
 
E

Erik

Is there a way I can define the ItemTemplate labels dynamically in code? The
number and definition of columns displayed is selected by the user.
Thanks, Erik
 
P

Phillip Williams

Hi Erik,

We have just displayed any number of controls (instead of HTML table
columns) into one label (which is inside one ItemTemplate).

This was just a modification to your original code to explain to you the
concept of building the controls dynamically. (Instead of concatenating
markup text that you started with, you now learned that you could add the
controls dynamically within the page initialization stage to maintain their
functions)

To reach to a full production outcome of the application that you desire,
you can build on the concepts of adding dynamic controls that we achieved in
this code by refining the way you place the controls.

For example, instead of using one label you can build a Table within the
DataListItem. You can start by trying a simple markup like this:

<asp:DataList ID="datalist1" Runat='server' CssClass="Container">
<ItemTemplate>
<%--leave it empty to be populated programmatically based on # of
columns--%>
</ItemTemplate>
</asp:DataList>

And then move the code where you created the buttons within the stage of
processing the DataList.ItemDataBound event like this:

Private Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As
DataListItemEventArgs) Handles datalist1.ItemDataBound
Dim drv As DataRowView = e.Item.DataItem()
Dim dt As DataTable = drv.Row.Table
Dim dc As DataColumn
Dim sColumnValue As String
Dim sColumnName As String
'each row would be formatted as a table that contains one row and as
many cells as there
'are columns on the datatable
Dim t As New Table
e.Item.Controls.Add(t) 'add the table to the datalist row
Dim r As New TableRow
t.Rows.Add(r)

For Each dc In dt.Columns
Dim c As New TableCell
r.Cells.Add(c)
'you have to add the imagebutton control as a control object to
the
'controls collection of the label so that it would be rendered
by the
'asp.net engine as a server control
Dim btnImg As New ImageButton
sColumnName = dc.ColumnName
sColumnValue = drv(sColumnName)
btnImg.ID = "Expand" + sColumnName
btnImg.CommandName = "Select" + sColumnName
btnImg.ImageUrl = "images/plus.gif"
c.Controls.Add(btnImg)
'add the description beside the image button also as a label
control
'to the original label's controls collection
Dim UrlLabel As New Label
UrlLabel.Text = sColumnValue
c.Controls.Add(UrlLabel)
Next

End Sub

Once you get the hang of this you might try a one-more step complex
approach: to dynamically create the ItemTemplates as in this sample:
http://msdn.microsoft.com/library/d...atingwebservercontroltemplatesdynamically.asp

If you still cannot get it to work, let me know and I might put a demo of it
on my website.
 
E

Erik

Good Morning Phillip,
Thanks you for the instruction. I have been working through the code, and
can't figure out an exception I am getting on line Dim drv As DataRowView =
e.Item.DataItem() in dlstParent1_ItemDataBound. e is Nothing.
Thanks, Erik
 
P

Phillip Williams

Hi Erik,

Can you post the code. (I know this page is getting pretty long, so you
might want to chop off the history out of it)

Also, have you looked at the demo using the datagrid that I posted. It
might prove easier in getting a tidy layout.
 
E

Erik

Hi Phillip,
I have your example working locally, and am working on making it data-driven.
Thanks,
Erik
 
E

Erik

Good Morning Phillip,
I hope you enjoyed the weekend. I have everything working, and just have
two questions regarding the dynamically created controls (imagebutton), and
formatting of the databound template columns.
When the user clicks the 'plus' button to expand the detail information, the
button originally was updated to a 'minus' button. Below is the adapted code
for the dynamically created controls:
btnDetails =
CType(DataGrid1.Items(e.Item.ItemIndex).FindControl(e.CommandName),
ImageButton)
btnDetails = CType(e.Item.FindControl(e.CommandName.ToString), ImageButton)
If Not (btnDetails Is Nothing) Then
btnDetails.ImageUrl = "images/minus.gif"
Else
lblErrorMsg.Text = "Control " & e.CommandName.ToString & " not found."
End If
The control is not being found, and I can't find the issue with the code.
Next, I was wondering if there is a way to format decimal values for the
databound template columns. I have been able to accomplish some formatting
through the stylesheet, but can't figure out how to explicitly define some
columns value to display as currency (in Sub DataGrid1_DataBinding1). For
example, if dc.ColumnName = "Price" then display the value as currency.
Thank you again for your help. You have again provided wonderful
instruction and patience.
Erik
 
E

Erik

Good Morning Phillip,
I was unable to see in your code where imgBtn.ImageUrl is assigned to
left.gif. Would you please point out in which function / sub the assignment
takes place?
Another question I had was calling the 'CreateTable' function twice in
Page_Init. Isn't datagrid1.DataSource = CreateTable() sufficient to create
the table for databinding?
Thanks, Erik
 
P

Phillip Williams

Good morning Erik,

Yes you are right on both counts; I missed uploading the source code
therefore you only found the old demo's source code; and the second one
(namely repeating the CreatTable method) was a typo on my behalf. I guess I
was too much engaged in watching the elections results on TV and listening to
the speech of our new Prime Minister that I was not fully paying attention
when I uploaded the demo. I corrected it now.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top