asp.net updatepanel inside usercontrol reload the whole control - asp.net

I want to create a user control that represents a progress bar.
ASCX:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ProgressBar.ascx.cs" Inherits="A2Controls.Controls.ProgressBar" %>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="<%# this.Value %>" aria-valuemin="0" aria-valuemax="100" style="width: <%# this.Value %>%">
<span class="sr-only"><%# this.Value %> Complete</span>
</div>
</div>
Code Behind:
public partial class ProgressBar : System.Web.UI.UserControl
{
public int Value { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
}
}
ASPX:
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Timer runat="server" ID="clock" OnTick="clock_Tick" Interval="1000" Enabled="true"></asp:Timer>
<uc1:ProgressBar runat="server" ID="ProgressBar" />
</ContentTemplate>
<Triggers >
<asp:AsyncPostBackTrigger ControlID="clock" EventName="Tick" />
</Triggers>
</asp:UpdatePanel>
Code Behind:
protected void clock_Tick(object sender, EventArgs e)
{
this.ProgressBar.Value++;
}
The problem is that every time the tick function is called, the updatepanel refreh and reload the whole usercontrol (calling the constructor I mean)! I've tried to put the updatepanel logic inside the usercontrol but there is no difference.
How can I prevent the usercontrol re-instantiate again?

You have to change your Value property to this:
public int Value
{
get
{
if (ViewState["Value"] != null)
return (int)ViewState["Value"];
else
return 0;
}
set
{
ViewState["Value"] = value;
}
}
In this way you keep the property's value across postbacks.
HTTP is a stateless protocol. Unfortunately you have to use some kind of trick to persist data across requests like the ViewState does. You better have a look here and here to deeply understand that there's nothing wrong here.

Related

Button not fired up inside asp user control used for umbraco macro

I'm searching solutions for my problem already since 2-3h and I decided better to ask.
I have created and empty web site and the installed umbraco, set up a new macro and it seemd ok but a button is not fired .
The code in Test.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Tests.ascx.cs" Inherits="Demo.Tests" %>
<h1>test</h1>
<form id="Form1" runat="Server">
<asp:Button ID="btnRunTest" OnClick="onClick_btnRunTest" Text="Run test" runat="server" CausesValidation = "false"/>
</form>
<div style="background-color: #de6363; padding: 10px;">
<asp:Label ID="lblMessage" runat="server" Text="" ForeColor="black" />
</div>
And code behind:
public partial class Tests : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//btnRunTest.Click += new EventHandler(this.onClick_btnRunTest);
}
public void onClick_btnRunTest(object sender, EventArgs e)
{
lblMessage.Text = "";
Stopwatch stopwatch = Stopwatch.StartNew();
DynSLinkedList<int?> list = new DynSLinkedList<int?>();
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Add(1);
list.Add(18);
list.Add(-1);
list.Add(-2);
list.Remove(18);
list.Remove(-2);
list.Remove(1);
var time = stopwatch.Elapsed.ToString();
lblMessage.Text = "Task finished in time "+time +"</br>";
}
}
When I hit the button page reloads but the onClick_btnRunTest is not hit

ViewState on programmatically loaded usercontrols (restored after Page_Load)

