15 января 2007

Nested Repeater - Вложенныйе Repeater

Очень часто при разработке веб-приложений приходится использовать двууровневую иерархию. Например вам нужно динамически вывести категории товаров и сами товары в категориях. Выглядеть это будет примерно так:

  1. Рыба
    1. Форель
    2. Семга
    3. Окунь
  2. Мясо
    1. Говядина
    2. Свинина

Обычно такие списки делаются с помощью Repeater. И действительно все что надо, что бы отобразить категории - пара строк кода:

<asp:Repeater runat="server" ID="catRepeater"> <HeaderTemplate><ul></HeaderTemplate> <ItemTemplate><li><%# DataBinder.Eval(Container.DataItem, "CategoryName")%></li></ItemTemplate> <FooterTemplate></ul></FooterTemplate> </asp:Repeater>

и

protected void Page_Load(object sender, EventArgs e) { SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString); SqlCommand command1 = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories", conn); SqlDataAdapter adapter = new SqlDataAdapter(command); DataTable dt = new DataTable(); adapter.Fill(dt); catRepeater.DataSource = dt; catRepeater.DataBind(); }

Но как же быть с собственно товарами? Очень просто - добавим вложенный Repeater:

<asp:Repeater runat="server" ID="catRepeater"> <HeaderTemplate><ul></HeaderTemplate> <ItemTemplate><li><%# DataBinder.Eval(Container.DataItem, "CategoryName")%><asp:Repeater runat="server" id="itemRepeater" datasource='<%# GetItemDS(DataBinder.Eval(Container.DataItem,"CategoryID").ToString())%>'> <ItemTemplate><%# DataBinder.Eval(Container.DataItem, "ItemName")</ItemTemplate> </asp:Repeater></li></ItemTemplate> <FooterTemplate></ul></FooterTemplate> </asp:Repeater>

Как видно из листинга второй Repeater самый обыкновенный за исключением параметра DataSource. За счет него при каждой инициализации вложенный Repeater получает новый DataSource относящийся к текущей категории(CategoryID). Это достигается выполнением метода GetItemDS(string categoryID), возвращающим DataTable. В качестве categoryID передается результат выполнения директивы привязки данных DataBinder.Eval(Container.DataItem,"CategoryID").ToString(). Благодаря тому, что первым параметром методу Eval передается Container.DataItem мы получаем CategoryID текущей категори. Вот его код метода GetItemDS:

protected DataTable GetItemDS(string categoryID) { SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString); SqlCommand command = new SqlCommand("SELECT ItemName FROM Items WHERE CategoryID=@CategoryID", conn); command.Parameter.Add("@CategoryID", SqlDbType.Int).Value = categoryID; SqlDataAdapter adapter = new SqlDataAdapter(command); DataTable dt = new DataTable(); adapter.Fill(dt); return dt; }

Вот собственно и все что нам требуется для достижения результата. Еще раз рассмотрим всю конструкцию. Первоначально мы имеем Repeater который берет данные и выводит категории. В нем мы имеем вложенный Repeater DataSource которого задается динамически с помощью вспомогательного метода GetItemDS и директивы привязки данных с помощью которой в метод передается CategoryID текущей категории. На основании полученной DataTable вложенный Repeater отображает все продукты текущей категории.

2 комментария:

Анонимный комментирует...

порядок разработки разработка сайтов http://web-miheeff.ru порядок разработки

Андрей Р. комментирует...

Ты очень помог, спасибо. Правда немного не понятно, как сделать привязку (бинд), если использую бизнес объекты, которые просто биндятся к репитеру (repCategory.datasource = catelog.GetCategory)...
Может покажешь, как в таком случае делать.

Заранее большое спасибо.