Geeks With Blogs
The Quandary Phase This code was generated by a tool.

I recently posted a short article on avoiding the use of dynamic controls in ASP.NET; for part 1, please click here.

Part 1 demonstrated the basics of using a listview control to dynamically generate a table containing a number of textboxes, allowing the user to select how many textboxes are required at runtime. This is the type of problem that is best solved without the use of dynamic controls, and part 1 explained why this is so.

This article will extend the code from part 1, to show how to preserve the values of the textboxes between postbacks.

When you run the code from the original article, you will notice that any existing values entered into the textboxes are lost each time a new textbox is added. This would make for a pretty user-unfriendly UI experience in a real-world application. Luckily, the solution is straightforward.

The first change I have made is to alter the databinding methodology slightly, so that the listview is now bound to a collection of strings, rather than a collection of integers. The integer collection served no purpose in the original article, other than to provide an IEnumerable implementation to databind to. Now the datasource will actually be a data source: it will be used to track the textbox text values.

First off, a reminder of the original page markup, which will remain unchanged:

<asp:ListView ID="lvDynamicTextboxes" runat="server" 
    ItemPlaceholderID="itemPlaceholder" 
    onitemdatabound="lvDynamicTextboxes_ItemDataBound">
    <LayoutTemplate>
        <table>
            <asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
        </table>
    </LayoutTemplate>
    <ItemTemplate>
        <tr>
            <asp:TextBox ID="txtText" runat="server">
            </asp:TextBox>
        </tr>
    </ItemTemplate>
</asp:ListView>
<br />
<asp:Button ID="btnAddTextBox" runat="server" 
    Text="Add" onclick="btnAddTextBox_Click" />

The initial alteration I made was to add two methods for saving and retrieving the string collection which will be the new data source for the listview control:

private List<string> GetDataSource()
{
    List<string> dataSource = null;
    if (ViewState["DataSource"] != null)
    {
        dataSource = (List<string>)ViewState["DataSource"];
    }
    else
    {
        dataSource = new List<string>();
        dataSource.Add(string.Empty);
        ViewState["DataSource"] = dataSource;
    }
    return dataSource;
}
 
private void SetDataSource(List<string> dataSource)
{
    ViewState["DataSource"] = dataSource;
}

I chose to use ViewState for persisting the collection, given that we are unlikely to be dealing with a large number of textboxes, so the collection size will remain fairly small.

Next up, I re-jigged the method which originally incremented the textbox count in ViewState, so that it increases the data source collection size by one instead:

private void IncrementTextboxCount()
{
    List<string> dataSource = this.GetDataSource();
    dataSource.Add(string.Empty);
    this.SetDataSource(dataSource);
}

The next step was to create a method which persists the existing textbox values. This is going to be called before rebinding the listview, and is the key method which will ensure the values are preserved:

private void UpdateDataSource()
{
    List<string> dataSource = new List<string>();
    foreach (ListViewItem item in this.lvDynamicTextboxes.Items)
    {
        if (item is ListViewDataItem)
        {
            TextBox txt = (TextBox)item.FindControl("txtText");
            dataSource.Add(txt.Text);
        }
    }
    this.SetDataSource(dataSource);
}

The method above iterates through the ListView rows, identifying the data rows which contain the textboxes. It then gets a reference to the textbox using FindControl, and stores the current text in the collection.

Finally, an event handler is added for the listview's ItemDataBound event, which allows the textbox text to be set for each row in the data source, as it is being databound:

protected void lvDynamicTextboxes_ItemDataBound(object sender, ListViewItemEventArgs e)
{
    if (e.Item is ListViewDataItem)
    {
        TextBox txt = (TextBox)e.Item.FindControl("txtText");
        txt.Text = ((ListViewDataItem)e.Item).DataItem.ToString();
    }
}

The DataItem property of the ListViewDataItem contains a reference to the item in the datasource collection which is currently being databound. As we are binding to a collection of strings, I simply call ToString() on the dataitem, as we know this will be of string type,

So, finally putting it all together we get:

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        this.BindListView();
    }
}
 
private void BindListView()
{
    //create an enumerable range based on the current count
    List<string> dataSource = this.GetDataSource();
 
    //bind the listview
    this.lvDynamicTextboxes.DataSource = dataSource;
    this.lvDynamicTextboxes.DataBind();
}
 
private void UpdateDataSource()
{
    List<string> dataSource = new List<string>();
    foreach (ListViewItem item in this.lvDynamicTextboxes.Items)
    {
        if (item is ListViewDataItem)
        {
            TextBox txt = (TextBox)item.FindControl("txtText");
            dataSource.Add(txt.Text);
        }
    }
    this.SetDataSource(dataSource);
}
 
private void IncrementTextboxCount()
{
    List<string> dataSource = this.GetDataSource();
    dataSource.Add(string.Empty);
    this.SetDataSource(dataSource);
}
 
