I have an update panel with a div (with runat="server") so I dynamically create and add buttons to it on a timer tick event.
The problem is that when a button is click, the is a postback but the button is gone and the event is not raised.
Here's my aspx page and my c# code behind. Nothing I write in the btn1_click actually occurs.
There's a continue to my question but in order to keep it simple, I would like to understand the above first.
I really need your help and i appreciate it, ty.
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:Timer ID="Timer1" runat="server" Interval="2000" ontick="Timer1_Tick">
</asp:Timer>
<asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
</Triggers>
<ContentTemplate>
<div id="div1" runat="server"></div>
</ContentTemplate>
</asp:UpdatePanel>
<div id="div2" runat="server">div2</div>
</form>
</body>
and this c# here.
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Timer1_Tick(object sender, EventArgs e)
{
CreateControl();
}
void CreateControl()
{
Button btn1 = new Button();
btn1.ID = "btn1";
btn1.Text = "click me";
btn1.Click += new EventHandler(btn1_Click);
div1.Controls.Add(btn1);
}
void btn1_Click(object sender, EventArgs e)
{
div1.InnerHtml += "btn1 was clicked";
}
}
For dynamically added controls you must add them in every page load event. Otherwise by the time it gets to the click event the are already gone. In this case I would add the button to a session collection of buttons every time you create one, then reload that entire collection on every postback, so it doesn't lose what you've already added. Also, save an int in session that you increment so they dont all have the same ID. IDs should be unique
something like:
protected void Page_Load(object sender, EventArgs e)
{
if(Page.IsPostBack)
{
CreateControls(YourCollectionInSession)
}
}
protected void Timer1_Tick(object sender, EventArgs e)
{
CreateControl();
}
void CreateControl()
{
Button btn1 = new Button();
btn1.ID = "btn" + yourSessionID;
btn1.Text = "click me";
btn1.Click += new EventHandler(btn1_Click);
div1.Controls.Add(btn1);
yourSessionID++;
YourCollectionInSession.Add(btn1);
}
void CreateControl(List<Button> buttons)
{
foreach(Button btn in buttons)
{
div1.Controls.Add(btn);
}
}
I've had to do the same thing before and this approach worked for me. Just remember the ASPx Page Lifecycle. It will always hit the page_init and page_load before it handles any post back events, meaning your controls are long gone.
Related
I've tried to keep this as basic as possible. Basically I just want to see my label update at each interval so I can see my timer is working before I plugin my real code that actually does stuff. So I've tried to go ultra simple and everything I've read tells me with this setup, my label should update with each Timer1_Tick event handler at 1 second intervals. Please tell me what Im missing here.
Here is my ASPX front page:
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<div>
<asp:Timer ID="Timer1" runat="server" OnTick="Timer1_Tick" Interval="1000" />
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick"/>
</Triggers>
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text="test"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
And my code behind page:
public partial class Default : System.Web.UI.Page
{
public Int32 timeCount=1;
protected void Page_Load(object sender, EventArgs e)
{ }
protected void Timer1_Tick(object sender, EventArgs e)
{
if (timeCount > 0)
{
Label1.Text = (timeCount + 1).ToString();
timeCount++;
}
}
protected void Button1_Click(object sender, EventArgs e)
{
Timer1.Enabled = true;
Timer1.Interval = 1000;
}
}
So my expectation is my Labe1.text should start count 2, then 3,4,5 and so on. At 1 second intervals basically. All I ever seem to get is one tick interval to 2 though. That's it though, no more tick events, it's stops at 2. How do I make it so that my button starts the timer and the label just starts updating at the tick intervals until I stop the timer (which in this case is just closing the browser to stop the debug)??
Thanks for you help.
Every timer tick your page is update and your 'timeCount'= 1 then you're checking if(timeCount > 0) <-always true, so the result timeCount + 1 will be 2 again, again and again
Try this: In ASPX front page
<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click" />
<asp:Timer runat="server" ID="Timer1" Enabled="False" Interval="1000" OnTick="Timer1_Tick"></asp:Timer>
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
</Triggers>
<ContentTemplate>
<asp:Label runat="server" ID="Label1"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
And then keep your Counter for example in ViewState
public int TimeCount = 1;
protected int Counter
{
get
{
if (ViewState["count"] == null)
return 0;
int temp;
return int.TryParse(ViewState["count"].ToString(), out temp) ? temp : 0;
}
set { ViewState["count"] = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ViewState["count"] = TimeCount.ToString();
}
}
protected void Timer1_Tick(object sender, EventArgs e)
{
Counter++;
Label1.Text = Counter.ToString();
}
protected void Button1_Click(object sender, EventArgs e)
{
Timer1.Enabled = true;
}
When ever the condition inside the Timer1_Tick gets satisfied, a postback is trigerred and thus resetting the timeCount varible. So use Session["timeCount"] to store the value instead of the timeCount varible :
protected void Page_Load(object sender, EventArgs e)
{
if (Session["timeCount"] == null)//this avoid resetting of the session on postback
{
Session["timeCount"] = 1;
}
}
protected void Timer1_Tick(object sender, EventArgs e)
{
Int32 count = Convert.ToInt32(Session["timeCount"].ToString());
if (count > 0)
{
Label1.Text = (count + 1).ToString();
count=count+1;
}
Session["timeCount"]=count;
}
TestUC.ascx Design Code
<asp:TextBox ID="txtbox1" runat="server" ClientIDMode="Static" placeholder="Enter Some Text" ></asp:TextBox><br />
<asp:Button ID="btn1" runat="server" Text="Click" OnClick="btn1_Click" ClientIDMode="Static" />
Test.aspx Page Code
<%# Register Src="~/WebUserControls/TestUC.ascx" TagName="WebUserControlTest"
TagPrefix="uctest" %>
<asp:Content ID="Content1" ContentPlaceHolderID="cphBody" runat="server">
<asp:Label ID="lbl1" runat="server" >Label</asp:Label>
<uctest:WebUserControlTest ID="ucTest" runat="server"></uctest:WebUserControlTest>
</asp:Content>
OutPut:
I Need ..
Step1: Enter Some text In Text Box
Step2:Then I Click Click Button
[Note: This Two Controls Are Bind From UserControl]
Step3:What Text Entered in TextBox Is Show In label [Note Label Present In Aspx Page]
You will need to have a custom event & you will also need to expose the Text property of the TextBox in your UserControl, like this.
public partial class YourUserControl : UserControl
{
public String Text
{
get
{
return this.txtBox1.Text;
}
//write the setter property if you would like to set the text
//of the TextBox from your aspx page
//set
//{
// this.txtBox1.Text = value;
//}
}
public delegate void TextAppliedEventHandler(Object sender, EventArgs e);
public event TextAppliedEventHandler TextApplied;
protected virtual void OnTextApplied(EventArgs e)
{
//Taking a local copy of the event,
//as events can be subscribed/unsubscribed asynchronously.
//If that happens after the below null check then
//NullReferenceException will be thrown
TextAppliedEventHandler handler = TextApplied;
//Checking if the event has been subscribed or not...
if (handler != null)
handler(this, e);
}
protected void yourUserControlButton_Click(Object sender, EventArgs e)
{
OnTextApplied(EventArgs.Empty);
}
}
Then in your aspx page, where you have placed YourUserControl (OR you are dynamically adding it from the code behind), you can subscribe to this event like this.
protected void Page_Load(Object sender, EventArgs e)
{
if (!IsPostBack)
{
yourUserControl.TextApplied += new YourUserControl.TextAppliedEventHandler(yourUserControl_TextApplied)
}
}
You can use the custom event of the user control in your page like this.
protected void yourUserControl_TextApplied(Object sender, EventArgs e)
{
yourLabelInYourPage.Text = yourUserControl.Text;
}
And you are done...
EDIT : You can rename the Controls & Events as you like. I have used the names only for the example purpose.
EDIT : In website projects, if you want to add your user control dynamically then,
you might need to include the namespace ASP in your page, like this.
using ASP;
And add this Directive in your page in the aspx markup.
<%# Reference Control="~/PathToYourUserControl/YourUserControl.ascx" %>
other solution : create an event in the usercontrol, which is called in the button click.
Subscribe to this event in the codebehind of the aspx page. that way you can update your interface only if a value is provided.
a little more complicated, but you could re-use this logic to more complex control / parent control feature in the future.
i can add code snippet if asked
This Answer Is Prepared By Help Of #Devraj Gadhavi i Edited Some Code .
UserControl Page Design Code
<asp:TextBox ID="txtbox1" runat="server" ClientIDMode="Static" placeholder="Enter Some Text" ></asp:TextBox><br />
<asp:Button ID="btn1" runat="server" Text="Click" OnClick="btn1_Click" ClientIDMode="Static" />
UserControl Page Code
public partial class TestUC : System.Web.UI.UserControl
{
public String Text
{
get
{
return this.txtbox1.Text;
}
}
public delegate void TextAppliedEventHandler(Object sender, EventArgs e);
public event EventHandler TextApplied;
protected virtual void OnTextApplied(EventArgs e)
{
if (TextApplied != null)
TextApplied(this, e);
}
protected void btn1_Click(object sender, EventArgs e)
{
OnTextApplied(EventArgs.Empty);
}
}
Aspx Page Design Code
<%# Register Src="~/WebUserControls/TestUC.ascx" TagName="WebUserControlTest"
TagPrefix="uctest" %>
<asp:Content ID="Content1" ContentPlaceHolderID="cphBody" runat="server">
<asp:Label ID="lbl1" runat="server" >Label</asp:Label>
<uctest:WebUserControlTest ID="ucTest" runat="server"></uctest:WebUserControlTest>
</asp:Content>
Aspx Cs File Code
public partial class Test2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ucTest.TextApplied += new EventHandler(ucTest_TextApplied);
}
protected void ucTest_TextApplied(Object sender, EventArgs e)
{
lbl1.Text = ucTest.Text;
}
}
Another method ,If you don't want to expose the Text property of the TextBox in your UserControl Just use method "UserControl.FindControl("Id Of your Textbox which is present in user control")" in your Case WebUserControlTest.FindControl("txtbox1").
And below is the simpler way to register an event handler on the parent web form's code behind.
Code goes as below for parent form asxp.cs
protected override void OnInit(EventArgs e)
{
//find the button control within the user control
Button button = (Button)WebUserControlTest.FindControl("btn1");
//wire up event handler
button.Click += new EventHandler(button_Click);
base.OnInit(e);
}
void button_Click(object sender, EventArgs e)
{
TextBox txt = (TextBox) WebUserControlTest.FindControl("txtbox1");
//id of lable which is present in the parent webform
lblParentForm.Text=txt.text;
}
Also, you can achieve this using JavaScript like below (given your code above):
<script type="text/javascript">
function getUCTextboxValue() {
let txtName = document.getElementById('<%=ucTest.FindControl("txtbox1").ClientID %>');
let lbl = document.getElementById('<%=lbl1.ClientID %>');
lbl.innerText = txtName.value
}
Also, from the parent page, you can add a HiddenField and save the textbox value on it (using the JavaScript code above) then catch its value from code behind.
I am trying to generate textboxes when the I press button add more so this is the code for onclick
protected void Add_TextBoxes(object sender, EventArgs e)
{
int index = int.Parse(ViewState["pickindex"].ToString());
TextBox MyTextBox = new TextBox();
MyTextBox.ID = "tbautogenerated"+index.ToString();
MyTextBox.Text = "tbautogenerated" + index.ToString();
MyTextBox.Width= 250;
MyTextBox.MaxLength = 128;
MyTextBox.Attributes.Add("runat", "server");
MyTextBox.CausesValidation = false;
MyTextBox.AutoPostBack = true;
MyTextBox.TextChanged += new EventHandler(MyTextBox_TextChanged);
picktexts.Controls.Add(MyTextBox);
}
void MyTextBox_TextChanged(object sender, EventArgs e)
{
TextBox MyTextBox = sender as TextBox;
}
but when I change in the textbox the textChanged doesn't work !!! what's wrong ?
HTML Code
<asp:UpdatePanel ID="UpdatePanel2" runat="server">
<ContentTemplate>
<div id="picktexts" runat="server">
<asp:TextBox ID="txtAdress" runat="server" MaxLength="128" Width="250" />
<asp:RequiredFieldValidator ControlToValidate="txtAdress" Display="Dynamic" ID="rfvAddress" Text="* Required" runat="server" />
<asp:Button ID="bt_addtxtbox" runat="server" Text="Add more" OnClick="Add_TextBoxes" CausesValidation="false" />
</div>
</ContentTemplate>
</asp:UpdatePanel>
I think the event handlers are getting lost between posts. the way ASP.NET works, every time you post a page back to itself, all objects are instantiated again, and their state is recovered from the ViewState. Normally a control that's declared in the aspx would reassociate itself with events by the declaration in its tag, which is not the case here.
So try associating the event handlers again during the page load. Like this:
void Page_Load (object sender, EventArgs e)
{
foreach (Control c in picktexts.Controls)
{
((TextBox)c).TextChanged += new EventHandler(MyTextBox_TextChanged);
}
}
And see if it works.
I want to know that how can I trace out the value of Textbox from ViewState.
As user enters any value into Textbox and click submit button because of postback Textbox value disappears ,
But if I used ViewState in this case , then is there any way to see or display that value from Viewstate?
<html>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click" /
</form>
</body>
</html>
protected void Button1_Click(object sender, EventArgs e)
{
TextBox1.Text += "X";
}
In your page load use this.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (ViewState["Values"] == null)
{
ViewState["Values"] = new string();
}
}
TextBox1.Text = ViewState["Values"].ToString();
}
After that use this.
protected void Button1_Click(object sender, EventArgs e)
{
ViewState["Values"] += TextBox1.Text;
}
In the first Page_Load method, You will create a ViewState if its not a postback and its null. After that write the textbox your viewstate, in Button1_Click you will add your new textbox1 to your viewstate.
I have a page in which I am loading a user control dynamically as follows:
Default.aspx:
<cc1:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</cc1:ToolkitScriptManager>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
Default.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
var ctrl = LoadControl("~/UserCtrl1.ascx");
ctrl.ID = "ucUserCtrl1";
PlaceHolder1.Controls.Add(ctrl);
}
Below is the code for UserCtrl1.ascx
<asp:Label ID="Label1" runat="server"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Button1" OnClick="Button1_Click" />
<br />
<asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>
I am dynamically loading another user control when the Button1 is clicked
UserCtrl1.ascx.cs
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = "UserControl - 1 button clicked!";
var ctrl = LoadControl("~/UserCtrl2.ascx");
ctrl.ID = "ucUserCtrl2";
PlaceHolder2.Controls.Add(ctrl);
}
Below is the markup for UserCtrl2.ascx
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="Label2" runat="server"></asp:Label>
<asp:Button ID="Button2" runat="server" Text="Button2" OnClick="Button2_Click" />
</ContentTemplate>
</asp:UpdatePanel>
UserCtrl2.ascx.cs
protected void Button2_Click(object sender, EventArgs e)
{
Label2.Text = "UserControl - 2 button clicked!";
}
After the page loads when I click the Button1 in UserCtrl1 the click event fires and I am able to see the Label1 text. It also properly loads the UserCtrl2, but when I click the Button2 in UserCtrl2 the click event dosent fire and even worse when I click the Button2 twice the UserCtrl2 control dissappears from the page. How can I fix this?
The problem with the second control is that you are loding it only after the click of button 1. But when some other (not button 1 click) postback happens your second control is not loaded.
One of possible fixes is saving some flag (e.g. in ViewState) that will help you to determine if your second control should be loaded (and load in on page load).
protected void Button1_Click(object sender, EventArgs e)
{
Label1.Text = "UserControl - 1 button clicked!";
var ctrl = LoadControl("~/UserCtrl2.ascx");
ctrl.ID = "ucUserCtrl2";
PlaceHolder2.Controls.Add(ctrl);
this.SecondControlLoaded = true; // This flag saves to ViewState that your control was loaded.
}
protected void Page_Load(object sender, EventArgs e)
{
var ctrl = LoadControl("~/UserCtrl1.ascx");
ctrl.ID = "ucUserCtrl1";
PlaceHolder1.Controls.Add(ctrl);
if (this.SecondControlLoaded)
{
var ctrl = LoadControl("~/UserCtrl2.ascx");
ctrl.ID = "ucUserCtrl2";
PlaceHolder2.Controls.Add(ctrl);
}
}