Добавление столбца GridView переключателей (VB)

Скотт Митчелл

Загрузить PDF-файл

В этом руководстве рассматривается добавление столбца переключателей в элемент управления GridView, чтобы предоставить пользователю более интуитивно понятный способ выбора одной строки GridView.

Введение

Элемент управления GridView предоставляет широкий набор встроенных функций. Он содержит ряд различных полей для отображения текста, изображений, гиперссылок и кнопок. Он поддерживает шаблоны для дальнейшей настройки. С помощью нескольких щелчков мыши можно создать GridView, в котором можно выбрать каждую строку с помощью кнопки, или включить возможности редактирования или удаления. Несмотря на множество предоставляемых функций, часто возникают ситуации, в которых потребуется добавить дополнительные, не поддерживаемые функции. В этом руководстве и в следующих двух мы рассмотрим, как улучшить функциональность GridView, чтобы включить дополнительные функции.

В этом и следующем руководстве основное внимание уделяется улучшению процесса выбора строк. Как было рассмотрено в разделе Master/Detail Using a Selectable master GridView with a Details DetailView , мы можем добавить CommandField в GridView, включающее кнопку Выбрать. При нажатии происходит обратная связь, и свойство GridView обновляется до индекса строки, для которой была нажата SelectedIndex кнопка Выбрать. В учебнике Master/Detail Using a Selectable Master GridView with a Details DetailView (Основные и подробные сведения) мы узнали, как использовать эту функцию для отображения сведений о выбранной строке GridView.

Хотя кнопка Выбрать работает во многих ситуациях, она может работать не так хорошо для других. Вместо кнопки для выбора обычно используются два других элемента пользовательского интерфейса: переключатель и флажок. Мы можем дополнить GridView так, чтобы вместо кнопки Выбрать каждая строка содержала переключатель или флажок. В сценариях, где пользователь может выбрать только одну из записей GridView, переключатель может быть предпочтительнее кнопки Выбрать. В ситуациях, когда пользователь может выбрать несколько записей, например в веб-приложении электронной почты, когда пользователю может потребоваться выбрать несколько сообщений, чтобы удалить флажок, предоставляет функциональные возможности, недоступные в пользовательских интерфейсах кнопки или переключателя.

В этом руководстве рассматривается добавление столбца переключателей в GridView. В этом руководстве рассматривается использование флажков.

Шаг 1. Создание расширения веб-страниц GridView

Прежде чем мы добавим в GridView столбец переключателей, давайте создадим страницы ASP.NET в проекте веб-сайта, необходимые для работы с этим руководством и двумя следующими. Начните с добавления новой папки с именем EnhancedGridView. Затем добавьте в нее следующие страницы ASP.NET, обязательно свяжите каждую страницу со страницей Site.master master:

  • Default.aspx
  • RadioButtonField.aspx
  • CheckBoxField.aspx
  • InsertThroughFooter.aspx

Добавление страниц ASP.NET для учебников по SqlDataSource-Related

Рис. 1. Добавление страниц ASP.NET для учебников по SqlDataSource-Related

Как и в других папках, Default.aspx в папке EnhancedGridView будет отображаться список учебников в своем разделе. Помните, что SectionLevelTutorialListing.ascx пользовательский элемент управления предоставляет эту функцию. Поэтому добавьте этот пользовательский элемент управления в , Default.aspx перетащив его из Обозреватель решений в режим конструктора страницы.

Добавьте пользовательский элемент управления SectionLevelTutorialListing.ascx в Default.aspx

Рис. 2. Добавление пользовательского SectionLevelTutorialListing.ascx элемента управления в Default.aspx (щелкните для просмотра полноразмерного изображения)

Наконец, добавьте эти четыре страницы в качестве записей в Web.sitemap файл. В частности, добавьте следующую разметку после элемента управления Using the SqlDataSource :<siteMapNode>

<siteMapNode 
    title="Enhancing the GridView" 
    url="~/EnhancedGridView/Default.aspx" 
    description="Augment the user experience of the GridView control.">
    <siteMapNode 
        url="~/EnhancedGridView/RadioButtonField.aspx" 
        title="Selection via a Radio Button Column" 
        description="Explore how to add a column of radio buttons in the GridView." />
    <siteMapNode 
        url="~/EnhancedGridView/CheckBoxField.aspx" 
        title="Selection via a Checkbox Column" 
        description="Select multiple records in the GridView by using a column of 
            checkboxes." />
    <siteMapNode 
        url="~/EnhancedGridView/InsertThroughFooter.aspx" 
        title="Add New Records through the Footer" 
        description="Learn how to allow users to add new records through the 
            GridView's footer." />
</siteMapNode>

