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

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

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

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

Введение

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

В этом и следующем руководстве основное внимание уделяется улучшению процесса выбора строк. Как описано в разделе Master/Details Using a Selectable Master GridView with a Details DetailsView , мы можем добавить CommandField в GridView, включающее кнопку Выбрать. При нажатии происходит обратная связь и свойство GridView обновляется до индекса строки, в которой была нажата SelectedIndex кнопка "Выбрать". В учебнике Master/Detail Using a Selectable Master GridView with a DetailsView (Основные и подробные сведения) мы узнали, как использовать эту функцию для отображения сведений о выбранной строке 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 s ID значение Suppliers и выберите из смарт-тега создать новый источник данных. В частности, создайте объект ObjectDataSource с именем SuppliersDataSource , который извлекает данные из SuppliersBLL объекта .

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

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

Снимок экрана: окно Настройка источника данных — SuppliersDataSource с выбранным бизнес-объектом SuppliersBLL и выделенной кнопкой Далее.

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

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

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

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

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

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

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

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

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

Несмотря на то, что использование TemplateField веб-элементов управления RadioButton не предоставляет необходимых функций, давайте реализуем этот подход, так как стоит изучить, почему результирующие переключатели не группируются. Для начала добавьте TemplateField в Элемент Управления GridView поставщиков, сделав его крайним левым полем. Затем в смарт-теге GridView щелкните ссылку Изменить шаблоны и перетащите веб-элемент управления RadioButton из панели элементов в TemplateField ( ItemTemplate см. рис. 10). Присвойте свойству RadioButton значение 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 в 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 элементами родительских переключателей, элементов управления IDGridViewRow GridViewID, элементов управления IDконтентом и веб-формы ID. Эти ID значения добавляются таким образом, чтобы каждый отображаемый веб-элемент управления в GridView был уникальным nameid.

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

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

Примечание

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

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

Чтобы правильно сгруппировать все переключатели в 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 s ItemTemplate, заменив его элементом управления Литерал. Присвойте элементу управления Литерал значение IDRadioButtonMarkup.

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

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

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

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

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // 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);
    }
}

Если выбрана строка GridView и происходит обратная связь, нас интересует SupplierID выбранный поставщик. Поэтому можно подумать, что значение каждого переключателя должно быть фактическим SupplierID (а не индексом строки GridView). Хотя это может работать в определенных обстоятельствах, было бы угрозой безопасности слепо принять и обработать SupplierID. Например, в gridView перечислены только те поставщики в США. Однако, если SupplierID передается непосредственно с переключателя, что делать, чтобы запретить озорному пользователю манипулировать значением SupplierID , отправленным обратно при обратной передаче? Используя индекс строки в valueкачестве , а затем получив SupplierID при обратной отправке из 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, давайте добавим SuppliersSelectedIndex свойство в класс кода программной части, который возвращает значение -1 , если переключатель не выбран, и выбранный индекс, если выбран один из переключателей.

private int SuppliersSelectedIndex
{
    get
    {
        if (string.IsNullOrEmpty(Request.Form["SuppliersGroup"]))
            return -1;
        else
            return Convert.ToInt32(Request.Form["SuppliersGroup"]);
    }
}

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

protected void Suppliers_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Grab a reference to the Literal control
        Literal output = (Literal)e.Row.FindControl("RadioButtonMarkup");
        // 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)
            output.Text += @" checked="checked"";
        // Add the closing tag
        output.Text += " />";
    }
}

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

На этом этапе мы добавили столбец сгруппированных переключателей в 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 через поле querystring с именем SupplierID.

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

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
    int supplierID = 
        Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
    Response.Redirect(
        "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
        + supplierID);
    }
}

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

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

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

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

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

protected void SendToProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
        ChooseSupplierMsg.Visible = true;
    else
    {
        // Send the user to ~/Filtering/ProductsForSupplierDetails.aspx
        int supplierID = 
            Convert.ToInt32(Suppliers.DataKeys[SuppliersSelectedIndex].Value);
        Response.Redirect(
            "~/Filtering/ProductsForSupplierDetails.aspx?SupplierID=" 
            + supplierID);
    }
}

Перейдите на страницу в браузере и нажмите кнопку 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 void ListProducts_Click(object sender, EventArgs e)
{
    // make sure one of the radio buttons has been selected
    if (SuppliersSelectedIndex < 0)
    {
        ChooseSupplierMsg.Visible = true;
        ProductsBySupplierPanel.Visible = false;
    }
    else
    {
        // Set the GridView's SelectedIndex
        Suppliers.SelectedIndex = SuppliersSelectedIndex;
        // Show the ProductsBySupplierPanel panel
        ProductsBySupplierPanel.Visible = true;
    }
}

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