| |
ASP.NET - объединение ячеек в GridView
В ASP.NET есть очень замечательный компонент GridView, его мощь трудно переоценить. Любым средством, конечно нужно уметь пользоваться, но иногда без трюков не обойтись. В этой статье рассказывается, как в GridView добавить в шапку таблицы вторую строку и объединить в ней ячейки. Т.е. мы хотим сделать что-то подобное:
Используя прием, описаный в этой статье, можно достичь ЛЮБОГО желаемого объединения ячеек в таблице. Например такого:
Первое, что нам необходимо сделать - это получить доступ к внутреннему объекту нашего GridView с типом Table, строками и ячейками которого мы будем достигать требуемого эффекта:
Dim gv As GridView
Dim t As Table
t=CType(gv.Controls(0), Table)
Теперь, используя стандартные коллекции Rows и Cells полученного Table, а также свойства ячеек ColumnSpan и RowSpan осуществляем любые необходимые объединения. Строка шапки имеет индекс 0 (также можно воспользоваться свойством HeaderRow самого GridView), строки с данными из таблицы имеют индексы 1, 2 и т.д.
Далее покажем работу с GridView на примере работы с шапкой:
Dim row = New GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal)
Dim r = gv.HeaderRow 'или CType(gv.Controls(0), Table).Rows(0)
Копируем строку шапки:
Dim cell As TableHeaderCell
For Each rcell As TableCell In r.Cells
cell = New TableHeaderCell
cell.Text = rcell.Text 'можем скопировать заголовки из шапки
cell.Style("text-align") = "center" 'можем задать какой-то стиль
row.Cells.Add(cell)
Next
Далее для нужных ячеек i устанавливаем объединение по горизонтали:
row.Cells(i).ColumnSpan="3" 'например, для 3-х объединяемых ячеек
Для ячеек, которые не будут объединены по горизонтали, устанавливаем объединение по вертикали на 2 строки:
row.Cells(i).RowSpan="2"
Не забудьте, что в "родной" строке шапки нужно удалить ячейки с индексами колонок, которые мы не объединяем по горизонтали (по индексу которых делали RowSpan="2"). А также необходимо удалить ячейки из нашей вновь добавляемой строки, потому что в местах объединения в ней ячеек (колонок шапки) меньше, чем в "родной" строке шапки:
row.Cells.RemoveAt(i)
r.Cells.RemoveAt(i)
И, наконец, добавляем нашу дополнительную строку на верх в шапку таблицы:
CType(gv.Controls(0), Table).Rows.AddAt(0, row)
Как видим, принцип довольно простой, расстраивает только одно, что необходимо не запутаться и удалить из обоих строк шапки требуемые ячейки, кроме того, не удобно каждый раз в программу вставлять такие большие куски кода для обработки шапки каждого GridView. Хорошо было бы написать универсальную процедуру, в качестве параметров которой передавать как-нибудь (понятненько и несложненько), что мы хотим объединить, а заодно и тексты для объединяемых ячеек. Например, вот так:
Dim a(,) As String = {{"Объединение 1", "4", "2"}, {"Объединение 2", "6", "4"}} 'и т.д., понятно, что перечень объединений может быть не ограничен
ApplyGridViewHeader(gv, a)
Где a(,) - ясное дело, динамический 2-х мерный массив строк, "Объединение 1" - это название объединения, следующее значение - индекс, начиная с которого будем объединять ячейки, а следующее значение - количество объединяемых ячеек.
Но об этом чуть позже. У нас осталась еще одна важная вещь - в какой момент производить обработку GridView? В Page_Load, Page_PreRender ? В произвольном месте кода страницы производить эту манипуляцию не удается, после первого postback вся наша конструкция "съезжает", сказывается работа GridView, связанная с ViewState этого контрола. И даже обработка во всемогущих событиях страницы PreRender и PreRenderComplete нас не спасает.
Поможет нам не такое популярное событие SaveStateComplete. Для желающих расширить свой кругозор в жизненном цикле страницы ASP.NET привожу ссылку, там есть очень наглядненькая (моя ненаглядненькая :) картиночка от Microsoft жизненный цикл и события страниц ASP.NET.
Важно! производить вышеописанные манипуляции с GridView нужно в событии страницы SaveStateComplete
Ну, и напоследок, для тех, кто хочет съэкономить свое время, и избежать алгоритмических баталий с ячейками GridView, текст написанной мной процедуры ApplyGridViewHeader(gv, a) по объединению ячеек в шапке таблицы (чуть выше я приводил пример вызова этой процедуры):
Namespace MyNamespace
' статический класс для работы с элементами управления
Public Class WebControlsProcsClass
Public Shared Sub ApplyGridViewHeader(ByRef gv As GridView, ByRef a(,) As String)
'процедура написана таким образом, что в нее всегда должны передаваться индексы с учетом только фактически отображаемых колонок
'т.е. при вычислении индекса объединяемой колонки (передаваемой в качестве параметра в процедуру) считается,
'что колонок со свойством Visible = false в таблице как бы нет.
'индексы (передаваемые в качестве параметров в процедуру) указываются по исходному порядку необъединенных колонок
If gv.Rows.Count > 0 Then
Dim row = New GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal)
Dim r = gv.HeaderRow
Dim cell As TableHeaderCell
Dim i, j As Integer
'следующие два цикла удаляют ячейки "родной" строки шапки таблицы, соответствующие колонкам с Visible = false
'если таковые, конечно, имеются
For i = 0 To gv.Columns.Count - 1
If Not (gv.Columns(i).Visible) Then
r.Cells(i).ColumnSpan = 100
End If
Next
i = 0
While i < r.Cells.Count
If r.Cells(i).ColumnSpan = 100 Then
r.Cells.RemoveAt(i)
Else : i = i + 1
End If
End While
'копируем "родную" строку шапки
For Each rcell As TableCell In r.Cells
cell = New TableHeaderCell
cell.Text = rcell.Text
cell.Style("text-align") = "center"
row.Cells.Add(cell)
Next
'для нужных ячеек в верхней строке, прописываем тексты объединяющих ячеек и их ColumnSpan
For i = 0 To a.GetUpperBound(0)
row.Cells(a(i, 1)).Text = a(i, 0)
row.Cells(a(i, 1)).ColumnSpan = a(i, 2)
Next
'идем по верхней строке у оставшихся ячеек (не задействованных) в предыдущем цикле ставим им RowSpan = 2
'одновременно ячееки с таким же индексом в нижней строке помечаем на удаление
For i = 0 To row.Cells.Count - 1
If row.Cells(i).ColumnSpan < 2 Then
row.Cells(i).RowSpan = 2
r.Cells(i).ColumnSpan = 100
Else
'пропускаем ячейки на которые распространяется ColumnSpan
i = i + row.Cells(i).ColumnSpan - 1
End If
Next
'удаляем помеченные ячейки в нижней строке
i = 0
While i < r.Cells.Count
If r.Cells(i).ColumnSpan = 100 Then
r.Cells.RemoveAt(i)
Else : i = i + 1
End If
End While
'идем по верхней строке удаляем соответствующее ColumnSpan количество ячеек после ячеек имеющих ColumnSpan > 1
i = 0
While i < row.Cells.Count
If row.Cells(i).ColumnSpan > 1 Then
For j = 1 To row.Cells(i).ColumnSpan - 1
row.Cells.RemoveAt(i + 1)
Next
End If
i = i + 1
End While
CType(gv.Controls(0), Table).Rows.AddAt(0, row)
End If
End Sub
End Class
End Namespace
|
|