После обновления Web.sitemapпросмотрите веб-сайт учебников в браузере. Меню слева теперь содержит элементы для редактирования, вставки и удаления учебников.

Карта сайта теперь включает записи для улучшения руководств по GridView

Рис. 3. Схема сайта теперь включает записи для улучшения руководств по GridView

Шаг 2. Отображение поставщиков в GridView

Для работы с этим руководством давайте создадим элемент GridView, который перечисляет поставщиков из США, при этом каждая строка GridView предоставляет переключатель. После выбора поставщика с помощью переключателя пользователь может просмотреть продукты поставщика, нажав кнопку. Хотя эта задача может показаться тривиальной, есть ряд тонкостей, которые делают ее особенно сложной. Прежде чем углубляться в эти тонкости, давайте сначала получим GridView со списком поставщиков.

Начните с открытия RadioButtonField.aspx страницы в папкеEnhancedGridView, перетащив GridView с панели элементов на Designer. Задайте для gridView значение IDSuppliers и выберите из смарт-тега создать новый источник данных. В частности, создайте объект ObjectDataSource с именем SuppliersDataSource , который извлекает свои данные из SuppliersBLL объекта .

Создание объекта ObjectDataSource с именем SuppliersDataSource

Рис. 4. Создание объекта ObjectDataSource с именем SuppliersDataSource (щелкните для просмотра полноразмерного изображения)

Снимок экрана: окно Configure Data Source — SuppliersDataSource (Настройка источника данных — Поставщики) с открытым раскрывающимся меню бизнес-объекта. Выбран пункт SuppliersBLL и выделена кнопка Далее.

Рис. 5. Настройка ObjectDataSource для использования SuppliersBLL класса (щелкните для просмотра полноразмерного изображения)

Так как мы хотим перечислить этих поставщиков только в США, выберите GetSuppliersByCountry(country) метод из раскрывающегося списка на вкладке SELECT.

Снимок экрана: окно Configure Data Source - SuppliersDataSource (Настройка источника данных — Поставщики) на вкладке SELECT с открытым раскрывающимся меню метода. Выбран параметр метода GetSupplierByCountry и выделена кнопка Далее.

Рис. 6. Настройка ObjectDataSource для использования SuppliersBLL класса (щелкните для просмотра полноразмерного изображения)

На вкладке ОБНОВЛЕНИЕ выберите параметр (Нет) и нажмите кнопку Далее.

Снимок экрана: окно Настройка источника данных — SuppliersDataSource на вкладке UPDATE с открытым раскрывающимся меню метода. Выбран параметр метода (Нет) и выделена кнопка Далее.

Рис. 7. Настройка ObjectDataSource для использования SuppliersBLL класса (щелкните для просмотра полноразмерного изображения)

GetSuppliersByCountry(country) Так как метод принимает параметр, мастер настройки источника данных запрашивает источник этого параметра. Чтобы указать жестко закодированное значение ( США в этом примере), оставьте для раскрывающегося списка Источник параметров значение Нет и введите значение по умолчанию в текстовое поле. Чтобы завершить работу мастера, нажмите кнопку Готово.

Используйте США в качестве значения по умолчанию для параметра country

Рис. 8. Использование США в качестве значения по умолчанию для country параметра (щелкните для просмотра полноразмерного изображения)

После завершения работы мастера GridView будет включать BoundField для каждого поля данных поставщика. Удалите все поля, кроме CompanyName, Cityи Country BoundFields, и переименуйте CompanyName свойство BoundFields HeaderText в Supplier. После этого декларативный синтаксис GridView и ObjectDataSource должен выглядеть следующим образом.

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliersByCountry" TypeName="SuppliersBLL">
    <SelectParameters>
        <asp:Parameter DefaultValue="USA" Name="country" Type="String" />
    </SelectParameters>
</asp:ObjectDataSource>

В этом руководстве пользователь может просматривать выбранные продукты поставщика на той же странице, что и список поставщиков, или на другой странице. Для этого добавьте на страницу два веб-элемента управления Button. Я установил ID для этих двух кнопок ListProducts значение и SendToProducts, с мыслью, что при ListProducts нажатии будет происходить обратная связь и продукты выбранного поставщика будут перечислены на той же странице, но при SendToProducts нажатии, пользователь будет взбит на другую страницу, которая перечисляет продукты.

На рисунке 9 показан элемент Suppliers управления GridView и два элемента управления Button Web при просмотре в браузере.

Эти поставщики из США указаны в списке их названия, города и страны

Рис. 9. Поставщики из США в списке их названия, города и страны (щелкните, чтобы просмотреть полноразмерное изображение)

Шаг 3. Добавление столбца переключателей

