Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Узнайте, как создать полностью редактируемый список данных, где все его элементы находятся в режиме редактирования и значения которых можно сохранить, нажав кнопку "Обновить все" на странице.
Введение
В предыдущем руководстве мы рассмотрели, как создать DataList элементного уровня. Как и стандартный редактируемый GridView, каждый элемент в DataList включал кнопку "Изменить", которая при щелчке сделает элемент редактируемым. Хотя редактирование на уровне элемента хорошо подходит для данных, которые обновляются только иногда, некоторые сценарии использования требуют, чтобы пользователь редактировал много записей. Если пользователю нужно изменить десятки записей и принудительно нажать кнопку "Изменить", внести изменения и нажать кнопку "Обновить" для каждой из них, количество щелчков может препятствовать ее производительности. В таких ситуациях лучше предоставить полностью редактируемый dataList, где все его элементы находятся в режиме редактирования и чьи значения можно изменить, нажав кнопку "Обновить все" на странице (см. рис. 1).
Рис. 1. Каждый элемент в полно редактируемом списке данных можно изменить (щелкните, чтобы просмотреть изображение полного размера)
В этом руководстве мы рассмотрим, как разрешить пользователям обновлять сведения об адресе поставщиков с помощью полно редактируемого списка данных.
Шаг 1. Создайте редактируемый пользовательский интерфейс в элементе ItemTemplate объекта DataList
В предыдущем руководстве, где мы создавали стандартный редактируемый список данных на уровне элементов, мы использовали два шаблона.
-
ItemTemplateсодержит интерфейс только для чтения (веб-элементы управления Label для отображения имени и цены каждого продукта). -
EditItemTemplateсодержит пользовательский интерфейс режима редактирования (два веб-элемента управления TextBox).
Свойство DataList EditItemIndex определяет, что DataListItem отображается, если имеется, с использованием EditItemTemplate. В частности, DataListItem, чье значение ItemIndex соответствует свойству DataList EditItemIndex, отображается с помощью EditItemTemplate. Эта модель хорошо работает, если только один элемент можно изменять одновременно, но разбивается при создании полно редактируемого списка данных.
Для полностью редактируемого списка данных мы хотим, чтобы всеDataListItem s отображались с помощью редактируемого интерфейса. Самый простой способ сделать это — определить редактируемый интерфейс в .ItemTemplate Для изменения сведений об адресе поставщиков редактируемый интерфейс содержит имя поставщика в виде текста, а затем текстовые поля для значений адреса, города и страны или региона.
Начните с открытия BatchUpdate.aspx страницы, добавьте элемент управления DataList и задайте для его свойства IDзначение Suppliers . В смарт-теге DataList выберите новый элемент управления ObjectDataSource с именем SuppliersDataSource.
Рис. 2. Создайте новый объект ObjectDataSource с именем SuppliersDataSource (Щелкните, чтобы просмотреть изображение в полном размере)
Настройте ObjectDataSource для получения данных с помощью SuppliersBLL метода класса GetSuppliers() (см. рис. 3). Как и в предыдущем руководстве, вместо обновления сведений о поставщике через ObjectDataSource, мы будем работать непосредственно с уровнем бизнес-логики. Поэтому установите раскрывающийся список в положение (Нет) на вкладке ОБНОВЛЕНИЕ (см. рис. 4).
Рис. 3. Получение сведений о поставщике GetSuppliers() с помощью метода (щелкните, чтобы просмотреть изображение полного размера)
Рис. 4. Задайте для списка Drop-Down значение (нет) на вкладке UPDATE (щелкните, чтобы просмотреть изображение полного размера)
После завершения работы мастера Visual Studio автоматически создает dataList для ItemTemplate отображения каждого поля данных, возвращаемого источником данных в веб-элементе управления Label. Необходимо изменить этот шаблон, чтобы он предоставлял интерфейс редактирования. Его ItemTemplate можно настроить с помощью конструктора с помощью параметра "Изменить шаблоны" из смарт-тега DataList или непосредственно с помощью декларативного синтаксиса.
Создайте интерфейс редактирования, отображающий имя поставщика в виде текста, но включает текстовые поля для адреса поставщика, города и страны или региона. После внесения этих изменений декларативный синтаксис страницы должен выглядеть следующим образом:
<asp:DataList ID="Suppliers" runat="server" DataKeyField="SupplierID"
DataSourceID="SuppliersDataSource">
<ItemTemplate>
<h4><asp:Label ID="CompanyNameLabel" runat="server"
Text='<%# Eval("CompanyName") %>' /></h4>
<table border="0">
<tr>
<td class="SupplierPropertyLabel">Address:</td>
<td class="SupplierPropertyValue">
<asp:TextBox ID="Address" runat="server"
Text='<%# Eval("Address") %>' />
</td>
</tr>
<tr>
<td class="SupplierPropertyLabel">City:</td>
<td class="SupplierPropertyValue">
<asp:TextBox ID="City" runat="server"
Text='<%# Eval("City") %>' />
</td>
</tr>
<tr>
<td class="SupplierPropertyLabel">Country:</td>
<td class="SupplierPropertyValue">
<asp:TextBox ID="Country" runat="server"
Text='<%# Eval("Country") %>' />
</td>
</tr>
</table>
<br />
</ItemTemplate>
</asp:DataList>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
</asp:ObjectDataSource>
Замечание
Как и в предыдущем руководстве, DataList в этом руководстве должен иметь включенное состояние представления.
ItemTemplate Я использую два новых класса CSS, SupplierPropertyLabel и SupplierPropertyValue, которые были добавлены в класс Styles.css и настроены для использования таких же параметров стиля, как классы CSS ProductPropertyLabel и ProductPropertyValue.
.ProductPropertyLabel, .SupplierPropertyLabel
{
font-weight: bold;
text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
padding-right: 35px;
}
После внесения этих изменений посетите эту страницу через браузер. Как показано на рисунке 5, каждый элемент DataList отображает имя поставщика в виде текста и использует textBoxes для отображения адреса, города и страны или региона.
Рис. 5. Каждый поставщик в DataList можно изменить (щелкните, чтобы просмотреть изображение полного размера)
Шаг 2. Добавление кнопки "Обновить все"
Хотя каждый поставщик на рис. 5 имеет свой адрес, город и поля страны или региона, отображаемые в текстовом поле, в настоящее время нет кнопки "Обновить". Вместо того чтобы иметь кнопку «Обновить» для каждого элемента, в DataLists с полной возможностью редактирования обычно существует одна кнопка «Обновить все» на странице, которая обновляет все записи в DataList при нажатии. В этом руководстве давайте добавим две кнопки "Обновить все" в верхней части страницы и один в нижней части (хотя нажатие одной кнопки будет иметь одинаковый эффект).
Сначала добавьте элемент управления Button Web над DataList и установите его свойство ID на UpdateAll1. Затем добавьте второй веб-элемент управления Button под DataList, задав для нее значение IDUpdateAll2.
Text Задайте свойства для двух кнопок, чтобы обновить все. Наконец, создайте обработчики для событий обеих кнопок Click . Вместо дублирования логики обновления в каждом обработчике событий, давайте вынесем эту логику в третий метод, UpdateAllSupplierAddresses при этом обработчики событий будут просто вызывать этот метод.
protected void UpdateAll1_Click(object sender, EventArgs e)
{
UpdateAllSupplierAddresses();
}
protected void UpdateAll2_Click(object sender, EventArgs e)
{
UpdateAllSupplierAddresses();
}
private void UpdateAllSupplierAddresses()
{
// TODO: Write code to update _all_ of the supplier addresses in the DataList
}
На рисунке 6 показана страница после добавления кнопок "Обновить все".
Рис. 6. На страницу были добавлены две кнопки обновления (щелкните, чтобы просмотреть изображение полного размера)
Шаг 3. Обновление всех сведений об адресах поставщиков
Когда все элементы DataList отображают интерфейс редактирования и добавлена кнопка "Обновить все", все, что остается сделать — это написать код для выполнения пакетного обновления. В частности, необходимо выполнить цикл по элементам DataList и вызвать SuppliersBLL метод класса UpdateSupplierAddress для каждого из них.
Коллекция экземпляров DataListItem, составляющих DataList, может быть получена через свойство Items DataList. Со ссылкой на DataListItem, можно извлечь соответствующий SupplierID из коллекции DataKeys и программно обратиться к элементам управления TextBox в ItemTemplate, как показано в следующем коде:
private void UpdateAllSupplierAddresses()
{
// Create an instance of the SuppliersBLL class
SuppliersBLL suppliersAPI = new SuppliersBLL();
// Iterate through the DataList's items
foreach (DataListItem item in Suppliers.Items)
{
// Get the supplierID from the DataKeys collection
int supplierID = Convert.ToInt32(Suppliers.DataKeys[item.ItemIndex]);
// Read in the user-entered values
TextBox address = (TextBox)item.FindControl("Address");
TextBox city = (TextBox)item.FindControl("City");
TextBox country = (TextBox)item.FindControl("Country");
string addressValue = null, cityValue = null, countryValue = null;
if (address.Text.Trim().Length > 0)
addressValue = address.Text.Trim();
if (city.Text.Trim().Length > 0)
cityValue = city.Text.Trim();
if (country.Text.Trim().Length > 0)
countryValue = country.Text.Trim();
// Call the SuppliersBLL class's UpdateSupplierAddress method
suppliersAPI.UpdateSupplierAddress
(supplierID, addressValue, cityValue, countryValue);
}
}
Когда пользователь нажимает одну из кнопок «Update All», метод UpdateAllSupplierAddresses выполняет итерацию по каждому DataListItem в Suppliers DataList и вызывает метод UpdateSupplierAddress класса SuppliersBLL, передавая соответствующие значения. Не введенное значение для адреса, города или страны или региона — это значение NothingUpdateSupplierAddress (а не пустая строка), которое приводит к базе данных NULL для полей базовой записи.
Замечание
В качестве улучшения может потребоваться добавить веб-элемент управления метки состояния на страницу, которая предоставляет некоторое сообщение подтверждения после выполнения пакетного обновления.
Обновление только тех адресов, которые были изменены
Алгоритм пакетного обновления, используемый в этом руководстве, вызывает UpdateSupplierAddress метод для каждого поставщика в DataList независимо от того, были ли изменены сведения об адресе. Хотя такие слепые обновления обычно не являются проблемой производительности, они могут привести к лишним записям, если вы выполняете аудит изменений в таблице базы данных. Например, если вы используете триггеры для записи всех записей UPDATE в Suppliers таблицу аудита, каждый раз, когда пользователь нажимает кнопку "Обновить все", новая запись аудита создаётся для каждого поставщика в системе, независимо от того, вносил(а) ли пользователь какие-либо изменения.
Классы DataTable и DataAdapter ADO.NET предназначены для поддержки пакетных обновлений, в которых только изменённые, удалённые или новые записи приводят к обмену данными с базой данных. Каждая строка в DataTable имеет RowState свойство , указывающее, была ли строка добавлена в DataTable, удалена из нее, изменена или остается неизменной. При первоначальном заполнении DataTable все строки помечаются без изменений. Изменение значения любого столбца строки помечает строку как измененную.
В классе SuppliersBLL мы обновляем сведения об адресе указанного поставщика, сначала считывая запись одного поставщика в объект SuppliersDataTable, а затем устанавливаем значения столбцов Address, City и Country, используя следующий код:
public bool UpdateSupplierAddress
(int supplierID, string address, string city, string country)
{
Northwind.SuppliersDataTable suppliers =
Adapter.GetSupplierBySupplierID(supplierID);
if (suppliers.Count == 0)
// no matching record found, return false
return false;
else
{
Northwind.SuppliersRow supplier = suppliers[0];
if (address == null)
supplier.SetAddressNull();
else
supplier.Address = address;
if (city == null)
supplier.SetCityNull();
else
supplier.City = city;
if (country == null)
supplier.SetCountryNull();
else
supplier.Country = country;
// Update the supplier Address-related information
int rowsAffected = Adapter.Update(supplier);
// Return true if precisely one row was updated,
// otherwise false
return rowsAffected == 1;
}
}
Этот код наивно назначает значения переданного адреса, города и страны или региона к SuppliersRow в SuppliersDataTable независимо от того, изменились ли значения. Эти изменения приводят к тому, что свойство SuppliersRow s RowState отмечается как измененное. Когда вызывается метод уровня Update доступа к данным, он видит, что SupplierRow был изменен, и поэтому отправляет UPDATE команду в базу данных.
Представьте себе, что мы добавили код в этот метод, чтобы назначить только переданные значения адреса, города и страны или региона, если они отличаются от существующих значений SuppliersRow . В случае, если адрес, город и страна или регион совпадают с существующими данными, изменения не будут вноситься, и они SupplierRowRowState будут оставлены без изменений. Конечный результат заключается в том, что при вызове метода DAL Update вызов к базе данных не будет выполнен, поскольку SuppliersRow не был изменен.
Чтобы принять это изменение, замените инструкции, которые слепо назначают переданные адреса, города и страны или региона следующим кодом:
// Only assign the values to the SupplierRow's column values if they differ
if (address == null && !supplier.IsAddressNull())
supplier.SetAddressNull();
else if ((address != null && supplier.IsAddressNull()) ||
(!supplier.IsAddressNull() &&
string.Compare(supplier.Address, address) != 0))
supplier.Address = address;
if (city == null && !supplier.IsCityNull())
supplier.SetCityNull();
else if ((city != null && supplier.IsCityNull()) ||
(!supplier.IsCityNull() && string.Compare(supplier.City, city) != 0))
supplier.City = city;
if (country == null && !supplier.IsCountryNull())
supplier.SetCountryNull();
else if ((country != null && supplier.IsCountryNull()) ||
(!supplier.IsCountryNull() &&
string.Compare(supplier.Country, country) != 0))
supplier.Country = country;
В этом добавленном коде метод DAL Update отправляет UPDATE инструкцию в базу данных только для тех записей, адресные значения которых изменились.
Кроме того, можно отслеживать наличие различий между переданными полями адресов и данными базы данных, а если нет, просто обойти вызов метода DAL Update . Этот подход хорошо работает, если используется прямой метод базы данных, так как при этом не передается экземпляр SuppliersRow, свойство RowState которого можно проверить для определения необходимости вызова базы данных.
Замечание
UpdateSupplierAddress При каждом вызове метода отправляется запрос в базу данных для получения информации об обновленной записи. Затем при наличии изменений в данных выполняется еще один вызов базы данных для обновления строки таблицы. Этот рабочий процесс можно оптимизировать, создав перегрузку UpdateSupplierAddress метода, которая принимает EmployeesDataTable экземпляр со всеми изменениями на BatchUpdate.aspx странице. Затем он может вызвать базу данных, чтобы получить все записи из Suppliers таблицы. Затем можно перечислить два набора результатов и обновить только те записи, в которых произошли изменения.
Сводка
В этом руководстве мы узнали, как создать полностью редактируемый Список данных, что позволяет пользователю быстро изменять сведения об адресе для нескольких поставщиков. Мы начали с редактирования интерфейса веб-элемента управления TextBox для адреса поставщика, города и страны/региона в элементе DataList ItemTemplate. Затем мы добавили кнопки «Обновить все» выше и ниже элемента DataList. После внесения изменений и нажатия одной из кнопок Update All элементы DataListItem перечисляются, и производится вызов метода класса SuppliersBLLUpdateSupplierAddress.
Счастливое программирование!
Сведения о авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.
Особое спасибо кому
Эта серия учебников была проверена многими полезными рецензентами. Ведущими рецензентами этого учебника были Зак Джонс и Кен Песписа. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.