Access to ASP controls in XSLT Layout

Topics: General, XSLT
Jun 7, 2011 at 5:40 PM

is there a way to add standard asp controls in the xslt layout such as

<asp:updatepanel>

<asp:button> etc.....

 

or even registering your own controls

<icg:textbox> etc....

 

or can this document type be removed <xmlns:asp="http://www.composite.net/ns/asp.net/controls">

Coordinator
Jun 7, 2011 at 5:49 PM

You can load in ASP.NET Controls by using the C1 Function features - for instance, if your XSLT emit the following in its result, a User Control will be loaded:

<f:function xmlns:f="http://www.composite.net/ns/function/1.0" name="Composite.AspNet.LoadUserControl"> 
  <f:param name="Path" value="~/My/Path.ascx" /> 
</f:function>
The concept is to emit C1 Function markup, and if those functions return ASP.NET controls, that is what you get. Check http://docs.composite.net/C1/ASP-NET/HelloWorldControl.aspx for more info.

Jun 7, 2011 at 5:51 PM

If you want to use standard asp.net controls and make them work together you should look at using Masterpage based layouting instead of XSLT. Webform controls don't do much by themselves and its first during postback and interaction with other controls in the control hierarchy them become truly powerful. With XSLT based layout every function is a self contained unit that is executed without knowledge of each other. This is also the behavior you'll see with ie. MVC. This has its advantages due to its simplicity but can be difficult get your head around if you're used to the rich environment that asp.net Webforms gives you with objects, control hierarchies and events.

Coordinator
Jun 7, 2011 at 6:03 PM

@burningice You can do layout using XSLT and use asp.net controls at the same time. If needed you can have the controls reference each other etc., they all end up in the same control tree. There is no need to use asp.net master pages to use controls.

Jun 7, 2011 at 6:43 PM
Edited Jun 7, 2011 at 6:44 PM

sure you can have several controls inside the same usercontrol referencing each other but thats also kinda where the fun stuff stops.

Say you wanted this

 

Lots of text

<f:function xmlns:f="http://www.composite.net/ns/function/1.0" name="Composite.AspNet.LoadUserControl"> 
  <f:param name="Path" value="~/My/Path.ascx" /> 
</f:function>

Lots of more text

<f:function xmlns:f="http://www.composite.net/ns/function/1.0" name="Composite.AspNet.LoadUserControl"> 
  <f:param name="Path" value="~/My/Other/Path.ascx" /> 
</f:function>

 

and you want some code in the first control to reference the second control... you don't define any server side ids so what would you do... a lot of Parent.Child[2].Parent.Child[1] perhaps, but thats just not feasible. Its hard to argue around that just as every other C1 function is a self-contained unit, that the same applies for the Composite.AspNet.LoadUserControl function. It's not simple to reference a textbox in one usercontrol from the button submit handler in another.

You can't

  • reference Page.Header since its not defined as a server control
  • do (Page as myBaseType).SomeBaseProperty since you don't have access to setting the type you want a template to inherit from
  • use Ajax Page Methods since they need to be defined on the page which you don't have access to
  • do template inheritance like with masterpages
  • use any of the Webform Menu Controls since they rely on asp.net Sitemap
Coordinator
Jun 7, 2011 at 8:13 PM
Edited Jun 8, 2011 at 8:00 PM

There are some rather large inaccuracies the claims above - we got a lot more asp.net webforms conformance than that.

> It's not simple to reference a textbox in one usercontrol from the button submit handler in another

False - your controls end up en the same control tree, below the same Page and you can define server side ID's all you wish - if you need to dig out a control from somewhere on the page, you can do this pretty easily. Code sample below.

> You can't ... reference Page.Header since its not defined as a server control

False - do this in a control, and you change the pages title: this.Page.Header.Title = "Hello World";

We create a Header element based on the <head /> that html, xslt'etc. generate - this Header can then be changed/used by asp.net.

> You can't ... do (Page as myBaseType).SomeBaseProperty since you don't have access to setting the type you want a template to inherit from

True - if ASP.NET Page sub classing is a requirement, Composite C1 wont help.

> You cant't ... use Ajax Page Methods since they need to be defined on the page which you don't have access to

False - if you need the <asp:ScriptManager /> on a page, include it. You can do so via a Control just fine.

> You cant't ... do template inheritance like with masterpages

False - you can do all kinds of crazy layout inheritance with the C1 Function system, and for instance XSLT. The XSLT starter site do this a lot.

True - if you specifically mean asp.net master page inheritance.

> You cant't ... use any of the Webform Menu Controls since they rely on asp.net Sitemap

False - you can add any control you want to. You would need to register a sitemap provider, but saying you can not have webforms menus is not true.

Video sample

Here is a video showing the bits below running: http://www.screenr.com/HAss

Code sample

A few of the above points is shown in this code sample. It is to user controls you can place where you want, and they will do AJAX, talk to (find) each other and update the page Header. To install it:

  1. Create a new Composite C1 site, use the XSLT templates if you please
  2. Copy the two controls below to your ~/Frontend folder
  3. Embed them on some page / template / a mix - just have the two controls active on the same page. Use the embed sample markup below, and use aither A.ascx or B.ascx.
  4. Save, publish, browse to the page and click/debug away.

A.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="A.ascx.cs" Inherits="ControlA" %>
<form runat="server">
<asp:TextBox ID="AText" runat="server" />
<asp:Button runat="Server" onclick="AButton_Click" Text="Click me" />

<asp:ScriptManager ID="ScriptManager1" runat="server" AjaxFrameworkMode="Enabled" />

<hr />

<asp:UpdatePanel runat="server" ChildrenAsTriggers="true" UpdateMode="Always">
<ContentTemplate>
<%= DateTime.Now %>.<%= DateTime.Now.Millisecond %>
<asp:Button Text="AJAX" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</form>

 

A.ascx.cs

using System;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class ControlA : System.Web.UI.UserControl
{
protected void AButton_Click(object sender, EventArgs e)
{
// Accessing the page head
this.Page.Header.Title = AText.Text;

// Grabbing a label from another control - we expect to find it or explode
Label bLabel = (Label)FindControlRecursive(this.Page,"BLabel");
bLabel.Text = "A's text box says " + AText.Text;
}

private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
return root;

foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
return t;
}

return null;
}
}

B.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="B.ascx.cs" Inherits="ControlB" %>
<asp:Label ID="BLabel" runat="server" />

B.ascx.cs

public partial class ControlB : System.Web.UI.UserControl
{
}

 

Embedding a user control on a page, template or xslt output:

    <f:function name="Composite.AspNet.LoadUserControl" xmlns:f="http://www.composite.net/ns/function/1.0">
<f:param name="Path" value="~/Frontend/A.ascx" />
</f:function>