Dynamically adding dropdownlists without data loss - c#

Ok so I've been working on this for like... I don't know, 5 hours? I'm pulling my hair out starting to think it's just not possible with asp.net! ugh! I've looked at all kinds of resources (I even tried implementing DynamicControlsPlaceholder that was created by someone else years ago - which failed miserably). So here's the issue in hopes someone here has a solution!
I'm trying to have a page where the user can dynamically add DropDownLists without forgetting the values they set in the previous lists. So for example, let's say the user is given 1 DropDownList and chooses index 2. There will be a button below that says "Add" and that will add another DropDownList. When doing this, however, the page does a postback and the previous DropDownList loses the value of index 2 and resets back to index 0 instead. I can't figure out how to save the state of the DropDownList before the postback is made. The point of this is so that when the user is complete, they can click "Submit" with all the values made in the DropDownLists. Here's the code I currently have (that's important) which simply regenerates the same number of DropDownLists as there's supposed to be (based on the ViewState["layoutCount"]). Naturally, I should be able to "restore" the index that was selected before a reload of the page...
aspx file:
<table style="text-align:center; width:60%;">
<asp:Panel ID="layoutAreaPanel" runat="server" CssClass="paragraphStyle" />
</table>
<asp:Button ID="cmdLayout1AddPage" runat="server" OnClick="cmdLayout1AddPage_Click" />
C#:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
CreatePanelInfo();
}
....
protected void CreatePanelInfo()
{
int layoutCount = 0;
if (ViewState["layoutCount"] != null)
layoutCount = (int)(ViewState["layoutCount"]);
for (int i = 0; i < layoutCount; i++)
{
TableRow mainRow = new TableRow();
TableCell labelCell = new TableCell();
TableCell dropDownListCell = new TableCell();
Label cellLabel = new Label();
cellLabel.Text = Language.GetLanguageText("ADDPAGE_PAGE", this.Page);
cellLabel.CssClass = "paragraphStyle";
labelCell.HorizontalAlign = HorizontalAlign.Right;
labelCell.Controls.Add(cellLabel);
DropDownList pnlDropDownList = new DropDownList();
pnlDropDownList.ID = "pnlDropDownList" + (i + 1);
pnlDropDownList.BorderWidth = 1;
pnlDropDownList.Width = new Unit("100%");
FillPageList(ref pnlDropDownList); //adds items to the list
dropDownListCell.Controls.Add(pnlDropDownList);
mainRow.Controls.Add(labelCell);
mainRow.Controls.Add(dropDownListCell);
layoutAreaPanel.Controls.Add(mainRow);
}
ViewState["layoutCount"] = layoutCount + 1;
}
....
protected void cmdLayout1AddPage_Click(object sender, EventArgs e)
{
CreatePanelInfo();
}
Hopefully that's enough information to get a good answer... :S

Only make your dropdown lists making a postback when their selected index changes.
In the code behind, store selections in Session variable.
public void AddDDL()
{
var tmp = new DropDownList();
tmp.SelectedIndexChanged += ddl_SelectedIndexChanged;
Page.Controls.Add(tmp);
}
protected void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
var ddl = sender as DropDownList;
var lists = Session["dropdownlists"] as Dictionary<DropDownList, int>;
lists[ddl] = ddl.SelectedIndex;
}
and finally in postback event set the selected indices again:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostback)
{
var lists = Session["dropdownlists"] as Dictionary<DropDownList, int>;
foreach (var item in lists)
item.Key.SelectedIndex = item.Value;
}
else Session["dropdownlists"] = new Dictionary<DropDownList, int>();
}
Postback is not recommended because it is not user friendly. You should use an UpdatePanel.

Related

Getting value of dropdownlist that's added onrowdatabound asp.net c#

