Как вложить репитеры в asp.net - PullRequest
7 голосов
/ 30 мая 2011

Мне нужно знать, как вкладывать ретрансляторы в пользовательский элемент управления. С html-стороны все в порядке, это связывание и код, с которыми мне нужна помощь. Мне удалось найти примеры только с использованием источника данных sql, который не очень помогает.

Мои ретрансляторы выглядят так:

<asp:Panel ID="pnlDiscipline" runat="server" CssClass="">
    <asp:Repeater ID="rptDiscipline" runat="server">
        <ItemTemplate>
            <h4><%#Eval("Discipline")%></h4>
            <ul>
                <asp:Repeater ID="rptPrograms" runat="server">
                    <ItemTemplate>
                        <li><asp:HyperLink runat="server" Text='<%#Eval("Name") %>' NavigateUrl='<%#Eval("Link") %>'></asp:HyperLink> <%#Eval ("Notation") %></li>
                    </ItemTemplate>
                </asp:Repeater>
            </ul>
        </ItemTemplate>
    </asp:Repeater>

То, что мне нужно сделать, мы надеемся, достаточно ясно - дисциплина h4 должна появиться один раз, все записи, которые относятся к дисциплине, перечислены ниже, затем следующий h4, затем соответствующий список, следующий h4 и так далее.

Источником данных является представление данных, созданное в кодовой области, где в каждой строке есть «Имя», «Ссылка», «Нотация» и «Дисциплина». Я привязал представление данных к самому внешнему повторителю, и он ведет себя как ожидалось - списки имя дисциплины для каждой записи, но во внутреннем повторителе нет данных.

Как мне сделать эту работу?

РЕДАКТИРОВАТЬ: Просто чтобы уточнить, у меня есть один дата в коде позади. Каждая строка в этой таблице является предметом, каждый предмет относится к дисциплине. Я хочу использовать внешний повторитель для перечисления дисциплин, внутренний - для перечисления элементов, сгруппированных по каждой дисциплине. Вот так:

<h4>DISCIPLINE 1</h4>
    <ul>
        <li>Item</li>
        <li>Item</li>
        <li>Item</li>
    </ul>
<h4>DISCIPLINE 2</h4>
    <ul>        
        <li>Item</li>            
        <li>Item</li>
    </ul>
<h4>DISCIPLINE 3</h4>
    <ul>        
        <li>Item</li>            
        <li>Item</li>
    </ul>

В настоящее время привязка данных к внешнему повторителю дает следующее (пример использует данные выше):

    <h4>DISCIPLINE 1</h4>
    <h4>DISCIPLINE 1</h4>
    <h4>DISCIPLINE 1</h4>
    <h4>DISCIPLINE 2</h4>
    <h4>DISCIPLINE 2</h4>
    <h4>DISCIPLINE 3</h4>
    <h4>DISCIPLINE 3</h4>

Я использовал OnItemDataBound на внешнем повторителе, как было предложено, и в качестве контрольного примера я могу получить доступ к данным:

protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e) 
{
    DataRowView drView = (DataRowView) e.Item.DataItem;
    string name = drView["Name"] as string;
    string link = drView["Link"] as string;
    string notation = drView["Notation"] as string;
    Response.Write(name + link + notation + "<br />")
}

Итак, данные есть, это именно то, что я ожидал увидеть, я просто не могу связать их с внутренним ретранслятором. Если есть более эффективный способ добиться того же, я с радостью переделаю свое решение.

Ответы [ 3 ]

7 голосов
/ 30 мая 2011

На внешнем элементе управления используйте событие ItemDataBound, например:

<asp:Repeater ID="rptDiscipline" runat="server"
     OnItemDataBound="rptDiscipline_ItemDataBound">
...

Затем в выделенном фрагменте кода обработайте событие rptDiscipline_ItemDataBound и вручную привяжите внутренний повторитель. Событие ItemDataBound повторителя запускается один раз для каждого повторяющегося элемента. Итак, вы будете делать что-то вроде этого:

protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e) 
{
    // To get your data item, cast e.Item.DataItem to 
    // whatever you're using for the data object; for example a DataRow.

    // Get the inner repeater:
    Repeater rptPrograms = (Repeater) e.Item.FindControl("rptPrograms");

    // Set the inner repeater's datasource to whatever it needs to be.
    rptPrograms.DataSource = ...
    rptPrograms.DataMember = ...
    rptPrograms.DataBind();
}

РЕДАКТИРОВАТЬ: Обновлено, чтобы соответствовать обновлению вашего вопроса.

Вам необходимо привязать внешний повторитель к источнику данных, который имеет только одну запись на элемент, который вы хотите, чтобы повторитель отображал. Это означает, что источник данных должен быть коллекцией / списком / данными / и т.д., в котором есть только дисциплины. В вашем случае я бы порекомендовал получить List<string> дисциплин из DataTable для внутренней коллекции и привязать к этому внешний ретранслятор. Затем внутренний повторитель связывается с подмножеством данных в DataTable, используя событие ItemDataBound. Чтобы получить подмножество, отфильтруйте DataTable через DataView.

Вот код:

protected void Page_Load(object sender, EventItems e)
{
    // get your data table
    DataTable table = ...

    if ( !IsPostBack )
    {
        // get a distinct list of disciplines
        List<string> disciplines = new List<string>();
        foreach ( DataRow row in table )
        {
            string discipline = (string) row["Discipline"];
            if ( !disciplines.Contains( discipline ) )
                disciplines.Add( discipline );
        }
        disciplines.Sort();

        // Bind the outer repeater
        rptDiscipline.DataSource = disciplines;
        rptDiscipline.DataBind();
    }
}

protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e) 
{
    // To get your data item, cast e.Item.DataItem to 
    // whatever you're using for the data object
    string discipline = (string) e.Item.DataItem;

    // Get the inner repeater:
    Repeater rptPrograms = (Repeater) e.Item.FindControl("rptPrograms");

    // Create a filtered view of the data that shows only 
    // the disciplines needed for this row
    // table is the datatable that was originally bound to the outer repeater
    DataView dv = new DataView( table );  
    dv.RowFilter = String.Format("Discipline = '{0}'", discipline);

    // Set the inner repeater's datasource to whatever it needs to be.
    rptPrograms.DataSource = dv;
    rptPrograms.DataBind();
}   
4 голосов
/ 30 мая 2011

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

<asp:Repeater runat="server" ID="OuterRepeater" >
    <ItemTemplate>
        Outer Content: <%# DataBinder.Eval(Container.DataItem, "ParentProperty")%>
        <asp:Repeater runat="server" ID="InnerRepeater" DataSource='<%# DataBinder.Eval(Container.DataItem, "ChildCollection")%>' >
            <ItemTemplate>
                <%# DataBinder.Eval(Container.DataItem, "ChildProperty")%>
            </ItemTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>
1 голос
/ 30 мая 2011

Сначала вам нужно два списка, список дисциплин, а затем список всех ваших данных.

Данные связывают список дисциплин с внешним повторителем.Если существует 6 дисциплин, повторитель должен повторить 6 раз.

    <asp:Repeater ID="rptDiscipline" runat="server" OnItemDataBound="rptDiscipline_ItemDataBound">
        <ItemTemplate>
            <h4><%# Eval("Discipline")%></h4>
            <ul>
                <asp:Repeater runat="server" ID="InnerRepeater" >
                    <ItemTemplate>
                        <li>
                            <asp:Label runat="server" ID="lbl" />
                        </li>
                    </ItemTemplate>
                </asp:Repeater>
            </ul>
        </ItemTemplate>
    </asp:Repeater>

protected void rptDiscipline_ItemDataBound(Object Sender, RepeaterItemEventArgs e) 
{    

    Repeater inner= (Repeater) e.Item.FindControl("InnerRepeater");

    //You want to bind all the data related to this discipline
    DataRowView drView = (DataRowView) e.Item.DataItem;
    string discipline= drView["Discipline"] as string;

    //filter your total data with ones that match the discipline

    inner.DataSource = //data bind the filtered list here
    inner.DataBind();
}
...