Опубликован: 04.05.2010 | Уровень: для всех | Доступ: платный
Практическая работа 2:

Применение технологии ASP.NET в разрабатываемом Интернет-магазине

< Лекция 6 || Практическая работа 2: 12345 || Лекция 7 >

8.2.4. Страница продуктов

На первом занятии, для того, чтобы отобразить список продуктов, мы использовали обычные HTML-таблицы. В общем случае, такой подход не удобен, так как данные, которые необходимо отобразить, постоянно меняются, что приводит к тому, что придется создавать разметку таблицы вручную в серверном коде (впрочем, такой подход в некоторых отдельных сложных случаях может оказаться удобен). Для того чтобы отображать и манипулировать данными, ASP предлагает несколько визуальных компонент, один из которых называется GridView. Он позволяет не только представить в удобной форме массив данных, но и предоставляет удобные механизмы для сортировки данных, выбора отдельных строк, добавления и редактирования данных.

Страница продуктов интернет-магазина, использующая GridView

увеличить изображение
Рис. 8.14. Страница продуктов интернет-магазина, использующая GridView

На рис. 8.14 видно, что страница продуктов похожа на ту, что было создана в первом семинаре, но сама таблица содержит дополнительный столбец с кнопками "Выбор". Рассмотрим код, который создает данную страницу:

<asp:Content ID="Content1" ContentPlaceHolderID="column_l_placeholder" Runat="Server">
 <asp:GridView ID="GridViewProducts" runat="server" CellPadding="4"
        GridLines="None" CssClass="GridViewProduct"
        AutoGenerateColumns="False"
        OnSelectedIndexChanged="OnSelectedIndexChanged" >
      <RowStyle CssClass="tr_nechet" />
      <AlternatingRowStyle CssClass="tr_chet" />
      <Columns>
            <asp:CommandField SelectText="Выбор" 
                ShowSelectButton="True" />
               <asp:TemplateField 
                HeaderText="Количество на&nbsp;складе" 
                SortExpression="StockCount" >
                 <ItemTemplate> 
                  <asp:Label ID="Label1" 
                    runat="server" 
                    Text='<%# Eval("StockCount") %>' >
                  </asp:Label>
               </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Название" SortExpression="Name" >
            <ItemTemplate> 
                <asp:Label ID="Label1" runat="server" 
                 Text='<%# Eval("Name") %>' >
                </asp:Label>
            </ItemTemplate>
         </asp:TemplateField>
      </Columns>
      <PagerStyle BackColor="#FFCC66" 
           ForeColor="#333333" 
           HorizontalAlign="Center" />
        <SelectedRowStyle BackColor="#FFCC66" Font-Bold="True" ForeColor="Navy" />
        <HeaderStyle CssClass="tr_main" />
    </asp:GridView>
</asp:Content>

Левый ContentPlaceHolder содержит внутри себя только один компонент – GridView. Рассмотрим подробнее его определение. В корневом теге определен идентификатор документа, что позволяет работать с этим компонентом через серверный код. Там же определен CSS-класс, который будет применяться к таблице, атрибутом GridLines="None" указано, что при отрисовке таблице не надо рисовать линии между ячейками, атрибутом AutoGenerateColumns="False" указано, что набор колонок этой таблицы будет определен вручную, и самому компоненту не надо пытаться его определить на основании переданных данных.

Примечание: В общем случае, если атрибуту AutoGenerateColumns присвоено значение True, то для объекта DataTable компонент создаст столбец для каждого DataColumn, определенного в коллекции Columns переданного объекта. Если же в качестве источника данных будет указан массив или список каких-либо объектов, то GridView создаст набор столбцов, соответствующих каждому публичному ( public ) свойству этих объектов.

Также в корневом теге указан серверный обработчик события OnSelectedIndexChanged, которое срабатывает, когда пользователь нажимает на кнопку "Выбор" в первом столбце. В теге RowStyle определен CSS-класс, который будет применяться к каждой нечетной строке, а в теге AlternatingRowStyle – стиль, который будет применяться к каждой четной строке.

Далее определяется набор столбцов, которые будут отображаться в таблице. Компонент поддерживает несколько видов колонок, среди которых CommandField, TemplateField и BoundField (последний используется при автоматической генерации колонок, или если источник данных для таблицы заранее определен). В нашем случае, для отображения столбца, позволяющего выбирать строки, воспользуемся колонкой типа CommandField, в которой укажем, что необходимо отобразить кнопку выбора ( ShowSelectButton="True" ) и текст этой кнопки ( SelectText="Выбор" ). Этот тип столбцов используется также для определения столбцов, содержащих кнопки удаления и редактирования записей.