I'm querying a database filling a gridview with values, also adding dropdown boxes into each cell within the dataview 'onrowdatabound' so these DDL's are populated when the gridview is populated.
I want to be able to click a button to get values from these DDL's however when the button is clicked postback happens and all the DDL's disappear and it gives me the default value for the DDL.
I assume they dissapear as they're not called on pageload (which I can't seem to do as they're called onrowdatabound)
<asp:GridView id="View" name="Spview" onrowdatabound="populateCellswithDDls" runat="server"></asp:GridView>
Adding the ddl with inside 'populateCellswithDDls' function looping each cell:
e.Row.Cells[i].Controls.Add(DDL1);
The next thing I've have a play with is ViewState and Sessions to save the dropdownlists on postback(Tried making sessions within 'populateCellswithDDls' function as so:
DropDownList DDL1 = new DropDownList();
//I've tried newSkillsMon.AutoPostBack = true; but this just removes them all too
Session.Add("ViewState", View);
Session.Add("DropdownState", DDL1);
I've tried all sorts do to with viewstate and session but unsure where to use them in relation to saving states the 'onrowdatabound' population.
My button currently looks like this:
protected void confirm_Click(object sender, EventArgs e){
{foreach (GridViewRow row in View.Rows)
// if (DDL1.SelectedItem.Value != "Select Item"){
if (IsPostBack)
{
Debug.WriteLine(DDL1.SelectedValue);
}
This just gives me X amount of "Select Item" rather than what i have selected in the DDL
What am I missing, where would I add these sessions to keep the ddl's created by onrowdatabound?
Thanks
When creating dynamic controls, you need to recreate them on every Page Load and that includes a PostBack. So start with binding the GridView data outside an IsPostBack check.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//normally you would bind here
}
//but now bind grid every page load
GridView1.DataSource = Common.LoadFromDB();
GridView1.DataBind();
}
Now in the RowDataBound event make sure the DropDownList has an ID
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
//check if the row is a datarow
if (e.Row.RowType == DataControlRowType.DataRow)
{
//create a dropdownlist and assign an ID
DropDownList DDL1 = new DropDownList();
DDL1.ID = "DDL1";
//add some dummy listitems
DDL1.Items.Insert(0, new ListItem() { Text = "A", Value = "A" });
DDL1.Items.Insert(1, new ListItem() { Text = "B", Value = "B" });
DDL1.Items.Insert(2, new ListItem() { Text = "C", Value = "C" });
//add the control to the row
e.Row.Cells[0].Controls.Add(DDL1);
}
}
Now you can get the value from the correct row on a button click.
protected void Button1_Click(object sender, EventArgs e)
{
//find the dropdownlist in the correct row and cast it back to one
DropDownList DDL1 = GridView1.Rows[i].FindControl("DDL1") as DropDownList;
//display the result
Label1.Text = DDL1.SelectedValue;
}
Something that might work for you instead of trying sessions is to use hiddenfields.
Make a hidden field for each dropdown location and then use javascript to populate the hidden fields with the dropdown values. (Possibly wanting some server side validation on submission)
Something like this with jQuery:
$(".dropdowns").on("change", function () {
$(this).closest('input:hidden').val($(this).val());
});
And in your confirmation:
if (HF_HiddenField1.Value != "Select Item")

Title of DropDownList's items is not shown in Chrome v.43

After a long time searching for this problem I've decided to try my luck here... I'm trying to add a tooltip (title) for the items in a Drop Down List.The title is showed in IE and Firefox browsers. The DDL is creating dynamically and the DDL's DataSource is a list called "labCourses" .This is my code:
protected void Page_Load(object sender, EventArgs e)
{
ExpScheduleClass ExpSC = new ExpScheduleClass();
List<string> labCourses = ExpSC.getCourseList();
// dynamically create a dropdown list (aka DDL)
DDLCourses = new DropDownList();
DDLCourses.DataSource = labCourses; // set the data source
DDLCourses.DataBind(); // bind the data to the DDL control
BindTooltip(DDLCourses);
DDLCourses.AutoPostBack = true;
DDLCourses.SelectedIndexChanged += DDLCourses_SelectedIndexChanged;
coursePH.Controls.Add(DDLCourses);
}
public void BindTooltip(ListControl lc)
{
for (int i = 0; i < lc.Items.Count; i++)
{
lc.Items[i].Attributes.Add("title", lc.Items[i].Text);
}
}
I looked at the option element with the web inspector and the title was there (in the html), but is does not shown when the mouse was over the option.
In other browsers the title is shown on mouse hover. What may be the cause for this? Thank you very much...

