Not as easy as it seems: Webform Dynamic Buttons
 
Published: 21 Oct 2003
Unedited - Community Contributed
Abstract
Solutions to two problems developing dynamic buttons for those switching to VB.NET from VB and/or C++: binding an event to a subroutine or function and generating buttons in a subroutine.
by Matthew Small
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 37747/ 72

The Newbie Problem, Part 1

This article was contributed by Matthew Small and he can be reached at matt@showstopperonline.com

The Newbie Problem Part 1

OK, I am a newbie to Visual Basic.NET. However, I am an experienced programmer, and have used a few languages in my day, including VB 6.0 and C++. I therefore should be able to pick up the syntax of VB.NET pretty easily. Take this for example:

<asp:linkbutton
          commandname="categoryid"
          commandargument="1"
          oncommand="lbLink_Click"
          text="Men’s Clothing" />

The above is the explicit placement of a linkbutton on the webform. Logically, it should be equivalent to this code below:

dim lbLink as new LinkButton
lbLink.Text = "Men’s Clothing"
lbLink.CommandName = "CategoryId"
lbLink.CommandArgument = "1"
lbLink.OnCommand = "lbLink_Click"

However, it is not. When run, this code will generate an error:

BC30390: 'System.Web.UI.WebControls.LinkButton.Protected Overridable Overloads Sub OnCommand(e As System.Web.UI.WebControls.CommandEventArgs)' is not accessible in this context because it is 'Protected'

Line 92:     lbLink.Text = "Men’s Clothing"
Line 93:     lbLink.CommandArgument = "1"
Line 94:     lbLink.OnCommand="lbLink_Click"
Line 95:
Line 96:

Ok, what does that mean? I really don’t know, but I do know that my code won’t work like that. The solution is simple but isn’t found in any of my ASP.NET books.

For reasons beyond my limited knowledge, Microsoft decided that instead of the logical dot-notation for adding a OnClick or OnCommand attribute to our Button, a separate statement was to be required: addhandler

dim lbLink as new LinkButton
lbLink.Text = "Men’s Clothing"
lbLink.CommandName = "CategoryId"
lbLink.CommandArgument = "1"
AddHandler lbLink.Command, AddressOf lbLink_Click

The addhandler statement binds an event to a subroutine or function of your choice. The generic syntax is:

AddHandler event, AddressOf subroutine

For more detailed information on it, go to

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vblr7/html/vastmAddHandlerStatement.asp

OK, that wasn’t so hard. We now have the correct syntax for binding an event to a subroutine or function.

The Newbie Problem Part 2

The Newbie Problem Part 2

The next problem comes when we generate these buttons in a subroutine. One of the first things I did when I started writing Webforms was to use the panels server control to create wizard-like pages. I did this independent of any knowledge that others were doing it, but there is a nice article by Rajiv. R on using this method to create your webforms located at: http://aspalliance.com/articles/panels.aspx

Let’s expand our code a bit:

Sub ChooseCategory (Sender As Object, e as EventArgs)
     pnlSelectCategory.visible = true
     pnlSelectItem.visible = false
     pnlViewItem.visible = false
     pnlViewCart.visible = false
     pnlCheckout.visible = false
     pnlOrderPlaced.visible = false

     'Get database information into my user-defined server control called database...
     'End database information

     dim lbLink as LinkButton
     dim dbRow as System.Data.DataRow

     for each dbRow in database.table("tablename").rows
          lbLink = new LinkButton lbLink.Text = dbrow.item("categoryname")
          lbLink.CommandName = "CategoryId"
          lbLink.CommandArgument = dbrow.item("CategoryId")
          AddHandler lbLink.Command, AddressOf lbLink_Click
          pnlSelectCategoryl.Controls.Add(lbLink)
     next
End Sub

Sub lbLink_Click (Sender As Object, e As CommandEventArgs)
     dim lbLink As LinkButton = CType(Sender, LinkButton)
     dim CategoryId as String = lbLink.CommandArgument
     ' Do things with this information
     ...
End Sub

What the "ChooseCategory" code does (should do) is

1) Set the panel "pnlSelectCategory" to visible
2) Gets information from a database
3) Loops over each row in the database
4) Generates a linkbutton for each category in the database, each of which will call the subroutine lbLink_Click

Ok, everything’s copasetic, right? Not exactly. When this code is executed, no errors will be generated. Your links will be generated nicely, they will be pretty, but they won’t do anything. You can click on them all day and all you will get is a page-repost. They will not fire the event which will run the subroutine lbLink_Click.

What’s the problem? Well the problem lies in the fact that these are dynamically defined, and not permanent web controls. When the page reposts, they are not recognized by the code because at that time, they don’t exist, and therefore will not fire the event to execute the subroutine. How do we fix this problem? Easy: re-create them everytime we create the page, in the page_load subroutine.

Let’s re-write the code:

Sub Page_Load (Sender As Object, e As EventArgs)
     CreateDynamicButtons()
End Sub

