Применение технологии ASP.NET в разрабатываемом Интернет-магазине
8.2.4. Страница продуктов
На первом занятии, для того, чтобы отобразить список продуктов, мы использовали обычные HTML-таблицы. В общем случае, такой подход не удобен, так как данные, которые необходимо отобразить, постоянно меняются, что приводит к тому, что придется создавать разметку таблицы вручную в серверном коде (впрочем, такой подход в некоторых отдельных сложных случаях может оказаться удобен). Для того чтобы отображать и манипулировать данными, ASP предлагает несколько визуальных компонент, один из которых называется 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="Количество на складе" 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" указано, что набор колонок этой таблицы будет определен вручную, и самому компоненту не надо пытаться его определить на основании переданных данных.
Также в корневом теге указан серверный обработчик события OnSelectedIndexChanged, которое срабатывает, когда пользователь нажимает на кнопку "Выбор" в первом столбце. В теге RowStyle определен CSS-класс, который будет применяться к каждой нечетной строке, а в теге AlternatingRowStyle – стиль, который будет применяться к каждой четной строке.
Далее определяется набор столбцов, которые будут отображаться в таблице. Компонент поддерживает несколько видов колонок, среди которых CommandField, TemplateField и BoundField (последний используется при автоматической генерации колонок, или если источник данных для таблицы заранее определен). В нашем случае, для отображения столбца, позволяющего выбирать строки, воспользуемся колонкой типа CommandField, в которой укажем, что необходимо отобразить кнопку выбора ( ShowSelectButton="True" ) и текст этой кнопки ( SelectText="Выбор" ). Этот тип столбцов используется также для определения столбцов, содержащих кнопки удаления и редактирования записей.
Далее идет определение двух колонок, которые будут отображать данные. Рассмотрим столбец, который будет отображать название продукта. Для его создания используется компонент с типом TemplateField. В корневом теге компонента указывается заголовок столбца, а также выражение, которое используется для сортировки (в этом примере – не используется). Далее определяется шаблон, который будет использоваться для отображения данных в табличке. В нашем примере используется компонент Label, который представляет собой обычную надпись, текст которой определяется атрибут Text.
Так как название каждого продукта отличается, указать в качестве текста обычную строку не получится. Для того чтобы отобразить название, воспользуемся серверным методом Eval. Метод заключен в специальную разметку <%# %>, которая в общем случае содержит любой исполняемый на сервере код. Когда к GridView привязывается определенный источник данных, то на этапе PreRender страницы у компонента вызывается метод отрисовки каждой строки (для каждой записи, которую необходимо отобразить срабатывает событие DataBinding ). Далее для каждой ячейки в строке также сработает событие DataBinding и вызывается код, написанный в <%# %>, причем в контексте текущей записи, которую необходимо отобразить. Код Eval ( "Name" ) возвратит свойство Name текущего объекта (или, если такого свойства нет, то попытается обратиться через итератор: DataItem["Name"] ), и и менно это значение и будет отображено.
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 — 30 oz.",StockCount = 175}); chs.Add(new CycleHelper() {Name = "Road Tire Tube",StockCount = 161}); chs.Add(new CycleHelper() {Name = "Fender Set — 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.