Show the page with particular item in RadGrid

I have a RadGrid that I supply with data using DataSourceID. The RadGrid has paging, and I want to show the page containing some particular item. To do this, I find the offset of the item in the data and set the page number:
var index = dataSource.Count(t => t.Id > _selectedTickId);
var page = index / rgTicks.PageSize;
rgTicks.CurrentPageIndex = page;
My question is where to put this code. In the OnDataBound I don't seem to have access to the data source. If I put it in the OnSelecting the retrieving of data has a side effect of setting the page number. Should I extend the GridTableView to implement this functionality? Which method should I override?
I will suggest to compute index value in OnSelecting (which is data dependent) while page index can be set in OnDataBound or PreRender event.
My usecase was to jump to an item that was just inserted using a popup editor. Here's how I solved it. I am omitting non relevant properties in the tag. All the data wiring is up to you, but here are the relevant bits. Important: use DataKeyNames to avoid messy digging in the GridDataItem for a value.
In the page I have:
<telerik:RadGrid ID="rgItems" runat="server" AllowPaging="true"
OnNeedDataSource="rgItems_NeedDataSource"
OnPreRender="rgItems_PreRender"
OnInsertCommand="rgItems_InsertCommand">
<MasterTableView
CommandItemDisplay="Top"
CommandItemSettings-AddNewRecordText="Add New Item"
CommandItemSettings-ShowAddNewRecordButton="True"
DataKeyNames="IntItemId"
EditMode="popup"
EditFormSettings-PopUpSettings-Modal="true">
And in code behind:
private bool itemInserted = false;
protected void rgItems_InsertCommand(object sender, GridCommandEventArgs e)
{
itemInserted = true;
}
protected void rgItems_PreRender(object sender, EventArgs e)
{
if (itemInserted)
{
// Select the record and set the page
int LastItem = 0; // Put code to get last inserted item here
int Pagecount = rgItems.MasterTableView.PageCount;
int i = 0;
GridDataItem GDI = null;
while (i < Pagecount)
{
rgItems.CurrentPageIndex = i;
rgItems.Rebind();
GDI = rgItems.MasterTableView.FindItemByKeyValue("IntItemId", LastItem);
if (GDI != null) break; // IMPORTANT: Breaking here if the item is found stops you on the page the item is on
i++;
}
if (GDI != null) GDI.Selected = true; // Optional: Select the item
itemInserted = false;
}
}

Dropdown gets cleared