На этом этапе Suppliers GridView имеет три BoundFields, отображающих название компании, город и страну каждого поставщика в США. Однако в нем по-прежнему отсутствует столбец переключателей. К сожалению, GridView не включает встроенный RadioButtonField, в противном случае мы могли бы просто добавить это в сетку и сделать. Вместо этого можно добавить TemplateField и настроить его ItemTemplate для отрисовки переключателя, в результате чего для каждой строки GridView будет отображаться переключатель.

Изначально можно предположить, что требуемый пользовательский интерфейс можно реализовать путем добавления веб-элемента управления RadioButton в ItemTemplate шаблон TemplateField. Хотя это действительно добавит один переключатель в каждую строку GridView, переключатели невозможно сгруппировать и, следовательно, не являются взаимоисключающими. То есть пользователь может одновременно выбрать несколько переключателей в GridView.

Несмотря на то, что использование TemplateField веб-элементов управления RadioButton не предоставляет необходимых функций, давайте реализуем этот подход, так как стоит изучить, почему результирующая переключатель не сгруппирована. Для начала добавьте TemplateField в Элемент GridView поставщиков, сделав его крайним левым полем. Затем в смарт-теге GridView щелкните ссылку Изменить шаблоны и перетащите веб-элемент управления RadioButton из панели элементов в TemplateField ( ItemTemplate см. рис. 10). Присвойте свойству RadioButton s ID значение RowSelector , а свойству GroupName — значение SuppliersGroup.

Добавление веб-элемента управления RadioButton в ItemTemplate

Рис. 10. Добавление веб-элемента управления RadioButton в ItemTemplate (щелкните для просмотра полноразмерного изображения)

После внесения этих дополнений в Designer разметка GridView должна выглядеть примерно так:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False"
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:RadioButton ID="RowSelector" runat="server" 
                    GroupName="SuppliersGroup" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CompanyName" HeaderText="Supplier" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
    </Columns>
</asp:GridView>

Свойство RadioButton s GroupName используется для группировки ряда переключателей. Все элементы управления RadioButton с одинаковым GroupName значением считаются сгруппированы. Одновременно из группы можно выбрать только один переключатель. Свойство GroupName задает значение для отрисованного атрибута переключателя name . Браузер проверяет атрибуты переключателей name , чтобы определить группирование переключателей.

Добавив элемент управления RadioButton Web в ItemTemplate, перейдите на эту страницу в браузере и щелкните переключатели в строках сетки. Обратите внимание, что переключатели не сгруппированы, что позволяет выбрать все строки, как показано на рисунке 11.

Переключатели GridView не сгруппированы

Рис. 11. Переключатели GridView не сгруппированы (щелкните для просмотра полноразмерного изображения)

Причина, по которой переключатели не группируются, заключается в том, что их отображаемые name атрибуты отличаются, несмотря на то, что у них одинаковые GroupName параметры свойства. Чтобы увидеть эти различия, выполните просмотр или источник в браузере и проверьте разметку переключателя:

<input id="ctl00_MainContent_Suppliers_ctl02_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl02$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl03_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl03$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl04_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl04$SuppliersGroup" 
    type="radio" value="RowSelector" />
<input id="ctl00_MainContent_Suppliers_ctl05_RowSelector" 
    name="ctl00$MainContent$Suppliers$ctl05$SuppliersGroup" 
    type="radio" value="RowSelector" />

Обратите внимание, name что атрибуты и id не являются точными значениями, указанными в окно свойств, но добавляются в начало рядом других ID значений. ID Дополнительные значения, добавленные в переднюю часть отрисовки id атрибутов и , name являются ID значениями родительских переключателей, элементами управления GridViewRowID s, GridView ID, элементами управления IDсодержимого и веб-формой ID. Эти ID элементы добавляются таким образом, чтобы каждый отображаемый веб-элемент управления в GridView был уникальным nameid и значением .

Для каждого отображаемого элемента управления требуется отдельный name элемент управления, id так как браузер однозначно идентифицирует каждый элемент управления на стороне клиента и как он определяет для веб-сервера, какое действие или изменение произошло при обратной отправке. Например, предположим, что мы хотим выполнить код на стороне сервера при каждом изменении состояния проверки RadioButton. Это можно сделать, присвоив свойству RadioButton значение AutoPostBackTrue и создав обработчик событий для CheckChanged события. Однако если отображаемые name значения и id для всех переключателей были одинаковыми, при обратной отправке мы не могли определить, какой конкретный элемент RadioButton был нажат.

Короче говоря, мы не можем создать столбец переключателей в GridView с помощью веб-элемента управления RadioButton. Вместо этого мы должны использовать довольно архаические методы, чтобы обеспечить внедрение соответствующей разметки в каждую строку GridView.

