I recently needed an expandable and collapsible GridView in a project I was working on, but couldn't find any simple solutions that met my criteria. Fortunately, it was fairly easy to write up. I have included the basic source code below, so it should be fairly easy to implement into other projects. The only thing you will need to do is find a collapse and expand icon and then update the image names accordingly in the code behind. (For SharePoint, you can use "_layouts\images\TPMin2.gif" for collapse and "_layouts\images\TPMax2.gif" for expand.)
Note: I have not included code for paging. This will require a little more work.
Requirements
- Use a standard ASP.NET GridView control.
- Ability to collapse or expand the whole GridView or selective parts of it.
- Use client side Javascript to ensure better performance and no browser refresh.
- Only show expand and collapse buttons and grouping value ("Company" in my case) if the next row has the same grouping value.
- Provide the ability to have the GridView collapsed initially. This is handled in the OnRowDataBound event handler.
Smoke Tests
- Collapse / Expand link works as expected and the text is updated accordingly. - PASS
- Collapse and expand button icons are updated properly when clicked and when using the Collapse / Expand link. - PASS
- Rows without expand and collapse behave properly, especially the first and last rows. - PASS
Screenshots
All Expanded
All Collapsed
Some Expanded and Some Collapsed
ASPX Code
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
<script type="text/javascript">
function ExpandCollapse(index, imageName) {
var continueLoop = new Boolean(true);
var imageMax = "TPMax2.gif";
var imageMin = "TPMin2.gif";
var rows = document.getElementById('<%= GridView1.ClientID %>').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
var image = document.getElementsByName(imageName);
var imageSrc = image[0].src;
if (imageSrc.match(imageMax) != null) {
image[0].src = imageMin;
index++;
while (continueLoop) {
if (rows[index].cells[1].innerHTML == "") {
rows[index].style.display = "block";
index++;
if (index >= rows.length) {
continueLoop = false;
}
}
else {
continueLoop = false;
}
}
}
else {
image[0].src = imageMax;
index++
while (continueLoop) {
if (rows[index].cells[1].innerHTML == "") {
rows[index].style.display = "none";
index++;
if (index >= rows.length) {
continueLoop = false;
}
}
else {
continueLoop = false;
}
}
}
}
function ExpandCollapseAll(linkId) {
var link = document.getElementById(linkId);
var imageMax = "TPMax2.gif";
var imageMin = "TPMin2.gif";
var rows = document.getElementById('<%= GridView1.ClientID %>').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
if (link.innerHTML == 'Expand All') {
link.innerHTML = 'Collapse All';
for (var i = 1; i < rows.length; i++) {
if (rows[i].cells[1].innerHTML != "") {
if (rows[i].cells[0].childNodes[0] != undefined) {
var img = rows[i].cells[0].childNodes[0];
img.src = imageMin;
}
}
else {
rows[i].style.display = "block";
}
}
}
else {
link.innerHTML = 'Expand All';
for (var i = 1; i < rows.length; i++) {
if (rows[i].cells[1].innerHTML != "") {
if (rows[i].cells[0].childNodes[0] != undefined) {
var img = rows[i].cells[0].childNodes[0];
img.src = imageMax;
}
}
else {
rows[i].style.display = "none";
}
}
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<div onclick="javascript:ExpandCollapseAll(this.id);" id="CollapseExpandAllLink"
style="color: Blue; text-decoration: underline; cursor: pointer" runat="server">
Collapse All</div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" OnRowDataBound="GridView1_OnRowDataBound"
OnDataBound="GridView1_DataBound">
<Columns>
<asp:ImageField DataImageUrlField="ImageUrl">
</asp:ImageField>
<asp:BoundField DataField="Company" HeaderText="Company" />
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
ASPX Code Behind
using System;
using System.Collections.Generic;
using System.Data;
using System.Web.UI.WebControls;
public partial class _Default : System.Web.UI.Page
{
public string PreviousGroupingValue { get; set; }
public string ImageMin = "TPMin2.gif";
public string ImageMax = "TPMax2.gif";
protected void Page_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add("ImageUrl");
dt.Columns.Add("Company");
dt.Columns.Add("FirstName");
dt.Columns.Add("LastName");
DataRow dr = dt.NewRow();
foreach (Employee employee in GetEmployees())
{
dr = dt.NewRow();
dr["ImageUrl"] = ImageMin;
dr["Company"] = employee.Company;
dr["FirstName"] = employee.FirstName;
dr["LastName"] = employee.LastName;
dt.Rows.Add(dr);
}
GridView1.DataSource = dt;
GridView1.DataBind();
}
protected void GridView1_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
string imageName = string.Empty;
bool collapsedInitially = true;
bool populateImageCtrl = false;
if (collapsedInitially)
{
CollapseExpandAllLink.InnerText = "Expand All";
}
else
{
CollapseExpandAllLink.InnerText = "Collapse All";
}
if (e.Row.RowType == DataControlRowType.DataRow)
{
imageName = "ImageExpand" + e.Row.RowIndex.ToString();
if (e.Row.RowIndex != 0)
{
if (GridView1.Rows[e.Row.RowIndex - 1].RowType == DataControlRowType.DataRow)
{
if (e.Row.Cells[1].Text == PreviousGroupingValue)
{
PreviousGroupingValue = e.Row.Cells[1].Text;
e.Row.Cells[1].Text = "";
((Image)e.Row.Cells[0].Controls[0]).Visible = false;
if (collapsedInitially)
{
e.Row.Style.Add("display", "none");
}
}
else
{
((Image)GridView1.Rows[e.Row.RowIndex - 1].Cells[0].Controls[0]).Visible = false;
populateImageCtrl = true;
}
}
}
else
{
populateImageCtrl = true;
}
if (populateImageCtrl)
{
((Image)e.Row.Cells[0].Controls[0]).Attributes.Add("name", imageName);
((Image)e.Row.Cells[0].Controls[0]).Attributes.Add("onclick", "javascript:ExpandCollapse(" + (Convert.ToInt32(e.Row.RowIndex + 1)).ToString() + ", '" + imageName + "');");
((Image)e.Row.Cells[0].Controls[0]).ImageUrl = ImageMax;
PreviousGroupingValue = e.Row.Cells[1].Text;
}
}
}
protected void GridView1_DataBound(object sender, EventArgs e)
{
if (GridView1.Rows.Count > 1)
{
if (GridView1.Rows[GridView1.Rows.Count - 1].Cells[1].Text != GridView1.Rows[GridView1.Rows.Count - 2].Cells[1].Text)
{
((Image)GridView1.Rows[GridView1.Rows.Count - 1].Cells[0].Controls[0]).Visible = false;
}
}
}
public List<Employee> GetEmployees()
{
List<Employee> employees = new List<Employee>();
employees.Add(new Employee { Company = "C Company", FirstName = "Helen", LastName = "Hamaguchi" });
employees.Add(new Employee { Company = "A Company", FirstName = "Ira", LastName = "Ivanovich" });
employees.Add(new Employee { Company = "D Company", FirstName = "Greg", LastName = "Good" });
employees.Add(new Employee { Company = "F Company", FirstName = "Adam", LastName = "Apple" });
employees.Add(new Employee { Company = "F Company", FirstName = "Carl", LastName = "Castle" });
employees.Add(new Employee { Company = "D Company", FirstName = "Delia", LastName = "Dunken" });
employees.Add(new Employee { Company = "D Company", FirstName = "Francis", LastName = "Frantz" });
employees.Add(new Employee { Company = "E Company", FirstName = "Katsuhiro", LastName = "Kawasaki" });
employees.Add(new Employee { Company = "D Company", FirstName = "Evan", LastName = "Erlich" });
employees.Add(new Employee { Company = "E Company", FirstName = "Leslie", LastName = "Lang" });
employees.Add(new Employee { Company = "F Company", FirstName = "Beverly", LastName = "Beard" });
employees.Add(new Employee { Company = "E Company", FirstName = "Marvin", LastName = "Marx" });
employees.Add(new Employee { Company = "Z Company", FirstName = "Nelson", LastName = "Nellis" });
employees.Add(new Employee { Company = "E Company", FirstName = "Jasmine", LastName = "Jobs" });
employees.Sort(delegate(Employee e1, Employee e2) { return e1.Company.CompareTo(e2.Company); });
return employees;
}
}
public class Employee
{
public string Company { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
No comments:
Post a Comment