Обзор событий, связанных со вставкой, обновлением и удалением (C#)

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

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

В этом руководстве мы рассмотрим использование событий, которые происходят до, во время и после операции вставки, обновления или удаления веб-элемента управления ASP.NET данных. Мы также посмотрим, как настроить интерфейс редактирования, чтобы обновить только подмножество полей продукта.

Введение

При использовании встроенных функций вставки, редактирования или удаления элементов управления GridView, DetailsView или FormView пользователь завершает процесс добавления новой записи, обновления или удаления существующей записи. Как мы уже говорили в предыдущем руководстве, при редактировании строки в GridПросмотре кнопка "Изменить" заменяется кнопкой "Обновить" и "Отмена", а boundFields превращается в TextBoxes. После того как пользователь обновит данные и нажмет кнопку Обновить, при обратной отправке выполняются следующие действия.

  1. GridView заполняет свои объекты ObjectDataSource UpdateParameters уникальными идентифицируемыми полями измененной записи (через DataKeyNames свойство) вместе со значениями, введенными пользователем.
  2. GridView вызывает метод ObjectDataSource Update() , который, в свою очередь, вызывает соответствующий метод в базовом объекте (ProductsDAL.UpdateProductв предыдущем руководстве).
  3. Базовые данные, которые теперь включают обновленные изменения, отскок в GridView

Во время этой последовательности шагов возникает ряд событий, что позволяет нам создавать обработчики событий для добавления пользовательской логики при необходимости. Например, до шага 1 возникает событие GridView RowUpdating . На этом этапе запрос на обновление можно отменить при возникновении ошибки проверки. При вызове Update() метода возникает событие ObjectDataSource Updating , что дает возможность добавить или настроить значения любого из UpdateParameters. После завершения выполнения метода базового объекта ObjectDataSource возникает событие ObjectDataSource Updated . Обработчик Updated события может проверить сведения об операции обновления, например количество затронутых строк и наличие исключения. Наконец, после шага 2 возникает событие GridView RowUpdated . Обработчик событий для этого события может изучить дополнительные сведения о только что выполненной операции обновления.

На рисунке 1 показана эта серия событий и шагов при обновлении GridView. Шаблон событий на рис. 1 не является уникальным для обновления с помощью GridView. При вставке, обновлении или удалении данных из GridView, DetailsView или FormView происходит одинаковая последовательность событий предварительного и последующего уровней как для веб-элемента управления данными, так и для ObjectDataSource.

При обновлении данных в GridView срабатывает ряд событий до и после

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

В этом руководстве мы рассмотрим использование этих событий для расширения встроенных возможностей вставки, обновления и удаления веб-элементов управления ASP.NET данных. Мы также посмотрим, как настроить интерфейс редактирования, чтобы обновить только подмножество полей продукта.

Шаг 1. Обновление полей иUnitPriceпродуктовProductName

В интерфейсы редактирования из предыдущего руководства необходимо было включить все поля продукта, которые не были доступны только для чтения. Если бы мы удалили поле из GridView, например QuantityPerUnit , при обновлении данных, веб-элемент управления данными не задал бы значение ObjectDataSource QuantityPerUnitUpdateParameters . Затем ObjectDataSource передает значение в nullUpdateProduct метод уровня бизнес-логики (BLL), который изменяет столбец измененной записи QuantityPerUnit базы данных на NULL значение. Аналогичным образом, если обязательное поле, например ProductName, удаляется из интерфейса редактирования, обновление завершится ошибкой с исключением "Столбец "ProductName" не допускает значений NULL". Причина такого поведения заключалась в том, что ObjectDataSource был настроен для вызова ProductsBLL метода класса UpdateProduct , который ожидал входной параметр для каждого поля продукта. Таким образом, коллекция ObjectDataSource содержала UpdateParameters параметр для каждого входного параметра метода.

Если требуется предоставить веб-элемент управления данными, который позволяет пользователю обновлять только подмножество полей, необходимо либо программно задать отсутствующие UpdateParameters значения в обработчике событий ObjectDataSource Updating , либо создать и вызвать метод BLL, который ожидает только подмножество полей. Давайте рассмотрим этот последний подход.

В частности, создадим страницу, которая отображает только ProductName поля и UnitPrice в редактируемом элементе GridView. Этот интерфейс редактирования GridView позволяет пользователю обновлять только два отображаемых поля: ProductName и UnitPrice. Так как этот интерфейс редактирования предоставляет только подмножество полей продукта, необходимо либо создать ObjectDataSource, использующий существующий метод BLL UpdateProduct и имеющий отсутствующие значения полей продукта, заданные программным способом в Updating обработчике событий, либо создать новый метод BLL, который ожидает только подмножество полей, определенных в GridView. В этом руководстве мы воспользуемся последним параметром и создадим перегрузку UpdateProduct метода , которая принимает только три входных параметра: productName, unitPriceи productID:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Update, false)]
public bool UpdateProduct(string productName, decimal? unitPrice, int productID)
{
    Northwind.ProductsDataTable products = Adapter.GetProductByProductID(productID);
    if (products.Count == 0)
        // no matching record found, return false
        return false;

    Northwind.ProductsRow product = products[0];

    product.ProductName = productName;
    if (unitPrice == null) product.SetUnitPriceNull();
      else product.UnitPrice = unitPrice.Value;

    // Update the product record
    int rowsAffected = Adapter.Update(product);

    // Return true if precisely one row was updated, otherwise false
    return rowsAffected == 1;
}

