Dynamic LinkButton

R

rn5a

In a shopping cart app, suppose a user has placed 5 orders, I want to
show him 5 LinkButtons (one for each order) so that when he clicks the
first LinkButton, he would be shown the details of his first order.
Likewise if he clicks the second LinkButton, he will be shown the
details of the second order he had placed. The Text of the LinkButtons
will be 1 2 3 etc. So this user would see 1 2 3 4 5 as the
LinkButtons.

The problem is how do I add the LinkButtons dynamically. Do I have to
first create a user control & then using Page.LoadControl add the
LinkButtons to the ASPX page? Or is there some other way out?

Can someone suggest me how do I go about it?
 
M

Marina Levit [MVP]

Create a link button using the New operator. Set all of its properties. Add
it to the page's Controls collection.

If you need finer control over where the buttons will appear (which I
suspect you do), add them to a panel you have placed in a particular spot.
 
M

Mark Rae

In a shopping cart app, suppose a user has placed 5 orders, I want to
show him 5 LinkButtons (one for each order) so that when he clicks the
first LinkButton, he would be shown the details of his first order.
Likewise if he clicks the second LinkButton, he will be shown the
details of the second order he had placed. The Text of the LinkButtons
will be 1 2 3 etc. So this user would see 1 2 3 4 5 as the
LinkButtons.

The problem is how do I add the LinkButtons dynamically. Do I have to
first create a user control & then using Page.LoadControl add the
LinkButtons to the ASPX page? Or is there some other way out?

Can someone suggest me how do I go about it?

Dead easy.

When your page loads, I'm assuming that you already know how many orders are
in the cart - mayhe you're storing the cart in a Session variable, or
fetching it from a database or whatever - doesn't really matter... The
following assumes that you've fetched it into

1) In Page_Init, not Page_Load, fetch your cart

2) For each element in the cart (order, product, whatever), create a new
LinkButton() object:

LinkButton lnkDynamic;

foreach(<whatever> in <cart>)
{
lnkDynamic = new LinkButton();
lnkDynamic.EnableViewState = true;
lnkDynamic.ID = "lnkDynamic_" + <identifier>;
lnkDynamic.Text = "SomeText";
lnkDynamic.Command += new CommandEventHandler(lnkDynamic_Process);
lnkDynamic.CommandName = <whatever>;
lnkDynamic.Visible = false;
this.Controls.Add(lnkDynamic);
}

That will have created as many individual buttons as there are elements in
your cart.

3) Create the event handler

private void lnkDynamic_Command(object sender, CommandEventArgs e)
{
// your code to process the individual elements goes here
// use e.CommandName to work out which button was clicked

}

4) Place the individual dynamic buttons on your form wherever they need to
be e.g. in the cells of a GridView, Repeater etc and make them visible.


Obviously you will need to adapt the above to suit your particular needs,
but it should be enough to get you started.
 
R

rn5a

Mark, I don't find Intellisense list any property named Command for the
LinkButton control as you have shown in your post but of course, the
LinkButton control does have a OnCommand property! So how do I get the
CommandName of each LinkButton?

Actually what I am doing is I am getting the total no. of orders a user
has placed from the database (using a stored procedure) & returning it
in a SqlDataReader. This is the function which does that in the VB
class file:

Namespace Shop
Public Class ShopCart
Private sqlConn As New SqlConnection(".....")
Public Function GetOrderCount(ByVal UserID As Integer) As
SqlDataReader
Dim sqlCmd As SqlCommand
Dim sqlReader As SqlDataReader

sqlCmd = New SqlCommand("CountOrders", sqlConn)
sqlCmd.CommandType = CommandType.StoredProcedure

Try
With sqlCmd
.Parameters.Add("@UserID", SqlDbType.Int).Value =
UserID
End With

sqlConn.Open()
sqlReader = sqlCmd.ExecuteReader
If (sqlReader.HasRows) Then
Return sqlReader
Else
Return Nothing
End If
Catch ex As Exception
Throw ex
End Try
End Function
End Class
End Namespace