Примечание

Как и элемент управления RadioButton Web, элемент управления HTML переключателя при добавлении в шаблон будет содержать уникальный name атрибут, что делает переключатели в сетке несгруппированы. Если вы не знакомы с элементами управления HTML, не стесняйтесь игнорировать это примечание, так как элементы управления HTML используются редко, особенно в ASP.NET 2.0. Но если вы хотите узнать больше, см. запись блога K. Scott AllenWeb Controls and HTML Controls.

Использование литерального элемента управления для внедрения разметки переключателя

Чтобы правильно сгруппировать все переключатели в GridView, необходимо вручную внедрить разметку переключателей в ItemTemplate. Каждому переключателю требуется один и тот же name атрибут, но он должен иметь уникальный id атрибут (если требуется получить доступ к переключателю через клиентский сценарий). После того как пользователь выберет переключатель и отправит страницу обратно, браузер отправит значение выбранного атрибута переключателя value . Поэтому каждому переключателю потребуется уникальный value атрибут. Наконец, при обратной отправке необходимо добавить checked атрибут в один выбранный переключатель. В противном случае после того, как пользователь сделает выбор и возвратит сообщение, переключатели вернутся в состояние по умолчанию (все не выбраны).

Существует два подхода, которые можно использовать для внедрения низкоуровневой разметки в шаблон. Один из них заключается в сочетании разметки и вызовов методов форматирования, определенных в классе кода программной части. Этот метод был впервые рассмотрен в руководстве Использование templateFields в элементе управления GridView . В нашем случае это может выглядеть примерно так:

<input type="radio" id='<%# GetUniqueRadioButtonID(...) %>' 
    name='SuppliersGroup' value='<%# GetRadioButtonValue(...) %>' ... />

Здесь и GetRadioButtonValue будут методами, GetUniqueRadioButton определенными в классе кода программной части, которые возвращают соответствующие id значения атрибутов и value для каждого переключателя. Этот подход хорошо подходит для назначения id атрибутов и value , но не соответствует значению checked атрибута, так как синтаксис привязки данных выполняется только при первой привязке данных к GridView. Таким образом, если в GridView включено состояние представления, методы форматирования будут запускаться только при первой загрузке страницы (или при явном восстановлении GridView к источнику данных), и поэтому функция, задающая checked атрибут, не будет вызываться при обратной отправке. Это довольно тонкая проблема и немного за пределами область этой статьи, так что я оставлю его на этом. Я, однако, призываю вас попробовать использовать приведенный выше подход и проработать его до точки, где вы получите застрять. Хотя такое упражнение не приблизит вас к рабочей версии, оно поможет глубже понять GridView и жизненный цикл привязки данных.

Другой подход к внедрению пользовательской низкоуровневой разметки в шаблон и подход, который мы будем использовать в этом руководстве, заключается в добавлении элемента управления Литерал в шаблон. Затем в обработчике событий GridView RowCreated или RowDataBound можно получить программный доступ к элементу управления Литерал, а его Text свойству присвоить разметку для выдачи.

Начните с удаления элемента RadioButton из templateField, ItemTemplateзаменив его элементом управления Литерал. Задайте для элемента управления литерала значение IDRadioButtonMarkup.

Добавление элемента управления

Рис. 12. Добавление литерального элемента управления в ItemTemplate (щелкните, чтобы просмотреть полноразмерное изображение)

Затем создайте обработчик событий для события GridView RowCreated . Событие RowCreated срабатывает один раз для каждой добавленной строки независимо от того, отскываются ли данные в GridView. Это означает, что даже при обратной отправке, когда данные перезагружаются из состояния представления, событие по-прежнему срабатывает, и именно по этой причине мы используем его вместо RowDataBound (который срабатывает только в том случае, RowCreated если данные явно привязаны к веб-элементу управления данными).

В этом обработчике событий мы хотим продолжить только в том случае, если мы имеем дело со строкой данных. Для каждой строки данных необходимо программно ссылаться на RadioButtonMarkup элемент управления Литерал и задать для его Text свойства разметку, которую нужно выпустить. Как показано в следующем коде, созданная разметка создает переключатель, атрибут которого name имеет значение SuppliersGroup, атрибут которого id имеет значение RowSelectorX, где X — индекс строки GridView, а value атрибут — индекс строки GridView.

Protected Sub Suppliers_RowCreated(sender As Object, e As GridViewRowEventArgs) _
    Handles Suppliers.RowCreated
    
    If e.Row.RowType = DataControlRowType.DataRow Then
        ' Grab a reference to the Literal control
        Dim output As Literal = _
            CType(e.Row.FindControl("RadioButtonMarkup"), Literal)
        ' Output the markup except for the "checked" attribute
        output.Text = String.Format( _
            "<input type="radio" name="SuppliersGroup" " & _
            "id="RowSelector{0}" value="{0}" />", e.Row.RowIndex)
    End If