Далее идет определение двух колонок, которые будут отображать данные. Рассмотрим столбец, который будет отображать название продукта. Для его создания используется компонент с типом TemplateField. В корневом теге компонента указывается заголовок столбца, а также выражение, которое используется для сортировки (в этом примере – не используется). Далее определяется шаблон, который будет использоваться для отображения данных в табличке. В нашем примере используется компонент Label, который представляет собой обычную надпись, текст которой определяется атрибут Text.

Так как название каждого продукта отличается, указать в качестве текста обычную строку не получится. Для того чтобы отобразить название, воспользуемся серверным методом Eval. Метод заключен в специальную разметку <%# %>, которая в общем случае содержит любой исполняемый на сервере код. Когда к GridView привязывается определенный источник данных, то на этапе PreRender страницы у компонента вызывается метод отрисовки каждой строки (для каждой записи, которую необходимо отобразить срабатывает событие DataBinding ). Далее для каждой ячейки в строке также сработает событие DataBinding и вызывается код, написанный в <%# %>, причем в контексте текущей записи, которую необходимо отобразить. Код Eval ( "Name" ) возвратит свойство Name текущего объекта (или, если такого свойства нет, то попытается обратиться через итератор: DataItem["Name"] ), и и менно это значение и будет отображено.

Примечание: на самом деле все эти действия можно, при необходимости, выполнить серверным кодом. Для этого необходимо будет в коллекцию Columns компонента GridView добавить объекты типа TemplateField, у которых свойство ItemTemplate означить объект собственного класса, наследующего от ITemplate. В этом классе необходимо будет определить метод InstantiateIn, как того требует сигнатура ITemplate, в котором создать объект типа Label и положить его в коллекцию контролов контейнера следующим кодом: container.Controls.Add(label);. Далее, в этом же коде необходимо привязать обработчик события label.DataBinding и в этом обработчике определить необходимый код, например:
private void label_DataBinding(object sender, EventArgs e)
        {
            var container = (GridDataItem) sender.NamingContainer;
            ((Label)sender).Value = ((CycleHelper) container.DataItem).Name;
        }

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

Подробнее об использовании методов Eval и Bind для привязки данных к различным компонентам можно почитать на сайте MSDN: http://msdn.microsoft.com/en-us/library/ms178366.aspx

Три заключительных тега – PagerStyle, SelectedRowStyle и HeaderStyle определяют внешний вид пейджера (компонента, позволяющего выводить данные постранично и выбирать текущую страницу), выбранной строки и заголовка таблицы.

Теперь, когда все готово для отображения таблицы, необходимо написать серверный код для отображения данных.

8.2.4.1. Переопределение Page_load

Прежде всего, определим структуру данных, которая будет использоваться для отображения. Назовем новый класс CycleHelper, и пусть он содержит два публичных свойства: StockCount и Name:

public class CycleHelper
    {
        public int StockCount
        {
            get; set;
        }

        public string Name
        {
            get; set;
        }
    }

Определим на самой странице типизированный список CycleHelper, который будем отображать, а в методе Page_Load заполним этот список значениями (позднее мы будем брать данные и базы данных) и привяжем методом DataBind() наш список к таблице:

List<CycleHelper> chs = new List<CycleHelper>();

    protected void Page_Load(object sender, EventArgs e)
    {      
        chs.Add(new CycleHelper() {Name = "Mountain Tire Tube",StockCount = 191});
        chs.Add(new CycleHelper() {Name = "Patch Kit/8 Patches",StockCount = 184});
        chs.Add(new CycleHelper() {Name = "Water Bottle&nbsp;&mdash; 30&nbsp;oz.",StockCount = 175});
        chs.Add(new CycleHelper() {Name = "Road Tire Tube",StockCount = 161});
        chs.Add(new CycleHelper() {Name = "Fender Set&nbsp;&mdash; Mountain",StockCount = 110});
        GridViewProducts.DataSource = chs;
        GridViewProducts.DataBind();
    }

Также добавим обработчик события OnSelectedIndexChanged компонента GridView:

protected void OnSelectedIndexChanged(object sender, EventArgs e)
    {
        var cycle = chs[GridViewProducts.SelectedIndex];
        ProductDetails.LoadContent(cycle.Name, cycle.StockCount);
    }

Чтобы этот код заработал, нам необходимо разработать собственный компонент ProductDetails.

< Лекция 6 || Практическая работа 2: 12345 || Лекция 7 >
Владимир Тадеуш
Владимир Тадеуш
Украина
Кирилл Дубовик
Кирилл Дубовик
Россия, Петрозаводск