Как и исходный UpdateProduct метод, эта перегрузка начинается с проверки наличия продукта в базе данных с указанным ProductID. В противном случае возвращается falseзначение , указывающее, что запрос на обновление сведений о продукте завершился сбоем. В противном случае он соответствующим образом обновляет существующие ProductNameUnitPrice поля и записи продукта и фиксирует обновление путем вызова метода TableAdapter Update() , передавая ProductsRow экземпляр .

С этим дополнением к нашему ProductsBLL классу мы готовы создать упрощенный интерфейс GridView. Откройте в DataModificationEvents.aspx папке EditInsertDelete и добавьте GridView на страницу. Создайте объект ObjectDataSource и настройте его для использования ProductsBLL класса с сопоставлением GetProducts методов с Select() перегрузкой UpdateProductUpdate(), принимающей productNameтолько входные параметры , unitPriceи productID . На рисунке 2 показан мастер создания источника данных при сопоставлении метода ObjectDataSource Update() с перегрузкой ProductsBLL нового UpdateProduct метода класса.

Сопоставление метода Update() ObjectDataSource с перегрузкой New UpdateProduct

Рис. 2. Сопоставление метода ObjectDataSource Update() с новой UpdateProduct перегрузкой (щелкните для просмотра полноразмерного изображения)

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

Выберите (Нет) в списке Drop-Down для вкладок INSERT и DELETE

Рис. 3. Выберите (нет) в списке Drop-Down для вкладок INSERT и DELETE (Щелкните для просмотра полноразмерного изображения)

После завершения работы мастера проверка флажок Включить редактирование из смарт-тега GridView.

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

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    OldValuesParameterFormatString="original_{0}" SelectMethod="GetProducts"
    TypeName="ProductsBLL" UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Так как нет сопоставлений для методов ObjectDataSource Insert() и Delete() , нет InsertParameters разделов и DeleteParameters . Кроме того, так как Update() метод сопоставляется с перегрузкой UpdateProduct метода, которая принимает только три входных параметра, UpdateParameters раздел содержит только три Parameter экземпляра.

Обратите внимание, что свойство ObjectDataSource OldValuesParameterFormatString имеет значение original_{0}. Это свойство автоматически задается Visual Studio при использовании мастера настройки источника данных. Однако, так как наши методы BLL не ожидают передачи исходного ProductID значения, полностью удалите это назначение свойства из декларативного синтаксиса ObjectDataSource.

Примечание