I'm trying to create a simple web page with a navigation bar and some usercontrols (ascx) programmatically loaded.
All controls are inside an update panel.
When I click on a link button (from the navigation bar) I do the following things:
I save the current usercontrol using viewstate.
Than I reload the current usercontrol.
My 'page_load' always reloads the current control.
Always assigning the same ID to the programmatically loaded control allows me to save the usercontrol viewstate.
So everything look good except one little thing: the usercontrol viewstate in not available during the usercontrol Page_Load!
Look below for (* HERE).
The 'txtTest.Text' value is always "0" (also during postback).
It seems that the user control viewstate is restored after the (usercontrol) Page_Load.
How is it possible?
--- "DEFAULT.ASPX": ---
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="sm" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="pnlMain" runat="server">
<ContentTemplate>
<div class="links">
<asp:LinkButton ID="lnkButton1" runat="server" OnClick="lnkButton1_Click" Text="Link 1"></asp:LinkButton>
<asp:LinkButton ID="lnkButton2" runat="server" OnClick="lnkButton2_Click" Text="Link 2"></asp:LinkButton>
</div>
<br />
<asp:Panel ID="pnlCtrl" runat="server"></asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
--- "DEFAULT.ASPX.CS": ---
private string CtrlAscx
{
get
{
if (ViewState["CtrlAscx"] == null)
{
ViewState["CtrlAscx"] = String.Empty;
}
return ViewState["CtrlAscx"].ToString();
}
set
{
ViewState["CtrlAscx"] = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
loadMyControl();
}
private void loadMyControl()
{
if (!String.IsNullOrEmpty(CtrlAscx))
{
pnlCtrl.Controls.Clear();
Control c = LoadControl(CtrlAscx);
c.ID = CtrlAscx + "ID"; // this line is mandatory in order to mantain the usercontrol viewstate
pnlCtrl.Controls.Add(c);
}
}
protected void lnkButton1_Click(Object sender, EventArgs e)
{
CtrlAscx = "Control1.ascx";
loadMyControl();
}
protected void lnkButton2_Click(Object sender, EventArgs e)
{
CtrlAscx = "Control2.ascx";
loadMyControl();
}
-- "CONTROL1.ASCX" --
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="Control1.ascx.cs" Inherits="WebTest.Control1" %>
Control1: <asp:TextBox id="txtTest" runat="server" Text="0"></asp:TextBox>
<asp:Button ID="btnTest" runat="server" />
-- "CONTROL1.ASCX.CS" --
public partial class Control1 : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (txtTest.Text == "0") // * HERE
{
txtTest.Text = "1";
}
}
}
Try the EnableViewState="true" attribure on txtTest as well as on your custom user control when creating it :
.
.
c.EnableViewState = true;
pnlCtrl.Controls.Add(c);

Cannot perform close/open ASP.Net Ajax ModalPopupExtenders in sequence from server side code