End Sub

Если выбрана строка GridView и происходит обратная связь, нас интересует SupplierID выбранный поставщик. Таким образом, можно подумать, что значение каждого переключателя должно быть фактическим SupplierID (а не индексом строки GridView). Хотя это может работать в определенных обстоятельствах, было бы угрозой безопасности слепое принятие и обработка SupplierID. Например, в элементе GridView перечислены только те поставщики в США. Однако если SupplierID передается непосредственно из переключателя, что делать, чтобы запретить озорному пользователю манипулировать значением SupplierID , отправленным обратно при обратной передаче? Используя индекс строки в valueкачестве , а затем получив SupplierID при обратной отправке из DataKeys коллекции, можно убедиться, что пользователь использует только одно из значений SupplierID , связанных с одной из строк GridView.

После добавления этого кода обработчика событий проверьте страницу в браузере. Во-первых, обратите внимание, что одновременно можно выбрать только один переключатель в сетке. Однако при выборе переключателя и нажатии одной из кнопок происходит обратная связь, и все переключатели отменить изменения в исходное состояние (то есть при обратной отправке выбранный переключатель больше не выбран). Чтобы устранить эту проблему, необходимо расширить RowCreated обработчик событий, чтобы он проверял выбранный индекс переключателей, отправленный из обратной передачи, и добавлял checked="checked" атрибут в выдаваемую разметку совпадений индекса строки.

При обратной отправке браузер отправляет и namevalue выбранного переключателя. Значение можно получить программным способом с помощью Request.Form("name"). СвойствоRequest.Form предоставляет объект , NameValueCollection представляющий переменные формы. Переменные формы — это имена и значения полей формы на веб-странице, которые отправляются веб-браузером при выполнении обратной передачи. Так как отображаемым name атрибутом переключателей в GridView является SuppliersGroup, при обратной публикации веб-страницы браузер отправляет SuppliersGroup=valueOfSelectedRadioButton обратно на веб-сервер (вместе с другими полями формы). Затем к этим сведениям можно получить доступ из Request.Form свойства с помощью : Request.Form("SuppliersGroup").

Так как нам нужно определить индекс выбранного переключателя не только в RowCreated обработчике событий, но и в Click обработчиках событий для веб-элементов управления Button, давайте добавим SuppliersSelectedIndex свойство в класс кода программной части, который возвращает значение -1 , если переключатель не выбран, и выбранный индекс, если выбран один из переключателей.

Private ReadOnly Property SuppliersSelectedIndex() As Integer
    Get
        If String.IsNullOrEmpty(Request.Form("SuppliersGroup")) Then
            Return -1
        Else
            Return Convert.ToInt32(Request.Form("SuppliersGroup"))
        End If
    End Get
End Property

При добавлении этого свойства мы знаем, что нужно добавить разметку checked="checked" в RowCreated обработчик событий, если SuppliersSelectedIndex равно e.Row.RowIndex. Обновите обработчик событий, чтобы включить следующую логику:

Protected Sub Suppliers_RowCreated(sender As Object, e As GridViewRowEventArgs) _
    Handles Suppliers.RowCreated
    
    If e.Row.RowType = DataControlRowType.DataRow Then
        ' Grab a reference to the Literal control
        Dim output As Literal = _
            CType(e.Row.FindControl("RadioButtonMarkup"), Literal)
        ' Output the markup except for the "checked" attribute
        output.Text = String.Format( _
            "<input type="radio" name="SuppliersGroup" " & _
            "id="RowSelector{0}" value="{0}"", e.Row.RowIndex)
        ' See if we need to add the "checked" attribute
        If SuppliersSelectedIndex = e.Row.RowIndex Then
            output.Text &= " checked="checked""
        End If
        ' Add the closing tag
        output.Text &= " />"
    End If
End Sub

При этом изменении выбранный переключатель остается выбранным после обратной передачи. Теперь, когда у нас есть возможность указать, какой переключатель выбран, можно изменить поведение, чтобы при первом посещении страницы был выбран первый переключатель строки GridView (вместо того, чтобы переключатели не были выбраны по умолчанию, что является текущим поведением). Чтобы первый переключатель был выбран по умолчанию, просто измените If SuppliersSelectedIndex = e.Row.RowIndex Then оператор на следующий: If SuppliersSelectedIndex = e.Row.RowIndex OrElse (Not Page.IsPostBack AndAlso e.Row.RowIndex = 0) Then.