Если вы просто очистите OldValuesParameterFormatString значение свойства из окно свойств в представлении конструктора, свойство будет по-прежнему существовать в декларативном синтаксисе, но будет иметь пустую строку. Либо полностью удалите свойство из декларативного синтаксиса, либо в окно свойств задайте значение по умолчанию , {0}.

Хотя objectDataSource содержит UpdateParameters только имя, цену и идентификатор продукта, Visual Studio добавил BoundField или CheckBoxField в GridView для каждого поля продукта.

GridView содержит BoundField или CheckBoxField для каждого поля продукта.

Рис. 4. GridView содержит BoundField или CheckBoxField для каждого поля продукта (щелкните для просмотра полноразмерного изображения)

Когда пользователь редактирует продукт и нажимает кнопку Обновить, GridView перечисляет поля, которые не были доступны только для чтения. Затем он задает значение соответствующего параметра в коллекции ObjectDataSource UpdateParameters в соответствии со значением, введенным пользователем. Если соответствующий параметр отсутствует, GridView добавляет его в коллекцию. Таким образом, если gridView содержит BoundFields и CheckBoxFields для всех полей продукта, ObjectDataSource в конечном итоге вызовет перегрузку UpdateProduct , которая принимает все эти параметры, несмотря на то, что декларативная разметка ObjectDataSource задает только три входных параметра (см. рис. 5). Аналогичным образом, если в GridView имеется какое-то сочетание полей продукта, не предназначенных только для чтения, которое не соответствует входным параметрам перегрузки UpdateProduct , при попытке обновления возникнет исключение.

GridView добавит параметры в коллекцию UpdateParameters ObjectDataSource.

Рис. 5. GridView добавит параметры в коллекцию ObjectDataSource UpdateParameters (щелкните для просмотра полноразмерного изображения)

Чтобы объект ObjectDataSource вызвал перегрузку UpdateProduct , которая принимает только имя, цену и идентификатор продукта, необходимо ограничить GridView наличием редактируемых полей только ProductName для и UnitPrice. Это можно сделать, удалив другие BoundFields и CheckBoxFields, задав для свойства этих полей ReadOnly значение trueили с помощью некоторого сочетания этих двух полей. В этом руководстве мы просто удалим все поля GridView, кроме ProductName и UnitPrice BoundFields, после чего декларативная разметка GridView будет выглядеть следующим образом:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
    </Columns>
</asp:GridView>

Несмотря на то, что перегрузка UpdateProduct ожидает три входных параметра, у нас есть только два BoundFields в GridView. Это связано с тем productID , что входной параметр является значением первичного DataKeyNames ключа и передается через значение свойства для измененной строки.

GridView вместе с UpdateProduct перегрузкой позволяет пользователю изменять только название и цену продукта, не теряя другие поля продукта.

Интерфейс позволяет изменять только название и цену продукта

Рис. 6. Интерфейс позволяет изменять только название и цену продукта (щелкните для просмотра полноразмерного изображения)

Примечание

Как обсуждалось в предыдущем руководстве, крайне важно включить состояние представления GridView (поведение по умолчанию). Если для свойства falseGridView задано EnableViewState значение , возникает риск того, что параллельные пользователи непреднамеренно удаляют или редактируют записи.

Улучшение форматированияUnitPrice

Хотя пример GridView, показанный на рис. 6, работает, UnitPrice поле вовсе не форматировано, что приводит к отображению цены, в котором отсутствуют символы валюты и четыре десятичных разряда. Чтобы применить форматирование валюты для нередактируемых строк, просто присвойте свойству UnitPrice BoundField DataFormatString значение {0:c} , а его HtmlEncode свойству — значение false.

Задайте соответствующие свойства DataFormatString и HtmlEncode объекта UnitPrice

Рис. 7. Задайте UnitPriceDataFormatString соответствующие свойства и HtmlEncode (щелкните, чтобы просмотреть полноразмерное изображение)

При этом изменении нередактируемые строки форматируют цену как валюту; Однако в измененной строке по-прежнему отображается значение без символа валюты и с четырьмя десятичными знаками.

