getting wrong value in dropdownlist in code behind - asp.net

I've read a few different examples of this, and it seems to be a clear newbie question for those that don't fully understand the asp.net page life cycle, sorry still learning. None of my attempts to fix have panned out.
aspx:
...
<%
for( int j = 0; j < 11; j++)
{
ChildWeightPounds.Items.Add( new ListItem(j.ToString(),j.ToString()));
}
%>
<asp:DropDownList ID="ChildWeightPounds" runat="server" OnSelectedIndexChanged="DropDownListSelected">
<asp:ListItem Value="">-Select-</asp:ListItem>
</asp:DropDownList>
...
<asp:Button ID="InsertButton" runat="server" Text="Submit" OnClick="InsertButton_Click" />
aspx.cs:
protected void InsertButton_Click(object sender, EventArgs e)
{
foreach (Control c in NewPatientForm.Controls)
{
....
if (c is TextBox)
{
TextBox tb = (TextBox)c;
//Expected response:
Response.Write( "field: " + tb.ID + " = " + tb.Text + "<br />");
}
if (c is DropDownList)
{
DropDownList ddl = (DropDownList)c;
//Unexpected response:
//this is not giving me my selected value, but only the top item ("--select--")
Response.Write("field: " + ddl.ID + ", selectedItem: " + ddl.SelectedItem.Value + "<br />");
}
}
}
It's pretty clear this is a IsPostBack, DataBind(), problem with my lack of understanding of the page life cycle. But what doesn't make sense, is i'm iterating through all controls, and textboxes, checkboxes, checkboxlists all work fine, and give me the value in the field, for some reason the dropdownlist doesn't give me the value.
I've tried using the OnSelectedIndexChanged event, I've tried using the DataBind() function, but playing with these, still hasn't gotten me the value.

The biggest issue with your example is you are using inline C# within your page with <% %>. This isn't advised for asp.net. That's more of a legacy/classic ASP approach which won't play well with .NET for many reasons.
Try moving your code that adds the items to the dropdownlist from the markup file into the .cs file, and be sure to hook into a page event that happens at or before OnPreRender. That is the last point you can alter the page controls and have viewstate/lifecycle work correctly.
protected void Page_Load(object sender, EventArgs e)
{
for( int j = 0; j < 11; j++)
{
ChildWeightPounds.Items.Add( new ListItem(j.ToString(),j.ToString()));
}
}
It's likely without running your example that the values are being inserted into the dropdownlist at the incorrect time in the lifecycle, and because of that when you try to access the selected value in the code behind it doesn't work.
Consider the following article on asp.net lifecycle which may assist you.

You can adjust AutoPostBack="true" on your DropDownList, and define OnSelecIndexChanged event
<asp:DropDownList ID="ChildWeightPounds" runat="server"
OnSelectedIndexChanged="DropDownListSelected" AutoPostBack="true>
<asp:ListItem Value="">-Select-</asp:ListItem>
</asp:DropDownList>
Code Behind
void DropDownListSelected(Object sender, EventArgs e)
{
var value = ChildWeightPounds.SelectedValue;
}

Related

ASPxGridview get row data from server-side

