Platform: asp.net 4.0
I load scriptmanager from a baseclass for custom cdn handling and scripts inserting in pages and other custom things.
The problem is that when I insert an UpdatePanel it doesn't find the script manager because updatepanel search for it to early.
Is there a solution that does not imply removing ScriptManager from the basePage.
this class is from our custom utility dll
public abstract class OurFrameworkBasePage:Page
{
protected override void OnInit(EventArgs e)
{
CurrentScriptManager = BuildScriptManager();
Form.Controls.AddAt(0, CurrentScriptManager);
base.OnInit(e);
}
private ScriptManager BuildScriptManager()
{
return new ScriptManager
{
//some scriptmanager settings
};
}
protected ScriptManager CurrentScriptManager { get; set; }
}
this is site specific basepage
public abstract class SiteBasePage:OurFrameworkBasePage
{
//some custom methods and utility for a specific site
}
the default.aspx page
<html>
<head runat="server"><title></title></head>
<body>
<form id="form1" runat="server">
<div>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Literal runat="server" ID="ltr"></asp:Literal>
<asp:Button runat="server" OnClick="btnOkClick" ID="btnOk" Text="ok"/>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
Hopefully you have control over your framework class, as this will fix your issue:
protected override ControlCollection CreateControlCollection()
{
CurrentScriptManager = BuildScriptManager();
ControlCollection pageControls = base.CreateControlCollection();
pageControls.AddAt(0, CurrentScriptManager);
return pageControls;
}
protected override void OnInit(EventArgs e)
{
Form.Controls.AddAt(0, CurrentScriptManager);
base.OnInit(e);
}
Needs to be in both places. First, in CreateControlCollection so that it is created along with all the other controls. Second, in OnInit, because the ScriptManager needs to reside in a form with runat="server"
GuthMD's solution is a great one.
in the meantime i found another solution that accomplish different needs and i write there for reference.
My solution imply that if you want to handle postback with updatePanel you have to put scriptmanager tag in aspx page otherwise scriptmanger will be inserted programmatically for scripts references
protected override void OnInit(EventArgs e)
{
CurrentScriptManager = BuildScriptManager();
base.OnInit(e);
}
private ScriptManager BuildScriptManager()
{
ScriptManager rtn;
var script = Items[typeof (ScriptManager)];
if (script == null)
{
rtn = new ScriptManager
{
EnablePartialRendering = false
};
Form.Controls.AddAt(0, rtn);
}
else
{
rtn = (ScriptManager) script;
}
rtn.EnablePageMethods = false;
rtn.AjaxFrameworkMode = AjaxFrameworkMode.Disabled;
rtn.EnableCdn = true;
return rtn;
}
Related
In a C# Webforms website (not web application), I have the following set up:
A page, which includes Step.ascx which includes an asp:Repeater.
The repeater in Step.ascx displays all sections (Section.ascx) within this step.
SectionInfoProvider.GetSections(1).ToList() returns a list of SectionInfo, which is a class several properties including DisplayName as string.
I'm getting a compilation error (The type or namespace name could not be found) when trying to dynamically set the SectionInfo property of the Section user control into the repeater in Step.ascx.cs. I've tried using the partial class name of the user control, and UserControl, but neither work.
I'm also trying to create a collection of SectionControls because I want to use that for something else on the page too.
What am I doing wrong here?
Step.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="~/Step.ascx.cs" Inherits="Custom_Step" %>
<%# Register TagPrefix="uc" TagName="Section" Src="~/Section.ascx" %>
<asp:Repeater runat="server" ID="rptSections" OnItemDataBound="rptSections_OnItemDataBound" EnableViewState="True">
<ItemTemplate>
<uc:Section runat="server" ID="Section" EnableViewState="True"/>
</ItemTemplate>
</asp:Repeater>
Step.ascx.cs
public partial class Custom_Step : System.Web.UI.UserControl
{
public IEnumerable<SectionInfo> Sections { get; set; }
private IEnumerable<???> SectionControls { get; set; } <-- What should ??? be?
protected override void OnLoad(EventArgs e)
{
Sections = SectionInfoProvider.GetSections(1).ToList();
rptSections.DataSource = Sections;
rptSections.DataBind();
}
protected void rptSections_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
var info = (SectionInfo)e.Item.DataItem;
var ctrl = (???)e.Item.FindControl("Section"); <-- What should ??? be?
ctrl.SectionInfo = info;
if (SectionControls == null) SectionControls = new List<???>(); <-- What should ??? be?
((List<???>)SectionControls).Add(ctrl); <-- What should ??? be?
}
}
Section.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="~/Section.ascx.cs" Inherits="Custom_Section " %>
<h3><asp:Literal runat="server" ID="litSectionHeading" /></h3>
Section.ascx.cs:
public partial class Custom_Section : System.Web.UI.UserControl
{
public SectionInfo SectionInfo { get; set; }
protected override void OnLoad(EventArgs e)
{
litSectionHeading.Text = SectionInfo.DisplayName;
}
}
I think you just need a typecast and an if.
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {`
...
var ctrl = e.Item.FindControl<Custom_Section>("Section");`
or
var ctrl = (Section)e.Item.FindControl("Section");
...
}
Is that something you already tried?
Creating the dynamic controls can be done but that's a separate question.
I have an UpdatePanel with two HiddenField elements to determine which UserControl to swap into the PlaceHolder element. On initial load, one is placed in (this works fine). There are two buttons, and depending on which one is clicked, a PostBack occurs and is supposed to be swapping in the selected control.
When a button is clicked, the PostBack occurs, but in the network call, I do not see any HTML being returned, and nothing renders on the page, obviously. I don't know too much about ASP.NET and search results have yet to lead me to a solution, or a proper how-to that works for me.
Update Panel
<!-- Update Panel -->
<asp:UpdatePanel ID="PendingApprovalList" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<!-- Page Navigation Bar -->
<div style="margin-top: 100px;">
<!-- Secret Sauce -->
<asp:HiddenField ID="hf_onChartsPage" runat="server" value="true" />
<asp:HiddenField ID="hf_onTablesPage" runat="server" value="false" />
<!-- Navigation Clickables -->
<a ID="ChartsTab" class="googleAnalyticsNav" runat="server" onserverclick="ChartsClicked">Chart View</a>
<a ID="TablesTab" class="googleAnalyticsNav" runat="server" onserverclick="TablesClicked">Table View</a>
</div>
<!-- Page Content PlaceHolder -->
<asp:PlaceHolder ID="AnalyticsContent" runat="server"></asp:PlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
Main Page Code Behind
public partial class LocalGoogleReports : System.Web.UI.UserControl {
//Constants
private const string CHARTS_PATH = #"~/userctrls/Admin/Dashboard/Local/AnalyticsCharts.ascx";
private const string TABLES_PATH = #"~/userctrls/Admin/Dashboard/Local/AnalyticsTables.ascx";
//Properties
public int CENTER_NUM;
public string CENTER_NAME;
public bool GoToChartsPage {
get {
return bool.Parse(hf_onChartsPage.Value);
}
set {
hf_onChartsPage.Value = value.ToString();
}
}
public bool GoToTablesPage {
get {
return bool.Parse(hf_onTablesPage.Value);
}
set {
hf_onTablesPage.Value = value.ToString();
}
}
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
CENTER_NUM = SessionManager.Center.CenterNumber;
CENTER_NAME = SessionManager.Center.CenterName.ToLower();
AnalyticsContent.Controls.Clear();
UserControl chartsControl = (UserControl)LoadControl(CHARTS_PATH);
AnalyticsContent.Controls.Add(chartsControl);
} else {
if (GoToChartsPage) {
LoadChartsUserControl();
} else {
LoadTablesUserControl();
}
}
}
protected void ChartsClicked(object sender, EventArgs e) {
GoToChartsPage = true;
GoToTablesPage = false;
}
protected void TablesClicked(object sender, EventArgs e) {
GoToTablesPage = true;
GoToChartsPage = false;
}
private void LoadChartsUserControl() {
AnalyticsContent.Controls.Clear();
UserControl chartsControl = (UserControl)LoadControl(CHARTS_PATH);
AnalyticsContent.Controls.Add(chartsControl);
ScriptManager.RegisterStartupScript(PendingApprovalList, GetType(), Page.UniqueID,
"getAnalyticData();", true);
}
private void LoadTablesUserControl() {
AnalyticsContent.Controls.Clear();
UserControl tablesControl = (UserControl)LoadControl(TABLES_PATH);
AnalyticsContent.Controls.Add(tablesControl);
}
}
Thanks in advance for any help!
Try to use PendingApprovalList.UpdatePanel(); after loading Chart or Table
I am learning ASP.net,
I have a variable in the code behind in c#:
public int hasCar= 1;
and in the aspx file I want to access this variable in javascript function:
function PrintCar( ) {
var ind = <%=this.hasCar%>
alert(ind);
}
but I get error:
does not contain a definition for 'hasCar' and no extension method 'hasCar' accepting a first argument of type 'ASP.vids_aspx' could be
found (are you missing a using directive or an assembly reference?)
what is wrong?
thank you
This works for me:
ASPX Page:
<body>
<script type="text/javascript">
function PrintCar( ) {
var ind = <%=this.HasCar%>
alert(ind);
}
</script>
<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="PrintCar();"/>
</form>
</body>
Code Behind
public partial class WebForm1 : System.Web.UI.Page
{
public int HasCar { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
HasCar = 1;
}
}
I want to offer a complimentary answer rather than simply copying what other people have said. Personally I write JS from my C# rather than putting markup in the aspx.
I use this extension method:
public static class ClientScriptManagerExtensions
{
/// <summary>
/// Registers an object as a variable on the page
/// </summary>
public static void RegisterObjectAsVariable(this ClientScriptManager mgr, Type type, string variableName, object objectToEncode)
{
mgr.RegisterClientScriptBlock(type,
string.Concat("ClientScriptManagerExtensions_", variableName),
string.Concat("var ", variableName, " = ", new JavaScriptSerializer().Serialize(objectToEncode), ";"),
true);
}
}
Then to call I do:
this.Page.ClientScript.RegisterObjectAsVariable(typeof(MyPage), "myVariable", new { myProperty = 123});
This creates a js object on your page:
var myVariable =
{
myProperty = 123
};
Which you can access via JS. I find this approach much cleaner and it lets you pass all sorts of complex objects to your code.
Have you the following line at start line of your .aspx page ?
<%# Page Language="C#" CodeBehind="default.aspx.cs" Inherits="YOURNAMESPACE._default" %>
I have created test project just for your problem.
Try this code
Aspx Code..
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="test.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<script type="text/javascript">
function PrintCar() {
var ind = <%=this.HasCar%>;
alert(ind);
}
</script>
<form id="form1" runat="server">
<asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="PrintCar()"/>
</form>
</body>
</html>
Code behind...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace test
{
public partial class WebForm1 : System.Web.UI.Page
{
public int HasCar { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
HasCar = 1;
}
}
}
I have a custom UserControl which uses a simple ITemplate:
<asp:Panel runat="server" ID="pnlExpander" CssClass="expander">
<asp:HyperLink runat="server" ID="lnkExpand" Text="More Options" NavigateUrl="#" CssClass="lnkExpand"/>
<asp:Panel runat="server" ID="pnlContent" CssClass="expanderContent" style="display: none">
<asp:PlaceHolder runat="server" ID="plcContent"/>
</asp:Panel>
</asp:Panel>
The template is rendered with two simple properties:
public class Expander {
private ITemplate _contentTemplate;
public ITemplate ContentTemplate {
get { return _contentTemplate; }
set { _contentTemplate = value; }
}
protected override void OnPreRender(EventArgs e) {
if (ContentTemplate != null) {
ContentTemplate.InstantiateIn(plcContent);
}
}
Everything displays correctly, but I can't use FindControl within the template. I get a reference to my combobox from VS intellisense, but a compilation error that it's null whern I actually load the page.
To find the combobox in th the template, I'm using:
var cboFilterCriticality = AspNetUtils.FindControlRecursive(optionsExpander,"cboFilterCriticality") as DropDownList;
And the actual template looks like this on the page:
<l49:Expander runat="server" ID="optionsExpander">
<ContentTemplate>
... other controls
<asp:DropDownList ID="cboFilterCriticality" runat="server" ValidationGroup="filterGrid" DataTextField="Key" DataValueField="Value" />
</ContentTemplate>
</l49:Expander>
I resolved this by changing the UserControl which used an ITemplate. For some reason, it was calling InstantiateIn in OnPreRender, which is clearly way too late to render anything to be picked up by Page_Load in the page - see the Page LifeCycle and UserControls (half way down). I moved InstantiateIn to OnInit in the UserControl, and the problem solved itself.
The Asp.net's WebForm page:
<asp:Panel runat="server" ID="pnlExpander" CssClass="expander">
<asp:HyperLink runat="server" ID="lnkExpand" Text="More Options" NavigateUrl="#" CssClass="lnkExpand"/>
<asp:Panel runat="server" ID="pnlContent" CssClass="expanderContent" style="display: none">
<asp:PlaceHolder runat="server" ID="plcContent"/>
</asp:Panel>
</asp:Panel>
define the Expander class as following:
public class Expander {
public ITemplate ContentTemplate {get ;set;}
public HtmlGenericControl ContentTemplateContainer{get;set;}
protected override void OnInit(EventArgs e) {
this.ContentTemplateContainer = new HtmlGenericControl("div");
if (ContentTemplate != null) {
ContentTemplate.InstantiateIn(container);
}
plcContent.Controls.Add(container);
}
}
in OnInit of Page:
public override void OnInit(EventArgs e){
base.OnInit(e);
ViewState["ContentTemplateContainerID"] = ContentTemplateContainer.ClientID;
}
and finally in Javascript :
var containerID = ViewState("ContentTemplateContainerID");
var elID = $get(containerID)[0].id;
var expander = $find(elID);
I'm trying to build a UserControl; a visually customizable LinkButton. All was well until UpdatePanels came into the mix: my FancyButton usercontrol causes a page refresh. For comparison I'm also using a traditional LinkButton, which works as intended.
//Doesn't work: Causes whole page to refresh/reload.
<as:FancyButton ID="fbUpload"
runat="server" Text="FancyButton"/>
//Works as intended: Causes ajax refresh of Update Panel.
<asp:LinkButton ID="btnUpload" runat="server" Text="LinkButton" />
Here's my updatePanel code:
<asp:UpdatePanel ID="upNewUpdatePanel" UpdateMode="Always" ChildrenAsTriggers="true"
runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="fbUpload" EventName="Click" />
<asp:AsyncPostBackTrigger ControlID="btnUpload" EventName="Click" />
</Triggers>
<ContentTemplate>
<asp:PlaceHolder ID="detailPlaceHolder" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
And here is the code for the FancyButton UserControl:
I am pretty sure the problem is in here:
using System;
using System.Web.UI.WebControls;
using System.Web.UI;
namespace Jake
{
public class FancyButton : WebControl, INamingContainer
{
private LinkButton _btn;
public string Text
{
get
{
EnsureChildControls();
return _btn.Text;
}
set
{
EnsureChildControls();
_btn.Text = value;
}
}
public string OnClientClick
{
get
{
EnsureChildControls();
return _btn.OnClientClick;
}
set
{
EnsureChildControls();
_btn.OnClientClick = value;
}
}
public delegate void ClickEventHandler(object sender, EventArgs e);
public event ClickEventHandler Click = delegate { };
protected void _btn_Click(object sender, EventArgs e)
{
Click(this, e);
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
EnsureChildControls();
}
protected override void CreateChildControls()
{
base.CreateChildControls();
_btn = new LinkButton { ID = "btn" };
Controls.Add(_btn);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
}
protected override void Render(HtmlTextWriter writer)
{
//<a class="btn {Color} btn-{Color}{CssClass?}{hasImage?}">
writer.AddAttribute(HtmlTextWriterAttribute.Class, "fancyButton");
_btn.RenderBeginTag(writer);
if (Text != null)
{
writer.Write(Text);
}
_btn.RenderEndTag(writer);
}
}
}
TL;DR: The normal linkbutton works as an async trigger; my custom, UserControl button does not. What am I doing wrong?
Solution from accepted answer
By inheriting LinkButton instead of WebControl, the Async panel update works as intended. Also, all of those pesky override methods became unnecessary.
namespace Jake
{
public class FancyButton : LinkButton
{
public string Color
{
get
{
if ( ViewState["Color"] != null && ((string)ViewState["Color"]).Length > 0)
{
return ((string)ViewState["Color"]).ToLower();
}
else return "white";
}
set { ViewState["Color"] = value; }
}
public string Icon
{
get { return (string)ViewState["Icon"]; }
set { ViewState["Icon"] = value; }
}
protected override void Render(HtmlTextWriter writer)
{
//<a class="btn {Color} btn-{Color}{CssClass?}{hasImage?}">
writer.AddAttribute(HtmlTextWriterAttribute.Class, string.Format("fancyButton {0}{1}{2}",
this.Color,
CssClass.Length > 0 ? " " + CssClass : string.Empty,
Icon != null && Icon.Length > 0 ? " hasIcon" : String.Empty));
this.RenderBeginTag(writer);
// <span>
writer.RenderBeginTag(HtmlTextWriterTag.Span);
// <div class="icon {IconClass}"></div>
if (Icon != null)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, string.Format("icon {0}{1}",
Icon,
Text != null ? " btnIconPadding" : ""));
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.RenderEndTag();
}
if (Text != null)
{
writer.Write(Text);
}
// </span>
writer.RenderEndTag();
this.RenderEndTag(writer);
}
}
}
Not 100% sure on this, but I'm guessing that the problem is that the button causing postback is a private one from inside your UserControl, which you can't add to your triggers so easily.
The cleanest workaround I can think of is to make a class that inherits from LinkButton for your customizable control rather than a UserControl. Disadvantage: no visual designer or markup page.
A quick Google on the issue brought me indirectly to a Microsoft Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/524827/dynamicdataentities-site-linkbutton-in-updatepanel#details
(Don't bother reading the thread he links from ASP.NET forums unless you like banging your head on the wall)