Отображение сводной информации в футере GridView (C#)

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

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

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

Введение

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

Эта задача представляет нам три задачи:

  1. Настройка GridView для отображения строки футера
  2. Определение суммарных данных; То есть как вычислить среднюю цену или общую сумму единиц акций?
  3. Вставка сводных данных в соответствующие ячейки строки нижнего колонтитула

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

Сводная информация отображается в нижней строке GridView

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

В этом руководстве с категорией к интерфейсу мастер/деталь продуктов, расширяются концепции, представленные в предыдущем руководстве по фильтрации мастер/деталь с помощью DropDownList. Если вы еще не работали с предыдущим руководством, сделайте это, прежде чем продолжить работу с этим.

Шаг 1. Добавление раскрывающегося списка категорий и таблицы продуктов GridView

Прежде чем приступить к добавлению сводной информации в нижний колонтитул GridView, сначала сначала создадим главный или подробный отчет. Завершив этот первый шаг, мы рассмотрим, как включить сводные данные.

Начните с открытия SummaryDataInFooter.aspx страницы в папке CustomFormatting . Добавьте элемент управления DropDownList и задайте его ID на Categories. Затем щелкните ссылку "Выбор источника данных" из смарт-тега DropDownList и выберите новый объект ObjectDataSource с именем CategoriesDataSource , который вызывает CategoriesBLL метод класса GetCategories() .

Добавление нового объекта ObjectDataSource с именем CategoriesDataSource

Рис. 2. Добавление нового имени ObjectDataSource (CategoriesDataSourceщелкните, чтобы просмотреть изображение полного размера)

Вызвать в ObjectDataSource метод GetCategories() класса CategoriesBLL

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

После настройки ObjectDataSource мастер возвращает нас к мастеру конфигурации источника данных DropDownList, где необходимо указать, какое значение поля данных должно отображаться и какое должно соответствовать значению DropDownList ListItem. Отобразите поле CategoryName и используйте CategoryID в качестве значения.

Используйте поля CategoryName и CategoryID в качестве текста и значения для ListItems соответственно

Рис. 4: Используйте CategoryName и CategoryID поля в качестве Text и Value для ListItem, соответственно (нажмите, чтобы просмотреть изображение в полном размере)

На этом этапе у нас есть выпадающий список (Categories), который перечисляет категории в системе. Теперь необходимо добавить GridView, который перечисляет те продукты, которые относятся к выбранной категории. Прежде чем мы сделаем это, обратите внимание на флажок Enable AutoPostBack в смарт-теге DropDownList. Как обсуждалось в руководстве по фильтрации основных и подробных сведений с помощью раскрывающегося списка, установив для свойства DropDownList значение AutoPostBack, страница будет отправлена обратно на сервер при каждом изменении значения true DropDownList. Это приведет к обновлению GridView, показывающее эти продукты для только что выбранной категории. AutoPostBack Если для свойства задано значение false (по умолчанию), изменение категории не приведет к обратной отправке и поэтому не будет обновлять перечисленные продукты.

Установите флажок Enable AutoPostBack в смарт-теге DropDownList

Рис. 5. Установите флажок "Включить autoPostBack" в смарт-теге DropDownList (щелкните, чтобы просмотреть изображение полного размера)

Добавьте элемент управления GridView на страницу, чтобы отобразить продукты для выбранной категории. Задайте для GridView IDProductsInCategory значение и привязать его к новому объекту ObjectDataSource с именем ProductsInCategoryDataSource.

Добавление нового объекта ObjectDataSource с именем ProductsInCategoryDataSource

Рис. 6. Добавление нового объекта ObjectDataSource С именем ProductsInCategoryDataSource (щелкните, чтобы просмотреть изображение полного размера)

Настройте ObjectDataSource таким образом, чтобы он запускал метод класса GetProductsByCategoryID(categoryID)ProductsBLL.

Чтобы объект ObjectDataSource вызвал метод GetProductsByCategoryID(categoryID)

Рис. 7. Вызов GetProductsByCategoryID(categoryID) метода ObjectDataSource (щелкните, чтобы просмотреть изображение полного размера)

Поскольку метод принимает входной параметр, на последнем шаге мастера GetProductsByCategoryID(categoryID) можно указать источник значения этого параметра. Чтобы отобразить эти продукты из выбранной категории, необходимо извлечь параметр из Categories DropDownList.

Снимок экрана: окно

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

После завершения работы мастера настроек GridView будет иметь BoundField для каждого свойства продукта. Давайте очистим эти BoundFields таким образом, чтобы отображались только ProductName, UnitPrice, UnitsInStock, и UnitsOnOrder BoundFields. Вы можете добавить все параметры уровня поля в оставшиеся поля BoundFields (например, форматирование UnitPrice в виде валюты). После внесения этих изменений декларативная разметка GridView должна выглядеть следующим образом:

<asp:GridView ID="ProductsInCategory" runat="server"
    AutoGenerateColumns="False" DataKeyNames="ProductID"
    DataSourceID="ProductsInCategoryDataSource" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product"
          SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}"
            HeaderText="Price"
            HtmlEncode="False" SortExpression="UnitPrice">
            <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
        <asp:BoundField DataField="UnitsInStock"
         HeaderText="Units In Stock" SortExpression="UnitsInStock">
            <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
        <asp:BoundField DataField="UnitsOnOrder"
           HeaderText="Units On Order" SortExpression="UnitsOnOrder">
            <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
    </Columns>