Нередактируемые строки теперь форматируются как денежные значения

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

Инструкции по форматированию, указанные в свойстве DataFormatString , можно применить к интерфейсу редактирования, задав свойству BoundField ApplyFormatInEditMode значение true (по умолчанию — false). Укажите некоторое время, чтобы присвоить этому свойству значение true.

Задайте для свойства ApplyFormatInEditMode объекта UnitPrice BoundField значение true.

Рис. 9. Задайте UnitPrice для свойства BoundField значение ApplyFormatInEditModetrue (щелкните для просмотра полноразмерного изображения)

При этом изменении значение UnitPrice , отображаемое в редактируемой строке, также форматируется как валюта.

Снимок экрана: GridView со значением UnitPrice измененной строки, отформатированным в виде валюты.

Рис. 10. Значение измененной строки UnitPrice теперь отформатировано как валюта (щелкните для просмотра полноразмерного изображения)

Однако при обновлении продукта с символом валюты в текстовом поле, например 19,00 долл. США, возникает исключение FormatException. Когда GridView пытается назначить предоставленные пользователем значения коллекции ObjectDataSource UpdateParameters , не удается преобразовать UnitPrice строку "$19,00" в decimal требуемую параметром (см. рис. 11). Чтобы устранить эту проблему, мы можем создать обработчик событий для события GridView RowUpdating и провести его синтаксический анализ предоставленного UnitPrice пользователем в формате decimalвалюты.

Событие GridView RowUpdating принимает в качестве второго параметра объект типа GridViewUpdateEventArgs, который включает NewValues словарь в качестве одного из своих свойств, содержащий предоставленные пользователем значения, готовые к назначению коллекции ObjectDataSource UpdateParameters . Мы можем перезаписать существующее UnitPrice значение в NewValues коллекции десятичным значением, проанализированным с помощью формата валюты со следующими строками кода в обработчике RowUpdating событий:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
  if (e.NewValues["UnitPrice"] != null)
    e.NewValues["UnitPrice"] =
        decimal.Parse(e.NewValues["UnitPrice"].ToString(),
            System.Globalization.NumberStyles.Currency);
}

Если пользователь предоставил UnitPrice значение (например, "$19,00"), это значение перезаписывается десятичным значением, вычисляемым методом Decimal.Parse, при анализе значения в виде валюты. При этом будет правильно проанализирован десятичный раздел в случае любых символов валют, запятых, десятичных запятых и т. д., а также будет использоваться перечисление NumberStyles в пространстве имен System.Globalization .

На рисунке 11 показана проблема, вызванная символами валюты в предоставленном UnitPriceпользователем , а также способ использования обработчика RowUpdating событий GridView для правильного анализа таких входных данных.

Схема, показывающая, как ObjectDataSource обрабатывает поле UnitPrice и как обработчик событий RowUpdate GridView преобразует строку в десятичное значение.

Рис. 11. Значение измененной строки UnitPrice теперь отформатировано в виде валюты (щелкните для просмотра полноразмерного изображения)

Шаг 2. ЗапретNULL UnitPrices

Хотя база данных настроена UnitPrice так, чтобы разрешить NULL значения в Products столбце таблицы, может потребоваться запретить пользователям, посещающим NULLUnitPrice эту страницу, указывать значение. То есть, если пользователю не удается ввести UnitPrice значение при редактировании строки продукта, вместо сохранения результатов в базе данных необходимо отобразить сообщение, информирующее пользователя о том, что на этой странице все измененные продукты должны иметь указанную цену.

Объект GridViewUpdateEventArgs , передаваемый в обработчик событий GridView RowUpdating , содержит Cancel свойство, которое, если задано значение true, завершает процесс обновления. Давайте расширим RowUpdating обработчик событий, чтобы задать значение e.Canceltrue и отобразить сообщение, объясняющее причину UnitPrice , если значение в NewValues коллекции равно null.

