Привязка данных во внутреннем элементе управления .ascx и FormView

У меня есть элемент управления ascx внутри FormView. Я бы хотел использовать синтаксис Bind внутри ascx. Вот моя страница:

    <asp:ObjectDataSource runat="server" ID="ods" TypeName="MyDS" SelectMethod="Get" UpdateMethod="Update" DataObjectTypeName="Ent">
    </asp:ObjectDataSource>
    <asp:FormView runat="server" DefaultMode="Edit" ID="fv1" DataSourceID="ods">
        <EditItemTemplate>
            <uc1:WebUserControl ID="WebUserControl1" runat="server" />
            <asp:Button runat="server" CommandName="Update" Text="Update"/>
        </EditItemTemplate>
    </asp:FormView>

Вот WebUserControl.ascx:

<asp:TextBox ID="txt1" runat="server" Text='<%# Bind("Name") %>' />

При выборе значений в TextBox все работает нормально. Bind заполняет текстовое поле ожидаемым значением. Но при нажатии кнопки "Обновить" метод Update источника ObjectDataSource получает экземпляр Ent с нулевым значением вместо Name, в то время как ожидается введенный текст. Просто для теста я поместил текстовое поле в .aspx, и все работает нормально.

Наконец, я декомпилировал с помощью рефлектора FormView, где ExtractRowValues ​​выглядит неудачно, поскольку итерации выполняются только по прямым дочерним элементам. Кто-нибудь знает, как работать с дочерними привязками?


person Dewfy    schedule 25.03.2010    source источник
comment
Я просто печатал тот же вопрос, твой пришел, и вот я здесь. Я также пытаюсь привязать свойство элемента управления ascx к форме и сталкиваюсь с той же проблемой. Поделитесь, если разобрались.   -  person The_AlienCoder    schedule 28.03.2010
comment
@The_AlienCoder Я дизассемблировал Reflector - для вложенных элементов управления вообще нет синтаксиса привязки синтаксического анализа для updateTemplate. Но тот же синтаксис представлен в itemTemplate, поэтому единственный способ — переопределить синтаксический анализ aspx.   -  person Dewfy    schedule 29.03.2010


Ответы (2)


Извините, если немного поздно :-)

«Бинд» — странный зверь. Метода Bind нет нигде. Это просто определенный токен ASP.NET, который указывает компилятору ASP.NET добавить вызов «Eval» (есть Eval действительно) при привязке данных и генерирует специальный скрытый метод извлечения кода для двойной привязки.

Но этот метод добавляется (и вызывается при извлечении) только для элементов управления, оснащенных ITemplate (например, ItemTemplate FormView, EditItemTemplate и т. д.), которые объявлены двусторонними.

К сожалению, для пользовательского элемента управления (ascx) нет простого способа сгенерировать такой метод.

Однако существует интерфейс IBindableControl, который вы может быть реализован в пользовательском элементе управления, который допускает некоторую интеграцию, хотя он менее автоматический, менее декларативный, например:

WebUserControl.ascx:

<asp:TextBox ID="txt1" runat="server" Text='<%# Eval("Name") %>' />

(Обратите внимание, что Bind бесполезен, поэтому вы можете просто придерживаться Eval).

WebUserControl.ascx.cs:

public partial class WebUserControl : UserControl, IBindableControl
{
    public void ExtractValues(IOrderedDictionary dictionary)
    {
        dictionary["Name"] = txt1.Text;
    }
}
person Simon Mourier    schedule 04.12.2012
comment
Я не могу сразу попробовать/проверить вашу идею, поэтому я поверю вам на слово, просто отвечу на одно: При выборе значений в TextBox все работает нормально. Bind заполняет текстовое поле ожидаемым значением. Но когда кнопка «Обновить» нажата, метод «Обновить» ObjectDataSource получает экземпляр Ent с нулевым значением — так будут ли вызываться методы IBindableControl во время обновления? - person Dewfy; 05.12.2012
comment
@Dewfy - Да, IBindableControl.ExtractValues ​​​​будет вызываться обработчиками команд FormView (это не идея, на самом деле это должно работать :-) - person Simon Mourier; 05.12.2012

Вы должны переместить синтаксис ‹%# Bind("") %> из пользовательского элемента управления (ASCX) на содержащую страницу (ASPX) и использовать свойства в своем пользовательском для получения и установки значений формы. Мой пример ниже адаптирован из решения, приведенного в http://oudinia.blogspot.co.uk/2007/12/aspnet-20-and-up-c-user-control-within.html с еще несколькими подробностями, чтобы попытаться сделать его реалистичным:

Разметка ASCX:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="PaperForm.ascx.cs" Inherits="PaperForm" %>

<asp:ValidationSummary runat="server" HeaderText="<b>Please supply the missing information below.</b>" />

