Поделиться через


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

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

Скачать в формате PDF

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

Введение

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

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

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

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

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

Прежде чем мы начнем улучшать GridView, добавляя в него столбец переключателей, давайте сначала уделим немного времени созданию ASP.NET страниц в нашем проекте веб-сайта, которые нам понадобятся для этого урока и следующих двух. Сначала добавьте новую папку с именем EnhancedGridView. Затем добавьте в нее следующие ASP.NET страницы, чтобы связать каждую страницу с главной страницей Site.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 файл. В частности, добавьте следующую разметку после элемента управления <siteMapNode>Using the SqlDataSource:

<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 с панели элементов в конструктор. Установите для параметра GridView s ID значение и Suppliers с помощью смарт-тега выберите создание нового источника данных. В частности, создайте ObjectDataSource с именем SuppliersDataSource , который извлекает данные из SuppliersBLL объекта.

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

Рисунок 4: Создание нового ObjectDataSource с именем SuppliersDataSource (Нажмите, чтобы просмотреть полноразмерное изображение)

Скриншот окна Configure Data Source - SuppliersDataSource с открытым выпадающим меню бизнес-объекта. Выбирается SuppliersBLL и выделяется кнопка Далее.

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

Поскольку мы хотим перечислить только тех поставщиков в США, выберите GetSuppliersByCountry(country) метод из выпадающего списка на вкладке ВЫБРАТЬ.

Скриншот окна Configure Data Source - SuppliersDataSource на вкладке SELECT с открытым выпадающим меню метода. Выбирается опция метода GetSupplierByCountry и выделяется кнопка Далее.

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

На вкладке «ОБНОВИТЬ» выберите параметр (Нет) и нажмите «Далее».

Скриншот окна Configure Data Source - SuppliersDataSource на вкладке UPDATE с открытым выпадающим меню метода. Выбирается вариант метода (None) и выделяется кнопка Next.

Рисунок 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 Web. Я установил ID s этих двух кнопок в положение ListProducts и SendToProducts, с идеей, что при ListProducts нажатии произойдет постбек, и продукты выбранного поставщика будут перечислены на той же странице, но при SendToProducts нажатии пользователь будет перенаправлен на другую страницу, на которой перечислены продукты.

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

У этих поставщиков из США указаны их имена, город и информация о стране

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

Шаг 3: Добавление колонки радиокнопок

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

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

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

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

Рисунок 10: Добавление веб-элемента управления RadioButton к (ItemTemplateНажмите, чтобы просмотреть полноразмерное изображение)

После внесения этих дополнений через дизайнер разметка вашего 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 — GroupName это то, что используется для группировки ряда переключателей. Все элементы управления RadioButton с одинаковым GroupName значением считаются сгруппированными; в каждый момент времени из группы можно выбрать только одну радиокнопку. Свойство GroupName указывает значение атрибута отображаемого радиокнопки s name . Браузер проверяет атрибуты радиокнопок name для определения группировок радиокнопок.

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

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

Рисунок 11: Переключатели GridView не сгруппированы (Нажмите, чтобы просмотреть полноразмерное изображение)

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

<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 and id не являются точными значениями, указанными в окне Properties, но предваряются рядом других ID значений. Дополнительными значениями, ID добавленными в переднюю часть отображаемого id и name атрибутов, являются s родительских элементов управления ID переключателямиGridViewRow, s s, GridView ID, элемента управления IDсодержимым s , и s IDвеб-формы.ID Эти ID элементы добавляются для того, чтобы каждый визуализированный веб-элемент управления в GridView имел уникальные id значения and name .

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

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

Замечание

Как и веб-элемент управления RadioButton, элемент управления HTML переключатель при добавлении в шаблон будет включать атрибут unique name , что делает переключатели в сетке разгруппированными. Если вы не знакомы с элементами управления HTML, не стесняйтесь игнорировать это замечание, так как элементы управления HTML используются редко, особенно в ASP.NET 2.0. Но если вы хотите узнать больше, см. запись в блоге К. Скотта Аллена«Веб-элементы управления и элементы управления HTML».

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

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

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

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

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

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

Начните с удаления RadioButton из TemplateField s ItemTemplate, заменив его литеральным элементом управления. Установите литеральный элемент управления s ID в положение RadioButtonMarkup.

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

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

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

