I'm reading data from database and showing it in a page for editing:
<h2>Create new topic:
<asp:Label ID="_lblTopicName" runat="server" Text=""></asp:Label></h2>
<p>
Edit Level:
<br/>
<asp:DropDownList ID="_dtlEditRole" runat="server"></asp:DropDownList>
<br/>
View Level:
<br/>
<asp:DropDownList ID="_dtlViewRole" runat="server"></asp:DropDownList>
<br/>
<asp:TextBox ID="_tbxTopicText" TextMode="MultiLine" runat="server" Height="204px"
Width="885px"></asp:TextBox>
</p>
<asp:Button ID="_btnSaveTopic" runat="server" Text="Save" onclick="_btnSaveTopic_Click" />
I fill the fields in Page_PreRender() like so:
private string _topicString;
private Topic _topic = null;
private Topics_GetTopicByTopicResult _findTopicResults = null;
protected void Page_PreRender(object sender, EventArgs e)
{
// Load the User Roles into checkboxes.
_dtlEditRole.DataSource = Roles.GetAllRoles();
_dtlEditRole.DataBind();
_dtlViewRole.DataSource = Roles.GetAllRoles();
_dtlViewRole.DataBind();
_topicString = Request.QueryString["Topic"];
if (String.IsNullOrEmpty(_topicString))
{
Response.Redirect("~/Default.aspx");
}
else
{
_topic = new Topic();
_findTopicResults = _topic.FindTopic(_topicString);
if (_topic != null)
{
// Check if the user has permission to access
if (RoleHelper.IsEditAllowed(_findTopicResults.ViewRoleName))
{
_lblTopicName.Text = _findTopicResults.Topic;
_tbxTopicText.Text = _findTopicResults.Text;
_dtlEditRole.SelectedValue = _findTopicResults.EditRoleName;
_dtlViewRole.SelectedValue = _findTopicResults.ViewRoleName;
}
else
{
Response.Redirect("~/Error.aspx?ReturnUrl=" + HttpUtility.UrlEncode(Request.RawUrl));
}
}
else
{
Response.Redirect("~/CreateTopic.aspx?Topic=" + _topicString);
}
}
}
But now when i click _btnSaveTopic button the fields:
private string _topicString;
private Topic _topic = null;
private Topics_GetTopicByTopicResult _findTopicResults = null;
They are all NULL and im not able to update aything.
Here's my button click event:
protected void _btnSaveTopic_Click(object sender, EventArgs e)
{
_topic.UpdateTopic(_findTopicResults.ID, _findTopicResults.Topic, _tbxTopicText.Text,
_dtlViewRole.SelectedItem.Text, _dtlEditRole.SelectedItem.Text);
Response.Redirect("~/ViewPage.aspx?Topic=" + _topicString);
}
What would be the right way doing this?
ASP.NET Page Life Cycle states that Page_Init should be used to 'initialize control properties' which looks like what you are doing.
Also, it's usually good practice to breakup such large sections of code into smaller refactored methods. Try to keep the amount of code directly placed in event handlers to a minimum.
You can start by right-clicking a section of highlighted code in visual studio -> refactor -> extract method
Also, if you need more help understanding how to improve your code, you should ask a question pointing to this question on the code review site: here
You are re-binding the drop down list (and therefore wiping out the 'SelectedValue') in your Page_PreRender method. Wrap the method in
protected void Page_PreRender(object sender, EventArgs e)
{
if( !IsPostBack){
//your current code
}
}
and it should work.
Related
I'm new to ASP.Net and trying to implement a search page in my project.
I created a simple search.aspx
<asp:TextBox runat="server" ID="txtSearch" MaxLength="250"/>
<asp:LinkButton ID="lnkSearch" runat="server" Text="Search" OnClick="Search_Click" ClientIDMode="Static" />
<asp:Repeater ID="rep" runat="server" >
....
</asp:Repeater>
and the search.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
txtSearch.Text = Request.Params["q"].ToString();
BindRepeater(); //reads Request.Params["q"] and fetches data
txtSearch.Focus();
this.Page.Form.DefaultButton = this.lnkSearch.UniqueID;
}
protected void Search_Click(object sender, EventArgs e)
{
Response.Redirect("/Search.aspx?q=" + txtSearch.Text);
}
Problem is that when I type something in txtSearch and hit enter or click search, the page reloads with the old query string and old search results, seems that txtSearch.Text is updated with old Query value before hitting Search_Click
For Example if I enter search.aspx?q=apple in address bar the page returns correct results and txtSearch's Text = "apple" .. if I type green apple and hit enter, page returns apple results, and txtSearch's Text = "apple", also the link is search.aspx?q=apple
I tried
AutoPostBack="True|False" for the TextBox
if (!IsPostBack)
txtSearch.Text = Request.Params["q"].ToString();
but I can't use it I guess since I'm posting back to same page, no?
I also tried
if (IsPostBack && txtSearch.Text != Request.Params["q"].ToString())
txtSearch.Text = Request.Params["q"].ToString();
This seems a strange way of doing it to me.
My preference would be to have the search logic in the event handler itself, rather than implementing this strange post-back loop.
protected void Page_Load(object sender, EventArgs e)
{
if (Page.IsPostBack == false)
{
// If passed in on first entry to the page
var searchQuery = Reqest.Params["q"];
if (String.IsNullOrWhitespace(searchQuery) == false)
{
txtSearch.Text = searchQuery;
Search_Click(null, null);
}
}
txtSearch.Focus();
this.Page.Form.DefaultButton = this.lnkSearch.UniqueID;
}
protected void Search_Click(object sender, EventArgs e)
{
// Pass the value of the search to the repeater
BindRepeater(txtSearch.Text);
}
Note that I'm passing the search text to BindRepeater so you'd have to update it to use the parameter value rather than query string
I have a grid view that has 3 columns(Name, Address, Status) and a checkbox.The Status has 3 properties, Active, Pending, and Disabled. The page load all the information from the database. When loading the page, only accounts that are ACTIVE should be displayed (and the checkbox should remain unchecked)
When clicking the checkbox, the page should load the DISABLED, along with the accounts already displayed When the page loads for the first time.
Aspx:
<asp:CheckBox ID="ChkBox1" runat="server" AutoPostBack="true" OnCheckedChanged="cbShowAllColumn_Changed" TextAlign="Right" Text="Show All"/>
</asp:Panel>
Code behind:
protected void cbShowColumn_Changed(object sender, EventArgs e)
{
string columnName = (sender as CheckBox).ID.Substring(1);
gvTest.Columns[(int)Enum.Parse(typeof(AccountColumns), columnName)].Visible = (sender as CheckBox).Checked;
}
protected void cbShowAllColumn_Changed(object sender, EventArgs e)
{
bool _checked = (sender as CheckBox).Checked;
foreach (Control ctrl in pAccount.Controls)
if (ctrl is CheckBox)
{
(ctrl as CheckBox).Checked = _checked;
gvMain.Columns[(int)Enum.Parse(typeof(AccountColumns), (ctrl as CheckBox).ID.Substring(2))].Visible = _checked;
}
}
I compiled a small asp .net page to do what you asked.
Note: In your project, you should probably take the "source" out of the BindGrid method, so that you don't "get" the data from scratch every time the page is posted back to. I did it that way because I used an anonymous type.
Note #2 I converted an int to your enum and then to a string. Since you use real data you should handle that differently, by using the enum itself.
Markup:
<asp:CheckBox ID="ChkBox1" runat="server" AutoPostBack="true" OnCheckedChanged="cbShowAllColumn_Changed" TextAlign="Right" Text="Show All"/>
<br/>
<asp:gridview ID="gvMain" runat="server" >
</asp:gridview>
Codebehind:
protected void Page_Load(object sender, EventArgs e)
{
BindGrid(false);
}
private void BindGrid(bool showActiveOnly)
{
var source = Enumerable.Range(1, 10)
.Select(number => new { number, status = (Enum.ToObject(typeof(Statuses), number % 3)).ToString() });
var filteredSource = source.Where(x => x.status == "Active" || !showActiveOnly);
gvMain.DataSource = filteredSource;
gvMain.DataBind();
}
protected void cbShowAllColumn_Changed(object sender, EventArgs e)
{
bool _checked = (sender as CheckBox).Checked;
BindGrid(_checked);
}
private enum Statuses
{
Active,
Pending,
Disabled
}
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
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);
}
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;
}
}