I'm working on a DevExpress Gridview and I want to get the data of the selected row (only one row can be selected at the time). I'm working on the Server-Side and I'm using FocusedRowChanged function.
EDIT: The FocusedRowChanged fire but nothing happen and the textboxes do not change value
protected void dxgrDepartement_FocusedRowChanged(object sender, EventArgs e)
{
Page.ClientScript.RegisterClientScriptBlock(GetType(), "FetchData", "<script language='javascript'>FetchData('4654654646')</script>");
txtDescription.Text = "patate";
//txtComments.Text = dxgrDepartement.GetRowValues(dxgrDepartement.FocusedRowIndex, "IdDepartment").ToString();
}
And the "FetchData :
function FetchData(text) {
//ClearField();
document.getElementById("<%= txtDescription.ClientID %>").value = text.toString();
}
BTW - Changing the callbacks property made no difference for us. We needed callbacks for other functionality so couldn't turn this off anyway.
The GetRowValues method did not work either.
This is a technique described on DevExpress' web site and it worked for us as long as we didnt use DevExpress' controls (ASPxDateEdit, ASPxTextBox):
ASPX page:
<dxwgv:GridViewDataTextColumn Caption="Dist. %" FieldName="DistributionPerc" VisibleIndex="3"
Width="50px">
<DataItemTemplate>
<asp:TextBox ID="txtDistPerc" runat="server" Text='<%# Eval("DistributionPercent") %>'
Width="50px" />
</DataItemTemplate>
</dxwgv:GridViewDataTextColumn>
Code behind:
for (int i = 0; i < grdHistory.VisibleRowCount; i++)
{
TextBox textbox = grdHistory.FindRowCellTemplateControl(i, grdHistory.Columns["DistributionPerc"] as GridViewDataColumn, "txtDistPerc") as TextBox;
var anything = textbox.Text;
}
Use:
gridView.GetRowValues(gridView.FocusedRowIndex, columnFieldName1, columnFieldName2, ..., columnFieldNameN)
Method ASPxGridView.GetRowValues
Property ASPxGridView.FocusedRowIndex
grid.EnableCallback = false; solved my problems!

Create Asp.net Reset Button

Is there any ways to create reset button to clear all text in text fields in asp form? When user hits the reset button, all text entered by them will clear and they are enable to enter back text in the area.
As per my knowledge there is no such reset functionality provided by Asp.Net.
We can achieve the reset like this
btnReset.Attributes.Add("onClick", "document.forms[0].reset();return false;");
Or
Like this
<input type='button' id='resetButton' value='Reset' onclick='theForm.reset();return false;'/>
Or OnClientclick of asp.net button use this theForm.reset();return false;
try this create a button with reset and in click event write ClearInputs(Page.Controls); and event will call this method.
protected void Button2_Click(object sender, EventArgs e)
{
ClearInputs(Page.Controls);
}
void ClearInputs(ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is TextBox)
((TextBox)ctrl).Text = string.Empty;
ClearInputs(ctrl.Controls);
}
}
In the button click method, set all textbox.text.length values to 0. either do it one by one, which is the simple way, or do it by getting all controls of type textbox on the page, which is tad bit more sophisticated, but could be much less typing, depending on the number of textboxes. Definitely more maintainable.
private void ChangeBtn_Click(object sender, EventArgs e)
{
foreach(Control c in Page.Controls)
{
if (c.Controls.Count > 0)
{
foreach(Control c2 in c.Controls)
{
if (c2.GetType().ToString() == "System.Web.UI.WebControls.TextBox")
{
myspan.InnerHtml = ((TextBox)c2).Text;
((TextBox)c2).Text = ""; //or ((TextBox)c2).Text.Length = 0;
}
}
}
}
}
http://msdn.microsoft.com/en-us/library/20zys56y(v=vs.90).aspx
Create a Click event to the Button control and use the following codes below:
foreach (Control control in Page.Controls)
{
if (control is TextBox)
{
TextBox txt = (TextBox)control;
txt.Text = "";
}
}
This will save you some time to clear all the textboxes inside the web form.
Use Jquery the easiest way to find any type of control and will not have post back event.
$('input[type=text], textarea')
Use foreach loop for clearing value.
Please note that
btnReset.Attributes.Add("onClick", "document.forms[0].reset();return false;");
will not work in clearing pages that are posted back, i.e. If a text box had a value "Silly me" and has been posted back, this code will reset to the post back value which is "Silly me".
The workaround is to repost the page with cleared values - try the following code (it worked for me)
OnClientClick="document.location.href=document.location.href;"
will reload the page with cleared values...
I have multiple type of inputs in my page (TextBox, DropDownList and CheckBox), so here is how I reset them all
Put an <asp:Panel> that wraps my inputs
Run BtnClear_Click on Clear button click
Loop each inputs and reset text/selection/checked value by types
The codes
Default.aspx
<asp:Panel ID="PanelReport" runat="server">
...
<asp:TextBox ID="fldSpeedoMula" runat="server"></asp:TextBox>
<asp:DropDownList ID="ddlPlateNo" runat="server" CssClass="form-control"></asp:DropDownList>
<asp:CheckBox ID="cbCard" runat="server" />
<asp:CheckBox ID="cbCash" runat="server" />
<asp:Button ID="BtnClear" runat="server" Text="Clear" CssClass="button" OnClick="BtnClear_Click"/>
...
</asp:Panel>
Default.aspx.cs
protected void BtnClear_Click(object sender, EventArgs e)
{
// Clear all inputs
foreach (DropDownList ddl in PanelReport.Controls.OfType<DropDownList>())
{
ddl.SelectedIndex = 0;
}
foreach (TextBox fld in PanelReport.Controls.OfType<TextBox>())
{
fld.Text = string.Empty;
}
foreach (CheckBox cb in PanelReport.Controls.OfType<CheckBox>())
{
cb.Checked = false;
}
}