This is the ASPX code that invokes the above function:

<%@ Import Namespace="Shop" %>
'importing other necessary Namespaces here

Sub Page_Load(.....)
Dim boShopCart As ShopCart
Dim lnkCount As LinkButton
Dim iCount As Integer = 1
Dim sqlReader As SqlDataReader

boShopCart = New ShopCart
sqlReader = boShopCart.GetOrderCount(iUserID)

While (sqlReader.Read)
If (sqlReader.GetValue(0) > 1) Then
iTotalOrder = sqlReader.GetValue(0)
Else
pnlLinks.Visible = False
End If
End While

For iCount = 1 To iTotalOrder
lnkCount = New LinkButton
lnkCount.ID = "lnkCount" & iCount
lnkCount.Text = iCount.ToString & "&nbsp;&nbsp;"
lnkCount.CommandName = iCount
pnlLinks.Controls.Add(lnkCount)
Next
End Sub

Assuming that a user has placed 5 orders, the above ASPX code is
displaying the 5 LinkButtons 1 2 3 4 5.....no problem till this
point but how do I get the CommandName of each LinkButton.

My main intention is to get the CommandName of the LinkButtons. Prior
to this, I was using HTML hyperlinks to show 1 2 3 4 5 & passing it
as a querystring. For e.g. the href value of the hyperlink would be,
say, ShowOrder.aspx?OrderID=23&PageNum=1 so that when the user clicks
1, 1 no longer remains a hyperlink.
 
M

Mark Rae

Mark, I don't find Intellisense list any property named Command for the
LinkButton control as you have shown in your post

Well you wouldn't - it's an event, not a property...
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.linkbutton.command.aspx
but of course, the LinkButton control does have a OnCommand property!

No it doesn't - it has an OnCommand *method*, not a property...
http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.linkbutton.oncommand.aspx

You may think I'm being pedantic here, but the understanding of (the
difference between) events and properties and methods is extremely
important...
So how do I get the CommandName of each LinkButton?

Exactly as I described in my previous post...

private void lnkDynamic_Command(object sender, CommandEventArgs e)
{
// your code to process the individual elements goes here
// use e.CommandName to work out which button was clicked
}

This is the function which does that in the VB class file:

You mean VB.NET, of course...

And that may be the problem - my code sample was C#, and it may work
differently in VB.NET
 
R

rn5a

No it doesn't - it has an OnCommand *method*, not a property

Sorry....I meant the OnCommand method (which raises the Command event)

Well I have had already a look at the 2 URLs you have cited in the
,NET2 SDK documentation but in both the articles, the app is aware of
the name of the LinkButton at design time but since I am creating the
LinkButtons dynamically, how does the app get the name of the
LinkButtons?

In simple words, since the following line

lnkCount.Command += New CommandEventHandler(lnkDynamic_Process)

won't work; so what should be the code that should replace the above
line in the For...Next loop? I guess I will have to use RaiseEvent but
I don't know how to go about it.
Exactly as I described in my previous post..

Well I am aware of that but as already said before how do I invoke the
sub lnkDynamic_Command in the first place when a LinkButton is clicked.
What should be the code for invoking lnkDynamic_Command?

I hope you understand where have I got stuck.
 
G

Gozirra

lets take everything that was already suggested and VB'ify it. That
will hopefully make things a little more clear. Take note of #1 below.
Your dynamic buttons' events will not fire if they are not recreated
during page_init. Thats why it is so important that you fetch the cart
during this page event instead of during load. Best I can do. Hope it
helps.

1) In Page_Init, not Page_Load, fetch your cart

2) For each element in the cart (order, product, whatever), create a
new button.

Dim lnkDynamic As LinkButton