I have one asp.net application, in which i have one dropdown which is binded to dataset. But after selecting one item, the drop down gets cleared all the value, How we can resolve this issue?
This is my dropdown list in design page:
<asp:DropDownList ID="ddlProduct" runat="server" CssClass="textEntry" Width="300px"
AutoPostBack="True" OnSelectedIndexChanged="ddlProduct_SelectedIndexChanged">
</asp:DropDownList>
and binding code is shown below.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
BindProductDdl();
}
private void BindProductDdl()
{
Products objProducts = new Products();
dsProducts dsProduct = new dsProducts();
ListItem olst = default(ListItem);
olst = new ListItem(" Select", "0");
dsProduct = objProducts.GetDataset("");
ddlProduct.DataSource = dsProduct;
ddlProduct.DataTextField = "Product";
ddlProduct.DataValueField = "Id";
ddlProduct.DataBind();
ddlProduct.Items.Insert(0, olst);
}
protected void ddlProduct_SelectedIndexChanged(object sender, EventArgs e)
{
Products objProducts = new Products();
dsProducts dsProduct = new dsProducts();
string criteria = "";
if (ddlProduct.SelectedItem.Text != " Select")
{
string id = ddlProduct.SelectedItem.Value;
criteria = "Id='" + id + "'";
dsProduct = objProducts.GetDataset(criteria);
productValue = Convert.ToDecimal(dsProduct.tblProducts.Rows[0]["Value"].ToString());
}
}
Thanks in advance..
From your question if I understand correctly you dont want the dropdown list to rebind if it is populated. Also please check your viewstate, this should not be happening, unless you have disabled viewstate
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack && ddlProduct.Items.count <=0 )
BindProductDdl();
}
Set the AppendDataBoundItems property of the dropdown to true and this will allow you to have a mix of databound items and non databound items (otherwise that insert statement is clearing your list)
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listcontrol.appenddatabounditems.aspx
Do you have viewstate disabled on the page? Since you are only loading the items into the dropdownlist on the first load of the page, if viewstate is not enabled there will be nothing in the list after the postback.
Not positive, but I've seen in other languages and false interpretation...
You have your product Value as convert of ToDecimal which implies 99.999 for example.
If your ID that you are binding to is based on a whole number (ie: Integer basis), the bound value won't match... even if Value = 1 vs Value = 1.00 it won't match and will not be considered a valid "value" that matches your list. Convert your answer to a whole/integer number and it might do what you expect.
Without seeing the full source for the page I am simply speculating, but have you disabled ViewState on the page? If so, the DropDownList cannot retain its values between postbacks and the lists will have to be reloaded each time.

How to get the bound item from within an ASP.NET repeater

I have to set a LinkButton's OnClientClick attribute but I don't know what this value is until the LinkButton is bound to. I'm trying to set the value when the repeater binds, but I can't workout how to get the 'boundItem/dataContext' value...
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:LinkButton Text="HelloWorld" ID="Hyper1" runat="server" OnDataBinding="Repeater1_DataBinding" >
</asp:LinkButton>
</ItemTemplate>
</asp:Repeater>
protected void Page_Load(object sender, EventArgs e)
{
var list = new List<TestObject>();
list.Add(new TestObject() {TestValue = "testing1"});
list.Add(new TestObject() { TestValue = "testing2" });
list.Add(new TestObject() { TestValue = "testing3" });
this.Repeater1.DataSource = list;
this.Repeater1.DataBind();
}
public void Repeater1_DataBinding(object sender, EventArgs e)
{
var link = sender as HyperLink;
//link.DataItem ???
}
Is there anyway to find out what the current rows bound item is?
Maybe you need to use ItemDataBound event. It provides RepeaterItemEventArgs argument which has DataItem available
this.Repeater1.ItemDataBound += Repeater1_ItemDataBound;
void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
var dataItem = e.Item.DataItem;
}
I assume you are trying to get the value for the row that is currently being databound?
You can change your function to:
public void Repeater1_DataBinding(object sender, EventArgs e)
{
var link = sender as HyperLink;
string valueYouWant = Eval("TestValue").ToString();
// You could then assign the HyperLink control to whatever you need
link.Target = string.Format("yourpage.aspx?id={0}", valueYouWant);
}
valueYouWant now has the value of the field TestValue for the current row that is being databound. Using the DataBinding event is the best way to do this compared to the ItemDataBound because you don't have to search for a control and localize the code specifically to a control instead of a whole template.
The MSDN library had this as a sample event handler:
public void BindData(object sender, EventArgs e)
{
Literal l = (Literal) sender;
DataGridItem container = (DataGridItem) l.NamingContainer;
l.Text = ((DataRowView) container.DataItem)[column].ToString();
}
(see http://msdn.microsoft.com/en-us/library/system.web.ui.control.databinding.aspx)
As you can see it is a simple demonstration of how to access the data item and get data from it. Adapting this to your scenario is an exercise left to the reader. :)

Categories