In "edmx" page I have button control with event "NextButton_Click" for click. When I click this button the variables "index" doesn't want to change to "40" and the "text"
variable doesn't want to change to "active". These variables are always in the same state "text" is always equal to "start" and "index" is always equal to "10". Why they don't want to change with (index = 40;
text = "active";) as I wrote in the click button event method ?
public partial class CountriesTowns : System.Web.UI.Page
{
int index = 10;
string text = "start";
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
index = 20;
text = "stop";
}
}
//click next button
protected void NextButton_Click(object sender, EventArgs e)
{
Response.Write(index);
Response.Write(text);
index = 40;
text = "active";
}
HTTP is stateless, every object like your index or text(and even all controls) are destroyed at the end of the page's life-cycle. So they are always initialized with their default value.
int index = 10;
string text = "start";
You can use a control(f.e. a TextBox or a HiddenField) to persist their value across postbacks.
But there are other options:
Nine Options for Managing Persistent User State in Your ASP.NET Application
You are not persisting the updated state of the index and text variables between post backs. As such, since a new instance of CountriesTowns is created per request, the values are re-initialised to their default values.
Every time you click a button, you cause what is known as a Postback. A Postback does not just run your click code... it also rebuilds your entire page. To do this, it creates a brand new instance of your Page class, which is then destroyed as soon as the html for your new page is completed. It has to do this because the original instance of your Page class was also destroyed as soon the html was rendered.
Related
What is a simple way to count in C# how many times an asp net button has been clicked in the same page e.g page1.aspx? The counter should be valid per user and reset when I go to page2.aspx, then return back to page1.aspx. the counter should persist in case of reloading the same page.
the button is created dynamically in Page Init
Button x = new Button();
I cannot use javascript. thanks
Create a class for maintain hit counters
public static class Counter
{
private static long hit;
public static void HitCounter()
{
hit++;
}
public static long GetCounter()
{
return hit;
}
}
Increment the value of counter at page load event
protected void Page_Load(object sender, EventArgs e)
{
Counter.HitCounter(); // call static function of static class Counter to increment the counter value
}
the time you redirect the user you can make count as null
The better way to use session, it enables you to store and retrieve values for a user as the user navigates ASP.NET pages in a Web application. So that you can access the value even when you returning from page2.aspx. the code for this will be
protected void button_Click(object sender, EventArgs e)
{
if(Session["ClickCount"]!=null)
Session["ClickCount"]=(int)Session["ClickCount"]++;
else
Session["ClickCount"]=0;
}
If you want to reset it when you leave the page means you can use:
if(Session["ClickCount"]!=null)
Session["ClickCount"]=0;
// Redirect to page
I'm making a web app in Asp.Net using c# that lets you add items into the list.
My problem is that each time that i click the button to add a new item into the list , its just shows me the last item and the list counter shows me only 1 .
What am I doing wrong??
Here is the code :
public partial class home : System.Web.UI.Page
{
List<string> messageboxs = new List<string>();
public string val = "";
public string data = "";
protected void Button1_Click(object sender, EventArgs e)
{
val = "";
messageboxs.Add(text1.Text);
ListBox1.DataSource = messageboxs;
ListBox1.DataBind();
val = messageboxs.Count.ToString();
}
}
Your list is not persisted between postbacks.
Every time you click a button a new instance of the page class and therefore list is created. This list is empty.
You should read up on ASP.NET Page Life Cycle Overview. In a nut shell, everytime you click the button it causes the page to postback which creates a new instance of the page. You are initializing an empty list on each instance of that page therefore when you come to adding the new item into the list...it's empty again.
What you need to do is store messageboxs somewhere which will allow it to persist across postbacks. For your particular example, you could use the ViewState e.g.
public partial class home : System.Web.UI.Page
{
private void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
// initialise list
ViewState["Messages"] = new List<string>();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
// get the old messages list
var messages = (List<string>)ViewState["Messages"];
messages.Add(text1.Text);
ListBox1.DataSource = messages;
ListBox1.DataBind();
// store the new messages list
ViewState["Messages"] = messages;
}
}
The problem is in how ASP.Net works. ASP.Net is recreating your "home" page on each button click. This then recreates the list, and you add one item to it. You need a way to save the list between button clicks. That's what, for example, the Session is for.
The list is created again on each postback. You should look at going through the existing items in ListBox1 and re-adding them to your List<string> then re-binding.
Make your messageboxs static variable as
static List messageboxs = new List();
But this makes the variable accessible from any page request.
meaning if someone else open this page and tried to add an item he/she will end up adding an item to someone else's list.
try using session state or view state instead.
How do I increment a step value to be processed when the page loads? For example, in the code below the viewstate variable is not incremented until after Page_Load, due to the ASP.NET page lifecycle.
protected void Page_Load(object sender, EventArgs e)
{
switch ((int)ViewState["step"])
{
//do something different for each step
}
}
protected void btnIncrementStep_Click(object sender, EventArgs e)
{
//when the button is clicked, this does not fire
//until after page_load finishes
ViewState["step"] = (int)ViewState["step"] + 1;
}
Just move the switch statement into an event that happens later. E.g. LoadComplete() or PreRender(). PreRender is probably a bit late, depending on what you want to do.
There's no way around this. Page_Load event will always happen before any control events get fired. If you need to do something after the control event, use Page_PreRender.
ASP.Net Page Lifecycle Image
Increment during the LoadComplete event or even during OnLoad.
You have all the information needed to make the decision whether to increment from the form data. You don't need to wait for the onClick() event. Check the form to see if the item will be clicked.
Look in the request.params("__EVENTARGS")
This identifies the control that caused the postback.
If you need to increment and check the value during Page_Load, then an option would be to store the value in the session instead of ViewState, e.g:
private int Step
{
get { return (int)Session["step"]; }
set { Session["step"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
Step = 0; // init
else
Step ++; // increment
switch (Step)
{
//do something different for each step
}
}
I need to generate buttons initially based on quite a processor and disk intensive search. Each button will represent a selection and trigger a postback. My issue is that the postback does not trigger the command b_Command. I guess because the original buttons have not been re-created. I cannot affort to execute the original search in the postback to re-create the buttons so I would like to generate the required button from the postback info.
How and where shoud I be doing this? Should I be doing it before Page_Load for example? How can I re-construct the CommandEventHandler from the postback - if at all?
namespace CloudNavigation
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
// how can I re-generate the button and hook up the event here
// without executing heavy search 1
}
else
{
// Execute heavy search 1 to generate buttons
Button b = new Button();
b.Text = "Selection 1";
b.Command += new CommandEventHandler(b_Command);
Panel1.Controls.Add(b);
}
}
void b_Command(object sender, CommandEventArgs e)
{
// Execute heavy search 2 to generate new buttons
Button b2 = new Button();
b2.Text = "Selection 2";
b2.Command += new CommandEventHandler(b_Command);
Panel1.Controls.Add(b2);
}
}
}
The b_Command Event Handler method is not being executed because on post back buttons are not being recreated (since they are dynamically generated). You need to re-create them every time your page gets recreated but in order to do this you need to explicitly cache information somewhere in state.
If this a page-scoped operation easiest way is to store it in the ViewState (as strings - if you start loading the ViewState with objects you'll see performance go down) so that you can check it on next load (or any other previous event) and re-create buttons when reloading the page.
If the operation is session-scoped, you can easily store an object (array or whatever) in session and retrieve it on next Load (or Init) to re-create your controls.
This scenario means that you need just to store some info about your button in your b_Command EventHandler instead of creating and adding buttons since if you do so you'll lose relative information in the next postback (as it is happening now).
so your code would become something like:
namespace CloudNavigation
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
this.recreateButtons();
}
else
{
// Execute heavy search 1 to generate buttons
Button b = new Button();
b.Text = "Selection 1";
b.Command += new CommandEventHandler(b_Command);
Panel1.Controls.Add(b);
//store this stuff in ViewState for the very first time
}
}
void b_Command(object sender, CommandEventArgs e)
{
//Execute heavy search 2 to generate new buttons
//TODO: store data into ViewState or Session
//and maybe create some new buttons
}
void recreateButtons()
{
//retrieve data from ViewState or Session and create all the buttons
//wiring them up to eventHandler
}
}
}
If you don't want to call recreateButtons on page load you can do it on PreLoad or on Init events, I don't see a difference since you'll be able to access ViewState/Session variables everywhere (on Init viewstate is not applied but you can access it to re-create your dynamic buttons).
Someone will hate this solution but as far as I know the only way to retain state data server-side is ViewState - Session - Page.Transfer or client-side cookies.
The buttons need to be created before the load event, or state won't be wired up correctly. Re-create your buttons in Init() instead.
As for how to do this without re-running the search, I suggest you cache the results somewhere. The existence of a result set in the cache is how your button code in the Init() event will know it needs to run.
Alternatively, you could place the buttons on the page statically. Just put enough there to handle whatever the search returns. If you're thinking that maybe that would be way too many items, then ask your self this: will your users really want to sort through that many items? Maybe you should consider paging this data, in which case static buttons aren't as big a deal any more.
What happens when the postback event handling tries to find the control it dosen't exists on the collection.
Checkout Denis DynamicControlsPlaceholder # http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
Hope it helps
Bruno Figueiredo
http://www.brunofigueiredo.com
Does your ASPX have the event handler wired up?
<asp:Button id="btnCommand" runat="server" onClick="b_Command" text="Submit" />
I agree with Joel about caching the search results. As for the buttons you can create them dynamically at the init or load phases of the page lifecycle but be aware that if you remove a button and then add it back programmatically you will mess up your state.
In one of my projects we have a dynamic form that generates field son the fly and the way we make it work is through an array that is stored in the cache or in the viewstate for the page. The array contains the buttons to display and on each page load it re-creates the buttons so that state can be loaded properly into them. Then if I need more buttons or a whole new set I flag the hide value in the array and add a new set of values in the array for the new set of corresponding buttons. This way state is not lost and the buttons continue to work.
You also need to ensure that you add a handler for the on_click event for your buttons if you create them programmatically which I think I see in your code up at the top.
Here is a sample with custom viewstate handling (note that buttons have EnableViewState = false):
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Execute heavy search 1 to generate buttons
ButtonTexts = new ButtonState[] {
new ButtonState() { ID = "Btn1", Text = "Selection 1" }
};
}
AddButtons();
}
void b_Command(object sender, CommandEventArgs e)
{
TextBox1.Text = ((Button)sender).Text;
// Execute heavy search 2 to generate new buttons
ButtonTexts = new ButtonState[] {
new ButtonState() { ID = "Btn1", Text = "Selection 1" },
new ButtonState() { ID = "Btn2", Text = "Selection 2" }
};
AddButtons();
}
private void AddButtons()
{
Panel1.Controls.Clear();
foreach (ButtonState buttonState in this.ButtonTexts)
{
Button b = new Button();
b.EnableViewState = false;
b.ID = buttonState.ID;
b.Text = buttonState.Text;
b.Command += new CommandEventHandler(b_Command);
Panel1.Controls.Add(b);
}
}
private ButtonState[] ButtonTexts
{
get
{
ButtonState[] list = ViewState["ButtonTexts"] as ButtonState[];
if (list == null)
ButtonTexts = new ButtonState[0];
return list;
}
set { ViewState["ButtonTexts"] = value; }
}
[Serializable]
class ButtonState
{
public string ID { get; set; }
public string Text { get; set; }
}
So I have a weird situation here... I have an System.Web.UI.WebControls.WebParts.EditorPart class. It renders a "Search" button, when you click this button, it's clickHandler method does a DB search, and dynamically creates a LinkButton for each row it returns, sets the CommandName and CommandArgument properties and adds a CommandEventHandler method, then adds the LinkButton control to the page.
The problem is, when you click a LinkButton, its CommandEventHandler method is never called, it looks like the page just posts back to where it was before the ORIGINAL "Search" button was pressed.
I have seen postings saying that you need to add the event handlers in OnLoad() or some other early method, but my LinkButtons haven't even been created until the user tells us what to search for and hits the "Search" button... Any ideas on how to deal with this?
Thanks!
This is my favorite trick :)
Our scenario is to first render a control. Then using some input from the user, render further controls and have them respond to events.
The key here is state - you need to know the state of the control when it arrives at PostBack - so we use ViewState. The issue becomes then a chicken-and-egg problem; ViewState isn't available until after the LoadViewState() call, but you must create the controls before that call to have the events fired correctly.
The trick is to override LoadViewState() and SaveViewState() so we can control things.
(note that the code below is rough, from memory and probably has issues)
private string searchQuery = null;
private void SearchButton(object sender, EventArgs e)
{
searchQuery = searchBox.Text;
var results = DataLayer.PerformSearch(searchQuery);
CreateLinkButtonControls(results);
}
// We save both the base state object, plus our query string. Everything here must be serializable.
protected override object SaveViewState()
{
object baseState = base.SaveViewState();
return new object[] { baseState, searchQuery };
}
// The parameter to this method is the exact object we returned from SaveViewState().
protected override void LoadViewState(object savedState)
{
object[] stateArray = (object[])savedState;
searchQuery = stateArray[1] as string;
// Re-run the query
var results = DataLayer.PerformSearch(searchQuery);
// Re-create the exact same control tree as at the point of SaveViewState above. It must be the same otherwise things will break.
CreateLinkButtonControls(results);
// Very important - load the rest of the ViewState, including our controls above.
base.LoadViewState(stateArray[0]);
}
You need to re-add the dynamically created controls, in the onload, so that they can be in the page hierarchy and fire their event.
LinkButton link= new LinkButton();
link.Command +=new CommandEventHandler(LinkButton1_Command);
protected void LinkButton1_Command(object sender, CommandEventArgs e)
{
try
{
System.Threading.Thread.Sleep(300);
if (e.CommandName == "link")
{
//////////
}
}
catch
{
}
}
A dirty hack I just came up with, is to create dummy LinkButtons with the same IDs as the real buttons.
So let's say you are going to create a LinkButton "foo" at Pre_Render (which is too late), then also create a dummy foo at Page_Load:
var link = new LinkButton();
link.ID = "foo";
link.Click += fooEventHandler;
dummyButtons.Controls.Add(link);
(Where "dummyButtons" is just a PlaceHolder on the page with Visibility set to false.)
It's ugly, but it works.