Sub CreateDynamicButtons ()

     'Get database information into my user-defined server control called database
     '...
     'End database information

     dim lbLink as LinkButton
     dim dbRow as System.Data.DataRow

     for each dbRow in database.table("tablename").rows
          lbLink = new LinkButton lbLink.Text = dbrow.item("categoryname")
          lbLink.CommandName = "CategoryId"
          lbLink.CommandArgument = dbrow.item("CategoryId")
          AddHandler lbLink.Command, AddressOf lbLink_Click
          pnlSelectCategoryl.Controls.Add(lbLink)
     next
End Sub

Sub ChooseCategory (Sender As Object, e as EventArgs)
     pnlSelectCategory.visible = true
     pnlSelectItem.visible = false
     pnlViewItem.visible = false
     pnlViewCart.visible = false
     pnlCheckout.visible = false
     pnlOrderPlaced.visible = false
End Sub

Sub lbLink_Click (Sender As Object, e As CommandEventArgs)
     dim lbLink As LinkButton = CType(Sender, LinkButton)
     dim CategoryId as String = lbLink.CommandArgument
     ' Do things with this information
     '...
End Sub

Now we have split the ChooseCategory subroutine into two parts that execute independently of each other and inserted a call to CreateDynamicButtons into the Page_Load subroutine. Now whenever the page is loaded, the CreateDynamicButtons subroutine is called, and it creates the buttons so that their events will be recognized by the AddHandler statement.

This article was contributed by Matthew Small and he can be reached at matt@showstopperonline.com

Matthew Small is the IT Supervisor for Showstopper, the national dance competition company located in Murrells Inlet, South Carolina. He was formerly a consultant for Allaire Corp., the creator of the ColdFusion Markup Language (CFML) and now spends his time working on his MIS Master’s Degree and trying to learn everything .NET. He can be reached at mattATShowstopperonline.com.



User Comments

Title: Thank you   
Name: Dimitris Kouzoudis
Date: 2010-10-18 4:30:48 AM
Comment:
Great article, solved my problem! I was working on asp.table with dynamic link buttons and faced the same (both) problems with the buttons
Title: Good, but...   
Name: Helvin
Date: 2009-02-10 3:41:44 AM
Comment:
Hey, thanks for pointing out this problem. I thought something was wrong with my code, and this is it. However, I am trying to display the results of a search, which would depend on the search string. So I cant just call my submit_search sub in page_load. (The results of the search include links, which calls another sub, so my situation is similar to yours.)
Title: Grand!   
Name: ElToro
Date: 2007-03-22 5:14:09 PM
Comment:
Finally an article on Panel worth reading! THX!
Title: I get an error   
Name: Andrew
Date: 2007-01-31 7:16:32 AM
Comment:
Testing the code, I get an error saying "'Command' is not an event of System.Object" for the codeline "AddHandler lbLink.Command, AddressOf lbLink_Click". Any clues to what's wrong? My test code is as below:

Dim i As Integer
For i = 0 To 20

Dim tr As New TableRow
Dim tc = New TableCell
Dim lbLink = New LinkButton
lbLink.Text = i
lbLink.CommandName = "CategoryId"
lbLink.CommandArgument = i
AddHandler lbLink.Command, AddressOf lbLink_Click
tc.Controls.Add(lbLink)
tr.Cells.Add(tc)
Table1.Rows.Add(tr)
Debug.WriteLine(i)
Next i
Title: thanks   
Name: Kristof Heyrman
Date: 2007-01-19 4:55:00 AM
Comment:
Thanks man, Your article was very usefull to me.
I didn't know how to give an extra parameter (argument) to the button_click function, eg. the tableRow number in a dataset.
piece of cake with the Button.commandArgument option.

kind regards
Kristof
Title: Grateful   
Name: Diane
Date: 2006-10-23 6:42:21 PM
Comment:
Have been searching for days on how to do this... I'm too much of a newbie to understand most of the things I saw (which I suspect didn't actually tell me this anyway). This was hard, too, but you're CLEAR so I could follow. Thankyou Thankyou Thankyou.
Title: Thank you!   
Name: Phil Strachan
Date: 2006-09-16 11:30:09 PM
Comment:
Thanks a bunch - part 1 was a life saver...late night, deadline looming - you know the drill. Thanks again!
Title: Thanks   
Name: Alex
Date: 2006-08-22 2:55:59 PM
Comment:
Thanks so much man. I decided to just dive into .net by building my own wed control and I couldn’t find a simple solution to do a post back to the control since all the examples use c# which seems to accept the syntax of linkbutton.command. Seeing the line AddHandler lbLink.Command, AddressOf lbLink_Click here saved me hours of banging my head against the desk
Title: Some what confuse   
Name: Sudhir Kumar Jena
Date: 2006-04-03 1:49:31 AM
Comment:
Sir,
I am some what confuse with this artical.Can you please explain me clearly.
Sub ChooseCategory (Sender As Object, e as EventArgs)
pnlSelectCategory.visible = true
pnlSelectItem.visible = false
pnlViewItem.visible = false
pnlViewCart.visible = false
pnlCheckout.visible = false
pnlOrderPlaced.visible = false
End Sub

This code is bit confuse.How we get that choosegatagory.If possible pl send me complete code bcoz i want immediatly.
thanking You
sudhirkumar_jena@yahoo.co.in

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2019 ASPAlliance.com  |  Page Processed at 2019-07-17 4:50:15 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search