foreach(<whatever> in <cart>)
lnkDynamic = new LinkButton()
lnkDynamic.EnableViewState = true
lnkDynamic.ID = "lnkDynamic_" + <identifier> 'Identifier can be
your order# or whatever your want
lnkDynamic.Text = "SomeText"
AddHandler lnkDynamic.Command, AddressOf lnkDynamic_Command
lnkDynamic.CommandName = "AnyTextYouWant"
lnkDynamic.Visible = false
Me.Controls.Add(lnkDynamic)
Next

That will have created as many individual buttons as there are elements
in
your cart.

3) Create the event handler


Public Sub lnkDynamic_Command(sender As object, e As CommandEventArgs)
' your code to process the individual elements goes here
' use e.CommandName to work out which button was clicked
' You could put the order number into the command name
' you could also cast sender to a LinkButton and check its ID if
you want. many different ways.
If e.CommandName = "1" Then
'Do stuff for 1
End If

or maybe

Dim lb As LinkButton
lb = DirectCast(sender, LinkButton) 'or whatever your favorite
method is
If lb.ID == "1" Then 'or whatever the heck you want to do
'Some stuff
End If
End Sub


4) Place the individual dynamic buttons on your form wherever they need
to
be e.g. in the cells of a GridView, Repeater etc and make them visible.
 
M

Mark Rae

Sorry....I meant the OnCommand method (which raises the Command event)
OK.

In simple words, since the following line

lnkCount.Command += New CommandEventHandler(lnkDynamic_Process)

won't work;

Yes it will, but in C#... Gozirra has converted my code into VB.NET for
you...
I hope you understand where have I got stuck.

See Gozirra's post...
 
R

rn5a

Gozirra, that's EXACTLY what I was looking out for (the AddHandler
lnkDynamic.Command, AddressOf lnkDynamic_Command line). Thanks a lot.

You as well as Mark have repeatedly stressed on fetching the cart (if I
am not mistaken, by "fetching the cart", you & Mark mean getting the
no. of orders a user has placed & the details of each & every order) in
the Page_Init sub & NOT in the Page_Load sub. But what I find is even
if I place the ASPX code I have shown in post #4 in this thread in the
Page_Load sub & NOT in the Page_Init sub, then not only do the
LinkButtons get recreated after each PostBack but also the events
associated with the LinkButtons (in this case, the Command event) fire
correctly after every PostBack. So why have you (& Mark) stressed on
fetching the cart in the Page_Init sub & NOT in the Page_Load sub?

Could you please clarify this point?
 
M

Mark Rae

Gozirra, that's EXACTLY what I was looking out for (the AddHandler
lnkDynamic.Command, AddressOf lnkDynamic_Command line). Thanks a lot.
Cool.

You as well as Mark have repeatedly stressed on fetching the cart (if I
am not mistaken, by "fetching the cart", you & Mark mean getting the
no. of orders a user has placed & the details of each & every order) in
the Page_Init sub & NOT in the Page_Load sub. But what I find is even
if I place the ASPX code I have shown in post #4 in this thread in the
Page_Load sub & NOT in the Page_Init sub, then not only do the
LinkButtons get recreated after each PostBack but also the events
associated with the LinkButtons (in this case, the Command event) fire
correctly after every PostBack. So why have you (& Mark) stressed on
fetching the cart in the Page_Init sub & NOT in the Page_Load sub?

Could you please clarify this point?

The salient point here is not the fetching of the cart per se - it's the
dynamic creation of webcontrols.

Generally speaking, dynamic control creation can only be pretty much
guaranteed to work when done in Page_Init, not Page_Load - if you have got
it to work in Page_Load, then you're lucky... Change one little thing in
your app and you might find it stops working...

However, since the dynamic creation of the webcontrols in this particular
instance is directly related to the cart, fetching the cart is required
before the controls can be dynamically created, which is why the cart needs
to be fetched in Page_Init, not Page_Load.

It's the same scenario with e.g. DropDownList controls - populate them in
Page_Init, not Page_Load otherwise you may just find that your ViewState
stops working properly.
 
R

rn5a

