Asp.net: conditional loading of user controls fails - asp.net

Hello (sorry for the poor title)
I have a user control which loads different additional user controls based on some conditions like this:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="SubPage.ascx.cs" Inherits="SubPage" %>
<%# Register Src="<srcA>" TagName="A" TagPrefix="CTRL" %>
<%# Register Src=">srcB>" TagName="B" TagPrefix="CTRL" %>
<% if (someValue == 1) { %>
Loading user control A..
<CTRL:A runat="server" />
<% } else { %>
Loading user control B..
<CTRL:B runat="server" />
<% } %>
The result will look correct; the expected content is displayed. But I noticed that even though someValue != 1 and control B is displayed, control A is still loaded behind the scenes (page load is called).
Why is this? And what would be a better approach? Thanks.

Page_Load is called because you handle this event.
Don't try to load them in this way but use the Visible-Property instead from codebehind.
Expose a public function that the controller(in your case SubPage.ascx) calls after it changed the visible state to load the content of the UserControl. Controls that aren't visible won't be rendered as html at all.
Loading controls dynamically if you don't really need can cause unnecessary ViewState- or Event-Handling issues. Here are some other disadvantages mentioned regarding dynamic UserControls.

You need to call LoadControl method instead
<% if (someValue == 1) { %>
Loading user control A..
Page.LoadControl(("~\ExampleUserControl_A.ascx");
<% } else { %>
Loading user control B..
this.LoadControl(("~\ExampleUserControl_B.ascx");
<% } %>

Code Front:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="SubPage.ascx.cs" Inherits="SubPage" %>
<%# Register Src="<srcA>" TagName="A" TagPrefix="CTRL" %>
<%# Register Src="<srcB>" TagName="B" TagPrefix="CTRL" %>
<asp:placeholder id="plhControls" runat="server" />
Code Behind:
if (someValue == 1) {
CTRLA ctrlA = (CTRLA)LoadControl("~/Controls/ctrlA.ascx");
plhControls.Controls.Add(ctrlA);
} else {
CTRLB ctrlB = (CTRLB)LoadControl("~/Controls/ctrlB.ascx");
plhControls.Controls.Add(ctrlB);
}

Related

My web control doesn't appear in my web page in a different folder

My web control doesn't appear in my web page in a different folder,
However it works in another web page in the same location.
My source code is like this :
..
<%Register src="~/UI/Human/HumanUserControl.wuc" TagPrefix="uc1"
TagName="HumanUserControl"/>
...
<uc1:HumanUserControl runat="Server" id="HumanUserControl"/>
...
Error:
Request is not available in this context
The syntax on your Register tag is incorrect. And I'm not sure why you're using a ".wuc" extension instead of the default ".ascx".
You need matching <% %> tags, like so:
<%# Register Src="~/UI/Human/HumanUserControl.wuc" TagPrefix="uc1" TagName="HumanUserControl" %>
If you delete the <%Register .../> and <uc1 .../> tags from your page completely, then in Visual Studio, drag-and-drop the user control from the Solution Explorer directly onto your page wherever you want the control to appear, it will automatically add the correct Register and user control tags for you.
If this doesn't clear things up, then provide more detailed error information, including the code where the exception is thrown.
The following works just fine:
~/UI/Human/HumanUserControl.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="HumanUserControl.ascx.cs" Inherits="UserControlTest.UI.Human.HumanUserControl" %>
<asp:Label ID="lblTest" runat="server" />
~/UI/Human/HumanUserControl.ascx.cs
namespace UserControlTest.UI.Human
{
public partial class HumanUserControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
lblTest.Text = Request.Browser.Browser;
}
}
}
~/Default.aspx
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="UserControlTest._Default" %>
<%# Register Src="~/UI/Human/HumanUserControl.ascx" TagPrefix="uc1" TagName="HumanUserControl" %>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
<uc1:HumanUserControl runat="server" id="HumanUserControl" />
</asp:Content>

Access in page an object from MasterPage that inherits from another MasterPage

I have the following hierarchy:
Site.Master
Site2.Master
Page1.aspx
Page2.aspx
Page3.aspx
Page4.aspx
On Page3 and Page4 I can access an object on Site.Master using <%# MasterType VirtualPath="~/Site.Master" %> on aspx file.
How can I access same object on Page1 and Page2?
I tried:
1) Put <%# MasterType VirtualPath="~/Site.Master" %> on Page1.aspx but I receive an error.
2) Put <%# MasterType VirtualPath="~/Site.Master" %> on Site2.Master and <%# MasterType VirtualPath="~/Site2.Master" %> on Page1.aspx. Page1.aspx open but I can't access object using Master property.
Thank you.
public Site TopMasterPage
{
get
{
return (this.Master as Site) ?? this.Master.Master as Site;
}
}

Rendering template for newform and code behind