В этом обработчике событий мы хотим продолжить работу только в том случае, если мы имеем дело со строкой данных. Для каждой строки данных мы хотим программно ссылаться на RadioButtonMarkup элемент управления Literal и установить его 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 , отправленным обратно на postback? Используя индекс строки в качестве value, а затем получая SupplierID обратную передачу on из DataKeys коллекции, мы можем гарантировать, что пользователь использует только одно из значений, SupplierID связанных с одной из строк GridView.

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

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

Поскольку нам потребуется определить выбранный индекс радиокнопки не только в обработчике RowCreated событий, но и в Click обработчиках событий для элементов управления Button Web, давайте добавим свойство 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 Web и SendToProducts. При нажатии на SendToProducts кнопку мы хотим отправить пользователя в ~/Filtering/ProductsForSupplierDetails.aspx. Эта страница была создана в учебном пособии по фильтрации основных и подробных данных на двух страницах и отображает продукты для поставщика, которые SupplierID проходят через поле строки запроса с именем SupplierID.

Чтобы обеспечить эту функциональность, создайте обработчик событий для SendToProducts события Button s 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. Установите его ID свойство в значение ChooseSupplierMsg, его CssClass свойство в значение Warning, его EnableViewState и Visible свойства в значение False, а его Text свойство в положение Пожалуйста, выберите поставщика из сетки. Класс Warning CSS отображает текст красным, курсивом, полужирным, крупным шрифтом и определяется в Styles.css. При установке EnableViewState свойств and Visible в значение False, метка не визуализируется, за исключением тех постбэков, где свойство s элемента управления Visible программно установлено в значение True.

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

Рисунок 13: Добавление веб-элемента управления метками над GridView (Нажмите, чтобы просмотреть полноразмерное изображение)

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

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 на которой был выбран поставщик Bigfoot Breweries.

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

Рисунок 14: Этикетка отображается, ChooseSupplierMsg если поставщик не выбран (нажмите, чтобы просмотреть полноразмерное изображение)

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

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

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

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

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

Привязка ProductsBySupplier GridView к новому ObjectDataSource

Рисунок 16: Привязка ProductsBySupplier GridView к новому ObjectDataSource (Нажмите, чтобы просмотреть полноразмерное изображение)

Затем настройте ObjectDataSource для использования ProductsBLL класса. Поскольку мы хотим получить только те продукты, которые предоставлены выбранным поставщиком, укажите, что ObjectDataSource должен вызывать GetProductsBySupplierID(supplierID) метод для получения своих данных. Выберите (Нет) из раскрывающихся списков на вкладках ОБНОВИТЬ, ВСТАВИТЬ и УДАЛИТЬ.

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

Рисунок 17: Настройка ObjectDataSource для использования GetProductsBySupplierID(supplierID) метода (Нажмите, чтобы просмотреть полноразмерное изображение)

Установите для Drop-Down списков значение (Нет) на вкладках ОБНОВИТЬ, ВСТАВИТЬ и УДАЛИТЬ

Рисунок 18: Установите Drop-Down Lists в положение (None) на вкладках UPDATE, INSERT и DELETE (Нажмите, чтобы просмотреть полноразмерное изображение)

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

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

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

Используйте ControlParameter для указания selectedValue от GridView в качестве источника параметра

Рисунок 19: Используйте параметр ControlParameter для указания выбранного значения GridView в качестве источника параметра (нажмите, чтобы просмотреть полноразмерное изображение)

После завершения работы мастера Visual Studio автоматически добавит поля для полей данных о продукте. Удалите все поля, ProductNameкроме , CategoryName, и UnitPrice BoundField, и измените 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 s SelectedIndex в значение, а SelectedSuppliersIndex свойство ProductsBySupplierPanel Panel s Visible — в положение True при ListProducts нажатии кнопки. Для этого создайте обработчик событий для ListProducts события s 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 показаны результаты после выбора поставщика Bigfoot Breweries и нажатия кнопки «Показать продукты на странице».

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

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

Сводка

Как обсуждалось в учебном пособии 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, а затем выполнить некоторую операцию со всеми выбранными строками (например, выбрать набор сообщений электронной почты в веб-клиенте электронной почты, а затем удалить все выбранные письма). В следующем уроке мы увидим, как добавить такую колонку.

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

Сведения о авторе

Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.

Особое спасибо кому

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