Sunday, October 19, 2008

DropDownList asp.net Control problems and challanges faced using appenddatabound items and autopostbacks

Sometimes we need a solution where we have to append certain hardcoded values which are given in the markup and then we have to append some values from the database after these hardcoded values.

These hardcoded value can be a single item saying "Select" or "Remove" or a list of asp list items.

So if we are not following the right steps in the sequence of databinding and clearing items from the dropdownlist control, this control may act a little different as we would have thought and create havoc in our programming life.

Today while building an application i came accross the similar situation where i have two dropdownlists one is "ddlCategories " where current categories to which a post belongs are coming form the datasource it alos has a listitem value which is hardcoded in the markup saying Remove Existing Categories which have a value of -1 and index value 0.

There is one more list called "ddlAddUserCategories" in which all the categories related to particular user are databound using the datasource.

Here also we are having a hardcoded value same as above but having a different text saying that Add Existing Categories....

Markup is give below

 1: <td>
 2: <asp:DropDownList ID="ddlCategories" runat="server" AutoPostBack="true" SkinID="ddlBlue"
 3: EnableViewState="true" OnSelectedIndexChanged="ddlCategories_SelectedIndexChanged">
 4: <asp:ListItem Text="Remove Existing Categories...." Value="-1" Selected="True" />
 5: </asp:DropDownList>
 6: <span class="spanAddCategory">Remove Existing Categories</span>
 7: </td>
 8: <td>
 9: <asp:DropDownList ID="ddlUserCategories" runat="server" AutoPostBack="true" SkinID="ddlBlue"
 10: EnableViewState="true" OnSelectedIndexChanged="ddlUserCategories_SelectedIndexChanged">
 11: <asp:ListItem Text="Apply Existing Categories....." Value="-1" Selected="True" />
 12: </asp:DropDownList>
 13: <span class="spanAddCategory">Apply Existing Categories</span>
 14: </td>

Now i want that whenever i postback using the autopostback property of the dropdownlist

i should have changes reflected in both the dropdownlists.

So first of all remember to keep the datasource and databinding code sequence inside

if (!Page.IsPostBack).If you simply keep it inside the page load event,every time the page loads it will again overwrite the values and you may lead to a situation in which even if you selecte different values, then also the same value for the selectedindex is returned.So to prevent this always keep your datasource code for the dropdownlist inside if(!Page.IsPostBack)

 1: protected void Page_Load(object sender, EventArgs e)
 2: {
 3:  
 4: if (!Page.IsPostBack)
 5: {
 6:  
 7: ddlCategories.DataSource = CategoryManager.PopulateCategoriesOfPost(post.PostID);
 8: ddlCategories.DataTextField = "CategoryName";
 9: ddlCategories.DataValueField = "CategoryID"; 
 10: ddlCategories.AppendDataBoundItems = true; 
 11: ddlCategories.DataBind(); 
 12: ddlUserCategories.DataSource = CategoryManager.PopulateUserCategory(BasePage.UserID); 
 13: ddlUserCategories.DataTextField = "CategoryName"; 
 14: ddlUserCategories.DataValueField = "CategoryID"; 
 15: ddlUserCategories.AppendDataBoundItems = true; ddlUserCategories.DataBind();
 16:  
 17: }
 18:  
 19: }

Now just go through the code for ddlCategories_SelectedIndexChanged and ddlUserCategories_selectedIndexChanged

 1: protected void ddlCategories_SelectedIndexChanged(object sender, EventArgs e)
 2: { 
 3: int postID = Int32.Parse(Request.QueryString["postID"].ToString());
 4: string categoryName = ddlCategories.SelectedItem.ToString();
 5: CategoryManager.RemoveCategoryFromPost(categoryName, postID); 
 6: ddlCategories.Items.Clear(); 
 7: ddlCategories.Items.Add("RemoveExistingCategories...."); 
 8: ddlCategories.Items[0].Value = "-1"; 
 9: ddlCategories.DataSource = CategoryManager.PopulateCategoriesOfPost(postID); 
 10: ddlCategories.DataTextField = "CategoryName"; 
 11: ddlCategories.DataValueField = "CategoryID"; 
 12: ddlCategories.AppendDataBoundItems = true; 
 13: ddlCategories.SelectedIndex = 0; 
 14: ddlCategories.DataBind(); 
 15: } 
 16:  
 17:  
 18: protected void ddlUserCategories_SelectedIndexChanged(object sender, EventArgs e)
 19: {
 20: int postID = Int32.Parse(Request.QueryString["postID"].ToString()); 
 21: string categoryName = ddlUserCategories.SelectedItem.ToString(); 
 22: CategoryManager.AddCategoryToPost(categoryName, postID); 
 23: ddlUserCategories.SelectedIndex = 0; 
 24: ddlCategories.Items.Clear(); 
 25: ddlCategories.Items.Add("RemoveExistingCategories...."); 
 26: ddlCategories.Items[0].Value = "-1"; 
 27: ddlCategories.DataSource = CategoryManager.PopulateCategoriesOfPost(postID); 
 28: ddlCategories.DataTextField = "CategoryName"; 
 29: ddlCategories.DataValueField = "CategoryID"; 
 30: ddlCategories.AppendDataBoundItems = true; 
 31: ddlCategories.DataBind();
 32: }

In this donot forget to clear the items otherwise you will again get creepy results which are far beyond your expectations.

So the tip of the day is whenever you want to refresh your list with the new changed database values just clear the existing values and than only start inserting the most recent values from the database.

Some people will suggest to Disable the viewstate but i have tried that it can overcome the problem of appending values i.e it stops the appendingvalues which means now it will not remember your existing state but it will cause problems in the situation mentioned above so for me this is the best solution.

If you have a better solution do leave a comment.

8 comments :

Bartekm said...

This is a very good article, and you've shown an elegant solution to a common problem.

Another issue that you may encounter though is that the dropdownlist may not contain your data record (because the record may have been deleted) and you get the dreaded 'dropdownlist1' has a SelectedValue which is invalid because it does not exist in the list of items'

There is a simple solution to this problem postedhere.

Thanks again!

Anonymous said...

People really should get in the habit of reducing undeeded nesting.

i.e. convert the if statement to if (this.IsPostback) return;

Kave said...

@Anonymous,
But ultimately you have to write that piece of code which is executed when there is no postback.
So there is no point in this condition to use if(this.IsPostback)return;
Above code will be achieving the same result.
In your case also we have to give other peice of code outside the if condition.
So what's the point in that.
If i have misunderstood something sorry for my ignorance and if you have a point do correct me.This solution looks fine to me although i have not tested it myself.

Anonymous said...

hmmm unless you all haven't paid much attention to compilers they are aware of code and conditions; it will do that anyways; so your return statement is not needed.

The compilers created nowadays are smarter than most give credit to them.

DotNetURL said...

Hi,

Nice blog..publish you new content url at www.dotneturl.com and get reader and back link form us for free.

Rem said...

nice blog...
visit also asp.net example

Shakti Singh Dulawat said...

This is very nice example mention my you, this is helpful for programming logic.
Thanks
Shakti
www.nextmvp.blogspot.com

Aashish said...

@all
Thanks for your valuable comments

Post a Comment