</asp:GridView>

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

Снимок экрана: отчет GridView для тех продуктов, которые относятся к категории

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

Элемент управления GridView может отображать как строку заголовка, так и строку нижнего колонтитула. Эти строки отображаются в зависимости от значений свойств ShowHeader и ShowFooter соответственно, при этом ShowHeader по умолчанию равняется true, а ShowFooter - до false. Чтобы включить нижний колонтитул в GridView, просто установите значение свойства ShowFooter в true.

Задайте для свойства ShowFooter GridView значение true

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

Строка нижнего колонтитула содержит ячейку для каждого из полей, определенных в GridView; однако эти ячейки пусты по умолчанию. Ознакомьтесь с нашим прогрессом в браузере. Теперь для свойства ShowFooter задано значение true, и GridView содержит пустую строку нижнего колонтитула.

GridView теперь включает строку нижнего колонтитула

Рис. 11. GridView теперь включает строку футера (нажмите, чтобы просмотреть изображение полного размера)

Строка в нижней части на рис. 11 не выделяется, так как она имеет белый фон. Давайте создадим FooterStyle класс CSS в Styles.css, который задает темно-красный фон, и затем настройте файл GridView.skin Skin в теме DataWebControls, чтобы этот класс CSS назначался свойству FooterStyle элемента GridView CssClass. Если вам нужно приступить к работе с кожей и темами, вернитесь к руководству по отображению данных с помощью ObjectDataSource .

Начните с добавления следующего класса CSS в Styles.css:

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

Класс FooterStyle CSS схож по стилю с классом HeaderStyle, однако цвет фона HeaderStyle немного темнее, а текст отображается жирным шрифтом. Кроме того, текст в нижнем колонтитуле выровнен по правому краю, а текст в верхнем колонтитуле выровнен по центру.

Затем, чтобы связать этот класс CSS с каждым нижним колонтитулом GridView, откройте файл GridView.skin в теме DataWebControls и задайте свойство FooterStyleCssClass. После этого добавления разметка файла должна выглядеть следующим образом:

<asp:GridView runat="server" CssClass="DataWebControlStyle">
   <AlternatingRowStyle CssClass="AlternatingRowStyle" />
   <RowStyle CssClass="RowStyle" />
   <HeaderStyle CssClass="HeaderStyle" />
   <FooterStyle CssClass="FooterStyle" />
   <SelectedRowStyle CssClass="SelectedRowStyle" />
</asp:GridView>

Как показано на снимке экрана ниже, это изменение делает нижний колонтитул более четким.

Снимок экрана, показывающий сводные данные в строке нижнего колонтитула GridView, отформатированные с новым фоновым цветом.

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

Шаг 3. Вычисление сводных данных

При показе подвала GridView следующей задачей является подсчёт итоговых данных. Существует два способа вычисления этой статистической информации:

  1. С помощью SQL-запроса можно выполнить дополнительный запрос к базе данных, чтобы вычислить сводные данные для определенной категории. SQL включает ряд агрегатных функций вместе с GROUP BY предложением, чтобы указать данные, над которыми должны быть обобщены данные. Следующий SQL-запрос возвратит необходимые сведения:

    SELECT CategoryID, AVG(UnitPrice), SUM(UnitsInStock),
    SUM(UnitsOnOrder)
    FROM Products
    WHERE CategoryID = categoryID
    GROUP BY CategoryID
    

    Конечно, вы не хотите выдавать этот запрос непосредственно со страницы SummaryDataInFooter.aspx, а вместо этого создать метод в ProductsTableAdapter и ProductsBLL.

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

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