I'm trying to create a rendering template for my forms which need complex validations treatments.
the rendering template is working fine wwith :
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Display>ListForm</Display>
<Edit>ChaisTemplate</Edit>
<New>ChaisTemplate</New>
</FormTemplates>
</XmlDocument>
</XmlDocuments>
and with my ascx :
<%# Control AutoEventWireup="true" CodeBehind="ChaisTemplate.ascx.cs"
Inherits="TransactionsFormsTemplates.ControlTemplates.ChaisTemplate, TransactionsFormsTemplates"
Language="C#" %>
<%# Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
Namespace="Microsoft.SharePoint.WebControls" %>
<%# Register TagPrefix="wssuc" TagName="ToolBar" Src="~/_controltemplates/ToolBar.ascx" %>
<%PageLoad(this, null);%>
<SharePoint:RenderingTemplate ID="ChaisTemplate" runat="server">
.....
but I can't have any control mappings in my code behind (in the webapp bin with cas policies, and it's correctly deployed)
this :
<asp:TextBox runat="server" ID="test"></asp:TextBox>
is null when it comes to :
public partial class ChaisTemplate : System.Web.UI.UserControl
{
protected TextBox test;
so everytime I call test.Text on functions, I get a nullreferenceexception, because test is never mapped to my ascx textbox. why ?
plus, the PageLoad is never called like in classic asp.net pages, even with <%PageLoad(this, null);%> at the beginning.
however every event works :
<asp:Button runat="server" ID="button" OnClick="button_OnClick"/>
this will actually call button_OnClick in my code behind. But all my properties are null because not mapped.
did I miss something?
I'v been doing it like this. Take this as an example RenderingTemplate:
<SharePoint:RenderingTemplate ID="ParentItemsListView" runat="server">
<Template>
<table cellpadding=0 cellspacing=0>
<tr><td nowrap class="UserGenericHeader"><asp:Label ID="lblParentItems" runat="server" /></td></tr>
<tr><td><SharePoint:ListViewByQuery ID="listViewByQuery" runat="server" /><br /></td></tr>
</table>
</Template>
</SharePoint:RenderingTemplate>
Then in Render event i can reference these controls like this:
[SharePointPermission(SecurityAction.Demand, ObjectModel = true)]
protected override void Render(HtmlTextWriter output)
{
if (this.Visible)
{
Label lblParentItems = this.TemplateContainer.FindControlRecursive<Label>("lblParentItems");
lblParentItems.Text = "Pievienotie " + this.ChildList.Title;
ListViewByQuery listView = TemplateContainer.FindControlRecursive<ListViewByQuery>("listViewByQuery");
listView.List = this.ChildList;
...
base.Render(output);
}
}
Ahh, yes, i use a handy extension function
public static T FindControlRecursive<T>(this Control parentControl, string id) where T : Control
{
T ctrl = default(T);
if ((parentControl is T) && (parentControl.ID == id))
return (T)parentControl;
foreach (Control c in parentControl.Controls)
{
ctrl = c.FindControlRecursive<T>(id);
if (ctrl != null)
break;
}
return ctrl;
}
However i had an issue where i inherited from SaveButton that i couldn't reference a control. In that case i changed so that i inherit from FormControl and i could find my control under this.Controls.
Also note that you cannot reference controls up until OnLoad event has executed (i.e if you're in OnLoad function, call base.OnLoad(e) before referencing controls.
Why is it so? I guess because it's not like you are having a template and then code behind (working with the same class/object), but it's more like you are rendering that ascx template in a different class/object file.

Access to MVC Models from standard ASCX UserControl

I've got a simple ASCX user control (non-MVC). The user control has a property on it (let's call it Title or something).
I've also got an MVC Partial View which contains the user control.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SomeModel>" %>
<%# Register TagPrefix="tag" TagName="Control" Src="~/path/to/ascx/control.ascx" %>
... snip ...
<tag:Control ID="myControl" runat="server" />
What I'd like to be able to do is something like this:
<tag:Control ID="myControl" runat="server" Title="<%= Model.Title %>" />
... so that I can access some property of the model inside my Control.
Unfortunately this method doesn't work, as I get a message saying "This is not scriptlet. Will be output as plain text".
Is what I'm trying to do even possible? If so, does anyone have any ideas how I can try and do it?
If it's relevant, this is a .Net 4 project, with MVC 2 components.
Thanks!
Neil
Is what I'm trying to do even possible?
Yes but it would be extremely ugly and it involves using a code behind (in an ASP.NET MVC view!!!):
<%# Page
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="AppName.Views.Home.Index"
CodeBehind="Index.aspx.cs"
%>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<asp:Label ID="Txt" runat="server" />
</asp:Content>
and in the corresponding code behind Index.aspx.cs (beurk..., I will vomit):
public partial class Index : System.Web.Mvc.ViewPage<AppName.Models.MyViewModel>
{
protected void Page_Load(object sender, EventArgs e)
{
Txt.Text = Model.Title;
}
}
which could be improved like this to avoid the code behind nonsense:
<%# Page
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<AppName.Models.MyViewModel>"
%>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Txt.Text = Model.Title;
}
</script>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<asp:Label ID="Txt" runat="server" />
</asp:Content>
I wouldn't recommend you doing something like this if you intend to migrate to ASP.NET MVC 3 and the Razor view engine one day.
I found a solution that's a little cleaner. Still not to my liking, but good enough to wash my hands of this annoying issue.
<% ViewBag.Item = item; %>
<gc:Ribbon runat="server">
<Content>
<strong><%= ViewBag.Item.DataItem.Name %></strong>
</Content>
</gc:Ribbon>
Instead of passing an object into the user control to use within, assign it to the ViewBag (for each iteration if you're looping), and use it globally. If memory serves me right, I believe MVC 2 uses ViewData["loosely typed name"] instead of the dynamic ViewBag.

view state in asp.net

I can disable viewstate of each control, but not entire page.
Is there a way to disable viewstate in whole page?
Set Page.EnableViewState to false. This can be done either in the code-behind or in the page directive:
<%# Page EnableViewState="false" %>
You can also disable ViewState at the application level by setting the enableViewState attribute of the pages node to false in your web.config:
<pages enableViewState="false"/>
You can do it in the page declaration:
<%# Page EnableViewState='false' %>
private void Page_Init(object sender, System.EventArgs e)
{
this.EnableViewState = false;
}
You can set Page.EnableViewState="false"
But no matter what there will be some very small ViewState footprint on any .aspx page you create.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" EnableViewState="false" %>

Resources