Add Controls Dynamically - Part 4

The part 3 of this series was getting a bit long for my taste so I decided to break it in 2. Here we’ll continue dealing with the controls added dynamically to our page only now we’re going to access them by ID.

Related posts:

Naming the controls

By now you have noticed that we haven’t explicitly set the ID of any of our controls. Of course the controls have ID’s but they are defined automatically by the Asp.Net framework when the controls are instantiated. The reason this works is because the framework will create the names consistently the same, again and again as long as you create the controls always in the same order (we are doing that).

It is this automatically naming feature that allows our components to keep their state between requests. When the page is submitted all of the controls states are sent back from the browser to the server, but the server doesn’t know how to create the controls that’s why we had to do it every time the page is submitted. After the control has been created the Asp.Net framework is able to get it’s state from the page based on it’s name.

Ok, enough theory. Let’s give our controls and ID manually. Since the controls are added dynamically the ID’s have to be something that can be predicted. Let’s say: TextBox + a number. For this will change the createDynamicControls method to add a parameter which will be the number of the control added.

//this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

When the add control button is clicked we need to pass the number to the method. We can use the control count that we’re storing in the ViewState.

protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

Another place we need to change is the Page_Load event when the controls are re-created. Here for loop when we pass in the new parameter:

for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }

To test our new functionality we will add TextBox, a Button and a Label. We are going to inform the ID of the TextBox we want to get the value for. When the button is clicked the event will get the control and display it’s value in the label.

<asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Valor: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>

And here is the event where we get the TextBox we want:

protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }

Now if you add 3 TextBoxes (which will have id’s TextBox0, TextBox1 and TextBox2) and you input TextBox0 in the interface and hit the button the LabelValue control will show the value in the first TextBox.

This one was a bit longer than I would like to so I’ll try to make the next article shorter.

Here is the final version of our page after all of our modifications:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

    //this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

    protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }

    protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
        <br />
        <asp:Button ID="ButtonAdd" runat="server" Text="Add all values" 
            onclick="ButtonAdd_Click" />
        <br />
        Total:<asp:Label ID="LabelTotal" runat="server" Text=""></asp:Label>
        <br />
        <br />
        <asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Value: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>
    </div>
    </form>
</body>
</html>

See you next time.

Add Controls Dynamically - Part 5

In parts 1 to 4 I have talked about creating dynamic controls and adding them to the page. I haven’t talked about a important aspect of Asp.Net that is very important for any developers and specially if you are dealing with dynamic controls. So in this article I’m going to talk about the Asp.Net Life cycle.

Related posts:

Asp.Net Life Cycle

As I said in previous articles the state of the page or any of it’s components is not stored on the sever. Everything is stored on the page. This is due to the characteristics of HTTP protocol which is stateless. Having this in mind, every time there is a postback the structure of the page is recreated so that you can have access to the controls through code. I’m not sure if I made myself clear so here another way to put it:

HTML is HTML and that is it. When you look at the page in the browser all there is is HTML, there is no C# or VB.Net. Only when the page is submitted to the server is that the HTML is going to be read transformed in server side controls. The programmer then uses these server side controls to manipulate the controls. At the end this controls will render HTML again which will be sent to the page.

Ok, so why is this important? Well, the process of creating the server side code from the HTML happens in several stages which fire events that let you interact with the components in the right moment.

The life cycle has a lot of stages but the ones we are interested in are the Initialization and Load. For more details on all stages check out MSDN

Initialization

In this stage the controls available on the page (not the ones created dynamically) become available. The ViewState has not been retrieved however and therefore the control values cannot be loaded in the controls. The postback data is also not available at this stage.

The Load stage has three events to help the programmer:

  1. PreInit
  2. Init
  3. InitComplete

In the PreInit event the controls don’t even exist yet. They have not been created.

If you set a property like the Text of a TextBox in these events this value will be lost in future stages when the control is loaded. If you want to use these events you need to declare the following methods in your code:

void Page_PreInit(object sender, EventArgs e)
    {

    }

    void Page_Init(object sender, EventArgs e)
    {

    }

    void Page_InitComplete(object sender, EventArgs e)
    {

    }

Load