How to add persistent dynamic controls based on user input (not on initial page load)

I am familiar with creating and persisting dynamic controls on the first load of a page and on subsequent postbacks but I am having trouble with the following user initiated scenario...
In my demo I have a placeholder, two buttons and a literal
<div>
<asp:PlaceHolder ID="phResponses" runat="server" />
</div>
<div>
<asp:Button ID="btnAdd" Text="Add" runat="server" OnClick="Add"/>
<asp:Button ID="btnInspect" Text="Inspect" runat="server" OnClick="Inspect"/>
</div>
<div>
<asp:Literal ID="litResult" runat="server"/>
</div>
I want the user to be able to click the add button to provide a response so I have...
protected void Page_Init(object sender, EventArgs e)
{
BuildControls();
}
protected void Add(object sender, EventArgs e)
{
BuildControls();
}
protected void BuildControls()
{
phResponses.Controls.Add(new LiteralControl { ID = "response_" + _Count.ToString() });
_Count++;
}
_Count is a static member variable to enable me to have unique ids for the new controls. I realise I need to rebuild the dynamic controls on Page_Init but the problem is that I end up with 2 new Literal controls on every postback. Also if any Text property is put into the new controls it is lost when the controls are rebuilt.
So how do I avoid adding multiple controls and how do I persist newly added properties when rebuilding these controls?
I use the following to inspect the responses
protected void Inspect(object sender, EventArgs e)
{
foreach (var control in phResponses.Controls)
{
if (control is LiteralControl)
{
litResults.Text += "<p>" + control.Text + " : " + control.ID + "</p>";
}
}
}
Which itself adds another unwanted control because of the rebuilding on Page_Init
I'd not sure that I quite understand what you're asking, but it looks like you just want to ensure that BuildControls is only called once per lifecycle. You could do that by making the following changes:
Add a new private bool _isControlsBuilt = false;.
Change Page_Init to check _isControlsBuilt before calling BuildControls.
Set _isControlsBuilt to true within BuildControls.
Make sure that BuildControls occurs earlier in the page lifecycle than Page_Init.
As for losing the values of controls on postback, it'll be that they're never hitting the viewstate. I'm not sure if it'd work, but my first guess would be to add a line to the end of BuildControls to call Page.RegisterRequiresControlState:
protected void BuildControls()
{
LiteralControl newLiteral = new LiteralControl { ID = "response_" + _Count };
this.RegisterRequiresControlState(newLiteral);
phResponses.Controls.Add(newLiteral);
_Count++;
_isControlsBuilt = true;
}
If that doesn't work (which might imply that it's the _view_state, not the _control_state that matters to you here), you may need to look at rolling your own viewstate. I wrote about how to do that in my answer to #3854193, which you might find useful.

How to programmatically create and use a list of checkboxes from ASP.NET?

