Preserving user control on autopostback asp.net - asp.net

I have two user controls: dsucTopLeft and dsucTopRight in an aspx page. Each of the user controls has a dropdownlist to select values from.
The aspx page has a button "Save".
In the OnClickEvent of the button, I take data from those user controls (which return the values from the drop down list). I need to insert these values into database. However, these values set to 0 after the button is clicked.
How would I preserve those values?
Code:
ParentTemplate.aspx
<div class="leftDashboard">
<uc:dsuc ID="dsucTopLeft" runat="server" />
</div>
<div id="rightDashboard">
<uc:dsuc ID="dsucTopRight" runat="server" />
</div>
It also has a button:
<asp:Button ID="SaveButton" runat="server" OnClick="SaveButton_Click" Text="Save Dashboard" />
This is the codebehind for the button:
protected void SaveButton_Click(object sender, EventArgs e)
{
//If the mode is "CREATE", then it needs to insert the information about dashboard and the charts it contains
for (int i = 0; i < dsuc.Length; i++)
{
dsuc[i].dashboardId = dashboardId;
if (dsuc[i].chartId != 0) //Here, the chartId remains 0
dsuc[i].insert();
}
}
dsuc is an array. It is being populated in the following way:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dsuc[0]=dsucTopLeft;
dsuc[1]=dsucTopRight;
}
}
UserControl:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
initializeDropDownList();//It initializes the drop down list
}
}
public void insert()
{
//It inserts into database
}
protected void chartDDLSelectedIndexChanged(object sender, EventArgs e)
{
oldChartId = chartId;
String chartTitle = chartDropDownList.SelectedItem.Text;
if (chartTitle != dropDownMessage)
{
chartId = int.Parse(chartDropDownList.SelectedItem.Value);
//Chart user control should be retrieved from the database and drawn.
chartTitleLabel.Text += "chart id : " + chartId.ToString() + " title: " + chartTitle;
//chartUserControl.Visible = true;
}
}
The user control i.e. the class of dsuc[] changes its chartId when an item in its drop down list is selected. I printed the value, it works. But that same value becomes 0 when the button in clicked.