This is an important stage for us because it is here that the values of the controls are loaded. Before this stage you might have the controls but it’s values have are not there yet.

The Load stage has three events to help the programmer:

  1. PreLoad
  2. Load
  3. LoadComplete

We have used the Page_Load event in our previous examples to create our dynamically created controls. The thing to watch is that when these controls are created they don’t have it’s values from the page loaded yet. If you want to get the values from the controls you can only do it in the Page_LoadComplete event. Only then all the values of the controls will be loaded.

You can test this using creating the method for each of these events and using the debugger to check the controls we the event is hit.

void Page_PreLoad(object sender, EventArgs e)
    {

    }

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }
        }
    }

    void Page_LoadComplete(object sender, EventArgs e)
    {

    }

Notice that I have used the Load event defined in the previous articles but the methods for the other events are new. If you set a breakpoint and use the Watch to inspect the controls you can see when the values have been loaded.

Ok, so if you need to create the controls you do it where we’ve been doing up to now: In the Page_Load

If you need to get the values from these controls right after you loaded them you need to wait for the Page_LoadComplete event.

Well, I hope this info was useful.

Add Controls Dynamically - Part 4

The part 3 of this series was getting a bit long for my taste so I decided to break it in 2. Here we’ll continue dealing with the controls added dynamically to our page only now we’re going to access them by ID.

Related posts:

Naming the controls

By now you have noticed that we haven’t explicitly set the ID of any of our controls. Of course the controls have ID’s but they are defined automatically by the Asp.Net framework when the controls are instantiated. The reason this works is because the framework will create the names consistently the same, again and again as long as you create the controls always in the same order (we are doing that).

It is this automatically naming feature that allows our components to keep their state between requests. When the page is submitted all of the controls states are sent back from the browser to the server, but the server doesn’t know how to create the controls that’s why we had to do it every time the page is submitted. After the control has been created the Asp.Net framework is able to get it’s state from the page based on it’s name.

Ok, enough theory. Let’s give our controls and ID manually. Since the controls are added dynamically the ID’s have to be something that can be predicted. Let’s say: TextBox + a number. For this will change the createDynamicControls method to add a parameter which will be the number of the control added.

//this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

When the add control button is clicked we need to pass the number to the method. We can use the control count that we’re storing in the ViewState.

protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

Another place we need to change is the Page_Load event when the controls are re-created. Here for loop when we pass in the new parameter:

 for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }

To test our new functionality we will add TextBox, a Button and a Label. We are going to inform the ID of the TextBox we want to get the value for. When the button is clicked the event will get the control and display it’s value in the label.

<asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Valor: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>

And here is the event where we get the TextBox we want:

protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }

Now if you add 3 TextBoxes (which will have id’s TextBox0, TextBox1 and TextBox2) and you input TextBox0 in the interface and hit the button the LabelValue control will show the value in the first TextBox.

This one was a bit longer than I would like to so I’ll try to make the next article shorter.

Here is the final version of our page after all of our modifications:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                //notice that now we pass the i as parameter
                createDynamicControls(i);
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls((int)ViewState["count"]);
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;
    }

    //this method takes care of creating the controls
    private void createDynamicControls(int count)
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        //now we set the control ID manually
        tb.ID = "TextBox" + count;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

    protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }

    protected void ButtonGetValue_Click(object sender, EventArgs e)
    {
        //find the control we want using the name informed by the user in the 
        //TextBoxControlId control
        TextBox tb = (TextBox)PlaceHolder1.FindControl(TextBoxControlId.Text);
        LabelValue.Text = tb.Text;
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
        <br />
        <asp:Button ID="ButtonAdd" runat="server" Text="Add all values" 
            onclick="ButtonAdd_Click" />
        <br />
        Total:<asp:Label ID="LabelTotal" runat="server" Text=""></asp:Label>
        <br />
        <br />
        <asp:TextBox ID="TextBoxControlId" runat="server"></asp:TextBox>
        <asp:button ID="ButtonGetValue" runat="server" text="Get value" 
            onclick="ButtonGetValue_Click" />
        Value: <asp:Label ID="LabelValue" runat="server" Text=""></asp:Label>
    </div>
    </form>
</body>
</html>

See you next time.

Add Controls Dynamically - Part 3

On the last article of this series we saw how we could assign event handlers to dynamically created controls and how the PlaceHolder control could help us add the controls in a more organized way.

Related posts:

In this article I want to show how you can keep a reference of a dynamically created control so that you can use it later somewhere else in your code. For this I’ll continue using the code created add the end of the last article of this series.

Now that you can add as many TextBoxes to the form as you want let’s say that you want to use them to input numeric values and then add up all the values for display. The first thing then is to decide where do we want to keep the reference to the controls. I chose to use a generic list of TextBox (List) but you could have chosen another structure that you feel more comfortable with.

System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

Now that the list is declared and created the next step is deciding when we are going to add the controls to the list. To me using the method that adds the controls dynamically feels like the best choice, maybe someone has another idea (please share if you do). So the method would look like this:

 private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

Easy, right? Ok, the last step now is adding a button to the form that will call the logic to add the values within all the controls and add a label that will display the result of the addition. The logic for adding the values is very simple, once you have a list with all the controls you only need to iterate through the list, get the value of the control and add it to a variable. Here is the code:

 protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }

Please notice that I have assumed that all the TextBoxes are provided with valid numeric values. We could improve the code to check for empty values and conversion errors however this is not the main goal of this article. Here is a complete version of the page after all our changes were made:

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    System.Collections.Generic.List<TextBox> controlsList = new System.Collections.Generic.List<TextBox>();

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                createDynamicControls();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls();
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;        
    }

    //this method takes care of creating the controls

    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        PlaceHolder1.Controls.Add(tb);
        controlsList.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

    protected void ButtonAdd_Click(object sender, EventArgs e)
    {
        int value = 0;
        foreach (TextBox tb in controlsList)
        {
            value += int.Parse(tb.Text);
        }
        LabelTotal.Text = value.ToString();
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <br />
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
        <br />
        <asp:Button ID="ButtonAdd" runat="server" Text="Add all values" 
            onclick="ButtonAdd_Click" />
        <br />
        Total:<asp:Label ID="LabelTotal" runat="server" Text=""></asp:Label>
    </div>
    </form>
</body>
</html>

 

Visual Studio 2008: WebForms Designer Annoyingly Slow

Lately one of the developers of my team had been complaining that the WebForms designer was very slow. Editing properties of controls was taking forever and switch from code view to design view was a test to his patience. He was the only one in the team having this problem but it didn’t take very long for me to find out that Microsoft has published a hotfix to deal with this issue among others.

If your Visual Studio is really slow take a look at the Visual Web Developer Team Blogfor the full list of issues addressed and the download link.

Design Pattern: Singleton

This is the first post on a series about Design Patterns using C#. I will not publish all the articles in a sequence but you can expect from time to time to have a new post about some pattern.

The first pattern I want to talk about is the Singleton.

Objective

You need a singleton when your application require one and only one instance of a single class and also that this instance can be accessed whenever necessary.

Case Scenario

Imagine that you want a Logger class that will store all messages in a internal list. You need the hold the all the messages in a single place. If you had more than one instance of a Logger class you would have the messages scattered over the various instances. To avoid this will use a singleton.

The Solution

We are going to create a Logger class in our example.

The first issue the singleton should handle is how to prevent users from creating multiple instances of a class. To achieve this you have to block (hide) the constructor. This can be done making it private.

private Logger() { }

Now the that the constructor is private how can you instantiate the class? You are right, you can’t do it from outside the class so we are going to do it from the inside. Since we need to keep the one instance we create we need a variable to hold it. We are going to declare this variable as static so that we don’t need the class to be instantiated in order to keep the value.

//this will hold our unique instance
private static Logger instance = null;

The next step is to come up with a way to create the only instance and at the same time gain Access to that instance. This can be done using a static method that will check the instance variable and if it is null it will create a new instance and return it, if it’s not null it will return the previously create instance.

public static Logger Instance()
        {
            //if the instance is null you have to instantiate it
            if (instance == null)
            {
                instance = new Logger();
            }
            return instance;
        }

This is all we need for our singleton but we still need to add the functionality for the Logger class. We need a list to store the messages, a method to add new messages and a method to print all the messages already stored. Here is the code for it:

//holds all the messages
        private List<string> messages = new List<string>();

        //add a new message to the Logger
        public void Log(string message)
        {
            messages.Add(message);
        }

        public void PrintAllMessages()
        {
            foreach (string message in messages)
            {
                Console.WriteLine(message);
            }
        }

Here is the code for the whole class:

public class Logger
    {
        private static Logger instance = null;

        private Logger() { }

        public static Logger Instance()
        {
            //if the instance is null you have to instantiate it
            if (instance == null)
            {
                instance = new Logger();
            }
            return instance;
        }

        //holds all the messages
        private List<string> messages = new List<string>();

        //add a new message to the Logger
        public void Log(string message)
        {
            messages.Add(message);
        }

        public void PrintAllMessages()
        {
            foreach (string message in messages)
            {
                Console.WriteLine(message);
            }
        }
    }

How to use it

Using the singleton is easy, the only difference from normal class use is that when you need an instance of the object you will not be able to call the constructor (it’s private now) so you need to request an instance through the Instance() method that we created.

In our usage examples I’ll declare two logger variables and pass different messages to each one. Since there’s only one instance both these variables will have references to the same object. This can be verified when you call the PrintAllMessages method of any of the loggers. You’ll notice that they will print all the messages that were passed to any of the variables.

Here is the code so you can test it at home:

 class Program
    {
        static void Main(string[] args)
        {
            Logger logger1 = Logger.Instance();
            Logger logger2 = Logger.Instance();

            logger1.Log("loading one");
            logger2.Log("loading two");

            logger1.Log("Success");
            logger2.Log("Failure");

            logger1.PrintAllMessages();
        }
    }

That’s it for the Singleton, I hope this is useful to someone somewhere :-)

 