На этом этапе мы добавили столбец сгруппированных переключателей в GridView, который позволяет выбирать и запоминать одну строку GridView во время обратной передачи. Далее необходимо отобразить продукты, предоставляемые выбранным поставщиком. На шаге 4 мы посмотрим, как перенаправить пользователя на другую страницу, отправив рядом с выбранным SupplierIDэлементом . На шаге 5 мы посмотрим, как отобразить выбранные продукты поставщика в GridView на той же странице.

Примечание

Вместо использования TemplateField (основное внимание на этом длинном шаге 3) можно создать пользовательский DataControlField класс, который отрисовывает соответствующий пользовательский интерфейс и функциональные возможности. Класс DataControlField является базовым классом, от которого наследуются поля BoundField, CheckBoxField, TemplateField и другие встроенные поля GridView и DetailsView. Создание пользовательского DataControlField класса означает, что столбец переключателей можно добавить только с помощью декларативного синтаксиса, а также значительно упростит репликацию функций на другие веб-страницы и другие веб-приложения.

Если вы когда-либо создавали пользовательские, скомпилированные элементы управления в ASP.NET, вы знаете, что для этого требуется изрядный объем работы с ног и несет в себе множество тонкостей и пограничных вариантов, которые должны быть тщательно обработаны. Поэтому сейчас мы откажемся от реализации столбца переключателей в качестве пользовательского DataControlField класса и будем использовать параметр TemplateField. Возможно, в будущем мы сможем изучить создание, использование и развертывание пользовательских DataControlField классов.

Шаг 4. Отображение продуктов выбранного поставщика на отдельной странице

После того как пользователь выберет строку GridView, необходимо отобразить продукты выбранного поставщика. В некоторых случаях может потребоваться отобразить эти продукты на отдельной странице, а в других — на той же странице. Сначала рассмотрим, как отобразить продукты на отдельной странице; На шаге 5 мы рассмотрим добавление GridView RadioButtonField.aspx в для отображения продуктов выбранного поставщика.

В настоящее время на странице ListProducts есть два веб-элемента управления Button и SendToProducts. При нажатии кнопки SendToProducts необходимо отправить пользователя в ~/Filtering/ProductsForSupplierDetails.aspx. Эта страница была создана в учебнике Фильтрация основных и подробных данных на двух страницах и отображает продукты для поставщика, который SupplierID передается через поле строки запроса с именем SupplierID.

Чтобы предоставить эту функцию, создайте обработчик событий для SendToProducts события Button Click . На шаге 3 мы добавили SuppliersSelectedIndex свойство , которое возвращает индекс строки, для которой выбран переключатель. Соответствующий SupplierID объект можно получить из коллекции GridView, DataKeys а затем ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID отправить пользователя с помощью Response.Redirect("url").

Protected Sub SendToProducts_Click(sender As Object, e As EventArgs) _
    Handles SendToProducts.Click
    
    ' Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    Dim supplierID As Integer = _
        Convert.ToInt32(Suppliers.DataKeys(SuppliersSelectedIndex).Value)
    Response.Redirect( _
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" & _
        supplierID)
End Sub

Этот код работает замечательно, если в GridView выбран один из переключателей. Если изначально в GridView не выбраны переключатели и пользователь нажимает SendToProducts кнопку , SuppliersSelectedIndex будет иметь -1значение , что приведет к возникновению исключения, так как -1 находится вне диапазона индексов DataKeys коллекции. Однако это не важно, если вы решили обновить RowCreated обработчик событий, как описано в шаге 3, чтобы изначально был выбран первый переключатель в GridView.

Чтобы вместить SuppliersSelectedIndex значение -1, добавьте элемент управления Label Web на страницу над GridView. Задайте свойству IDChooseSupplierMsgзначение , свойству EnableViewStateWarningCssClass и Visible свойству Falseзначение , а свойству — значение , а свойству Text — значение Выберите поставщика из сетки. Класс Warning CSS отображает текст красным курсивом, полужирным, крупным шрифтом и определяется в Styles.css. Если задать EnableViewState для свойств и Visible значение False, метка не отображается, за исключением тех обратных передач, в которых свойству элемента управления Visible программно задано значение True.

Добавление веб-элемента управления

Рис. 13. Добавление веб-элемента управления "Метка" над GridView (щелкните для просмотра полноразмерного изображения)

Затем добавьте Click обработчик событий, чтобы отобразить ChooseSupplierMsg метку, если SuppliersSelectedIndex меньше нуля, и перенаправьте пользователя на в ~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=SupplierID противном случае.