Для начала добавьте элемент управления Label Web на страницу с именем MustProvideUnitPriceMessage. Этот элемент управления Метка будет отображаться, если пользователю не удается указать UnitPrice значение при обновлении продукта. Задайте для свойства Label Text значение "Вы должны указать цену на продукт". Я также создал новый класс CSS в с Styles.css именем Warning со следующим определением:

.Warning
{
    color: Red;
    font-style: italic;
    font-weight: bold;
    font-size: x-large;
}

Наконец, присвойте свойству CssClass Label значение Warning. На этом этапе Designer должно отображать предупреждающее сообщение красным, полужирным, курсивом, очень большим размером шрифта над GridView, как показано на рисунке 12.

Над GridView добавлена метка

Рис. 12. Над gridView добавлена метка (щелкните для просмотра полноразмерного изображения)

По умолчанию эта метка должна быть скрыта, поэтому присвойте ее Visible свойству значение false в обработчике Page_Load событий:

protected void Page_Load(object sender, EventArgs e)
{
    MustProvideUnitPriceMessage.Visible = false;
}

Если пользователь пытается обновить продукт без указания UnitPrice, мы хотим отменить обновление и отобразить метку предупреждения. Дополните обработчик событий GridView RowUpdating следующим образом:

protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    if (e.NewValues["UnitPrice"] != null)
    {
        e.NewValues["UnitPrice"] =
            decimal.Parse(e.NewValues["UnitPrice"].ToString(),
                System.Globalization.NumberStyles.Currency);
    }
    else
    {
        // Show the Label
        MustProvideUnitPriceMessage.Visible = true;

        // Cancel the update
        e.Cancel = true;
    }
}

Если пользователь пытается сохранить продукт без указания цены, обновление отменяется и отображается полезное сообщение. Хотя база данных (и бизнес-логика) позволяет NULLUnitPrice использовать объекты , эта конкретная страница ASP.NET — нет.

Пользователь не может оставить unitPrice пустым

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

На данный момент мы видели, как использовать событие GridView RowUpdating для программного изменения значений параметров, назначенных коллекции ObjectDataSource UpdateParameters , а также как полностью отменить процесс обновления. Эти понятия переносятся на элементы управления DetailsView и FormView, а также применяются к вставке и удалению.

Эти задачи также можно выполнять на уровне ObjectDataSource с помощью обработчиков Insertingсобытий , Updatingи Deleting . Эти события возникают перед вызовом связанного метода базового объекта и предоставляют возможность в последний раз изменить коллекцию входных параметров или отменить операцию. Обработчикам событий для этих трех событий передается объект типа ObjectDataSourceMethodEventArgs , имеющий два интересующих свойства:

  • Отмена, которая, если задано trueзначение , отменяет выполняемую операцию.
  • InputParameters, представляющий собой коллекцию InsertParameters, UpdateParametersили DeleteParameters, в зависимости от того, является ли обработчик события , InsertingUpdatingили Deleting

Чтобы проиллюстрировать работу со значениями параметров на уровне ObjectDataSource, давайте добавим на страницу DetailsView, который позволяет пользователям добавлять новый продукт. Этот DetailsView будет использоваться для предоставления интерфейса для быстрого добавления нового продукта в базу данных. Чтобы обеспечить согласованность пользовательского интерфейса при добавлении нового продукта, давайте разрешим пользователю вводить только значения для ProductName полей и UnitPrice . По умолчанию значения, которые не предоставляются в интерфейсе вставки DetailsView, будут иметь NULL значение базы данных. Однако мы можем использовать событие ObjectDataSource Inserting для внедрения различных значений по умолчанию, как мы увидим вскоре.

Шаг 3. Предоставление интерфейса для добавления новых продуктов