Add Controls Dynamically - Part 2

This post continues what’s been done in the Part 1

On my last post I talked about creating controls dynamically in asp.net. In this post I’m going to continue with common issues or needs that users have based on what I noticed on the Asp.Net Forums

Related posts:

First I want to talk about assigning events to the controls that we are creating, this is a simple task but still and important topic.

Adding Events

The first thing we need to do is create a method that will be the handler for the event. When the event is fired on the control this is the method we want to be called to handle the event. In our example we are using TextBoxes so we want to handle the TextChanged event and make the background of the control yellow. Here is the method:

private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }

The name of the method is irrelevant but it’s return type and parameters are not. If you create an event through VisualStudio you’ll notice that the signature of the method is the same.

Now that we have the method we need to set this method as the handler for the event on the controls that we are creating. Adding the method to the controls handler is as simples as this:

tb.TextChanged += TextBox_TextChanged;

If you add your controls now all of them will have this handler and it’s background will turn yellow (after submit) if you change the content of the textbox.

PlaceHolder

Up until now we’ve been adding the controls directly to the Form. This will cause the controls to be added to the end of the page after all other controls. This is fine as an example but might not be you desired result. We will you the PlaceHolder control as a container to our controls, this way we can put the PlaceHolder wherever we want in the page and the controls will be added within it.

Another advantage of the PlaceHolder control is that it doesn’t generate any html, it’s just the to serve (as it’s own name says) as a place holder. So you don’t need to worry about adding extra html just to have a place to put your controls in.

In our example I will put the PlaceHolder before the button that we are using just to show that the controls will no longer be added to the end of the page.

