Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια

Dynamically adding controls to ASPX pages (web forms) and assigning event handlers

Although I've seen a lot of articles describing how to dynamically add controls to a Web Form, few mention even a little hint to how you can make event handlers actually WORK with dynamically-added controls. This article may seem (and probably is) a beginner-level one, but I think it's essential to cover this issue.

There are a lot of reasons why you would want to dynamically generate Web Forms, i.e. add controls at runtime. Suppose your form's structure depends on metadata stored in a database, or has to change depending on what data it has to do with every time. Whatever the reason, you probably need to dynamically add controls to it like a textbox or two, or even your own complex, fully functional user controls.

How do you do that?

First, let's understand the various ways we can add controls to a web form. We can do it in either of three ways:

1. Declaratively (at design time)
2. Programmatically (at design time)
3. Dynamically (at run-time)

The first two ways are simple: Either we do a declaration somewhere and let VS.NET write the code for us (1), or we just type our own code, including the designer code (2). Both are done in design time. What we are interested in is (3): Doing it at run time.

(We'll be using the Page_Load sub for all our examples, although it's not always the most convenient place to put dynamic control code - just for the sake of simplicity)

The WRONG way

That's what people usually do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Public Partial Class WebForm1
Inherits System.Web.UI.Page

Protected WithEvents _tx As TextBox

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
_tx = New TextBox
_tx.ID = "textbox1"
Form.Controls.Add(_tx)
End Sub


Private Sub _tx_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _tx.TextChanged
'do something
End Sub
End Class

This works well if we have only ONE textbox. In order to handle events with the _tx_TextChanged sub which uses the HANDLES keyword, we had to declare our _tx variable as at least visible from everywhere from our page and use the keyword "withevents". We also have to declare an event handling method using the keyword "handles".

What happens, though, if we have to dynamically add an unknown number of textboxes? A number that might change with each run because it depends on some external factor like query results from a database?

Well, the answer is that we can thoretically do that in the way mentioned above, but good-bye event handling. We can set _txt to another new textbox and add that as well to our controls collection. BUT! The _tx_TextChanged event handler will be working only for the LAST textbox added (the one we last set _txt to refer to). Like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Public Partial Class WebForm1
Inherits System.Web.UI.Page

Protected WithEvents _tx As TextBox

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
_tx = New TextBox
_tx.ID = "textbox1"
Form.Controls.Add(_tx)


_tx = New TextBox
_tx.ID = "textbox2"
Form.Controls.Add(_tx)

End Sub


Private Sub _tx_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles _tx.TextChanged
'do something
End Sub
End Class

If we change the text of the FIRST textbox and put a breakpoint in line 12, we will notice it is NEVER being hit. That is because _tx_TextChanges can handle only one reference: The one variable _tx was assigned last, and that is the reference for the SECOND text box.

The RIGHT way

The right way to handle events in dynamically added controls is to forget the "handles" keyword and use the AddHandler method, like in the following example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
Partial Public Class _Default
Inherits System.Web.UI.Page

Protected _genTextbox As TextBox
Protected _genButton As Button


Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

_genButton = New Button
_genButton.ID = "btn1"
_genButton.Text = "btn1"
AddHandler _genButton.Click, AddressOf Click1
Form.Controls.Add(_genButton)


_genButton = New Button
_genButton.ID = "btn2"
_genButton.Text = "btn2"
AddHandler _genButton.Click, AddressOf click2
Form.Controls.Add(_genButton)

Dim b As New Button
b.ID = "btn3"
AddHandler b.Click, AddressOf Click3
Form.Controls.Add(b)

_genTextbox = New TextBox
_genTextbox.ID = "txt1"
Form.Controls.Add(_genTextbox)

_genTextbox = New TextBox
_genTextbox.ID = "txt2"
Form.Controls.Add(_genTextbox)


End Sub


Private Sub Click1(ByVal sender As Object, ByVal e As System.EventArgs)
DirectCast(Me.FindControl("txt1"), TextBox).Text = "button 1 pressed"
DirectCast(Me.FindControl("txt2"), TextBox).Text = ""
End Sub
Private Sub Click2(ByVal sender As Object, ByVal e As System.EventArgs)
DirectCast(Me.FindControl("txt1"), TextBox).Text = ""
DirectCast(Me.FindControl("txt2"), TextBox).Text = "button 2 pressed"
End Sub
Private Sub Click3(ByVal sender As Object, ByVal e As System.EventArgs)
DirectCast(Me.FindControl("txt1"), TextBox).Text = "button 3 pressed"
DirectCast(Me.FindControl("txt2"), TextBox).Text = "button 3 pressed"
End Sub

End Class

In this code, we create three buttons and two textboxes dynamically. Each button is assigned an event handler which does something to the two textboxes. Let's examine some interesting things here:

For the buttons, we didn't use the "withevents" keyword in line 4. Of course, we didn't use the "handles" keyword as well. We just assigned event handlers to our two buttons in lines 9 and 14 respectively, passing the addresses of the Click1 and Click2 methods which we have constructed by hand. Although there is only ONE variable for the two buttons, the handlers both work fine! That is because the handlers are not hooked to the _genbutton variable and its current reference any more, as when the "handles" keyword is used.

You might also have noticed something strange - a third button being initialized at line 16, with a variable totally local to the Page_Load sub, which is too assigned an event handler -  and works just fine! So you don't even have to declare protected variables as placeholders for references if you don't want to. Local variables will do just the same.

You have already probably noticed that we are setting the ID property of every control we create. Why? Well, since these controls have not been officially declared in the page, intellisense does not work for them. So, the only way to find what we have constructed is to use the FindControl method which takes a control ID as an argument and returns an object which we must cast to the right type, as is done in all 3 event handlers.

 

Conclusion

In order to achieve fully dynamic addition of controls in web forms you have to:

- Forget about the "handles" keyword. Use the AddHandler method instead. Copy signatures from the event handling methods generated when you use the "withevents" and "handles" keywords in Visual Studio, if you feel you can't remember that argument each handler uses, and create your own handling methods which you'll link to your controls with the help of the AddHandler method.

- No need to declare protected stuff if you don't need to. Even local variables will do. If you do declare protected / private stuff, event handlers will work quite as well since they aren't hooked to what your variable refers to at runtime.

- Always set the control's ID property so you can find it again at runtime using the FindControl method.

Hope that helped a bit.

 

kick it on DotNetKicks.com

 

 

 

Έχουν δημοσιευτεί Πέμπτη, 8 Νοεμβρίου 2007 2:09 μμ από το μέλος cap
Δημοσίευση στην κατηγορία:

Ενημέρωση για Σχόλια

Αν θα θέλατε να λαμβάνετε ένα e-mail όταν γίνονται ανανεώσεις στο περιεχόμενο αυτής της δημοσίευσης, παρακαλούμε γίνετε συνδρομητής εδώ

Παραμείνετε ενήμεροι στα τελευταία σχόλια με την χρήση του αγαπημένου σας RSS Aggregator και συνδρομή στη Τροφοδοσία RSS με σχόλια

Σχόλια:

# Dynamically adding controls to ASPX pages (web forms) and assigning ev

Πέμπτη, 8 Νοεμβρίου 2007 3:00 μμ by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Ποιά είναι η άποψή σας για την παραπάνω δημοσίευση;

(απαιτούμενο)
απαιτούμενο
(απαιτούμενο)
ÅéóÜãåôå ôïí êùäéêü:
CAPTCHA Image