Question

Can anyone explain why you can’t use inline code blocks within server control declarations in ASP.Net?

The following is a simple example...

....
<form id="form1" runat="server">
    <asp:Label ID="Label1" runat="server" Text="<%= SomeProperty %>"></asp:Label>
</form>
....

The code block is rendered literally to the page...

<span id="Label1"><%= SomeProperty %></span>

My initial thoughts are it has to do with the order that these things are processed in the page life-cycle. The <%=...%> blocks are, as I understand it, equivalent to a Response.Write(...) in code-behind. And since the server control is not actually rendered as declared in the markup, I suppose it may not be possible to process an embedded code block before this rendering takes place.

I would be very grateful of anyone could explain that a little better.

However, the data binding code block <%#...%> is obviously different in the way it behaves, but can anyone tell me why it is possible to embed these within a server control...

....
<asp:Repeater id=Repeater1 runat="server">
    ....
    <ItemTemplate>
        <asp:Label ID="Label1" runat="server" Text='<%# Eval(“SomeProperty”) %>'></asp:Label>
    </ItemTemplate>
    ....
</asp:Repeater>
....

This works fine.

Was it helpful?

Solution

Your mostly right about the <%=...%> syntax. Here is an example of what happens under the hood:

<script runat="server">
    public string SomeProperty { get { return "Hello World!"; } }
</script>

<form id="form1" runat="server">
    <%= SomeProperty %>
    <div>
        <asp:Label ID="Label1" runat="server" Text="<%= SomeProperty %>"></asp:Label>
    </div>
</form>

This is parsed and the following C# code is created (I've simplified it a bit):

private Label @__BuildControlLabel1() 
{
    Label @__ctrl = new Label();

    this.Label1 = @__ctrl;
    @__ctrl.ApplyStyleSheetSkin(this);
    @__ctrl.ID = "Label1";
    @__ctrl.Text = "<%= SomeProperty %>";
    return @__ctrl;
}

private void @__Renderform1(HtmlTextWriter @__w, Control parameterContainer) 
{
    @__w.Write( SomeProperty );
    @__w.Write("\r\n    <div>\r\n        ");
    parameterContainer.Controls[0].RenderControl(@__w);
    @__w.Write("\r\n    </div>\r\n    ");
}

Here is an example of what happens under the hood for the <%#...%> syntax:

<script runat="server">
    public string SomeProperty { get { return "Hello World!"; } }
    protected void Page_Load(object sender, EventArgs e) { Label1.DataBind(); }
</script>

<form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="<%# SomeProperty %>"></asp:Label>
    </div>
</form>

Generates this code:

private Label @__BuildControlLabel1() 
{
    Label @__ctrl = new Label();

    this.Label1 = @__ctrl;
    @__ctrl.ApplyStyleSheetSkin(this);
    @__ctrl.ID = "Label1";
    @__ctrl.DataBinding += new System.EventHandler(this.@__DataBindingLabel1);
    return @__ctrl;
}

public void @__DataBindingLabel1(object sender, EventArgs e) 
{
    Label dataBindingExpressionBuilderTarget = ((Label)(sender));
    Page Container = ((Page)(dataBindingExpressionBuilderTarget.BindingContainer));

    dataBindingExpressionBuilderTarget.Text = System.Convert.ToString( SomeProperty , System.Globalization.CultureInfo.CurrentCulture);
}

As you can see the <%=...%> syntax can be used outside of a server control's properties to directly render the returned value. On the other hand the <%#...%> syntax generates a event handler for the DataBinding event of the label. This event sets the value of the label's property to the value of SomeProperty. The DataBinding event fires whenever the DataBind method is called which is why I added that call to the Page_Load event.
Hopefully this will help you understand the difference between them.

OTHER TIPS

You could create a custom ExpressionBuilder so you use something like <%$ Code: SomeProperty %>

You can create a custom databound control, e.g.

namespace FooBar.WebControls
{
    public class DataBoundPlaceHolder:PlaceHolder
    {
        private bool hasDataBound = false;
        protected override void CreateChildControls()
        {
            if (!hasDataBound)
            {
                this.DataBind();
                hasDataBound = true;
            }
            base.CreateChildControls();
        }
    }
}

Then wrap your code in this new control, and use the <%# %> syntax, e.g.

<%@ Register TagPrefix="WebControls" Namespace="FooBar.WebControls" Assembly="FooBar" %>

<form id="form1" runat="server">
    <WebControls:DataBoundPlaceHolder runat="server">
        <asp:Label ID="Label1" runat="server" Text='<%# SomeProperty %>'></asp:Label>
    </WebControls:DataBoundPlaceHolder>
</form>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top