Перетащите Элемент DetailsView из панели элементов в Designer над GridView, очистите его Height свойства и Width и привяжите его к объекту ObjectDataSource, который уже присутствует на странице. Это приведет к добавлению BoundField или CheckBoxField для каждого поля продукта. Так как мы хотим использовать этот DetailsView для добавления новых продуктов, необходимо проверка параметр Включить вставку из смарт-тега. Однако такой параметр отсутствует, так как метод ObjectDataSource Insert() не сопоставлен с методом в ProductsBLL классе (напомним, что для этого сопоставления задано значение (Нет) при настройке источника данных см. рис. 3.

Чтобы настроить ObjectDataSource, выберите ссылку Настройка источника данных из смарт-тега, запустив мастер. Первый экран позволяет изменить базовый объект, к которому привязан объект ObjectDataSource. Оставьте для него значение ProductsBLL. На следующем экране перечислены сопоставления методов ObjectDataSource с базовыми объектами. Несмотря на то, что мы явно указали Insert() , что методы и Delete() не должны сопоставляться ни с какими методами, при переходе на вкладки INSERT и DELETE вы увидите, что сопоставление существует. Это связано с тем, что ProductsBLLAddProduct методы и DeleteProduct используют DataObjectMethodAttribute атрибут , чтобы указать, что они являются методами по умолчанию для Insert() и Delete()соответственно. Таким образом, мастер ObjectDataSource выбирает их каждый раз при запуске мастера, если не указано другое значение явно.

Insert() Оставьте метод, указывающий на AddProduct метод, но снова задайте для раскрывающегося списка вкладки DELETE значение (Нет).

Задайте для списка Drop-Down вкладки INSERT значение AddProduct Method

Рис. 14. Задайте для списка AddProduct Drop-Down вкладки INSERT значение Метод (щелкните для просмотра полноразмерного изображения)

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

Рис. 15. Присвойте списку Drop-Down на вкладке DELETE значение (Нет) (щелкните для просмотра полноразмерного изображения)

После внесения этих изменений декларативный синтаксис ObjectDataSource будет расширен, чтобы включить коллекцию InsertParameters , как показано ниже:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    SelectMethod="GetProducts" TypeName="ProductsBLL"
    UpdateMethod="UpdateProduct" OnUpdating="ObjectDataSource1_Updating"
    InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
    <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>

Повторное выполнение мастера вернуло OldValuesParameterFormatString свойство . Уделите немного времени, чтобы очистить это свойство, задав ему значение по умолчанию ({0}) или полностью удалив его из декларативного синтаксиса.

Если ObjectDataSource предоставляет возможности вставки, смарт-тег DetailsView теперь будет включать флажок Включить вставку; вернитесь к Designer и проверка этот параметр. Затем выполните синтаксический анализ DetailsView, чтобы в нем было только два BoundFields - ProductName и UnitPrice - и CommandField. На этом этапе декларативный синтаксис DetailsView должен выглядеть следующим образом:

<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Fields>
        <asp:BoundField DataField="ProductName"
          HeaderText="ProductName" SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice"
          SortExpression="UnitPrice" />
        <asp:CommandField ShowInsertButton="True" />
    </Fields>
</asp:DetailsView>

На рисунке 16 показана эта страница при просмотре в браузере на данный момент. Как видите, в DetailsView перечислены название и цена первого продукта (Chai). Однако нам нужен интерфейс вставки, который позволяет пользователю быстро добавить новый продукт в базу данных.

Представление DetailsView в настоящее время отображается в режиме Read-Only

Рис. 16. Представление DetailsView в настоящее время отображается в режиме Read-Only (щелкните для просмотра полноразмерного изображения)

Чтобы отобразить DetailsView в режиме вставки, необходимо задать для свойства значение DefaultModeInserting. Это отображает DetailsView в режиме вставки при первом посещении и сохраняет его там после вставки новой записи. Как показано на рисунке 17, такой элемент DetailsView предоставляет быстрый интерфейс для добавления новой записи.

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

Рис. 17. DetailsView предоставляет интерфейс для быстрого добавления нового продукта (щелкните для просмотра полноразмерного изображения)

Когда пользователь вводит название продукта и цену (например, Acme Water и 1.99, как показано на рис. 17) и нажимает кнопку Вставка, происходит обратная связь и начинается рабочий процесс вставки, кульминацией которого является добавление новой записи продукта в базу данных. DetailsView сохраняет интерфейс вставки, и GridView автоматически возвращается к источнику данных, чтобы включить новый продукт, как показано на рис. 18.

Продукт

Рис. 18. Продукт Acme Water добавлен в базу данных

Хотя GridView на рис. 18 не отображает его, полям продукта, отсутствуют в интерфейсе CategoryIDDetailsView , SupplierID, QuantityPerUnitи т. д., присваиваются NULL значения базы данных. Это можно увидеть, выполнив следующие действия.

  1. Перейдите к Обозреватель сервера в Visual Studio.
  2. Развертывание NORTHWND.MDF узла базы данных
  3. Щелкните правой Products кнопкой мыши узел таблицы базы данных.
  4. Выберите Показать данные таблицы.

Вы увидите список всех записей в Products таблице. Как показано на рисунке 19, все столбцы нового продукта, отличные от ProductID, ProductNameи UnitPrice , имеют NULL значения.

Полям продукта, не указанным в представлении DetailsView, присваиваются значения NULL

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

Может потребоваться указать значение по умолчанию, отличное NULL от одного или нескольких из этих значений столбцов, потому что NULL не является лучшим вариантом по умолчанию или потому, что сам столбец базы данных не разрешает NULL использовать значения . Для этого можно программно задать значения параметров коллекции DetailsView InputParameters . Это назначение можно выполнить в обработчике событий для события DetailsView ItemInserting или события ObjectDataSource Inserting . Так как мы уже рассмотрели использование событий предварительного и последующего уровней на уровне веб-элемента управления данными, на этот раз рассмотрим события ObjectDataSource.

Шаг 4. Назначение значенийCategoryIDпараметрам иSupplierID

В этом руководстве давайте представим, что для нашего приложения при добавлении нового продукта через этот интерфейс ему должно быть присвоено CategoryID значение и SupplierID значение 1. Как упоминалось ранее, ObjectDataSource имеет пару событий предварительного и постуровневого уровня, которые возникают во время процесса изменения данных. При вызове метода Insert() ObjectDataSource сначала вызывает событие Inserting , затем вызывает метод, с которым сопоставлен его Insert() метод, и, наконец, вызывает Inserted событие . Обработчик Inserting событий предоставляет нам последнюю возможность настроить входные параметры или отменить операцию.

Примечание

В реальном приложении вы, скорее всего, захотите либо разрешить пользователю указать категорию и поставщика, либо выбрать это значение для них на основе некоторых критериев или бизнес-логики (вместо того, чтобы слепо выбирать идентификатор 1). Несмотря на это, в примере показано, как программно задать значение входного параметра из события предварительного уровня ObjectDataSource.

Создайте обработчик событий для события ObjectDataSource Inserting . Обратите внимание, что второй входной параметр обработчика событий является объектом типа ObjectDataSourceMethodEventArgs, который имеет свойство для доступа к коллекции параметров (InputParameters) и свойство для отмены операции (Cancel).

protected void ObjectDataSource1_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{

}

На этом этапе свойство содержит коллекцию ObjectDataSource InsertParameters со значениями, InputParameters назначенными из DetailsView. Чтобы изменить значение одного из этих параметров, просто используйте : e.InputParameters["paramName"] = value. Поэтому, чтобы задать CategoryID для и SupplierID значение 1, настройте Inserting обработчик событий следующим образом:

protected void ObjectDataSource1_Inserting
    (object sender, ObjectDataSourceMethodEventArgs e)
{
    e.InputParameters["CategoryID"] = 1;
    e.InputParameters["SupplierID"] = 1;
}

На этот раз при добавлении нового продукта (например, Acme Soda) CategoryID столбцы и SupplierID нового продукта имеют значение 1 (см. рис. 20).

Для новых продуктов теперь заданы значения CategoryID и SupplierID, равные 1

Рис. 20. Для новых продуктов теперь заданы CategoryID значения и SupplierID 1 (щелкните для просмотра полноразмерного изображения)

Сводка

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

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

Об авторе

Скотт Митчелл (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.