Protected Sub SendToProducts_Click(sender As Object, e As EventArgs) _
    Handles SendToProducts.Click
    
    ' make sure one of the radio buttons has been selected
    If SuppliersSelectedIndex < 0 Then
        ChooseSupplierMsg.Visible = True
    Else
        ' Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        Dim supplierID As Integer = _
            Convert.ToInt32(Suppliers.DataKeys(SuppliersSelectedIndex).Value)
        Response.Redirect( _
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" & _
            supplierID)
    End If
End Sub

Перейдите на страницу в браузере и нажмите кнопку SendToProducts перед выбором поставщика из GridView. Как показано на рисунке 14, отображается метка ChooseSupplierMsg . Затем выберите поставщика и нажмите кнопку SendToProducts . Вы перейдете на страницу со списком продуктов, поставляемых выбранным поставщиком. На рисунке 15 показана ProductsForSupplierDetails.aspx страница, когда был выбран поставщик пивоваренных заводов для снежного человека.

Метка ChooseSupplierMsg отображается, если поставщик не выбран

Рис. 14. Метка ChooseSupplierMsg отображается, если поставщик не выбран (щелкните для просмотра полноразмерного изображения)

Продукты выбранного поставщика отображаются в ProductsForSupplierDetails.aspx

Рис. 15. Продукты выбранного поставщика отображаются в ProductsForSupplierDetails.aspx (щелкните, чтобы просмотреть полноразмерное изображение)

Шаг 5. Отображение продуктов выбранного поставщика на той же странице

На шаге 4 мы узнали, как отправить пользователя на другую веб-страницу для отображения продуктов выбранного поставщика. Кроме того, выбранные продукты поставщика могут отображаться на той же странице. Чтобы проиллюстрировать это, мы добавим еще один элемент GridView для RadioButtonField.aspx отображения продуктов выбранного поставщика.

Так как мы хотим, чтобы этот элемент GridView продуктов отображался только после выбора поставщика, добавьте веб-элемент управления Панель под Suppliers GridView, задав для него ID значение ProductsBySupplierPanel , а свойству Visible — значение False. На панели добавьте текст Products for the Selected Supplier (Продукты для выбранного поставщика), а затем GridView с именем ProductsBySupplier. В смарт-теге GridView выберите привязку к новому объекту ObjectDataSource с именем ProductsBySupplierDataSource.

Привязка элемента GridView ProductsBySupplier к новому объекту ObjectDataSource

Рис. 16. Привязка ProductsBySupplier GridView к новому объекту ObjectDataSource (щелкните для просмотра полноразмерного изображения)

Затем настройте ObjectDataSource для использования ProductsBLL класса . Так как мы хотим получить только те продукты, которые предоставляются выбранным поставщиком, укажите, что ObjectDataSource должен вызывать GetProductsBySupplierID(supplierID) метод для получения его данных. Выберите (Нет) в раскрывающихся списках на вкладках UPDATE, INSERT и DELETE.

Настройка ObjectDataSource для использования метода GetProductsBySupplierID(supplierID)

Рис. 17. Настройка ObjectDataSource для использования GetProductsBySupplierID(supplierID) метода (щелкните для просмотра полноразмерного изображения)

Задайте для Drop-Down Списки значение (Нет) на вкладках UPDATE, INSERT и DELETE.

Рис. 18. Задайте для Drop-Down Списки значение (Нет) на вкладках UPDATE, INSERT и DELETE (щелкните для просмотра полноразмерного изображения)

Настроив вкладки SELECT, UPDATE, INSERT и DELETE, нажмите кнопку Далее. GetProductsBySupplierID(supplierID) Так как метод ожидает входной параметр, мастер создания источника данных предлагает указать источник для значения параметра.

У нас есть несколько вариантов указания источника значения параметра. Можно использовать объект Parameter по умолчанию и программно присвоить значение SuppliersSelectedIndex свойства свойству Parameters DefaultValue в обработчике Selecting событий ObjectDataSource. Вернитесь к учебнику Программное задание значений параметров ObjectDataSource , чтобы ознакомиться с программным назначением значений для параметров ObjectDataSource.

Кроме того, можно использовать ControlParameter и ссылаться на Suppliers свойство GridView (SelectedValueсм. рис. 19). Свойство GridView SelectedValue возвращает значение, DataKey соответствующее свойствуSelectedIndex . Чтобы этот параметр работал, необходимо программно задать для свойства GridView SelectedIndex значение выбранной строки при нажатии кнопки ListProducts . В качестве дополнительного преимущества, задав SelectedIndex, выбранная запись примет на SelectedRowStyle себя значение, определенное DataWebControls в теме (желтый фон).

Использование controlParameter для указания SelectedValue gridView в качестве источника параметров

Рис. 19. Использование controlParameter для указания selectedValue gridView s в качестве источника параметров (щелкните, чтобы просмотреть полноразмерное изображение)