The new page with the events and the PlaceHolder control will be like this:

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                createDynamicControls();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls();
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;        
    }

    //this method takes care of creating the controls
    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        tb.TextChanged += TextBox_TextChanged;
        PlaceHolder1.Controls.Add(tb);
    }

    private void TextBox_TextChanged(object sender, EventArgs e)
    {
        //the sender is the control that fired the event
        //that is the control we want to change the color
        TextBox tb = (TextBox)sender;
        tb.BackColor = System.Drawing.Color.Yellow ;
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

Stay tuned for more about dynamically created controls.

Add Controls Dynamically

Dynamic controls are an interesting topic that keep showing up in the asp.net forums. I’ll try to explain the main points about creating and working with dynamically created controls in a few articles (this one would be too long otherwise).

First of all there are two points you need to understand:
  1. Adding the controls dynamically is easy, the tricky part is getting them to stick around.
  2. The controls are not kept between postbacks therefore you have to keep recreating them every time there is a postback.
  3. The best place to recreate the controls in the Page_Load or Page_Init events.

Creating a new control is easy, it’s just a matter of instantiate the class. Adding the control to the page is also easy you only need to add the new control to the page controls.

//create a new textbox
TextBox tb = new TextBox();
//add the new textbox to the page
Page.Form.Controls.Add(tb);

You’ve seen how easy it is to add the controls but if you don’t keep recreating them when you submit the page the dynamic controls will be gone.

First understand that this need to be recreated is not exclusive for dynamic created controls. Every time there is a postback the whole page is recreated. The difference is that all the controls that are declared in the aspx page are created automatically what gives the user the impression that the controls are always there (they are not!).

Since dynamically created controls are not hard coded anywhere (obviously) you are the one responsible for recreating them.

If you create a control in the Page_Load event you’ll notice that it works just like any control already in the aspx page:

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        TextBox tb = new TextBox();
        Page.Form.Controls.Add(tb);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    </div>
    </form>
</body>
</html>

Granted that if you could create the control like this you might declare it in the aspx page as well. Ok, so let’s improve our example and create a button that adds one and only one edit to the page. If the edit already exists the button won’t do any thing.

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        //means that the control has been created already so you 
        //need to recreate it
        if (ViewState["tb"] != null)
        {
            createDynamicControls();
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        //means the control has not been created yet
        //create the control and store the viewstate
        if (ViewState["tb"] == null)
        {
            createDynamicControls();
            ViewState["tb"] = true;
        }        
    }

    //this method takes care of creating the controls
    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        Page.Form.Controls.Add(tb);
    }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

Notice that in this version of the code I created a method responsible for creating the dynamic control. This will help to encapsulate the method creation and avoid duplicating code. Also notice that I’m using the ViewState to help maintain a variable that indicates if the control has been added yet in order to avoid duplication.

When the user clicks the button I check my ViewState variable to see if the TextBox has been created, if it hasn’t I create the TextBox, add it to the page and set the ViewState variable. Now, as long as you don’t leave the page the control and it’s state will be maintained.

We could also let the user add an undefined number of TextBoxes to the page making some small changes.

<script runat="server">

    void Page_Load(object sender, EventArgs e)
    {
        //when the user first enters the page set the count as zero
        if (!IsPostBack)
        {
            ViewState["count"] = 0;
        }
        //on every subsequent postback, check the control count
        //and recreated all the controls
        else
        {
            int controlCount = (int)ViewState["count"];
            for (int i = 0; i < controlCount; i++)
            {
                createDynamicControls();
            }
        }
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        createDynamicControls();
        //increment the number of controls
        ViewState["count"] = (int)ViewState["count"] + 1;        
    }

    //this method takes care of creating the controls
    private void createDynamicControls()
    {
        TextBox tb = new TextBox();
        Page.Form.Controls.Add(tb);
    }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Add TextBox" 
            onclick="Button1_Click" />
    </div>
    </form>
</body>
</html>

Now you are able to add any number of controls keeping the state of them all. On my next post I’ll keep working with dynamic created controls so stay tuned.

Related posts:

Bind DropDownList to Enum

Unfortunately you can’t Databind an Enum to a DropDownList or to any control for that matter. You can however transform the Enum into something “bindable” like a HashTable.

First let’s define an Enum to use in our example:

public enum Cars
{
    Ford = 1,
    Kia = 2, 
    Mitsubishi = 3,
    Volkswagen = 4
}

Now that we have a method that will allow an enum to a HashTable all we need to do is bind the hash to the DropDownList.

//call our previously defined method to create the HashTable
        Hashtable ht = GetEnumForBind(typeof(Cars));

        //set the HashTable as the DataSource
        DropDownList1.DataSource = ht;
        //set the value of the Hash as the display
        DropDownList1.DataTextField = "value";
        //set the key of the Hash as the value
        DropDownList1.DataValueField = "key";

        DropDownList1.DataBind();

That is it, it should now bind without problems. There are alternate solutions that do not involve binding but instead adding each item of the enum to the DropDownList. You can take a look at the asp.net forums to see alternate solutions proposed by other members.