Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Узнайте, как создать полностью редактируемый список данных, где все его элементы находятся в режиме редактирования и значения которых можно сохранить, нажав кнопку "Обновить все" на странице.
Введение
В предыдущем руководстве мы рассмотрели, как создать dataList уровня элемента. Как и стандартный редактируемый GridView, каждый элемент в DataList включал кнопку "Изменить", которая при щелчке сделает элемент редактируемым. Хотя редактирование на уровне элемента хорошо подходит для данных, которые обновляются только иногда, некоторые сценарии использования требуют, чтобы пользователь редактировал много записей. Если пользователю нужно изменить десятки записей и принудительно нажать кнопку "Изменить", внести изменения и нажать кнопку "Обновить" для каждой из них, количество щелчков может препятствовать ее производительности. В таких ситуациях лучше предоставить полностью редактируемый dataList, где все его элементы находятся в режиме редактирования и чьи значения можно изменить, нажав кнопку "Обновить все" на странице (см. рис. 1).
Рис. 1. Каждый элемент в полно редактируемом списке данных можно изменить (щелкните, чтобы просмотреть изображение полного размера)
В этом руководстве мы рассмотрим, как разрешить пользователям обновлять сведения об адресе поставщиков с помощью полно редактируемого списка данных.
Шаг 1. Создание редактируемого пользовательского интерфейса в элементе ItemTemplate DataList
В предыдущем руководстве, где мы создадим стандартный редактируемый 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, мы будем работать непосредственно с уровнем бизнес-логики. Поэтому в раскрывающемся списке (Нет) на вкладке UPDATE (см. рис. 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 В i m using two new CSS classSupplierPropertyLabel, and , которые были добавлены в SupplierPropertyValue класс и Styles.cssнастроены для использования одинаковых параметров стиля, что ProductPropertyLabel и ProductPropertyValue классы CSS.
.ProductPropertyLabel, .SupplierPropertyLabel
{
font-weight: bold;
text-align: right;
}
.ProductPropertyValue, .SupplierPropertyValue
{
padding-right: 35px;
}
После внесения этих изменений посетите эту страницу через браузер. Как показано на рисунке 5, каждый элемент DataList отображает имя поставщика в виде текста и использует textBoxes для отображения адреса, города и страны или региона.
Рис. 5. Каждый поставщик в DataList можно изменить (щелкните, чтобы просмотреть изображение полного размера)
Шаг 2. Добавление кнопки "Обновить все"
Хотя каждый поставщик на рис. 5 имеет свой адрес, город и поля страны или региона, отображаемые в текстовом поле, в настоящее время нет кнопки "Обновить". Вместо того чтобы иметь кнопку «Обновить» для каждого элемента, в DataLists с полной возможностью редактирования обычно существует одна кнопка «Обновить все» на странице, которая обновляет все записи в DataList при нажатии. В этом руководстве давайте добавим две кнопки "Обновить все" в верхней части страницы и один в нижней части (хотя нажатие одной кнопки будет иметь одинаковый эффект).
Сначала добавьте веб-элемент управления Button над DataList и задайте для него значение ID свойства UpdateAll1. Затем добавьте второй веб-элемент управления Button под DataList, задав для нее значение IDUpdateAll2.
Text Задайте свойства для двух кнопок, чтобы обновить все. Наконец, создайте обработчики событий для обоих событий Button 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 и вызывает SuppliersBLL метод класса UpdateSupplierAddress , передавая соответствующие значения. Не введенное значение для адреса, города или страны или региона — это значение NothingUpdateSupplierAddress (а не пустая строка), которое приводит к базе данных NULL для полей базовой записи.
Замечание
В качестве улучшения может потребоваться добавить веб-элемент управления метки состояния на страницу, которая предоставляет некоторое сообщение подтверждения после выполнения пакетного обновления.
Обновление только тех адресов, которые были изменены
Алгоритм пакетного обновления, используемый в этом руководстве, вызывает UpdateSupplierAddress метод для каждого поставщика в DataList независимо от того, были ли изменены сведения об адресе. Хотя такие слепые обновления обычно не являются проблемой производительности, они могут привести к лишним записям, если вы выполняете аудит изменений в таблице базы данных. Например, если вы используете триггеры для записи всех UPDATE s в Suppliers таблицу аудита, каждый раз, когда пользователь нажимает кнопку "Обновить все", новая запись аудита будет создана для каждого поставщика в системе независимо от того, вносил ли пользователь какие-либо изменения.
Классы dataTable и DataAdapter ADO.NET предназначены для поддержки пакетных обновлений, в которых только изменены, удалены и новые записи приводят к любому обмену данными с базой данных. Каждая строка в DataTable имеет RowState свойство , указывающее, была ли строка добавлена в DataTable, удалена из нее, изменена или остается неизменной. При первоначальном заполнении DataTable все строки помечаются без изменений. Изменение значения любого столбца строки помечает строку как измененную.
SuppliersBLL В классе мы обновляем сведения об адресе указанного поставщика, сначала считывая запись одного поставщика в объектSuppliersDataTable, а затем задали AddressCityзначения столбцов, 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;
}
}
Этот код наивно назначает значения переданного адреса, города и страны или региона SuppliersRowSuppliersDataTable в зависимости от того, изменились ли значения. Эти изменения приводят 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. Затем мы добавили кнопки Update All выше и ниже DataList. После внесения изменений и нажатия одной из кнопок Update All перечисляются и DataListItem выполняется вызов SuppliersBLL метода класса UpdateSupplierAddress .
Счастливое программирование!
Сведения о авторе
Скотт Митчелл, автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга — Sams Teach Yourself ASP.NET 2.0 за 24 часа. С ним можно связаться по адресу mitchell@4GuysFromRolla.com.
Особое спасибо кому
Эта серия учебников была проверена многими полезными рецензентами. Ведущие рецензенты для этого руководства были Зак Джонс и Кен Песписа. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com.