Есть ли способ декларативно передавать значения свойства code-behind для серверных элементов управления?

Может кто-нибудь объяснить, почему вы не можете использовать встроенные блоки кода в объявлениях управления сервером в ASP.Net?

Ниже приведен простой пример...

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

Блок кода отображается буквально на странице...

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

Мои первые мысли о том, что это связано с порядком обработки этих вещей в жизненном цикле страницы. <%=...%> блоки, насколько я понимаю, эквивалентны Response.Write(...) в коде позади. И поскольку серверный элемент управления фактически не отображается, как объявлено в разметке, я предполагаю, что может быть невозможно обработать блок встроенного кода до того, как произойдет это отображение.

Я был бы очень благодарен любому, кто мог бы объяснить это немного лучше.

Тем не менее, блок кода привязки данных <%#...%> очевидно, отличается в том, как он ведет себя, но может кто-нибудь сказать мне, почему это можно встроить в элемент управления сервером...

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

Это отлично работает.

3 ответа

Решение

Ты в основном прав насчет <%=...%> синтаксис. Вот пример того, что происходит под капотом:

<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>

Это анализируется и создается следующий код C# (я немного упростил его):

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    ");
}

Вот пример того, что происходит под капотом для <%#...%> синтаксис:

<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>

Создает этот код:

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);
}

Как вы можете видеть <%=...%> Синтаксис может использоваться вне свойств серверного элемента управления для прямой визуализации возвращаемого значения. С другой стороны <%#...%> синтаксис генерирует обработчик события для события DataBinding метки. Это событие устанавливает значение свойства метки равным значению SomeProperty. Событие DataBinding вызывается всякий раз, когда вызывается метод DataBind, поэтому я добавил этот вызов в событие Page_Load.
Надеюсь, это поможет вам понять разницу между ними.

Вы можете создать собственный ExpressionBuilder, чтобы использовать что-то вроде <%$ Code: SomeProperty %>

Вы можете создать собственный элемент управления привязкой данных, например,

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

Затем оберните ваш код в этот новый элемент управления и используйте <%# %> синтаксис, например

<%@ 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>
Другие вопросы по тегам