I'm having a problem hiding one ModalPopupExtender and Showing another within the same server-side call.
My app requires user input on some validating conditions. These conditions are evaluated in sequence and when certain conditions are true it requires a user to verify (click yes or no) via a ModalPopupExtender window. If the user clicks Yes, evaluation should continue and if another condition requires user input it should also open a modal dialog - until all conditions are passed.
I've got no problem if only one of the conditions requires input, but if more than one require input, only the first modal is displayed and I can't figure out why. When tracing the code it's clear that the Hide() on the first popup is hit and the Show() on the second popup is hit, but the second popup never shows up.
I've tried to pull out the relevant code blocks here with extreme simplification. It's a really complex project and I may have missed something but I hope it's enough to describe my problem.
Problematic process flow:
User clicks "Continue" -> DoContinue is called -> set conditions flags -> Show first modal popup -> Return to user
User clicks "Yes" -> calls condition 1 Yes click handler (set handled flag, hide modal popup) -> call DoContinue-> re-evaluate conditions flags -> attempt to show second modal popup -> return to user.
The first popup disappears but the second is never shown.
It's only a problem when Hide() is being called on the first modal in the same request where Show() is being called on the second.
MyContainerControl.ascx:
<%# Control Language="C#" AutoEventWireup="true" Inherits="MyContainerControl" %>
<input Type="Submit"
id="btnContinue"
Name="btnContinue"
Value="Continue"
OnServerClick="Continue_Click"
runat="server"/>
<asp:UpdatePanel
ID="updateCondition1"
runat="server"
ChildrenAsTriggers="false" UpdateMode="Conditional">
<ContentTemplate>
<ajaxToolkit:ModalPopupExtender
ID="modalCondition1"
runat="server"
BehaviorID="dlgCondition1"
TargetControlID="btnFakeInvokeModalCondition1"
PopupControlID="divCondition1"
BackgroundCssClass="modalBackground"
DropShadow="true"
PopupDragHandleControlID="divDragCondition1"
RepositionMode="RepositionOnWindowResize"
CancelControlID="btnCondition1No" />
<input type="button"
id="btnFakeInvokeModalCondition1"
runat="server"
style="display: none" />
<div id="divCondition1"
runat="server"
class="modalPopup">
<custom:Condition1Control id="condition1" runat="server" visible="false" />
<div id="divDragCondition1"></div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel
ID="updateCondition2"
runat="server"
ChildrenAsTriggers="false" UpdateMode="Conditional">
<ContentTemplate>
<ajaxToolkit:ModalPopupExtender
ID="modalCondition2"
runat="server"
BehaviorID="dlgCondition2"
TargetControlID="btnFakeInvokeModalCondition2"
PopupControlID="divCondition2"
BackgroundCssClass="modalBackground"
DropShadow="true"
PopupDragHandleControlID="divDragCondition2"
RepositionMode="RepositionOnWindowResize"
CancelControlID="btnCondition2No" />
<input type="button"
id="btnFakeInvokeModalCondition2"
runat="server"
style="display: none" />
<div id="divCondition2"
runat="server"
class="modalPopup">
<custom:Condition2Control id="condition2" runat="server" visible="false" />
<div id="divDragCondition2"></div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
MyContainerControl.cs:
public class MyContainerControl : System.Web.UI.UserControl
{
protected HtmlInputImage btnContinue;
//Condition1
protected AjaxControlToolkit.ModalPopupExtender modalCondition1;
protected UpdatePanel updateCondition1;
protected HtmlGenericControl divCondition1;
protected Condition1Control condition1;
//Condition2
protected AjaxControlToolkit.ModalPopupExtender modalCondition2;
protected UpdatePanel updateCondition2;
protected HtmlGenericControl divCondition2;
protected Condition2Control condition2;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
condition1.Condition1RaisedEvent += HandleCondition1Event;
condition2.Condition2RaisedEvent += HandleCondition2Event;
btnContinue.ServerClick += btnContinue_ServerClick;
}
protected void HandleCondition1Event(object sender, Condition1EventArgs e)
{
// use ship to store
ViewState["Condition1Yes"] = true;
ViewState["Condition1Value"] = e.Condition1Value;
modalCondition1.Hide();
DoContinue(sender);
}
protected void HandleCondition2Event(object sender, Condition2EventArgs e)
{
// use ship to store
ViewState["Condition2Yes"] = true;
ViewState["Condition2Value"] = e.Condition2Value;
modalCondition2.Hide();
DoContinue(sender);
}
protected void btnContinue_ServerClick(object sender, EventArgs e)
{
DoContinue(sender);
}
protected void DoContinue(object sender)
{
// test for conditions - just plug to true for demonstration
bool throwCondition1 !(ViewState["Condition1Yes"] == null ? false : (bool)ViewState["Condition1Yes"])
bool throwCondition2 = !(ViewState["Condition2Yes"] == null ? false : (bool)ViewState["Condition2Yes"])
// analyze conditions
if (throwCondition1)
{
var condition1Yes = ViewState["Condition1Yes"] == null ? false : (bool)ViewState["Condition1Yes"];
if (!condition1Yes)
{
divCondition1.Visible = true;
modalCondition1.Show();
return;
}
}
if (throwCondition2)
{
var condition2Yes = ViewState["Condition2Yes"] == null ? false : (bool)ViewState["Condition2Yes"];
if (!condition2Yes)
{
divCondition2.Visible = true;
modalCondition1.Show();
return;
}
}
// do other work
}
}
Condition1UI.ascx - Condition2UI.ascx is very similar:
<%# Control Language="C#" AutoEventWireup="true" Inherits="Condition1Control" %>
<div id="divCondition1Container" runat="server">
<input id="hdnCondition1Value" type="hidden" runat="server" value="<%# this.Condition1Value %>" />
<asp:Panel ID="pnlCondition1UI" runat="server">
<br />
<h2>
Warning!</h2>
<hr />
<br />
<div>
<p>Condition1 has been met.</p>
<br />
<br />
<p>Would you like to continue?</p>
</div>
<br />
<br />
</asp:Panel>
<div>
<table>
<tr>
<td align="center">
<asp:Button ID="btnCondition1Yes" runat="server" class="green" Text="Yes" style="padding: 3px 7px;" OnClick="DoCondition1YesClick" OnClientClick="$find('dlgCondition1').hide();" />
</td>
<td align="center">
<button id="btnCondition1No" class="red">No</button>
</td>
</tr>
</table>
<br />
</div>
<br />
</div>
Condition1Control.cs - Condition2Control.cs is almost identical:
public class Condition1EventArgs : EventArgs
{
public string Condition1Value { get; set; }
}
public class Condition1Control : System.Web.UI.UserControl
{
public HtmlInputHidden Condition1Value;
public event EventHandler<Condition1EventArgs> Condition1RaisedEvent;
protected virtual void RaiseCondition1Event(Condition1EventArgs e)
{
EventHandler<Condition1EventArgs> handler = Condition1RaisedEvent;
if (handler == null)
{
return;
}
handler(this, e);
}
public void DoCondition1ButtonYesClick(object sender, EventArgs e)
{
RaiseCondition1Event(new Condition1EventArgs{
Condition1Value = Condition1Value.Value
});
}
}
Change UpdatePanel's UpdateMode property to "Always" or don't forget to call 'Update' method of UpdatePanel which UI you want to update as result of postback fired from another UpdatePanel. So try to add updateCondition2.Update method call after modalCondition2.Show method in your code.