RowDataBound Создайте обработчик событий для GridView, выбрав GridView в Конструкторе, щелкнув значок молнии в окне свойств и дважды щелкнув на событии RowDataBound. При этом будет создан новый обработчик событий с именем ProductsInCategory_RowDataBound в классе кода програмного модуля страницы SummaryDataInFooter.aspx.

protected void ProductsInCategory_RowDataBound
    (object sender, GridViewRowEventArgs e)
{
}

Чтобы поддерживать текущий итог, необходимо определить переменные вне области обработчика событий. Создайте следующие четыре переменные уровня страницы:

  • _totalUnitPrice, тип decimal
  • _totalNonNullUnitPriceCount, тип int
  • _totalUnitsInStock, тип int
  • _totalUnitsOnOrder, тип int

Затем напишите код, чтобы увеличить эти три переменные для каждой строки данных, обнаруженной в обработчике RowDataBound событий.

// Class-scope, running total variables...
decimal _totalUnitPrice = 0m;
int _totalNonNullUnitPriceCount = 0;
int _totalUnitsInStock = 0;
int _totalUnitsOnOrder = 0;
protected void ProductsInCategory_RowDataBound(object sender,
  GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // Reference the ProductsRow via the e.Row.DataItem property
        Northwind.ProductsRow product =
          (Northwind.ProductsRow)
          ((System.Data.DataRowView)e.Row.DataItem).Row;
        // Increment the running totals (if they are not NULL!)
        if (!product.IsUnitPriceNull())
        {
            _totalUnitPrice += product.UnitPrice;
            _totalNonNullUnitPriceCount++;
        }
        if (!product.IsUnitsInStockNull())
            _totalUnitsInStock += product.UnitsInStock;
        if (!product.IsUnitsOnOrderNull())
            _totalUnitsOnOrder += product.UnitsOnOrder;
    }
}

Обработчик RowDataBound событий начинается с обеспечения того, что мы имеем дело с DataRow. После того как это установлено, экземпляр Northwind.ProductsRow, который только что был привязан к объекту GridViewRow, e.Row хранится в переменной product. Затем переменные текущей суммы увеличиваются на соответствующие значения текущего продукта (при условии, что они не содержат значения базы данных NULL). Мы отслеживаем как общую суммуUnitPrice, так и количество неNULLUnitPrice записей, так как средняя цена является частным этих двух чисел.

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

protected void ProductsInCategory_RowDataBound
    (object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
      ... Increment the running totals ...
    }
    else if (e.Row.RowType == DataControlRowType.Footer)
    {
      ... Display the summary data in the footer ...
    }
}

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

Чтобы отобразить текст в определенной ячейке нижнего колонтитула, используйте e.Row.Cells[index].Text = value, где Cells индексирование начинается с 0. Следующий код вычисляет среднюю цену (общую цену, деленную на количество товаров) и выводит их вместе с общим числом единиц на складе и единиц в заказе в соответствующих ячейках нижнего колонтитула GridView.

protected void ProductsInCategory_RowDataBound
    (object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
      ... <i>Increment the running totals</i> ...
    }
    else if (e.Row.RowType == DataControlRowType.Footer)
    {
      // Determine the average UnitPrice
      decimal avgUnitPrice = _totalUnitPrice / (decimal) _totalNonNullUnitPriceCount;
      // Display the summary data in the appropriate cells
      e.Row.Cells[1].Text = "Avg.: " + avgUnitPrice.ToString("c");
      e.Row.Cells[2].Text = "Total: " + _totalUnitsInStock.ToString();
      e.Row.Cells[3].Text = "Total: " + _totalUnitsOnOrder.ToString();
    }
}

На рисунке 13 показан отчет после добавления этого кода. Обратите внимание, что ToString("c") сводная информация о средней цене будет отформатирована как валюта.

Скриншот, показывающий сводные данные в нижней строке GridView, отформатированной как валюта.

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

Итоги

Отображение сводных данных является общим требованием к отчету, и элемент управления GridView упрощает включение таких сведений в строку нижнего колонтитула. Строка нижнего колонтитула отображается, когда свойство GridView ShowFooter задано true и может иметь текст в своих ячейках, заданный программно с помощью обработчика событий RowDataBound. Вычисление суммарных данных можно выполнить путем повторного запроса базы данных или с помощью кода в классе кода ASP.NET страницы для программного вычисления сводных данных.

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

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

Об авторе

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