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


Вставка новой записи из подвала GridView (C#)

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

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

Хотя элемент управления GridView не предоставляет встроенную поддержку вставки новой записи данных, в этом руководстве показано, как расширить GridView для включения интерфейса вставки.

Введение

Как описано в руководстве по вставке, обновлению и удалению данных , элементы управления GridView, DetailsView и FormView Web включают встроенные возможности изменения данных. При использовании с декларативными элементами управления источниками данных эти три веб-элемента управления можно быстро и легко настроить для изменения данных и в сценариях без необходимости писать одну строку кода. К сожалению, только элементы управления DetailsView и FormView предоставляют встроенные возможности вставки, редактирования и удаления. GridView предлагает только поддержку редактирования и удаления. Тем не менее, приложив немного усилий, мы можем усовершенствовать GridView, чтобы включить интерфейс вставки.

При добавлении возможностей вставки в GridView мы отвечаем за решение о том, как будут добавляться новые записи, создавать интерфейс вставки и писать код для вставки новой записи. В этом руководстве мы рассмотрим, как добавить интерфейс вставки в строку нижнего колонтитула GridView (см. рис. 1). Ячейка футера для каждого столбца включает соответствующий элемент пользовательского интерфейса для сбора данных (текстовое поле для имени продукта, выпадающий список для поставщика и т. д.). Нам также нужен столбец для кнопки "Добавить", которая при нажатии приведет к обратной отправке и вставке новой записи в Products таблицу с использованием значений, предоставленных в строке нижнего колонтитула.

Строка нижнего колонтитула предоставляет интерфейс для добавления новых продуктов

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

Шаг 1. Отображение сведений о продукте в GridView

Прежде чем мы займемся созданием интерфейса вставки в нижней части GridView, давайте сначала сосредоточимся на добавлении GridView на страницу для отображения продуктов из базы данных. Начните с открытия InsertThroughFooter.aspx страницы в EnhancedGridView папке и перетащите GridView из панели элементов в конструктор, установив для свойства GridView ID значение Products. Затем используйте смарт-тег GridView, чтобы привязать его к новому объекту ObjectDataSource с именем ProductsDataSource.

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

Рис. 2. Создайте новый объект ObjectDataSource с именем ProductsDataSource (Щелкните, чтобы просмотреть изображение в полном размере)

Настройте ObjectDataSource для использования метода ProductsBLL класса GetProducts() для получения сведений о продукте. В этом руководстве мы сосредоточимся строго на добавлении функций вставки и не будем беспокоиться о редактировании и удалении. Поэтому убедитесь, что в раскрывающемся списке на вкладке INSERT задано AddProduct() значение, а в раскрывающихся списках на вкладках UPDATE и DELETE задано значение (Нет).

Сопоставление метода AddProduct с методом Insert() ObjectDataSource

Рис. 3. Сопоставление AddProduct метода с методом ObjectDataSource Insert() (щелкните, чтобы просмотреть изображение полного размера)

Задайте для вкладок UPDATE и DELETE Drop-Down списки (Нет)

Рис. 4. Установите вкладки UPDATE и DELETE списков Drop-Down на (нет) (щелкните, чтобы просмотреть изображение полного размера)

После завершения мастера настройки источника данных ObjectDataSource Visual Studio автоматически добавит поля в GridView для каждого из соответствующих полей данных. Теперь оставьте все поля, добавленные Visual Studio. Позже в этом руководстве мы вернемся и удалим некоторые поля, значения которых не нужно указывать при добавлении новой записи.

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

На этом этапе декларативная разметка GridView и ObjectDataSource должны выглядеть следующим образом:

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
    AllowPaging="True" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
            SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" 
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
            SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" 
            SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" 
            SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" 
            SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" 
            SortExpression="Discontinued" />
        <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="SupplierName" 
            ReadOnly="True" SortExpression="SupplierName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetProducts" TypeName="ProductsBLL">
    <InsertParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
    </InsertParameters>
</asp:ObjectDataSource>

Все поля данных продукта отображаются в разбитом на страницы GridView

Рис. 5. Все поля данных продукта отображаются в paged GridView (щелкните, чтобы просмотреть изображение полного размера)

Вместе со строками заголовков и данных GridView включает в себя строку нижнего колонтитула. Строки верхнего и нижнего колонтитулов отображаются в зависимости от значений свойств ShowHeader и ShowFooter GridView. Чтобы отобразить нижний колонтитул, просто задайте свойству ShowFooter значение true. Как показано на рисунке 6, установка свойства ShowFooter в true добавляет строку нижнего колонтитула в сетку.

Чтобы отобразить строку нижнего колонтитула, установите ShowFooter в True

Рис. 6. Чтобы отобразить строку нижнего колонтитула, установите ShowFooter в True (щелкните, чтобы просмотреть изображение в полном размере)

Обратите внимание, что нижний колонтитул имеет темно-красный фон. Это связано с темой DataWebControls, которую мы создали и применили ко всем страницам в руководстве по отображению данных с помощью ObjectDataSource . В частности, GridView.skin файл настраивает FooterStyle свойство так, чтобы использовался FooterStyle класс CSS. Класс FooterStyle определяется Styles.css следующим образом:

.FooterStyle
{
    background-color: #a33;
    color: White;
    text-align: right;
}

Замечание

Мы рассматривали использование подвальной строки GridView в предыдущих руководствах. При необходимости вернитесь к разделу Отображение сводной информации в нижнем колонтитуле GridView для освежения памяти.

После задания свойства ShowFooter на true, уделите время, чтобы просмотреть выходные данные в браузере. В настоящее время строка нижнего колонтитула не содержит текста или веб-элементов управления. На шаге 3 мы изменим нижний колонтитул для каждого поля GridView, чтобы он включает соответствующий интерфейс вставки.

Пустая строка нижнего колонтитула отображается над элементами управления интерфейсом разбиения по страницам

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

В руководстве по элементу управления GridView мы узнали, как значительно настроить отображение определенного столбца GridView с помощью TemplateFields (в отличие от BoundFields или CheckBoxFields); При настройке интерфейса изменения данных мы рассмотрели использование TemplateFields для настройки интерфейса редактирования в GridView. Помните, что TemplateField состоит из ряда шаблонов, определяющих сочетание разметки, веб-элементов управления и синтаксиса привязки данных, используемого для определенных типов строк. ItemTemplateНапример, задает шаблон, используемый для строк, доступных только для чтения, а EditItemTemplate шаблон определяется для редактируемой строки.

Наряду с ItemTemplate и EditItemTemplate, TemplateField также включает FooterTemplate, которое определяет содержимое строки нижнего колонтитула. Поэтому можно добавить веб-элементы управления, необходимые для каждого поля интерфейса вставки в FooterTemplate. Чтобы начать, преобразуйте все поля в GridView в TemplateFields. Это можно сделать, щелкнув ссылку "Изменить столбцы" в смарт-теге GridView, выбрав каждое поле в левом нижнем углу и нажав кнопку "Преобразовать это поле в ссылку TemplateField".

Преобразование каждого поля в templateField

Рис. 8. Преобразование каждого поля в templateField

Нажав на «Преобразовать это поле в TemplateField», текущий тип поля изменится на эквивалентный TemplateField. Например, каждый BoundField заменяется TemplateField, в котором ItemTemplate содержит метку, отображающую соответствующее поле данных, а EditItemTemplate отображает поле данных в текстовом поле. ProductName BoundField был преобразован в следующую разметку TemplateField:

<asp:TemplateField HeaderText="ProductName" SortExpression="ProductName">
    <EditItemTemplate>
        <asp:TextBox ID="TextBox1" runat="server" 
            Text='<%# Bind("ProductName") %>'></asp:TextBox>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="Label2" runat="server" 
            Text='<%# Bind("ProductName") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>

Подобно тому, как Discontinued CheckBoxField был преобразован в TemplateField, в котором ItemTemplate и EditItemTemplate содержат веб-элемент управления CheckBox (с отключенным флажком ItemTemplate). Приложение BoundField только для ProductID чтения было преобразовано в TemplateField с элементом управления Label в обоих ItemTemplate и EditItemTemplate. Короче говоря, преобразование существующего поля GridView в TemplateField — это быстрый и простой способ переключиться на более настраиваемый TemplateField, не теряя ни одной из существующих функций поля.

Так как GridView, с которым мы работаем, не поддерживает редактирование, вы можете удалить EditItemTemplate из каждого TemplateField, оставив только ItemTemplate. После этого декларативная разметка GridView должна выглядеть следующим образом:

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
    AllowPaging="True" EnableViewState="False" ShowFooter="True">
    <Columns>
        <asp:TemplateField HeaderText="ProductID" InsertVisible="False" 
            SortExpression="ProductID">
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("ProductID") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="ProductName" SortExpression="ProductName">
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="SupplierID" SortExpression="SupplierID">
            <ItemTemplate>
                <asp:Label ID="Label3" runat="server" 
                    Text='<%# Bind("SupplierID") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="CategoryID" SortExpression="CategoryID">
            <ItemTemplate>
                <asp:Label ID="Label4" runat="server" 
                    Text='<%# Bind("CategoryID") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="QuantityPerUnit" 
            SortExpression="QuantityPerUnit">
            <ItemTemplate>
                <asp:Label ID="Label5" runat="server" 
                    Text='<%# Bind("QuantityPerUnit") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="UnitPrice" SortExpression="UnitPrice">
            <ItemTemplate>
                <asp:Label ID="Label6" runat="server" 
                    Text='<%# Bind("UnitPrice") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="UnitsInStock" 
            SortExpression="UnitsInStock">
            <ItemTemplate>
                <asp:Label ID="Label7" runat="server" 
                    Text='<%# Bind("UnitsInStock") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="UnitsOnOrder" 
            SortExpression="UnitsOnOrder">
            <ItemTemplate>
                <asp:Label ID="Label8" runat="server" 
                    Text='<%# Bind("UnitsOnOrder") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="ReorderLevel" 
            SortExpression="ReorderLevel">
            <ItemTemplate>
                <asp:Label ID="Label9" runat="server" 
                    Text='<%# Bind("ReorderLevel") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Discontinued" 
            SortExpression="Discontinued">
            <ItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" 
                    Checked='<%# Bind("Discontinued") %>' Enabled="false" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="CategoryName" 
            SortExpression="CategoryName">
            <ItemTemplate>
                <asp:Label ID="Label10" runat="server" 
                    Text='<%# Bind("CategoryName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="SupplierName" 
            SortExpression="SupplierName">
            <ItemTemplate>
                <asp:Label ID="Label11" runat="server" 
                    Text='<%# Bind("SupplierName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Теперь, когда каждое поле GridView было преобразовано в TemplateField, мы можем ввести соответствующий интерфейс вставки в каждое поле FooterTemplate. Некоторые поля не будут иметь интерфейс вставки (ProductIDнапример, например), другие будут отличаться в веб-элементах управления, используемых для сбора сведений о новом продукте.

Чтобы создать интерфейс редактирования, выберите ссылку "Изменить шаблоны" из смарт-тега GridView. Затем в раскрывающемся списке выберите соответствующее поле FooterTemplate и перетащите нужный элемент управления из панели инструментов в конструктор.

Добавьте соответствующий интерфейс вставки данных в FooterTemplate каждого поля

Рис. 9. Добавление соответствующего интерфейса вставки в каждое поле FooterTemplate (щелкните, чтобы просмотреть изображение полного размера)

Следующий маркированный список перечисляет поля GridView, указывая интерфейс вставки для добавления:

  • ProductID никакой.
  • ProductName добавьте текстовое поле и задайте для нее значение IDNewProductName. Добавьте элемент управления RequiredFieldValidator, чтобы убедиться, что пользователь вводит значение для имени нового продукта.
  • SupplierID никакой.
  • CategoryID никакой.
  • QuantityPerUnit добавьте текстовое поле, задав для нее значение IDNewQuantityPerUnit.
  • UnitPrice добавьте TextBox с именем NewUnitPrice и CompareValidator, который гарантирует, что введенное значение является значением в валюте, больше или равно нулю.
  • UnitsInStock используйте TextBox, для которого ID задано значение NewUnitsInStock. Включите CompareValidator, который гарантирует, что введенное значение является целым числом больше или равно нулю.
  • UnitsOnOrder используйте TextBox, для которого ID задано значение NewUnitsOnOrder. Включите CompareValidator, который гарантирует, что введенное значение является целым числом больше или равно нулю.
  • ReorderLevel используйте TextBox, для которого ID задано значение NewReorderLevel. Включите CompareValidator, который гарантирует, что введенное значение является целым числом больше или равно нулю.
  • Discontinued добавьте флажок, установив его ID на NewDiscontinued.
  • CategoryName добавьте DropDownList и установите ее ID на NewCategoryID. Привяжите его к новому объекту данных ObjectDataSource с именем CategoriesDataSource и настройте его для использования метода CategoriesBLL класса GetCategories(). Сделайте так, чтобы раскрывающийся список ListItem отображал поле данных CategoryName, используя поле данных CategoryID в качестве их значений.
  • SupplierName добавьте DropDownList и установите ее ID на NewSupplierID. Привяжите его к новому объекту данных ObjectDataSource с именем SuppliersDataSource и настройте его для использования метода SuppliersBLL класса GetSuppliers(). Сделайте так, чтобы раскрывающийся список ListItem отображал поле данных CompanyName, используя поле данных SupplierID в качестве их значений.

Для каждого элемента управления проверки удалите ForeColor свойство, чтобы FooterStyle цвет белого переднего плана класса CSS использовался вместо красного цвета по умолчанию. Также используйте ErrorMessage свойство для подробного описания, но присвойте Text свойству звездочку. Чтобы предотвратить перенос текста элемента управления проверки, вызывающий перенос интерфейса вставки на две строки, установите для свойства FooterStyle значение false у каждого из Wrap, которые используют элемент управления проверки. Наконец, добавьте элемент управления ValidationSummary под GridView и задайте для свойства ShowMessageBox значение true, а для свойства ShowSummary значение false.

При добавлении нового продукта необходимо предоставить CategoryID и SupplierID. Сведения записываются в раскрывающихся списках в ячейках нижнего колонтитула для полей CategoryName и SupplierName. Я решил использовать эти поля вместо CategoryID и SupplierID TemplateFields, потому что в данных строках сетки пользователь, вероятно, больше заинтересован в просмотре имен категорий и поставщиков, а не их идентификаторов. CategoryID Так как теперь значения SupplierID и CategoryName записываются в интерфейсы вставки полей SupplierName, можно удалить CategoryID и SupplierID TemplateFields из GridView.

Аналогичным образом, ProductID не используется при добавлении нового продукта, поэтому ProductID TemplateField также можно удалить. Однако давайте оставим ProductID поле в сетке. Помимо элементов управления TextBoxes, DropDownLists, CheckBoxes и проверки, составляющих интерфейс вставки, нам также потребуется кнопка "Добавить", которая при нажатии выполняет логику для добавления нового продукта в базу данных. На шаге 4 мы добавим кнопку "Добавить" в интерфейс вставки в ProductID TemplateField FooterTemplate.

Вы можете улучшить внешний вид различных полей GridView. Например, может потребоваться отформатировать UnitPrice значения в виде валюты, выровнять по правому краю поля UnitsInStock, UnitsOnOrder и ReorderLevel, а также обновить HeaderText значения для TemplateFields.

После создания множества интерфейсов вставки в FooterTemplate, удаления SupplierID, CategoryID TemplateFields и улучшения эстетики сетки путем форматирования и выравнивания TemplateFields, декларативная разметка GridView должна выглядеть следующим образом:

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
    AllowPaging="True" EnableViewState="False" ShowFooter="True">
    <Columns>
        <asp:TemplateField HeaderText="ProductID" InsertVisible="False" 
            SortExpression="ProductID">
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("ProductID") %>'></asp:Label>
            </ItemTemplate>
            <ItemStyle HorizontalAlign="Center" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewProductName" runat="server"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                    runat="server" ControlToValidate="NewProductName"
                    Display="Dynamic"  ForeColor="
                    ErrorMessage="You must enter a name for the new product.">
                    * </asp:RequiredFieldValidator>
            </FooterTemplate>
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
            <ItemTemplate>
                <asp:Label ID="Label10" runat="server" 
                    Text='<%# Bind("CategoryName") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:DropDownList ID="NewCategoryID" runat="server" 
                    DataSourceID="CategoriesDataSource"
                    DataTextField="CategoryName" DataValueField="CategoryID">
                </asp:DropDownList>
                <asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
                    OldValuesParameterFormatString="original_{0}" 
                    SelectMethod="GetCategories" TypeName="CategoriesBLL">
                </asp:ObjectDataSource>
            </FooterTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Supplier" SortExpression="SupplierName">
            <ItemTemplate>
                <asp:Label ID="Label11" runat="server" 
                    Text='<%# Bind("SupplierName") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:DropDownList ID="NewSupplierID" runat="server" 
                    DataSourceID="SuppliersDataSource"
                    DataTextField="CompanyName" DataValueField="SupplierID">
                </asp:DropDownList><asp:ObjectDataSource ID="SuppliersDataSource" 
                    runat="server" OldValuesParameterFormatString="original_{0}" 
                    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
                </asp:ObjectDataSource>
            </FooterTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Qty/Unit" SortExpression="QuantityPerUnit">
            <ItemTemplate>
                <asp:Label ID="Label5" runat="server" 
                    Text='<%# Bind("QuantityPerUnit") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewQuantityPerUnit" runat="server"></asp:TextBox>
            </FooterTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <ItemTemplate>
                <asp:Label ID="Label6" runat="server" 
                    Text='<%# Bind("UnitPrice", "{0:c}") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                $<asp:TextBox ID="NewUnitPrice" runat="server" Columns="8" />
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ControlToValidate="NewUnitPrice"
                    ErrorMessage="You must enter a valid currency value greater than 
                        or equal to 0.00. Do not include the currency symbol."
                    ForeColor="" Operator="GreaterThanEqual" Type="Currency" 
                    ValueToCompare="0" Display="Dynamic">
                    * </asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Units In Stock" 
            SortExpression="Units In Stock">
            <ItemTemplate>
                <asp:Label ID="Label7" runat="server" 
                    Text='<%# Bind("UnitsInStock") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewUnitsInStock" runat="server" Columns="5" />
                <asp:CompareValidator ID="CompareValidator2" runat="server" 
                    ControlToValidate="NewUnitsInStock" Display="Dynamic" 
                    ErrorMessage="You must enter a valid numeric value for units 
                        in stock that's greater than or equal to zero."
                    ForeColor="" Operator="GreaterThanEqual" Type="Integer" 
                        ValueToCompare="0">*</asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Units On Order" SortExpression="UnitsOnOrder">
            <ItemTemplate>
                <asp:Label ID="Label8" runat="server" 
                    Text='<%# Bind("UnitsOnOrder") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewUnitsOnOrder" runat="server" Columns="5" />
                <asp:CompareValidator ID="CompareValidator3" runat="server" 
                    ControlToValidate="NewUnitsOnOrder" Display="Dynamic" 
                    ErrorMessage="You must enter a valid numeric value for units on 
                        order that's greater than or equal to zero."
                    ForeColor="" Operator="GreaterThanEqual" Type="Integer" 
                    ValueToCompare="0">*</asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Reorder Level" SortExpression="ReorderLevel">
            <ItemTemplate>
                <asp:Label ID="Label9" runat="server" 
                    Text='<%# Bind("ReorderLevel") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewReorderLevel" runat="server" Columns="5" />
                <asp:CompareValidator ID="CompareValidator4" runat="server" 
                    ControlToValidate="NewReorderLevel" Display="Dynamic" 
                    ErrorMessage="You must enter a valid numeric value for reorder 
                        level that's greater than or equal to zero."
                    ForeColor="" Operator="GreaterThanEqual" Type="Integer" 
                    ValueToCompare="0">*</asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
            <ItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" 
                    Checked='<%# Bind("Discontinued") %>' Enabled="false" />
            </ItemTemplate>
            <FooterTemplate>
                <asp:CheckBox ID="NewDiscontinued" runat="server" />
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Center" />
            <FooterStyle HorizontalAlign="Center" />
        </asp:TemplateField>
    </Columns>
</asp:GridView>

При просмотре в браузере строка нижнего колонтитула GridView теперь включает завершенный интерфейс вставки данных (см. рис. 10). На этом этапе интерфейс вставки не включает средства для пользователя, чтобы указать, что она ввела данные для нового продукта и хочет вставить новую запись в базу данных. Кроме того, мы еще не рассмотрели, как данные, введенные в нижний колонтитул, будут преобразовываться в новую запись в Products базе данных. На шаге 4 мы рассмотрим, как включить кнопку "Добавить" в интерфейс вставки и как выполнить код на этапе возврата данных при нажатии. На шаге 5 показано, как вставить новую запись с помощью данных из нижнего колонтитула.

Нижний колонтитул GridView предоставляет интерфейс для добавления новой записи

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

Шаг 4. Включение кнопки "Добавить" в интерфейс вставки

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

В Дизайнере щелкните ссылку "Изменить шаблоны" в смарт-теге GridView'а и выберите ProductID поля FooterTemplate из раскрывающегося списка. Добавьте элемент управления Web (или LinkButton или ImageButton, если вы предпочитаете) в шаблон, присвойте ему идентификатор AddProduct, установите значение CommandName на Insert и его свойство Text на Add, как показано на рисунке 11.

Поместите кнопку

Рис. 11. Поместите кнопку "Добавить" в ProductID templateField s FooterTemplate (щелкните, чтобы просмотреть изображение полного размера)

После включения кнопки "Добавить" проверьте страницу в браузере. Обратите внимание, что при нажатии кнопки "Добавить" с недопустимыми данными в интерфейсе вставки, процесс обратной передачи данных прерывается, и элемент управления ValidationSummary указывает на недопустимые данные (см. рис. 12). При вводе соответствующих данных нажатие кнопки "Добавить" приводит к обратной отправке. Однако запись не добавляется в базу данных. Нам потребуется написать немного кода, чтобы действительно выполнить вставку.

Вызов обратной связи кнопки

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

Замечание

Элементы управления валидацией в интерфейсе вставки не были назначены группе валидации. Это работает нормально при условии, что интерфейс вставки является единственным комплектом контролей валидации на странице. Однако если на странице есть другие элементы управления проверкой (например, элементы управления проверки в интерфейсе редактирования сетки), элементы управления проверкой в интерфейсе вставки и свойства кнопки "Добавить" ValidationGroup должны быть назначены таким же значением, чтобы связать эти элементы управления с определенной группой проверки. Дополнительные сведения о разделении элементов управления и кнопок на странице в группы проверки можно найти в статье Dissecting the Validation Controls in ASP.NET 2.0.

Шаг 5. Вставка новой записи в таблицуProducts

При использовании встроенных функций редактирования GridView, GridView автоматически обрабатывает всю необходимую работу для выполнения обновления. В частности, когда нажимается кнопка "Обновить", она копирует значения, введенные из интерфейса редактирования, в параметры коллекции UpdateParameters ObjectDataSource и запускает обновление, вызывая метод Update() ObjectDataSource. Так как GridView не предоставляет такие встроенные функции для вставки, необходимо реализовать код, который вызывает метод Insert() в ObjectDataSource и копирует значения из интерфейса вставки в коллекцию InsertParameters в ObjectDataSource.

Эта логика вставки должна выполняться после нажатия кнопки "Добавить". Как обсуждалось в руководстве по добавлению и реагированию на кнопки в GridView, при каждом клике на кнопку, LinkButton или ImageButton в GridView, событие RowCommand GridView запускается при обратной отправке. Это событие срабатывает как в случае явного добавления кнопок Button, LinkButton или ImageButton, например, кнопки "Добавить" в нижнем колонтитуле, так и в случае их автоматического добавления компонентом GridView (например, LinkButton в верхней части каждого столбца при активированном параметре сортировки или LinkButton в интерфейсе перехода по страницам при активированном параметре пагинации).

Таким образом, чтобы ответить пользователю, нажав кнопку "Добавить", необходимо создать обработчик событий для события GridView RowCommand . Так как это событие запускается при нажатии любой кнопки, LinkButton или ImageButton в GridView, важно продолжать логику вставки только в том случае, если CommandName свойство, переданное в обработчик событий, сопоставляется со CommandName значением кнопки "Добавить" (Insert). Кроме того, мы также должны продолжать работу, только если контрольные элементы проверки сообщат о действительных данных. Для этого создайте обработчик событий для RowCommand события со следующим кодом:

protected void Products_RowCommand(object sender, GridViewCommandEventArgs e)
{
    // Insert data if the CommandName == "Insert" 
    // and the validation controls indicate valid data...
    if (e.CommandName == "Insert" && Page.IsValid)
    {
        // TODO: Insert new record...
    }
}

Замечание

Возможно, вам интересно, почему обработчик событий трудится проверять свойство Page.IsValid. Ведь обратная передача не будет отключена, если в интерфейс вставки предоставлены недопустимые данные? Это предположение правильно, если пользователь не отключил JavaScript или принял меры, чтобы обойти логику проверки на стороне клиента. Короче говоря, никогда не следует полагаться строго на проверку на стороне клиента; Перед работой с данными всегда следует выполнять проверку на стороне сервера.

На шаге 1 мы создали ProductsDataSource ObjectDataSource так, чтобы его метод Insert() был сопоставлен с методом ProductsBLL класса AddProduct. Чтобы вставить новую запись в Products таблицу, можно просто вызвать метод ObjectDataSource Insert() :

protected void Products_RowCommand(object sender, GridViewCommandEventArgs e)
{
    // Insert data if the CommandName == "Insert" 
    // and the validation controls indicate valid data...
    if (e.CommandName == "Insert" && Page.IsValid)
    {
        // Insert new record
        ProductsDataSource.Insert();
    }
}

Теперь, когда метод Insert() был вызван, все, что остается, заключается в копировании значений из интерфейса вставки в параметры, переданные методу ProductsBLL класса AddProduct. Как мы уже видели в руководстве по изучению событий, связанных с вставкой, обновлением и удалением , это можно сделать с помощью события ObjectDataSource Inserting . Inserting В случае, если необходимо программно ссылаться на элементы управления из строки нижнего колонтитула Products GridView и назначать их значения в коллекцию e.InputParameters. Если пользователь пропустит значение, например, оставив ReorderLevel поле TextBox пустым, нужно указать, что вставленное в базу данных значение должно быть NULL. AddProducts Так как метод принимает типы, допускающие значение NULL для полей базы данных, допускающих значение NULL, просто используйте тип, допускающий значение NULL, и задайте его значение null в том случае, если входные данные пользователя опущены.

protected void ProductsDataSource_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{
    // Programmatically reference Web controls in the inserting interface...
    TextBox NewProductName = 
        (TextBox)Products.FooterRow.FindControl("NewProductName");
    DropDownList NewCategoryID = 
        (DropDownList)Products.FooterRow.FindControl("NewCategoryID");
    DropDownList NewSupplierID = 
        (DropDownList)Products.FooterRow.FindControl("NewSupplierID");
    TextBox NewQuantityPerUnit = 
        (TextBox)Products.FooterRow.FindControl("NewQuantityPerUnit");
    TextBox NewUnitPrice = 
        (TextBox)Products.FooterRow.FindControl("NewUnitPrice");
    TextBox NewUnitsInStock = 
        (TextBox)Products.FooterRow.FindControl("NewUnitsInStock");
    TextBox NewUnitsOnOrder = 
        (TextBox)Products.FooterRow.FindControl("NewUnitsOnOrder");
    TextBox NewReorderLevel = 
        (TextBox)Products.FooterRow.FindControl("NewReorderLevel");
    CheckBox NewDiscontinued = 
        (CheckBox)Products.FooterRow.FindControl("NewDiscontinued");
    // Set the ObjectDataSource's InsertParameters values...
    e.InputParameters["productName"] = NewProductName.Text;
    
    e.InputParameters["supplierID"] = 
        Convert.ToInt32(NewSupplierID.SelectedValue);
    e.InputParameters["categoryID"] = 
        Convert.ToInt32(NewCategoryID.SelectedValue);
    
    string quantityPerUnit = null;
    if (!string.IsNullOrEmpty(NewQuantityPerUnit.Text))
        quantityPerUnit = NewQuantityPerUnit.Text;
    e.InputParameters["quantityPerUnit"] = quantityPerUnit;
    decimal? unitPrice = null;
    if (!string.IsNullOrEmpty(NewUnitPrice.Text))
        unitPrice = Convert.ToDecimal(NewUnitPrice.Text);
    e.InputParameters["unitPrice"] = unitPrice;
    short? unitsInStock = null;
    if (!string.IsNullOrEmpty(NewUnitsInStock.Text))
        unitsInStock = Convert.ToInt16(NewUnitsInStock.Text);
    e.InputParameters["unitsInStock"] = unitsInStock;
    short? unitsOnOrder = null;
    if (!string.IsNullOrEmpty(NewUnitsOnOrder.Text))
        unitsOnOrder = Convert.ToInt16(NewUnitsOnOrder.Text);
    e.InputParameters["unitsOnOrder"] = unitsOnOrder;
    short? reorderLevel = null;
    if (!string.IsNullOrEmpty(NewReorderLevel.Text))
        reorderLevel = Convert.ToInt16(NewReorderLevel.Text);
    e.InputParameters["reorderLevel"] = reorderLevel;
    
    e.InputParameters["discontinued"] = NewDiscontinued.Checked;
}

После завершения обработчика событий Inserting, новые записи можно добавлять в таблицу базы данных Products через нижнюю строку GridView. Идите вперед и попробуйте добавить несколько новых продуктов.

Повышение и настройка операции добавления

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

GridView, используемый в этом руководстве, не применяет порядок сортировки к перечисленным продуктам и не позволяет конечным пользователям сортировать данные. Следовательно, записи упорядочены в том порядке, в котором они находятся в базе данных по полю первичного ключа. Каждая новая запись имеет ProductID значение, которое больше, чем у предыдущей, поэтому каждый раз, когда добавляется новый продукт, запись помещается в конец сетки. Поэтому вы можете автоматически отправить пользователя на последнюю страницу GridView после добавления новой записи. Это можно сделать, добавив следующую строку кода после вызова ProductsDataSource.Insert() в RowCommand обработчик событий, чтобы указать, что пользователь должен быть отправлен на последнюю страницу после привязки данных к GridView:

// Indicate that the user needs to be sent to the last page
SendUserToLastPage = true;

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

protected void Products_DataBound(object sender, EventArgs e)
{
    // Send user to last page of data, if needed
    if (SendUserToLastPage)
        Products.PageIndex = Products.PageCount - 1;
}

Причина, по которой свойство PageIndex задано в обработчике событий DataBound (в отличие от обработчика событий RowCommand), заключается в том, что при срабатывании обработчика событий RowCommand мы еще не добавили новую запись в таблицу базы данных Products. Поэтому в обработчике RowCommand событий последний индекс страницы (PageCount - 1) представляет последний индекс страницы перед добавлением нового продукта. Для большинства добавляемых продуктов последний индекс страницы совпадает после добавления нового продукта. Но если добавленный продукт приводит к новому индексу последней страницы, и мы неправильно обновим PageIndex в обработчике события RowCommand, то перейдем на предпоследнюю страницу (индекс страницы до добавления нового продукта) вместо нового индекса последней страницы. DataBound Поскольку обработчик событий срабатывает после добавления нового продукта и привязки данных обратно к сетке, задавая свойство PageIndex, мы знаем, что получаем правильный индекс последней страницы.

Наконец, GridView, используемый в этом руководстве, довольно широк из-за количества полей, которые необходимо собрать для добавления нового продукта. Из-за этой ширины может быть предпочтителен вертикальный макет DetailsView. Общая ширина GridView может быть сокращена путем сбора меньшего количества входных данных. Возможно, нам не нужно собирать поля UnitsOnOrder, UnitsInStock и ReorderLevel при добавлении нового продукта, в этом случае эти поля можно удалить из GridView.

Чтобы настроить собранные данные, можно использовать один из двух подходов:

  • Продолжайте использовать AddProduct метод, который ожидает значения для UnitsOnOrderUnitsInStockполей и ReorderLevel полей. В обработчике Inserting событий укажите жестко закодированные значения по умолчанию для этих входных данных, которые были удалены из интерфейса вставки.
  • Создайте новую перегрузку метода AddProduct в классе ProductsBLL, которая не принимает входные данные для полей UnitsOnOrder, UnitsInStock и ReorderLevel. Затем на странице ASP.NET настройте ObjectDataSource для использования этой новой перегрузки.

Любой из вариантов также будет работать одинаково. В предыдущих руководствах мы использовали последний вариант, создавая несколько перегрузок метода ProductsBLL класса UpdateProduct.

Сводка

GridView не имеет встроенных возможностей вставки, как в DetailsView и FormView, но интерфейс вставки можно добавить в строку футера, приложив небольшие усилия. Чтобы отобразить строку нижнего колонтитула в GridView, просто задайте для его свойства значение ShowFootertrue. Содержимое строки нижнего колонтитула можно настроить для каждого поля, преобразовав поле в TemplateField и добавив интерфейс вставки в FooterTemplate. Как мы видели в этом руководстве, FooterTemplate может содержать кнопки, текстовые поля, выпадающие списки, флажки, элементы управления источниками данных для заполнения веб-элементов управления на основе данных (таких как выпадающие списки), и элементы управления проверки. Наряду с элементами управления для сбора входных данных пользователя требуется кнопка "Добавить", LinkButton или ImageButton.

При нажатии кнопки "Добавить" вызывается метод ObjectDataSource Insert() для запуска рабочего процесса вставки. ObjectDataSource вызовет настроенный метод вставки (метод класса ProductsBLLAddProduct в этом руководстве). Необходимо скопировать значения из интерфейса вставки GridView в коллекцию ObjectDataSource InsertParameters перед вызовом метода вставки. Это можно сделать программным способом за счёт использования веб-элементов управления интерфейса вставки в обработчике событий ObjectDataSource Inserting.

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

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

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

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

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

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