Well there's another place where I am getting stuck. The stored
procedure that gets the no. of orders a user has placed (please have a
look at the VB class file in post #4 in this thread) also gets the
OrderID of each order. In other words, the stored procedure retrieves 2
columns. I did like to set the OrderID as the CommandArgument of each
LinkButton but as shown in post #4, I am creating the LinkButtons
dynamically OUTSIDE the While(sqlReader.Read) loop since creating the
LinkButtons inside the While loop would mean looping the For...Next
loop (to create the dynamic LinkButtons) within the While loop. Under
such circumstances, a user who has placed, say, 4 orders would see the
LinkButtons 1 2 3 4 thrice which is something which I don't want.

But how do I get the OrderID of each order OUTSIDE the While
(sqlReader.Read) loop?
 
G

Gozirra

Why build the list outside of the while loop then? Try something like
this. Since I do not know exactly what data is coming back, its kind
of hard to determine exactly what all of the possibilities are. But
hopefully it'll give you an idea if you haven't already gotten
everything fixed.

While (sqlReader.Read)
If (sqlReader.GetValue(0) > 1) Then
iTotalOrder = sqlReader.GetValue(0)

lnkDynamic = new LinkButton()
lnkDynamic.EnableViewState = true
lnkDynamic.ID = "lnkDynamic_" + <identifier> 'Identifier
can be your order# or whatever your want
lnkDynamic.Text = "SomeText"
AddHandler lnkDynamic.Command, AddressOf lnkDynamic_Command

lnkDynamic.CommandName = "AnyTextYouWant"
'sqlReader.GetValue(1) perhaps
lnkDynamic.Visible = false
Me.Controls.Add(lnkDynamic)
Else
pnlLinks.Visible = False
End If
End While
 
R

rn5a

Gozirra, the main reason why I want to get the OrderID of each order
outside the While(sqlReader.Read) loop is because I want to pass the
OrderID to another sub named 'GetAddress' which expects 2 parameters -
the UserID & the OrderID. Depending upon the OrderID (& of course, the
UserID), the 'GetAddress' sub will retrieve the billing address &
shipping address pertaining to that OrderID. So even if I create the
dynamic links inside the While(sqlReader.Read) loop as you have
suggested, I still can't access the OrderID outside the While loop. In
order to access the OrderID outside the While loop, I will have to use
Session variables something like this:

Sub Page_Init(....)
iUserID = Request.Cookies("UserID").Value

While(sqlReader.Read)
If (sqlReader.GetValue(0) > 1) Then
iTotalOrders = sqlReader.GetValue(0)
'get the OrderID in Session variable
Session("OrderID") = sqlReader.GetValue(1)
lnkCount = New LinkButton
lnkCount.ID = "lnkCount" & iCount
lnkCount.Text = iCount.ToString
lnkCount.CommandName = iCount
lnkCount.CommandArgument = Session("OrderID")
AddHandler lnkCount.Command, AddressOf CommandCount
pnlLinks.Controls.Add(lnkCount)
iCount = iCount + 1
Session("TotalOrders") = iTotalOrders
Else
pnlLinks.Visible = False
End If
End While

GetAddress(iUserID, CInt(Session("OrderID")))
End Sub

This does serve my purpose & gets the correct billing & shipping
address corresponding to the UserID & OrderID but I did like to avoid
using Session variables.

Can you suggest some way by which I can avoid using Session variables
to store the OrderID?
 
G

Gozirra

Sorry I got really busy at work and wasn't able to check back in. Is
this still an issue for you? If not, everyone just ignore me.

Given the code example you have below, you want to pass the last
orderid retrieved to a subroutine when the loop has completed. So just
pull the last orderid from the commandargument of lnkCount. The last
time through the loop you will have the same value as you have in your
session variable in the code below. This way you do not have to use a
session variable. You could also create a local variable and assign
the value as you iterate the records. That may be a little cleaner and
easier to understand if someone has to come back and look at this
routine later.
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top