I have a page with a table of stuff and I need to allow the user to select rows to process. I've figured out how to add a column of check boxes to the table but I can't seem to figure out how to test if they are checked when the form is submitted. If they were static elements, I'd be able to just check do this.theCheckBox but they are programaticly generated.
Also I'm not very happy with how I'm attaching my data to them (by stuffing it in there ID property).
I'm not sure if it's relevant but I'm looking at a bit of a catch-22 as I need to known which of the checkboxes that were created last time around were checked before I can re-run the code that created them.
Edit:
I've found an almost solution. By setting the AutoPostBack property and the CheckedChanged event:
checkbox.AutoPostBack = false;
checkbox.CheckedChanged += new EventHandler(checkbox_CheckedChanged);
I can get code to be called on a post back for any check box that has changed. However this has two problems:
The call back is processed after (or during, I'm not sure) Page_Load where I need to use this information
The call back is not called for check boxes that were checked when the page loaded and still are.
Edit 2:
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.
I'm going to assume you're using a DataList but this should work with and Control that can be templated. I'm also going to assume you're using DataBinding.
Code Front:
<asp:DataList ID="List" OnItemDataBound="List_ItemDataBound" runat="server">
<ItemTemplate>
<asp:CheckBox ID="DeleteMe" runat="server"/>
<a href="<%# DataBinder.Eval(Container, "DataItem.Url")%>" target="_blank">
<%# DataBinder.Eval(Container, "DataItem.Title")%></a>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="DeleteListItem" runat="server" OnClick="DeleteListItem_Click" ></asp:Button>
Code Behind:
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadList();
}
protected void DeleteListItem_Click(object sender, EventArgs e)
{
foreach (DataListItem li in List.Items)
{
CheckBox delMe = (CheckBox)li.FindControl("DeleteMe");
if (delMe != null && delMe.Checked)
//Do Something
}
}
LoadList();
}
protected void LoadList()
{
DataTable dt = //Something...
List.DataSource = dt;
List.DataBind();
}
protected void List_ItemDataBound(object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
{
string id = DataBinder.Eval(e.Item.DataItem, "ID").ToString();
CheckBox delMe = (CheckBox)e.Item.FindControl("DeleteMe");
if (delMe != null)
delMe.Attributes.Add("value", id);
}
}
}
First, make sure that each Checkbox has an ID and that it's got the 'runat="server"' in the tag.
then use the FindControl() function to find it.
For example, if you're looping through all rows in a GridView..
foreach(GridViewRow r in Gridview1.Rows)
{
object cb = r.FindControl("MyCheckBoxId");
if(r != null)
{
CheckBox chk = (CheckBox)cb;
bool IsChecked = chk.Checked;
}
}
Postback data is restored between the InitComplete event and the PreLoad event. If your checkboxes are not created until later then the checkboxes will play "catch up" with their events and the data will be loaded into the control shortly after it is created.
If this is to late for you then you will have to do something like what you are already doing. That is you will have to access the post data before it is given to the control.
If you can save the UniqueId of each CheckBox that you create then can directly access the post data without having to given them a special prefix. You could do this by creating a list of strings which you save the ids in as you generate them and then saving them in the view state. Of course that requires the view state to be enabled and takes up more space in the viewstate.
foreach (string uniqueId in UniqueIds)
{
bool data = Convert.ToBoolean(Request.Form[uniqueId]);
//...
}
Your post is a little vague. It would help to see how you're adding controls to the table. Is it an ASP:Table or a regular HTML table (presumably with a runat="server" attribute since you've successfully added items to it)?
If you intend to let the user make a bunch of selections, then hit a "Submit" button, whereupon you'll process each row based on which row is checked, then you should not be handling the CheckChanged event. Otherwise, as you've noticed, you'll be causing a postback each time and it won't process any of the other checkboxes. So when you create the CheckBox do not set the eventhandler so it doesn't cause a postback.
In your submit button's eventhandler you would loop through each table row, cell, then determine whether the cell's children control contained a checkbox.
I would suggest not using a table. From what you're describing perhaps a GridView or DataList is a better option.
EDIT: here's a simple example to demonstrate. You should be able to get this working in a new project to test out.
Markup
<form id="form1" runat="server">
<div>
<table id="tbl" runat="server"></table>
<asp:Button ID="btnSubmit" runat="server" Text="Submit"
onclick="btnSubmit_Click" />
</div>
</form>
Code-behind
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
var row = new HtmlTableRow();
var cell = new HtmlTableCell();
cell.InnerText = "Row: " + i.ToString();
row.Cells.Add(cell);
cell = new HtmlTableCell();
CheckBox chk = new CheckBox() { ID = "chk" + i.ToString() };
cell.Controls.Add(chk);
row.Cells.Add(cell);
tbl.Rows.Add(row);
}
}
protected void btnSubmit_Click(object sender, EventArgs e)
{
foreach (HtmlTableRow row in tbl.Rows)
{
foreach (HtmlTableCell cell in row.Cells)
{
foreach (Control c in cell.Controls)
{
if (c is CheckBox)
{
// do your processing here
CheckBox chk = c as CheckBox;
if (chk.Checked)
{
Response.Write(chk.ID + " was checked <br />");
}
}
}
}
}
}
What about using the CheckBoxList control? I have no Visual Studio open now, but as far as I remember it is a DataBound control, providing DataSource and DataBind() where you can provide a list at runtime. When the page does a postback you can traverse the list by calling something like myCheckBoxList.Items and check whether the current item is selected by calling ListItem.Selected method. This should work.
Add them in an override of the CreateChildControls method of the Page. Be sure to give them an ID! This way they get added to the control tree at the correct time.
IMHO The best way would be to use DataBound Templated Control though, i.e. something like a ListView (in .NET 3.5). then in pageload after postback traverse all items in the databound control and use item.FindControl to get at the actual checkbox.
What I ended up doing was tagging all my ID's with a know prefix and stuffing this at the top of Form_Load:
foreach (string v in this.Request.Form.AllKeys)
{
if (v.StartsWith(Prefix))
{
var data = v.Substring(Prefix.Length);
}
}
everything else seems to run to late.

