Can an "ascx" user control wrap content? - asp.net

I'm trying to create an ascx control that can wrap content like a panel. I'm looking to do something like -
<%# Register TagPrefix="FOO" TagName="Section" Src="CollapsibleSection.ascx" %>
<Foo:Section runat="server">
[ Section of asp.net webforms page ]
</Foo:Section>
It has been a while since I've done web forms and cannot remember if this is possible to do? While I could write a fully custom control, there are many advantages in my app if this is possible.

You need to decorate your user control with TemplateContainerAttribute and inherit from INamingContainer.

This is referred to as a templated control.
Here's a simple tutorial explaining how this is done in both C# and VB.Net: How to: Create Templated ASP.NET User Controls
Quoted from MSDN (link above):
In the .ascx file, add an ASP.NET PlaceHolder control where you want the template to appear.
In the user control's code, implement a property of type ITemplate.
Define a server control class that implements the INamingContainer interface as a container in which to create an instance of the
template. This is called the template's naming container.
Apply the TemplateContainerAttribute to the property that implements ITemplate and pass the type of the template's naming
container as the argument to the attribute's constructor.
In the control's Init method, repeat the following steps one or more times:
Create an instance of the naming container class.
Create an instance of the template in the naming container.
Add the naming container instance to the Controls property of the PlaceHolder server control.

Related

ASP.NET composite control doesn't bubble event but template does

I am developing a composite control for an ASP.NET application and just by chance initially developed the control to use an ITemplate to create its child controls. There will be a series of buttons within the child controls that are to be handled in the root control. I am using the OnBubbleEvent with CommandName/CommandArgument properties on the buttons to wire it all up. And everything worked great... until I changed the templates to controls.
When I converted the template to a Control and called Controls.Add(new ChildControl()) in my root control instead of InstantiateIn(this), event bubbling no longer works.
Any idea why?
(Everything, and I mean everything, else is the same.)
Your composite control must implement INamingContainer interface in order to receive OnBubbleEvent calls. The CompositeControl class already implements this interface... in your case it stopped working not because of ITemplate thing, but because you changed inheritance from CompositeControl to Control.
See this: http://msdn.microsoft.com/en-us/library/system.web.ui.control.onbubbleevent.aspx
they say it there.

ASP.NET - ascx.designer 'properties' not showing up in reflection at runtime

I have a very simple setup, single mycontrol.ascx with assoicated mycontrol.ascx.designer.vb and mycontrol.ascx.vb file.
mycontrol.ascx embeds a single reference to a custom control: "MyMenu":
<mM:myMenu id="myMenu1" runat="server" />
This has created a protected reference in the mycontrol.ascx.designer.vb file:
Protected WithEvents myMenu1 As Global.CustomControls.MyMenu
Now, when I breakpoint the Page_Load() event of mycontrol.ascx, and inspect the members returned from the type via:
Me.GetType().GetMembers()
I cannot any reference to myMenu1. If I look at the control with intellisence, the property is accessible:
Me.myMenu1
Can anyone explain exactly what I'm missing and what I need to do to access designer created properties at runtime through reflection?
Cheers
Yum.
Your .acsx file creates a separate class (generated by the compiler) that inherits the codebehind class.
GetMembers only returns the members defined directly on the class, not any members inherited from its base class.
You need to get the members defined on the base class, like this:
Me.GetType().BaseType.GetMembers()
what I need to do to access designer created properties at runtime through reflection?
I don't know your menu control but you don't need to grasp the members of the user control, you need to get to the members of the menu control.
myMenu1.GetType().GetMembers()
Besides why use reflection? Doesn't your custom control expose properties with which you can set your settings like
myMenu1.SelectedMenuItem = 3

Server ccntrols in user control are null when user control serves as a base user control (asp.net)

I don't think I understand fully how ASP.NET does inheritance of controls.
I have a user control, ucBase, which has an asp.net label in the ascx file. Code behind references the label and it works fine during run time if the control is not a parent for another user parent.
If I have another user control, ucChild, inheriting from ucBase, the label in ucBase's code is always null. ucChild has no controls in its ascx file
The server controls (like the label) needs to be declared in the ascx file and not created programmatically.
What needs to be done for ucBase to see its own controls when it's a parent user control?
The issue:
Inheritance only inherits the code part of your user control. Markup is not something that can be inherited, since it is dynamically compiled at runtime.
The relationship between the markup and your code-behind is done through the .designer.cs partial class that comes with your user control. This designer file contains declarations for all the objects in your markup. This basically decorates the code-behind class with a bunch of fields that are null object references - these will be initialized with actual instances when the compiled markup code is run.
When you inherit from the .ascx file, you are inheriting all these null object placeholders. However, since the markup in your new control is not the same as the parent control, none of those objects are actually created when the new control's markup doesn't contain the corresponding markup, and when it is parsed and compiled, all the references stay null. Does this make sense?
The fix:
The best way to do this is to make your user controls self contained, i.e. favor code-based composition rather than markup based. In other words, instead of using markup, set up your user control using Page_Init and adding all the controls you need to the Controls collection in code behind.
Then when you inherit this class, all the same code will be executed, ensuring that your child usercontrol has the same UI controls in it.

Is there a better way to access controls in an ITemplate than FindControl()?

When a control is added to an UpdatePanel, it can still be accessed from the code behind of the containing page. How is this achieved? Can custom control developers do the same?
In other words, if I develop a template control using the ITemplate Interface, is there a way to wire it up (like the UpdatePanel seems to) so that any controls contained within (declaratively) can be accessed from the containing page also?
You can add a TemplateInstanceAttribute on your ITemplate property to achieve this, it has the effect of promoting the controls to page level:
[TemplateInstance(TemplateInstance.Single)]
public ITemplate AnonymousTemplate {
get { ... }
set { ... }
}
From MSDN:
The TemplateInstanceAttribute class allows you to mark a template property as one that allows single or multiple instantiations. A template that only allows a single instantiation can have the controls that are contained inside of it referenced. The ZoneTemplate property is an example of a property that can be instantiated only one time.

Javascript function is not working properly in Master pages

document.getelementbyid('txtbox') is not working when I used in content page as it is working in the normal web page. The value is null when it is used in contentpage. Plz anybody help me
The id will have changed, you can use something like:
document.getelementbyid(<%=txtTextBox.ClientID%>).value
or you can view the source to get the id in the hopes that it will not change again.
If you have the option I'd switch to some other engine, such as asp.net mvc where you have control over the HTML.
When the page renders, if the textBox is under another control, the Id tends to change.
You can use the ClientId property:
document.getElementById("<%= txtbox.ClientID %>")
Read this article
Control ID Naming in Content Pages
ASP.NET allows certain controls to be
denoted as naming containers. A naming
container serves as a new ID
namespace. Any server controls that
appear within the naming container
have their rendered id value prefixed
with the ID of the naming container
control.
Naming containers not only change the
rendered id attribute value, but also
affect how the control may be
programmatically referenced from the
ASP.NET page's code-behind class. The
FindControl("controlID") method is
commonly used to programmatically
reference a Web control. However,
FindControl does not penetrate through
naming containers. Consequently, you
cannot directly use the
Page.FindControl method to reference
controls within a GridView or other
naming container.
Master pages and ContentPlaceHolders
are both implemented as naming
containers.

Resources