<p class="SectionHeading">Section A: Your Details</p>
<table border="1" width="100%">
  <tr>
    <td width="220px">Membership number</td>
    <td colspan="3"><asp:TextBox ID="txtMemNo" runat="server" MaxLength="9"></asp:TextBox>
        <asp:RegularExpressionValidator runat="server" ControlToValidate="txtMemNo" Display="Dynamic" Text="Please check your membership number" ValidationExpression="\d{9}"></asp:RegularExpressionValidator>
    </td>
  </tr>
  <tr>
    <td><asp:Label ID="lblFirstName" runat="server">First name</asp:Label></td>
    <td><asp:TextBox ID="txtForename" runat="server"></asp:TextBox>
        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtForename" Text="Required"></asp:RequiredFieldValidator>
    </td>
    <td width="110px"><asp:Label ID="lblLastName" runat="server">Last name</asp:Label></td>
    <td><asp:TextBox ID="txtSurname" runat="server"></asp:TextBox>
        <asp:RequiredFieldValidator runat="server" ControlToValidate="txtSurname" Text="Required"></asp:RequiredFieldValidator>
    </td>
  </tr>
  ...
</table>

<script type="text/javascript" language="javascript">
  // perform additional client-side validation in JavaScript
  function ValidateForm()
  {
    // check membership number (via web-service)
    ...
  }
</script>

Код ASCX:

public partial class PaperForm : UserControl
{
    // **public properties representing form data**
    public string MemNo { get { return txtMemNo.Text; } set { txtMemNo.Text = value; } }
    public string Forename { get { return txtForename.Text; } set { txtForename.Text = value; } }
    public string Surname { get { return txtSurname.Text; } set { txtSurname.Text = value; } }
    ...

    protected void Page_Load(object sender, EventArgs e)
    {
        // prevent browser caching
        ...
    }
}

Разметка ASPX:

<%--register the user control here--%>
<%@ Register TagPrefix="UC" TagName="PaperForm" Src="~/Proposals/PaperForm.ascx" %>

<asp:FormView ID="fvPaper" runat="server" DataKeyNames="PprPropID" DataSourceID="tblPprProp" DefaultMode="Insert" Width="780px">    
  <InsertItemTemplate>

    <%--insert the user control here, **and bind the database fields to its properties**--%>
    <UC:PaperForm ID="pf" runat="server" MemNo='<%# Bind("MemNo") %>' Forename='<%# Bind("Forename") %>' Surname='<%# Bind("Surname") %>' ... />
    ...
    <%--can use the JavaScript ValidateForm() function defined in the ASCX file--%>
    <asp:Button ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert" Text="Submit" BackColor="#C2D9EC" OnClientClick="return ValidateForm();" />
  </InsertItemTemplate>
</asp:FormView>

<%--define the data-source here rather than in the ASCX file--%>
<asp:SqlDataSource ID="tblPprProp" runat="server" ConflictDetection="CompareAllValues" ConnectionString="<%$ ConnectionStrings:confConnectionString %>" OnInserted="AfterInsertion" 
  InsertCommand="INSERT INTO [tblPprProp] ([MemNo], [Surname], [Forename], ...) VALUES (@MemNo, @Surname, @Forename, ...); SELECT @RowID = SCOPE_IDENTITY()" 
  OldValuesParameterFormatString="original_{0}">
  <InsertParameters>
    <asp:Parameter Name="MemNo" Type="String" />
    <asp:Parameter Name="Surname" Type="String" />
    <asp:Parameter Name="Forename" Type="String" />
    ...
  </InsertParameters>
</asp:SqlDataSource>

Код ASPX:

public partial class PaperProposal : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    protected void AfterInsertion(object sender, SqlDataSourceStatusEventArgs e)
    {
        // get Proposal ID
        string rowId = e.Command.Parameters["@RowID"].Value.ToString();
        // get e-mail address from ASCX property
        string address = ((PaperForm)this.fvPaper.FindControl("pf")).Email;
        // send acknowledgement e-mail
        ...
    }
}
person Ed Graham    schedule 13.07.2012
comment
пожалуйста, внимательно прочитайте то, что я написал: Просто для проверки я поместил текстовое поле в .aspx, и все работает нормально, так что это очевидно. Вы не ответили на вопрос, как использовать привязку внутри .ascx. И выходит за рамки - если вы публикуете какое-то решение, постарайтесь минимизировать образцы, из 4 огромных листингов выше непонятно, о чем вы говорите. - person Dewfy; 14.07.2012
comment
Я правильно вас понял с первого раза; мой ответ остается в силе. Вы хотите знать, как использовать синтаксис Bind() с пользовательским элементом управления с привязкой к данным, не так ли? Мой ответ заключается в том, что вы не можете иметь синтаксис Bind() в пользовательском элементе управления: вы должны иметь его на содержащей ASPX-странице и использовать свойства в пользовательском элементе управления. Я дал вам примеры файлов ASCX и ASPX, чтобы показать, как они связаны друг с другом. Мне жаль, если вам не нравится мой ответ — учитывая, что это единственный ответ, который вы получили за два года, прошедшие с тех пор, как вы задали вопрос, я думаю, что ваши ожидания могут быть немного завышены. - person Ed Graham; 03.08.2012
comment
ваш ответ не стоит - потому что это копия из уже изложенного ранее. Об ответе - я уже решил эту проблему, и вы можете увидеть это в моем вопросе - так что за это время не было никаких ожиданий. Мне было интересно, существует ли более элегантное решение этого. Также давайте предположим, что какой-то новичок перейдет на эту страницу - он / она не сможет извлечь из вашего ответа ничего полезного, потому что ваш список огромен. Даже с этой точки зрения я не могу принять ваш ответ как правильный и полезный. Спасибо за внимание и надеюсь, что это не оскорбит вас, попробуйте больше, и вы скоро достигнете уровня эксперта. - person Dewfy; 03.08.2012