ASP.NET - Control Events Not Firing Inside Repeater

This is a absurdly common issue and having exhausted all of the obvious solutions, I'm hoping SO can offer me some input... I have a UserControl inside a page which contains a repeater housing several controls that cause postback. Trouble is, all of the controls inside of the repeater never hit their event handlers when they postback, but controls outside of the repeater (still in the UC) are correctly handled. I already made sure my controls weren't being regenerated due to a missing if(!IsPostBack) and I verified that Request.Form["__EVENTTARGET"] contained the correct control ID in the Page_Load event. I attempted to reproduce the symptoms in a separate project and it worked as it should.
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="NoteListControl.ascx.cs"
Inherits="SantekGBS.Web.UserControls.NoteListControl" %>
<asp:UpdatePanel ID="upNotes" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<div class="NoteList" id="divNoteList" runat="server">
<asp:Repeater ID="repNotes" runat="server">
<HeaderTemplate>
<table width="98%" cellpadding="3" cellspacing="0">
</HeaderTemplate>
<ItemTemplate>
<tr class="repeaterItemRow">
<asp:ImageButton ID="ImageButton1" runat="server" ImageUrl="~/Content/images/DeleteIcon.gif"
OnClick="ibRemove_Click" CommandArgument='<%# Container.ItemIndex %>' CommandName='<%# Eval("ID") %>'
CausesValidation="false" AlternateText="Delete" />
<%# Eval("Text") %></td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
<asp:PlaceHolder ID="phNoNotes" runat="server" Visible="false">
<div class="statusMesssage">
No notes to display.
</div>
</asp:PlaceHolder>
</div>
</ContentTemplate>
</asp:UpdatePanel>
public partial class NoteListControl : UserControl
{
[Ninject.Inject]
public IUserManager UserManager { get; set; }
protected List<Note> Notes
{
get
{
if (ViewState["NoteList"] != null)
return (List<Note>)ViewState["NoteList"];
return null;
}
set { ViewState["NoteList"] = value; }
}
public event EventHandler<NoteEventArgs> NoteAdded;
public event EventHandler<NoteEventArgs> NoteDeleted;
public event EventHandler<NoteEventArgs> NoteChanged;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
UtilityManager.FillPriorityListControl(ddlPriority, false);
}
}
protected void ibRemove_Click(object sender, ImageClickEventArgs e)
{
System.Diagnostics.Debug.WriteLine("ibRemove POSTBACK"); // This is NEVER hit
}
public void Fill(List<Note> notes)
{
Notes = notes;
RefreshRepeater();
}
private void RefreshRepeater()
{
if (Notes != null && Notes.Any())
{
var sorted = Notes.OrderByDescending(n => n.Timestamp);
Notes = new List<Note>();
Notes.AddRange(sorted);
repNotes.Visible = true;
phNoNotes.Visible = false;
repNotes.DataSource = Notes;
repNotes.DataBind();
}
else
{
repNotes.Visible = false;
phNoNotes.Visible = true;
}
}
}
public class NoteEventArgs : EventArgs
{
public Note Note { get; set; }
public NoteEventArgs()
{ }
public NoteEventArgs(Note note)
{
this.Note = note;
}
}
The code is intentionally missing functionality so just disregard that fact.
Your edited code has residual CommandArgument and CommandName properties; are you actually handling the Repeater.ItemCommand event?
If so, and if your page calls the control's Fill method on postbacks, that would explain it.
This classic ASP.NET hair-tearing problem is explained in these posts: A Stumper of an ASP.NET Question and A Stumper of an ASP.NET Question: SOLVED!
The explanation is a little mind-bending, but the crux of it is that Repeater.DataBind interferes with ASP.NET's ability to determine which repeater button caused a postback.
I found a missing td-tag in the Itemtemplate, sometimes when DOM is incorrect, the updatapanel do strange things.
Just about EVERY time I run into this problem it's because DataBind() is being called when it shouldn't be. This will kill most events from controls inside a repeater. I see you have an !IsPostBack check in your Page_Load... so that's a start. But try putting a breakpoint on repNotes.DataBind() and see if it's getting called when you don't expect it.
Does it work OK outside of an UpdatePanel?
I ran into the same problem. It happened with me if I've ran the DataBind twice. In other words when I populate the repeater control twice (for any reason) the events wont fire.
I hope that helps.