После завершения работы мастера Visual Studio автоматически добавит поля для полей данных продукта. Удалите все поля, кроме ProductName, CategoryNameи UnitPrice BoundFields, а затем измените HeaderText свойства на Product, Category и Price. UnitPrice Настройте BoundField так, чтобы его значение было отформатировано в виде валюты. После внесения этих изменений декларативная разметка Panel, GridView и ObjectDataSource должна выглядеть следующим образом:

<asp:Panel runat="server" ID="ProductsBySupplierPanel" Visible="False">
    <h3>
        Products for the Selected Supplier</h3>
    <p>
        <asp:GridView ID="ProductsBySupplier" runat="server" 
            AutoGenerateColumns="False" DataKeyNames="ProductID"
            DataSourceID="ProductsBySupplierDataSource" EnableViewState="False">
            <Columns>
                <asp:BoundField DataField="ProductName" HeaderText="Product" 
                    SortExpression="ProductName" />
                <asp:BoundField DataField="CategoryName" HeaderText="Category" 
                    ReadOnly="True" SortExpression="CategoryName" />
                <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
                    HeaderText="Price" HtmlEncode="False" 
                    SortExpression="UnitPrice" />
            </Columns>
        </asp:GridView>
        <asp:ObjectDataSource ID="ProductsBySupplierDataSource" runat="server" 
            OldValuesParameterFormatString="original_{0}"
            SelectMethod="GetProductsBySupplierID" TypeName="ProductsBLL">
            <SelectParameters>
                <asp:ControlParameter ControlID="Suppliers" Name="supplierID" 
                    PropertyName="SelectedValue" Type="Int32" />
            </SelectParameters>
        </asp:ObjectDataSource>
    </p>
</asp:Panel>

Чтобы выполнить это упражнение, необходимо присвоить свойству GridView SelectedIndex значение , SelectedSuppliersIndex а свойству ProductsBySupplierPanel Panel Visible — значение True при нажатии ListProducts кнопки. Для этого создайте обработчик событий для ListProducts события элемента управления Click Button Web и добавьте следующий код:

Protected Sub ListProducts_Click(sender As Object, e As EventArgs) _
    Handles ListProducts.Click
    
    ' make sure one of the radio buttons has been selected
    If SuppliersSelectedIndex < 0 Then
        ChooseSupplierMsg.Visible = True
        ProductsBySupplierPanel.Visible = False
    Else
        ' Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex
        ' Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = True
    End If
End Sub

Если поставщик не был выбран в GridView, отображается метка, ChooseSupplierMsg а панель скрыта ProductsBySupplierPanel . В противном случае, если поставщик был выбран, ProductsBySupplierPanel отображается и обновляется свойство GridView SelectedIndex .

На рисунке 20 показаны результаты после выбора поставщика "Пивоварни снежного человека" и нажатия кнопки "Показать продукты на странице".

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

Рис. 20. Продукты, предоставляемые пивоваренными компаниями снежного человека, перечислены на той же странице (щелкните, чтобы просмотреть полноразмерное изображение)

Сводка

Как описано в учебнике Master/Detail Using a Selectable Master GridView with a Details DetailView ,записи можно выбрать из GridView с помощью CommandField, свойство которого ShowSelectButton имеет значение True. Но commandField отображает свои кнопки в виде обычных кнопок, ссылок или изображений. Альтернативным пользовательским интерфейсом выбора строк является предоставление переключателя или флажка в каждой строке GridView. В этом руководстве мы рассмотрели, как добавить столбец переключателей.

К сожалению, добавление столбца переключателей не так просто, как можно было бы ожидать. Отсутствует встроенный элемент RadioButtonField, который можно добавить нажатием кнопки, а использование веб-элемента управления RadioButton в TemplateField вызывает собственный набор проблем. В конце концов, чтобы предоставить такой интерфейс, необходимо либо создать пользовательский DataControlField класс, либо прибегнуть к внедрению соответствующего HTML-кода в TemplateField во время RowCreated события.

Изучив, как добавить столбец переключателей, давайте обратим внимание на добавление столбца флажков. С помощью столбца флажков пользователь может выбрать одну или несколько строк GridView, а затем выполнить некоторые операции со всеми выбранными строками (например, выбрать набор сообщений электронной почты из веб-клиента электронной почты, а затем удалить все выбранные сообщения электронной почты). В следующем руководстве мы посмотрим, как добавить такой столбец.

Счастливое программирование!

Об авторе

Скотт Митчелл (Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с Веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Его можно связать по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Отдельная благодарность

Эта серия учебников была проверена многими полезными рецензентами. Ведущим рецензентом этого руководства был Дэвид Суру. Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, опустите мне строку в mitchell@4GuysFromRolla.com.