Выражения привязки к данным в приложениях ASP.NET – это небольшие участки кода, которые вы видите в aspx-файлах между символами <%# и %>. Обычно мы видим такие выражения при использовании компонентов Repeater (шаблон ItemTemplate) и DataGrid (шаблон TemplateColumn). Также нужно заметить, что выражения привязки к данным часто содержат вызов метода DataBinder.Eval. И хотя это довольно типичный сценарий для привязки в ASP.NET, зная процессы, происходящие за кулисами, можно сделать гораздо больше в этом направлении. В этой статье мы рассмотрим процессы работы привязки к данным, как и когда они работают и продемонстрируем некоторые трюки, которые можно использовать для более тонкой настройки выражений привязки к данным. Для начала посмотрим на простую вебформу с выражением для привязки к данным: <form id="Form2" method="post" runat="server"> <table ID="Table3"> <asp:Repeater id="Repeater1" runat="server"> <ItemTemplate> <tr> <td><%# DataBinder.Eval(Container.DataItem, "Name") %></td> <td><%# DataBinder.Eval(Container.DataItem, "HexValue") %></td> </tr> </ItemTemplate> </asp:Repeater> </table> </form> Такая форма выводит на экран пару имя цвета – его шестнадцатиричное значение. Например, AliceBlue #F0F8FF. В этом примере для отображения данных мы используем компонент Repeater. Мы знаем, что мы можем привязать Repeater к объектам DataTable, DataView, SqlDataReader и т.д. Одна из приятных особенностей привязки к данным – способ, каким ASP.NET абстрагирует источник исходных данных, юлагодаря чему нам не нужно точно знать тип объекта, к которому мы привязываемся. Первым нашим трюком будет возможность привязки к коллекции, которая содержит набор пользовательских объектов. Например, в нашей форме-примере, мы используем ArrayList наполненный классами типа Color, а класс Color и есть наш собственный класс, реализация которого приведена ниже. public class Color { public Color(string name, byte r, byte g, byte b) { this.name = name; hexValue = String.Format("#{0:X2}{1:X2}{2:X2}",r, g, b); } public string Name { get { return name; } } public string HexValue { get { return hexValue; } } private string name; private string hexValue; } Конструктор класса Color принимает в качестве параметра имя цвета и значения красной, зелёной и голубой составляющих для его описания. Такой ArrayList, наполненный классами, мы можем построить с помощью такого кода: public static ArrayList GetColors() { ArrayList list = new ArrayList(); list.Add(new Color(System.Drawing.Color.AliceBlue.Name, System.Drawing.Color.AliceBlue.R, System.Drawing.Color.AliceBlue.G, System.Drawing.Color.AliceBlue.B) ); list.Add(new Color(System.Drawing.Color.Beige.Name, System.Drawing.Color.Beige.R, System.Drawing.Color.Beige.G, System.Drawing.Color.Beige.B) ); list.Add(new Color(System.Drawing.Color.Chocolate.Name, System.Drawing.Color.Chocolate.R, System.Drawing.Color.Chocolate.G, System.Drawing.Color.Chocolate.B) ); list.Add(new Color(System.Drawing.Color.DarkMagenta.Name, System.Drawing.Color.DarkMagenta.R, System.Drawing.Color.DarkMagenta.G, System.Drawing.Color.DarkMagenta.B) ); list.Add(new Color(System.Drawing.Color.Fuchsia.Name, System.Drawing.Color.Fuchsia.R, System.Drawing.Color.Fuchsia.G, System.Drawing.Color.Fuchsia.B) ); list.Add(new Color(System.Drawing.Color.PapayaWhip.Name, System.Drawing.Color.PapayaWhip.R, System.Drawing.Color.PapayaWhip.G, System.Drawing.Color.PapayaWhip.B) ); list.Add(new Color(System.Drawing.Color.Violet.Name, System.Drawing.Color.Violet.R, System.Drawing.Color.Violet.G, System.Drawing.Color.Violet.B ) ); list.Add(new Color(System.Drawing.Color.Black.Name, System.Drawing.Color.Black.R, System.Drawing.Color.Black.G, System.Drawing.Color.Black.B ) ); return list; } Отображение значений внутри тэгов <td> не единственное место для использования выражений привязки к данным. Их также можно применить для изменения внешнего вида элемента управления. В следующем примере мы установим фоновый цвет ячейки в цвет выводимого цвета, используя привязку к данным: <asp:Repeater id="Repeater1" runat="server"> <ItemTemplate> <tr bgcolor="<%# DataBinder.Eval(Container.DataItem, "HexValue")%>"> <td><%# DataBinder.Eval(Container.DataItem, "Name") %></td> <td><%# DataBinder.Eval(Container.DataItem, "HexValue") %></td> </tr> </ItemTemplate> </asp:Repeater> В заключительной части мы глубже рассмотрим процесс привязки к данным в режиме времени выполнения приложения. За кулисами выражений привязки к данным Для того, чтобы действительно иметь представление о том, что происходит за кулисами привязки к данным, давайте взглянем на код, сгенерированный библиотекой времени выполнения для файла ASPX. public void __DataBind__control3(object sender, System.EventArgs e) { System.Web.UI.WebControls.RepeaterItem Container; System.Web.UI.DataBoundLiteralControl target; target = ((System.Web.UI.DataBoundLiteralControl)(sender)); Container = ((System.Web.UI.WebControls.RepeaterItem)(target.BindingContainer)); #line 17 "E:\dev\xprmnt\aspnet\DataBinding\SimpleData.aspx" target.SetDataBoundString(0, System.Convert.ToString(DataBinder.Eval(Container.DataItem, "HexValue"))); #line 18 "E:\dev\xprmnt\aspnet\DataBinding\SimpleData.aspx" target.SetDataBoundString(1, System.Convert.ToString(DataBinder.Eval(Container.DataItem, "Name"))); #line 19 "E:\dev\xprmnt\aspnet\DataBinding\SimpleData.aspx" target.SetDataBoundString(2, System.Convert.ToString(DataBinder.Eval(Container.DataItem, "HexValue"))); } Вышеприведенный код взят из временного файла, который сгенерирован из нашей вебформы и размещён ASP.NET во временном каталоге. Здесь мы видим, как переменная Container, которую мы используем для вызова Eval, устанавливается в ссылку на BindingContainer. Этот метод, обработчик событий, будет исполняться всякий раз, когда элемент управления будет вязаться к данным (один раз для каждой строки или один раз для каждого пункта списка, как в этом примере). Наиболее важно уяснить себе то, что выражение, которое мы использовали для привязки к данным, используется в качестве параметра в методе Convert.ToString. Это значит, что мы можем использовать любое выражение, возвращающее строковый тип. Например, такой вот шаблон ItemTemplate проделает тоже, что и предыдущий код: <asp:Repeater id="Repeater1" runat="server"> <ItemTemplate> <tr bgcolor="<%# ((Color)Container.DataItem).HexValue %>"> <td><%# ((Color)Container.DataItem).Name %></td> <td><%# ((Color)Container.DataItem).HexValue %></td> </tr> </ItemTemplate> </asp:Repeater> В этом случае мы не обращаемся к методу DataBind.Eval и приводим DataItem к нашему типу Color (заметьте, что в этом случае вам надо импортировать пространство имён, в котором объявлен класс Color, с помощью директивы <@ Import > , например, <%@ Import Namespace="aspnet.DataBinding" %> , если тип Color находится в файле с пространством имён aspnet.DataBinding. Использование DataBinder.Eval позволяет избежать беспорядочных приведений типов в файле ASPX. Вместо этих приведений, Eval использует технику отражений (reflection) для динамического обнаружения свойства по имени в режиме времени выполнения. Ну а поскольку отражение относительно медленно работает, то и использование Eval относительно медленнее, чем использование приведений. С другой стороны, сильным местом DataBinder.Eval является то, что он работает как с файлом ASPX на C#, так и на VB.NET. В приведенном же выше виде, такой код ASPX будет компилироваться только на C#. В то время, как вышеприведенный пример демонстрирует каким образом можно избежать использования DataBinder.Eval в наших выражениях привязки к данным, давайте сделаем ещё один концептуальный шаг вперёд и вызовем метод из выражения привязки к данным: <asp:Repeater id="Repeater1" runat="server"> <ItemTemplate> <tr bgcolor="<%# ((Color)Container.DataItem).HexValue %>"> <td><%# GetColorName(Container.DataItem) %></td> <td><%# ((Color)Container.DataItem).HexValue %></td> </tr> </ItemTemplate> </asp:Repeater> Здесь мы вызываем метод GetColorName и передаём в него DataItem как параметр. Вызов метода из такого выражения предоставляет нам возможность использования дополнительной логики. Этот метод должен быть объявлен как защищённый (protected) в классе code-behind кода, поскольку динамически генерируемый класс из ASPX наследуется именно из него. Этот метод показан ниже. protected string GetColorName(object o) { string name = string.Empty; Color color = o as Color; if(color != null) { name = color.Name; int i = 1; do { if(char.IsUpper(name, i)) { name = name.Insert(i, " "); i = i +2; } else { i = i + 1; } } while(i < name.Length); } return name; } Этот метод принимает имя цвета как параметр, например “PapayaWhip”, и вставляет пробелы перед каждой большой буквой такого цвета, выдавая, например, “Papaya Whip”. Надеюсь, в этой статье продемонстрированы некоторые полезные трюки, которые вы сможете использовать в своих собственных сценариях привязки к данным.
|