How to bind a nested control from main page code behind

I have the following structure in place and need to rebind the lower control (DropDownList)
from the code behind of the MainPage.
x MainPage1 x---- Panel1 (modal popup)
x--------- UpdatePanel (upMailOrStatusAction, on Panel1)
x-------------- RadioButtonList (rblActionLevel, on UpdatePanel)
x-------------- SubForm1 (on Panel1)
x------------------- CustomControl1 (on Subform1)
x------------------------ DropDownList (on CustomControl1)
What would be the correct way to accomplish this?
I added a public method "BindMailActionLookup()" to the control, but how do I call it from the main page? I get "does not exist in the current context"?
Here is the markup of the subform:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MailAddSubform.ascx.cs"
Inherits="Company.Solutions.Web.Controls.MailAddSubform" %>
<%# Register TagPrefix="st" TagName="MailActionLookup" Src="~/Controls/StMailActionLookup.ascx" %>
<div class="NinetyNinePercentWide">
<div class="NinetyNinePercentWide EightPixelBottomMargin">
<div class="RowHeader" style="padding-top: 20px;">
<span class="labelfield" >Action:</span>
</div>
<div>
<st:MailActionLookup ID="mailActionLookup" runat="server" />
</div>
</div>
<div class="NinetyNinePercentWide EightPixelBottomMargin" >
<br class="NinetyNinePercentWide" Text="&nbsp" />
<div class="RowHeader" >
<span class="labelfield" >Message:</span>
</div>
<div class="TwelvePixelLeftPad" >
<asp:TextBox ID="txtMailActionMessage" runat="server" MaxLength="40" />
</div>
</div>
</div>
Here is the markup for the custom control:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="StMailActionLookup.ascx.cs" Inherits="Company.Solutions.Web.Controls.StMailActionLookup" %>
<div id="mainControlContainer" style="width:99%; padding:8px;">
<div id="comboContainer" style="float:left; padding-top:12px;padding-left:5px; padding- right:5px; padding-bottom:3px;">
<asp:UpdatePanel runat="server" ID="mailActionUpdater">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="chkForms" EventName="CheckedChanged" />
<asp:AsyncPostBackTrigger ControlID="chkRequested" EventName="CheckedChanged" />
<asp:AsyncPostBackTrigger ControlID="chkOther" EventName="CheckedChanged" />
</Triggers>
<ContentTemplate>
<asp:DropDownList runat="server" ID="ddlLookup" width="240px" ondatabound="ddlLookup_DataBound1" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
<div id="filterContainer" style="text-align:left;padding-left:6px;width:275px">
<fieldset style="width:260px;">
<legend>Filters</legend>
<asp:CheckBox ID="chkForms" runat="server" Text="Forms" AutoPostBack="true" />
<asp:CheckBox ID="chkRequested" runat="server" Text="Requested Info" AutoPostBack="true" />
<asp:CheckBox ID="chkOther" runat="server" Text="Other" AutoPostBack="true" />
</fieldset>
</div>
</div>
And here is part of the code behind where I added the public method:
namespace Company.Solutions.Web.Controls
{
public partial class StMailActionLookup : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
BindForm();
}
public void BindMailActionLookup()
{
BindForm();
}
protected void BindForm()
{
GetActionLevel();
IEnumerable actions = GetClaimMailActions(GetFilter());
ddlLookup.DataSource = actions;
ddlLookup.DataTextField = "CodeAndDescription";
ddlLookup.DataValueField = "ActionCd";
ddlLookup.DataBind();
}
}
}
You shouldn't be exposing the internals of CustomControl1 to a consumer, so the most correct way would be to expose a public method (maybe call it "ResetDropDowns") on your CustomControl1 that the main page could call into.
CustomControl1 knows about it's own dropdowns, so it can easily find and rebind the control when someone calls the method.
Ok, we have a solution thanks to "womp's" suggestions and one of my co-workers.
Just keep nesting the public calls in a chain:
This in the main Claim Info code behind:
// Rebind the action code drop down to restrict to base level
mailAddSubform.BindMailActionLookup();
Then this in the subform code behind:
public void BindMailActionLookup()
{
mailActionLookup.BindMailActionLookup();
}
And finally, this in the lookup control:
public void BindMailActionLookup()
{
BindForm();
}

Resources