Adding controls dynamically to an UpdatePanel in ASP.NET AJAX

I have the following really simple code
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:PlaceHolder ID="PlaceHolder1" runat="server">
</asp:PlaceHolder>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" />
</ContentTemplate>
</asp:UpdatePanel>
And the codebehind
protected void Button1_Click(object sender, EventArgs e)
{
Literal literal = new Literal();
literal.Text = DateTime.Now.ToString();
literal.ID = DateTime.Now.Ticks.ToString();
// These both work fine the first time the button is clicked
// but the second time nothing is added.
UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
PlaceHolder1.Controls.Add(literal);
}
My problem comes in that the Literal control is only ever added once. I've scoured google and blog sites (plus books) but without any luck. What am I missing?
In asp.net, the controls in the ASPX file are automatically generated on each postback. The controls you've created are not in the ASPX code so the framework does not create them for you. The first time you execute the Button1_Click method, you add one extra control to the page. The second time you execute the Button1_Click method, you're on another post back and that first extra button has been forgotten about. So the result of that postback is you get one extra button again.
This will create one extra control each time you click the button (although the timestamps will update each time you press the button because the controls are being re-created)
protected void Button1_Click(object sender, EventArgs e)
{
int count = 0;
if (ViewState["ButtonCount"] != null)
{
count = (int)ViewState["ButtonCount"];
}
count++;
ViewState["ButtonCount"] = count;
for (int i = 0; i < count; i++)
{
Literal literal = new Literal();
literal.Text = DateTime.Now.ToString();
literal.ID = DateTime.Now.Ticks.ToString();
UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
PlaceHolder1.Controls.Add(literal);
}
}
I agree to the answer above, However this approach will not save the state of the dynamic controls (or to be accurate, it will save the state but not load them back).
Load view state is called in Load event section of page life cycle,where it assigns back the control values saved in view state.
However if the controls are not created by this time, They can not be loaded with previous data so for the state to be maintained, the new controls must be recreated on or before load event.
protected void Page_Load(object sender, EventArgs e)
{
//PS: Below approach saves state as id is constant, it simply generates a new control with same id hence viewstate loads the value
if (IsPostBack)
{
int count = 0;
if (ViewState["ButtonCount"] != null)
{
count = (int)ViewState["ButtonCount"];
}
count++;
ViewState["ButtonCount"] = count;
for (int i = 0; i < count; i++)
{
TextBox literal = new TextBox();
//literal.Text = DateTime.Now.ToString();
literal.ID = "Textbox" + i.ToString();
//UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
PlaceHolder1.Controls.Add(literal);
}
}
}
Dynamically adding controls
View State and postback

Resources