Remove the if (!Page.IsPostBack)from
if (!Page.IsPostBack)
{
dsuc[0]=dsucTopLeft;
dsuc[1]=dsucTopRight;
}
If not, it will only populate it when is not post back. As a click produces a post back, you'll want that code being executed :)
Also, it is probably that your clickp event is being called beforeselectedindexchanged`. In that case, the code that sets chartId is not executed (yet) when the click event is fired. You can solve that doing this:
public int ChartId { get { return int.Parse(chartDropDownList.SelectedItem.Value); }}
and calling that property instead. Also, you can use that property in your selectedindexchanged event handler

Related

Radio button doesn't get selected after a post back

I have an item template within repeater:
<ItemTemplate>
<li>
<input type="radio"
value="<%# GetAssetId((Guid) (Container.DataItem)) %>"
name="AssetId"
<%# SelectAsset((Guid) Container.DataItem) %> />
</li>
</ItemTemplate>
I have a method that compares ids and decides whether to check the radio button.
protected string SelectAsset(Guid uniqueId)
{
if (uniqueId == GetSomeId())
return "checked=\"checked\"";
return string.Empty;
}
SelectAsset gets hit, but it doesn't select a radio button on a post back, but it does work if I just refresh the page. What am I doing wrong here?
Answer here: How to display "selected radio button" after refresh? says that it's not possible to achieve, is this really the case?
Thank you
Update
It appears that view state isn't available for simple controls if they don't have a runat attribute. I have solved this by using a custom GroupRadioButton control. Thank you for your help.
I'd suggest using a RadioButtonList:
Page Code
<asp:RadioButtonList RepeatLayout="UnorderedList" OnSelectedIndexChanged="IndexChanged" AutoPostBack="true" ID="RadioRepeater" runat="server" />
<asp:Label ID="SelectedRadioLabel" runat="server" />
Code Behind
if (!Page.IsPostBack)
{
/* example adds items manually
- you could iterate your datasource here as well */
this.RadioRepeater.Items.Add(new ListItem("Foo"));
this.RadioRepeater.Items.Add(new ListItem("Bar"));
this.RadioRepeater.Items.Add(new ListItem("Baz"));
this.RadioRepeater.SelectedIndex = this.RadioRepeater.Items.IndexOf(new ListItem("Bar"));
this.RadioRepeater.DataBind();
}
protected void IndexChanged(object sender, EventArgs e)
{
this.SelectedRadioLabel.Text = string.Format("Selected Item Text: {0}", this.RadioRepeater.SelectedItem.Text);
}
I assume you only need to select one item.
As described in the comments, it even works to access the SelectedItem in the Page_Loadevent handler:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// previous code omitted
}
else
{
string foo = this.RadioRepeater.SelectedItem.Text;
}
}
If you are creating all your controls dynamically at run-time (directly from code), then things are a little different. Here is the code that I used:
Page Code
<form id="form1" runat="server">
</form>
Code Behind
protected void Page_Load(object sender, EventArgs e)
{
RadioButtonList rbl = new RadioButtonList();
rbl.AutoPostBack = true;
rbl.SelectedIndexChanged += rbl_SelectedIndexChanged;
rbl.Items.Add("All");
// generate your dynamic radio buttons here
for (int i = 0; i<5; i++)
{
rbl.Items.Add(string.Format("Dynamic{0}", i));
}
form1.Controls.Add(rbl);
if (!Page.IsPostBack)
{
rbl.SelectedValue = "All";
PopulateTextBox(rbl.SelectedValue);
}
}
void rbl_SelectedIndexChanged(object sender, EventArgs e)
{
RadioButtonList foo = (RadioButtonList)sender;
PopulateTextBox(foo.SelectedValue);
}
void PopulateTextBox(string selection)
{
TextBox box = new TextBox();
box.Text = selection;
form1.Controls.Add(box);
}

Handling events from dynamic controls NOT added on Page_Load?

I've read a few articles on here and the web that have informed me that I cannot simply add a new control dynamically to the page, wire it to a handler, and expect it to work.
The solution given each time is that the dynamic controls need to be added to the page on Init each time.
My problem is, my controls are NOT added to the page on init, they are added after ANOTHER postback.
the workflow is this:
Page Loads
User fills in a textbox, clicks a button
Page Posts back, creating dynamic link controls in the button_click event based on the input
User clicks one of those link controls to proceed to the next step.
so if this is the behavior I need to support, is there any way to do this? It has to happen in the button_click of step 2, because the dynamic controls are based on the input the user puts in step 2.
have I painted myself into a corner here? how else could I handle such a workflow?
After you dynamically create a link button, set a flag in your page's view state. On postback, re-create the link button if the flag is set in view state. Here's a demo:
Markup:
<asp:Button runat="server" ID="button1" OnClick="button_Click" Text="Create button A" CommandArgument="A" />
<asp:Button runat="server" ID="button2" OnClick="button_Click" Text="Create button B" CommandArgument="B" />
<asp:PlaceHolder runat="server" ID="placeHolder"></asp:PlaceHolder>
Code-behind:
public partial class Default : System.Web.UI.Page
{
private bool LinkButtonCreated
{
get { return ((bool?)this.ViewState["LinkButtonCreated"]).GetValueOrDefault(); }
set { this.ViewState["LinkButtonCreated"] = value; }
}
private string LinkButtonCommandArgument
{
get { return (string)this.ViewState["LinkButtonCommandArgument"]; }
set { this.ViewState["LinkButtonCommandArgument"] = value; }
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
if (this.LinkButtonCreated)
this.CreateLinkButton(this.LinkButtonCommandArgument);
}
protected void button_Click(object sender, EventArgs e)
{
if (!this.LinkButtonCreated)
{
string commandArgument = ((Button)sender).CommandArgument;
this.LinkButtonCreated = true;
this.LinkButtonCommandArgument = commandArgument;
this.CreateLinkButton(commandArgument);
}
}
private void CreateLinkButton(string commandArgument)
{
LinkButton linkButton =
new LinkButton
{
ID = "linkButton",
Text = "Click me",
CommandArgument = commandArgument,
};
linkButton.Click += this.linkButton_Click;
this.placeHolder.Controls.Add(linkButton);
}
private void linkButton_Click(object sender, EventArgs e)
{
LinkButton linkButton = (LinkButton)sender;
linkButton.Text = "I was clicked! Argument: " + linkButton.CommandArgument;
}
}

How can this codebehind be written better?

I have a form which has a single textbox that sends some data to the database upon hitting enter. Data is displayed below the textbox in a repeater control. Input data is displayed on the form immediately by binding the data to the repeater in the TextChanged event of that textbox.
In the CodeBehind, I am calling BindRepeater method twice, once on every new page load and once on the TextChanged event of the textbox.
How can this be rewritten to call the BindRepeater only once and still achieve the same effect?
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
BindRepeater();
}
}
protected void BindRepeater()
{
// data retrieval
// repeater binding
}
protected void CreateData(string newdata)
{
// data insert
}
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
if (TextBox1.Text != string.Empty)
{
string _newData = TextBox1.Text.Trim();
CreateData(_newData);
BindRepeater();
}
}
Use an event that would be fired after the text changed event to do the binding in. you can now remove it from the page load event.

Viewstate null on postback

So I have a listbox on my page and some textfields. Through the textfields I can add an item to my listbox (click the button, it adds it to a private List which is then set as a ViewState and the list is databound again). My listbox is also in an updatepanel which gets triggered on the button's Click event. Problem: My Viewstate remains null on a postback so it gets reset each time.
Some code:
private const string VIEW_INGREDIENTS = "IngredientsList";
private const string VIEW_LANGUAGE = "CurrentLanguage";
private List<IngredientData> _ingredientsList;
protected void Page_PreInit(object sender, EventArgs e)
{
if (Page.IsPostBack)
{
if (ViewState[VIEW_INGREDIENTS] != null)
{
_ingredientsList = (List<IngredientData>) ViewState[VIEW_INGREDIENTS];
}
}
else
{
// prepare ingredient lists
_ingredientsList = new List<IngredientData>();
}
}
protected void Page_Load(object sender, EventArgs e)
{
lstIngredients.DataSource = _ingredientsList;
lstIngredients.DataTextField = "Text";
lstIngredients.DataValueField = "Name";
lstIngredients.DataBind();
}
protected void btnAddIngredient_Click(object sender, EventArgs e)
{
_ingredientsList.Add(new IngredientData { Name = txtIngredientName.Text, Quantity = txtUnitQuantity.Text, Unit = lstUnits.SelectedValue });
ViewState[VIEW_INGREDIENTS] = _ingredientsList;
lstIngredients.DataSource = _ingredientsList;
lstIngredients.DataBind();
}
You're using vewstate during PreInit ? Try to check that a bit later during PreLoad.
Check if the page has EnableViewState="true":
<%# Page Language="C#" EnableViewState="true" ...
And verify the site-wide setting in web.config:
<pages enableViewState="true" enableViewStateMac="true" ... />
Now ASP.NET has built-in viewstate for list controls, so I wonder why you're writing custom code for it. The default viewstate should work well for what you're trying to accomplish.

Validation, Page events and ViewState

i have two buttons on the page. One button is responsible for text fields validation that are to do with registration and the other with loging in. The problem was when i press one of the buttons it refreshes the page and shows all the invalid fields (i dont want the registration fields to be checked by the RequiredFieldValidator whent the user presses the login button).
so what i did i used the initialization event.. to prevent this from happening...
static bool oneButtonPressed;
protected void Page_Init(object sender, EventArgs e)
{
if (oneButtonPressed)
{
REgisterAge.Visible = false;
RegisterAge2.Enabled = false;
RegisterAge3.Enabled = false;
RegisterPassword.Enabled = false;
RegisterPassword2.Enabled = false;
RegisterEmail.Enabled = false;
RegisterEmail2.Enabled = false;
}
else
{
EntryPasswordRequiredFieldValidator10.Enabled = false;
EntryNameEntryRequiredFieldValidator9.Enabled = false;
}
}
protected void entry_Click(object sender, EventArgs e)
{
oneButtonPressed = true;
}
protected void submitButton_Click(object sender, EventArgs e)
{
oneButtonPressed = false;
}
}
The probelm here is that the bool is always false when the page is posted back and loads again.. i do remember my teacher saying i could either use a ViewState or a static variable/method to preserve my values. Am i being wrong here.. do i have to use the ViewState?
Why don't you assign a validationgroup to each of the fields + the relevant submit button.
Different validation groups will ensure that validation won't fire on the irrelevant form.
<asp:TextBox runat="server" ID="txtName" ValidationGroup="vRegistration"></asp:TextBox>
<asp:LinkButton runat="server" ID="btnSubmit" ValidationGroup="vRegistration"></asp:LinkButton>

Resources