private List<string> GetDataSource()
{
    List<string> dataSource = null;
    if (ViewState["DataSource"] != null)
    {
        dataSource = (List<string>)ViewState["DataSource"];
    }
    else
    {
        dataSource = new List<string>();
        dataSource.Add(string.Empty);
        ViewState["DataSource"] = dataSource;
    }
    return dataSource;
}
 
private void SetDataSource(List<string> dataSource)
{
    ViewState["DataSource"] = dataSource;
}
 
protected void btnAddTextBox_Click(object sender, EventArgs e)
{
    this.UpdateDataSource();
    this.IncrementTextboxCount();
    this.BindListView();
}
 
protected void lvDynamicTextboxes_ItemDataBound(object sender, ListViewItemEventArgs e)
{
    if (e.Item is ListViewDataItem)
    {
        TextBox txt = (TextBox)e.Item.FindControl("txtText");
        txt.Text = ((ListViewDataItem)e.Item).DataItem.ToString();
    }
}

And the page now not only allows the user to dynamically increase the number of textboxes displayed, but also preserves all existing values each time a new textbox is added.

You can download the full source code using the link at the top of the article.

Posted on Thursday, October 23, 2008 12:39 PM | Back to top


Comments on this post: ASP.NET: Alternatives to Dynamic Controls - Part 2

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Just what I was looking for. Thanks!
Left by Ken on Feb 22, 2009 3:05 AM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
THis is great! Thanks mate - i do have a question though that i am trying to figure out.

How to add other fields around this and do an INSERT using the ListView control.
Left by Gavin on Feb 23, 2009 8:41 PM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
This is a great post. Thanks!

Do you have any thoughts or advice on being able to extend this for adding dynamic "types" of controls? (i.e. when you don't know how many controls OR don't know at design-time which TYPE of control to render)

For example, I have a user control that is getting from the database a list of user preferences (one to many) which render on the user form as a control based on applicability to the Type of control to render (e.g. DropDownList (single choice), TextBox (single entry), CheckBoxList (multiple choice), etc.).

I've built this , but I've dynamically created the controls and added them to the user control with the type that is created being determined by a switch statement based on data from database.

e.g.
switch (pref.ControlType)
{
case ControlType.Dropdown:
control = new DropDownList();
// populate the Items, etc. here
break;
case ControlType.Checkbox:
control = new CheckBoxList();
//etc.
break;
}

Any thoughts on making this better?

Left by Rich on Mar 25, 2009 4:20 PM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Thank you for the interesting articles.

If you know of a book that gives a full explanation of the ASP.NET ListView control, could you please let me know?

Thank you very much for your trouble.

Eric
Left by Eric on Apr 29, 2009 5:57 PM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Great post man, I was thinking this same approach as to solve this problem, glad you wen way ahead of me!

Thanks!
Left by murki on Jun 04, 2009 6:57 AM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Hi. It's good tutorial.t
Thanks.

I have some question.
How I should modify the code if I want to add Remove button and Add button near the textbox in case user should to remove some row (from the middle, or from the end), or to add some row in the button clicked position?

This very important for me. I hope your quickly answer.

Thanks
Left by Akim Khalilov on Jul 25, 2009 4:26 AM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Thank you very much ... THIS IS EXACTLY what I was looking for ... By the way, I have a site working on Framework 2.0 so to my code I did some tweaks to work with an asp:Repeater control and works great! ... I will also post this method in my blog (in Spanish) and will mention you as the source.
Thanks!
Left by Hector Hernandez on Oct 25, 2009 10:50 AM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Great Work. It will solve many problems which we face while using dynamic control.
Left by Muhammad Farhan on Jul 02, 2010 2:25 AM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
Do you know to do this with duplicating multiple text boxes? When I try it puts the content in the wrong sections
Left by Bryan on Jul 06, 2010 1:57 PM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
This is great. How about if the control is not a TextBox but a custom UserControl, can this be used?

_hector
Left by Hector Sanchez on Sep 29, 2010 8:28 AM

# re: ASP.NET: Alternatives to Dynamic Controls - Part 2
Requesting Gravatar...
I have some question.
How I should modify the code if I want to add Remove button and Add button near the textbox in case user should to remove some row (from the middle, or from the end), or to add some row in the button clicked position?
Please answer my question,I really thank you for it..
Left by Indonesian Teak Garden Furniture on Dec 07, 2010 5:22 AM

# 先生
Requesting Gravatar...
I am thoroughly convinced in this said post. I am currently searching for ways in which I could enhance my knowledge in this said topic you have posted here. It does help me a lot knowing that you have shared this information here freely.
Left by Cheap Ray Ban Sunglasses on Mar 17, 2011 8:55 PM

Comments have been closed on this topic.
Copyright © Adam Pooler | Powered by: GeeksWithBlogs.net