this is a table in my database. I want to create a Gridview with collapsable and expandable rows.
StartDate EndDate Section_Name Section_Value
2017-06-27 2017-06-28 Section 1 pump1 300
2017-06-27 2017-06-28 Section 1 pump2 256
2017-06-27 2017-06-28 Section 1 pump3 11
2017-06-27 2017-06-28 Section 1 pump4 5252
2017-06-27 2017-06-28 Section 2 pump1 300
2017-06-27 2017-06-28 Section 2 pump2 256
2017-06-27 2017-06-28 Section 2 pump3 212
2017-06-27 2017-06-28 Section 3 pump1 1222
How I want it to look in the gridview:
(+-) SECTION 1 TOTAL: 5819
Section 1 pump1 300
Section 1 pump2 256
Section 1 pump3 11
Section 1 pump4 5252
(+-) SECTION 2 TOTAL: 786
Section 2 pump1 300
Section 2 pump2 256
Section 2 pump3 212 and so on...
If you click on SECTION 1 it should display all that falls under section 1 and so forth.
The code (javascript):
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$('.ExpandCollapseStyle').click(function () {
var orderId = $(this).attr('alt');
if (!isDisplayed($('.ExpandCollapse' + orderId))) {
$(this).attr('src', 'images/minus.gif');
$('.ExpandCollapse' + orderId).css("display", "block");
}
else {
$(this).attr('src', 'images/plus.gif');
$('.ExpandCollapse' + orderId).css("display", "none");
}
})
$('.ExpandCollapseGrandStyle').click(function () {
$(".grdViewOrders tr").each(function () {
var orderId = $(this).find(".ExpandCollapseStyle").attr('alt');
if (orderId != 'undefined') {
if ($(this).attr('alt') == 'Expanded') {
$(this).find(".ExpandCollapseStyle").attr('src', 'images/minus.gif');
$('.ExpandCollapse' + orderId).css("display", "block");
$(this).attr('alt', 'Collapsed');
}
else {
$(this).find(".ExpandCollapseStyle").attr('src', 'images/plus.gif');
$('.ExpandCollapse' + orderId).css("display", "none");
$(this).attr('alt', 'Expanded');
}
}
});
if ($('.ExpandCollapseGrandStyle').attr('alt') == 'Expanded') {
$('.ExpandCollapseGrandStyle').attr('src', 'images/plus.gif');
$('.ExpandCollapseGrandStyle').attr('alt', 'Collapsed');
}
else {
$('.ExpandCollapseGrandStyle').attr('src', 'images/minus.gif');
$('.ExpandCollapseGrandStyle').attr('alt', 'Expanded');
}
})
function isDisplayed(object) {
// if the object is visible return true
if ($(object).css('display') == 'block') {
return true;
}
// if the object is not visible return false
return false;
};
});
</script>
(Gridview)
<asp:GridView ID="grdViewOrders" BackColor="WhiteSmoke" runat="server" AutoGenerateColumns="False" CssClass="grdViewOrders"
GridLines="Vertical" ShowFooter="True" OnRowDataBound="grdViewOrders_RowDataBound"
onrowcreated="grdViewOrders_RowCreated" >
<Columns>
<asp:TemplateField HeaderText="Section Name" >
<ItemStyle Width="10px" />
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Section Value">
<ItemStyle Width="10px" />
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="" DataField="Section_Name">
<HeaderStyle Width="150px" />
<ItemStyle Width="150px" />
</asp:BoundField>
<asp:BoundField HeaderText="" DataField="Section_Value">
<HeaderStyle Width="150px" />
<ItemStyle Width="150px" />
</asp:BoundField>
</Columns>
<HeaderStyle Height="25px" Font-Bold="True" BackColor="DimGray" ForeColor="White"
HorizontalAlign="Center" VerticalAlign="Middle" />
<RowStyle Height="25px" BackColor="Gainsboro" HorizontalAlign="Center" VerticalAlign="Middle" />
<AlternatingRowStyle Height="25px" BackColor="LightGray" HorizontalAlign="Center"
VerticalAlign="Middle" />
<FooterStyle BackColor="Gray" />
</asp:GridView>
(Code Behind C#)
public partial class Default3 : System.Web.UI.Page
{
// To keep track of the previous row Group Identifier
string strPreviousRowID = string.Empty;
// To keep track the Index of Group Total
int intSectionTotalIndex = 1;
string strGroupHeaderText = string.Empty;
double dblSectionTotal = 0;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
Method();
}
}
protected void Method()
{
connection made to sql db and bind data to gv
}
protected void grdViewOrders_RowCreated(object sender, GridViewRowEventArgs e)
{
bool IsSectionTotalRowNeedtoAdd = false;
if ((strPreviousRowID != string.Empty) && (DataBinder.Eval(e.Row.DataItem, "Section_Name") == null))
{
IsSectionTotalRowNeedtoAdd = true;
intSectionTotalIndex = 0;
}
if (IsSectionTotalRowNeedtoAdd)
{
#region SectionTotal
GridView grdViewOrders = (GridView)sender;
// Creating a Row
GridViewRow row = new GridViewRow(0, 0, DataControlRowType.DataRow, DataControlRowState.Insert);
//Adding Group Expand Collapse Cell
TableCell cell = new TableCell();
System.Web.UI.HtmlControls.HtmlImage img = new System.Web.UI.HtmlControls.HtmlImage();
img.Src = "images/minus.gif";
img.Attributes.Add("class", "ExpandCollapseGrandStyle");
img.Attributes.Add("alt", "Expanded");
cell.Controls.Add(img);
cell.HorizontalAlign = HorizontalAlign.Left;
row.Cells.Add(cell);
//Adding Expand Collapse Cell
cell = new TableCell();
row.Cells.Add(cell);
//Adding Header Cell
cell = new TableCell();
cell.Text = "Section 1 Total";
cell.HorizontalAlign = HorizontalAlign.Left;
cell.ColumnSpan = 1;
row.Cells.Add(cell);
//Adding Amount Column
cell = new TableCell();
cell.HorizontalAlign = HorizontalAlign.Right;
row.Cells.Add(cell);
//Adding the Row at the RowIndex position in the Grid
grdViewOrders.Controls[0].Controls.AddAt(e.Row.RowIndex, row);
#endregion
}
}
protected void grdViewOrders_RowDataBound(object sender, GridViewRowEventArgs e)
{ if (e.Row.RowType == DataControlRowType.DataRow)
{
strPreviousRowID = DataBinder.Eval(e.Row.DataItem, "Section_Name").ToString();
double dblSAmount = Convert.ToDouble(DataBinder.Eval(e.Row.DataItem, "Section_Value").ToString());
dblSectionTotal += dblSAmount;
e.Row.Style.Add("display", "block");
e.Row.CssClass = "ExpandCollapse" + strPreviousRowID;
}
}
If there is an easier way to do this, please leave a link or some tips. Thank you.
For further reference I was trying to make use of the source:
http://www.dotnettwitter.com/2012/07/group-total-and-grand-total-in-gridview_15.html
Try this example:
ASPX Code:
<asp:GridView ID="gvCustomers" runat="server" AutoGenerateColumns="false" CssClass="Grid"
DataKeyNames="CustomerID" OnRowDataBound="OnRowDataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<img alt = "" style="cursor: pointer" src="images/plus.png" />
<asp:Panel ID="pnlOrders" runat="server" Style="display: none">
<asp:GridView ID="gvOrders" runat="server" AutoGenerateColumns="false" CssClass = "ChildGrid">
<Columns>
<asp:BoundField ItemStyle-Width="150px" DataField="OrderId" HeaderText="Order Id" />
<asp:BoundField ItemStyle-Width="150px" DataField="OrderDate" HeaderText="Date" />
</Columns>
</asp:GridView>
</asp:Panel>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField ItemStyle-Width="150px" DataField="ContactName" HeaderText="Contact Name" />
<asp:BoundField ItemStyle-Width="150px" DataField="City" HeaderText="City" />
</Columns>
.CS Code
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
gvCustomers.DataSource = GetData("select top 10 * from Customers");
gvCustomers.DataBind();
}
}
private static DataTable GetData(string query)
{
string strConnString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (SqlConnection con = new SqlConnection(strConnString))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = query;
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (DataSet ds = new DataSet())
{
DataTable dt = new DataTable();
sda.Fill(dt);
return dt;
}
}
}
}
}
protected void OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string customerId = gvCustomers.DataKeys[e.Row.RowIndex].Value.ToString();
GridView gvOrders = e.Row.FindControl("gvOrders") as GridView;
gvOrders.DataSource = GetData(string.Format("select top 3 * from Orders where CustomerId='{0}'", customerId));
gvOrders.DataBind();
}
}
Client side Expand Collapse functionality using jQuery and JavaScript
For Expand and Collapse of the Child GridViews I have made use of jQuery
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$("[src*=plus]").live("click", function () {
$(this).closest("tr").after("<tr><td></td><td colspan = '999'>" + $(this).next().html() + "</td></tr>")
$(this).attr("src", "images/minus.png");
});
$("[src*=minus]").live("click", function () {
$(this).attr("src", "images/plus.png");
$(this).closest("tr").next().remove();
});
Link 1: https://www.aspsnippets.com/Articles/Nested-GridView-Example-in-ASPNet-using-C-and-VBNet.aspx
Link 2: http://www.c-sharpcorner.com/UploadFile/b926a6/nested-grid-view-in-Asp-Net/
Related
I have a server side div tag in my za.aspx page which contains a label and dropdownlist
<div id="SkillsStatus" runat="server" style="display:none">
<asp:Label ID="Label1" runat="server" Text="Please select a skill"
Font-Bold="True" Font-Italic="False" Font-Size="Larger"></asp:Label>
<asp:DropDownList ID="SkillsStatusddl" runat="server" AutoPostBack="True"
onselectedindexchanged="SkillsStatusddl_SelectedIndexChanged"
CssClass="selectpicker">
<asp:ListItem Value="0">Choose An Option</asp:ListItem>
</asp:DropDownList>
now, i am binding data to dropdownlist at codebehind file, with that i am binding a cusom control in code behind file
PreChatSurvey customPrechatSurvey = new PreChatSurvey
{
ID = "customPrechatSurvey",
ForeColor = Color.Black,
SurveyId = 0,
IsPreview = false
};
protected override void OnInit(EventArgs e)
{
SkillsStatus.Attributes.Add("style", "display:block");
SkillsStatusddl.DataSource = "";
orgID = Convert.ToInt32(Request.QueryString["OrgID"]);
DataSet ds = SubCampaignBase.GetSkillStatus(orgID);
DataTable dt = ds.Tables[0];
foreach (DataRow row in dt.Rows)
{
ListItem li = new ListItem();
li.Text = row["SubCampaignName"].ToString();
li.Value = row["SubCampaignId"].ToString();
li.Attributes.Add("data-icon", "glyphicon glyphicon-user");
if (Convert.ToBoolean(row["soa_status"]))
{
li.Attributes.CssStyle.Add(HtmlTextWriterStyle.Color, "green");
li.Attributes.CssStyle.Add(HtmlTextWriterStyle.BackgroundColor, "white");
}
else
{
li.Attributes.CssStyle.Add(HtmlTextWriterStyle.Color, "black");
li.Attributes.CssStyle.Add(HtmlTextWriterStyle.BackgroundColor, "white");
}
SkillsStatusddl.Items.Add(li);
}
base.OnInit(e);
}
now it loads a custom control and dropdown on same page, this custom control have a button, and on that button click, i want to hide the div tag containing the dropdown so i write following on button click
private void btnSubmit_Click(object sender, EventArgs e)
{
DropDownList dd = (DropDownList)this.Parent.FindControl("SkillsStatusddl");
dd.Enabled = false;
HtmlGenericControl div = (HtmlGenericControl)this.Parent.FindControl("SkillsStatus");
div.Attributes.Add("style", "display:none");
}
For safety, i have tried two things,
But nothing is working, neither the div gets disappear nor dropdown gets disabled
I have a requirement to add a panel containing a user control (textbox) + 2 Gridviews with their own item templates + other validations operating on these controls, on a Web-Form dynamically resulting from a button click. So every time a user clicks a button "Add Panel", a new panel would be generated with the above controls.
I am trying the route of Data Lists and repeaters but binding the data to the above controls is becoming a challenge. I would like to investigate other frontiers to achieve this before going forward.
Any help, links, suggestions or pointers would be appreciated?
Just to get you started.
UserControl: DynamicUC.ascx
Page using that user control: DynamicPage.aspx
DyanamicUC.ascx
<div style="float: left">
<asp:TextBox ID="tbMyTextBox" runat="server" />
<asp:GridView runat="server" ID="gvNumbers" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="Serial" HeaderText="Seiral" />
<asp:TemplateField HeaderText="Item Name">
<ItemTemplate>
<%# Eval("Item") %>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
DynamicUC.ascx.cs
public partial class DynamicUC : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public void PopulateData(string value)
{
tbMyTextBox.Text = value;
gvNumbers.DataSource = Enumerable.Range(1, 5).Select(i => new { Serial = i, Item = "Item " + i });
gvNumbers.DataBind();
}
public string GetData()
{
return Server.HtmlEncode(tbMyTextBox.Text);
}
}
DynamicPage.aspx
<asp:Button ID="btnAddUC" Text="Add UC" runat="server" OnClick="btnAddUC_Click" />
<asp:Button ID="btnGetUCValues" Text="Get UC Values" runat="server" OnClick="btnGetUCValues_Click" />
<asp:Panel runat="server" ID="pnlDynamicUCPanel" Style="overflow: auto;">
</asp:Panel>
<asp:Label ID="lblUCValues" runat="server" Style="clear: both;" />
DynamicPage.aspx.cs
public partial class DynamicPage : System.Web.UI.Page
{
private int NumberOfDynamicControls
{
get
{
var numberOfDynamicControls = ViewState["__dynamicUCCount"];
if (numberOfDynamicControls != null)
{
return (int)numberOfDynamicControls;
}
return 0;
}
set
{
ViewState["__dynamicUCCount"] = value;
}
}
private List<DynamicUC> _dynamicUCList;
protected void Page_Load(object sender, EventArgs e)
{
RestoreDynamicUC();
}
protected void btnAddUC_Click(object sender, EventArgs e)
{
CreateDyanamicUC(NumberOfDynamicControls);
NumberOfDynamicControls++;
}
private void RestoreDynamicUC()
{
if (NumberOfDynamicControls == 0)
return;
for (int i = 0; i < NumberOfDynamicControls; i++)
{
CreateDyanamicUC(i);
}
}
private void CreateDyanamicUC(int dataIndex)
{
if (_dynamicUCList == null)
{
_dynamicUCList = new List<DynamicUC>();
}
var dynamicUC = LoadControl("DynamicUC.ascx") as DynamicUC;
dynamicUC.PopulateData("Data " + dataIndex);
pnlDynamicUCPanel.Controls.Add(dynamicUC);
_dynamicUCList.Add(dynamicUC);
}
protected void btnGetUCValues_Click(object sender, EventArgs e)
{
var valuesText = "";
if (_dynamicUCList != null)
{
valuesText = string.Join(", ", _dynamicUCList.Select(duc => duc.GetData()));
}
lblUCValues.Text = "UC Values: " + valuesText;
}
}
There is a lot to explain; but I am afraid I have little time. But this should give some hint.
I am setting the datasource at the client side but the get_masterTableView returns null
var tableView = radGrid
.get_masterTableView();
i tried it setting on button click just to be sure that the Radgrid is completely created but it still returns null.. This is my code
<h4>Client Side Binding</h4>
<telerik:RadButton
ID="RadButton1"
AutoPostBack="False"
OnClientClicked="RadButton1_OnClientClicked"
runat="server"
Text="Load Items"></telerik:RadButton>
<telerik:RadGrid
ID="RadGrid1"
AutoGenerateColumns="False"
runat="server">
<MasterTableView>
<Columns>
<telerik:GridBoundColumn
DataField="Name"
HeaderText="Name">
</telerik:GridBoundColumn>
<telerik:GridBoundColumn
DataField="Age"
HeaderText="Age">
</telerik:GridBoundColumn>
<telerik:GridBoundColumn
DataField="Address.City"
HeaderText="City">
</telerik:GridBoundColumn>
</Columns>
</MasterTableView>
<ClientSettings>
<ClientEvents OnGridCreated="RadGrid1_OnGridCreated" />
</ClientSettings>
</telerik:RadGrid>
and this is on the Javascript
<telerik:RadScriptBlock runat="server">
<script>
function pageLoad(sender, args) {
//rebindGrid();
}
function RadButton1_OnClientClicked(sender, args) {
rebindGrid();
}
function RadGrid1_OnGridCreated(sender, args) {
//rebindGrid();
}
function rebindGrid() {
var ds = dataSource();
var radGrid = $find('<%= RadGrid1.ClientID %>');
var tableView = radGrid
.get_masterTableView();
console.log(radGrid);
if (tableView) {
tableView.set_dataSource(ds);
tableView.dataBind();
tableView.set_virtualItemCount(2);
} else {
alert('Table View is null');
}
}
function dataSource() {
var items = [];
items.push({
Name: 'Enteng',
Age: 25,
Address: {
City: 'Dipolog City'
}
});
items.push({
Name: 'Vincent',
Age: 27,
Address: {
City: 'Dumaguete City'
}
});
return items;
}
</script>
</telerik:RadScriptBlock>
pageLoad doesn't work
RadButton1_OnClientClicked doesn't work
RadGrid1_OnGridCreated doesn't work
any help would be appreciated..
TYI
OnGridCreated should work. I think there is a bug in your code:
This:
var radGrid = $find('<%= RadGrid1.ClientID %>');
should look like:
var radGrid = $find('#<%= RadGrid1.ClientID %>');
Alternatively you can use the sender argument to get a handle on your radgrid:
function RadGrid1_OnGridCreated(sender, args) {
rebindGrid(sender);
}
function rebindGrid(sender) {
var tableView = sender.get_masterTableView();
... etc
EDIT:
As stated in the comment below the problem is that the radgird is not bound to any data
source. Thus get_masterTableView() returns null.
The following piece of code, that binds the grid to a dummy data source, solves the problem:
protected void Page_Load(object sender, EventArgs e)
{
RadGrid1.DataSource = new List<int>();
}
There is a radgrid with one of the column as checkbox in
itemtemplate.
I want to loop through this radgrid's items. And based on each item's checkbox.checked condition, enable a seperate button control.(in client-side using javascript)
I've deviced code for this, but it is not giving the desired output.
What's wrong in this please.
Javascript:
<telerik:RadScriptBlock ID="scriptBlock1" runat="server">
<script type="text/javascript">
function checkRestrictionAcceptance()
{
var masterTable = $find("<%=RGGroupedCartRestrictedAssets.ClientID%>").get_masterTableView();
var count = masterTable.get_dataItems().length;
var checkbox;
var item;
for (var i = 0; i < count; i++)
{
item = masterTable.get_dataItems()[i];
checkbox = item.findElement("AcceptedCheckbox");
alert(checkbox.checked);
if (checkbox.checked)
{
var DownloadButton = document.getElementById('DownloadButton');
DownloadButton.enabled = false;
}
}
}
</script>
</telerik:RadScriptBlock>
Aspx:
<telerik:RadGrid ID="RGGroupedCartRestrictedAssets" runat="server" DataSourceID="CslaDSGroupedCartRestrictedAssets" AutoGenerateColumns="False"
GridLines="None" AllowPaging="True" AllowSorting="True" AllowFilteringByColumn="True" EnableEmbeddedSkins="false">
<MasterTableView DataSourceID="CslaDSGroupedCartRestrictedAssets" DataKeyNames="RestrictionText">
<Columns>
<telerik:GridTemplateColumn>
<ItemTemplate>
<asp:Checkbox ID="AcceptedCheckbox" runat="server" />
</ItemTemplate>
</Columns>
</MasterTableView>
</telerik:RadGrid>
<asp:Button ID="DownloadButton" runat="server" Text = "Test" OnClientClick ="checkRestrictionAcceptance();"/>
You need to specify the clientID of the DownloadButton
var DownloadButton = document.getElementById('<%=DownloadButton.ClientID%>');
I'm not sure which browser you're using, but I think that using the 'i' directly in get_dataItems() can be problematic with Firefox. Your code worked fine for me in IE10 using Telerik.Web.UI 2013.3.1324.45 - I am getting the value of checkbox.checked. Try this instead though, it might help:
function checkRestrictionAcceptance() {
var masterTable = $find("<%=RGGroupedCartRestrictedAssets.ClientID%>").get_masterTableView();
var count = masterTable.get_dataItems().length;
var checkbox;
var items = masterTable.get_dataItems();
for (var i = 0; i < count; i++) {
checkbox = items[i].findElement("AcceptedCheckbox");
alert(checkbox.checked);
if (checkbox.checked) {
var downloadButton = document.getElementById('<%=DownloadButton.ClientID%>');
downloadButton.enabled = false;
}
}
I'm roughly following the concept from this link. To simulate a nested GridView.
It looks like this:
Basically I'm creating a second row which is display:none and want to toggle it using JavaScript.
JavaScript and aspx code:
<script type="text/javascript" language="JavaScript">
function detailsToggle(Company_ID) {
try {
detail_row = document.getElementById('detailsRow_' + Company_ID);
parent_row = document.getElementById('parentRow_' + Company_ID);
img = parent_row.cells[0].firstChild;
if (detail_row.className !== 'hidden') {
detail_row.className = detail_row.className + ' hidden';
img.src = '../Images/icons/+.gif';
}
else {
detail_row.className = detail_row.className.replace(/\bhidden\b/, '');
img.src = '../Images/icons/-.gif';
}
}
catch(ex) { alert(ex); }
}
</script>
<style type="text/css">
.hidden
{
display: none;
}
</style>
<asp:GridView ID="gvLegalEntityBrowser" DataKeyNames="Company_ID" AutoGenerateColumns="False"
runat="server" CellPadding="4" ForeColor="#333333" GridLines="None"
OnRowDataBound="gvLegalEntityBrowser_RowDataBound" OnPageIndexChanging="pagingIndexChanged"
AllowPaging="True" PageSize="25" AllowSorting="false">
<AlternatingRowStyle BackColor="White" ForeColor="#284775" />
<Columns>
<asp:TemplateField>
<ItemTemplate>
<%--Placeholder --%>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="CompanyCode" HeaderText="CompanyCode" SortExpression="CompanyCode" />
<asp:BoundField DataField="CompanyName" HeaderText="CompanyName" SortExpression="CompanyName" />
</Columns>
<EmptyDataTemplate>No data</EmptyDataTemplate>
<EditRowStyle BackColor="#999999" />
<FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Center" />
<RowStyle BackColor="#F7F6F3" ForeColor="#333333" />
<SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" />
<SortedAscendingCellStyle BackColor="#E9E7E2" />
<SortedAscendingHeaderStyle BackColor="#506C8C" />
<SortedDescendingCellStyle BackColor="#FFFDF8" />
<SortedDescendingHeaderStyle BackColor="#6F8DAE" />
</asp:GridView>
... and my apsx.cs RowDataBound Method:
//Idea from : http://www.codeproject.com/Articles/160773/Expandable-Rows-in-GridView
protected void gvLegalEntityBrowser_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
GridViewRow gvRow = e.Row as GridViewRow;
Int64 iCompanyID = 0; //Get Company_ID for Legal Entity Row
iCompanyID = System.Convert.ToInt64(gvLegalEntityBrowser.DataKeys[gvRow.RowIndex]["Company_ID"]);
GridView gvLegalEntityRelation = new GridView();
gvRow.ID = "parentRow_" + iCompanyID;
gvRow.ClientIDMode = ClientIDMode.Static; //Set HTML ID element = control.ID
//Add javascript toggle button to each row
System.Web.UI.WebControls.ImageButton toggleButton = new System.Web.UI.WebControls.ImageButton();
toggleButton.ID = "btnToggle_" + iCompanyID;
toggleButton.ImageUrl = "../Images/icons/+.gif";
toggleButton.OnClientClick = "detailsToggle(" + (iCompanyID) + ")";
gvRow.Cells[0].Controls.Add(toggleButton);
toggleButton.Attributes.Add("onmouseover","this.style.cursor='hand'");
toggleButton.Attributes.Add("onmouseout", "this.style.cursor='default'");
using (dsLegalEntitiesTableAdapters.View_LegalEntityRelationCountTableAdapter daLERelCount = new dsLegalEntitiesTableAdapters.View_LegalEntityRelationCountTableAdapter())
{
//Set Details Data Source
gvLegalEntityRelation.DataSource = daLERelCount.GetRelationsDataByCompanyID(iCompanyID);
gvLegalEntityRelation.AutoGenerateColumns = true;
GridViewRow detailsgvRow = new GridViewRow(gvRow.RowIndex + 1, -1, DataControlRowType.EmptyDataRow, DataControlRowState.Normal);
detailsgvRow.CssClass = "hidden";
detailsgvRow.ID = "detailsRow_" + iCompanyID;
detailsgvRow.ClientIDMode = ClientIDMode.Static; //Set HTML ID element = control.ID
TableCell cell = new TableCell();
cell.ColumnSpan = 4;
cell.BorderStyle = BorderStyle.None;
cell.Controls.Add(gvLegalEntityRelation);
detailsgvRow.Cells.Add(cell);
((GridView)sender).Controls[0].Controls.Add(detailsgvRow);
gvLegalEntityRelation.DataBind();
}
}
}
The JavaScript works fine, and I even see the correct Result for a split second:
... but the the parent GridView rebuilds into something like this:
Q: Does anyone have an Idea what may be causing the GridView to rebuild??
So... the problem was actually quite basic. A colleague pointed this out to me.
I used an ImageButton to expand the inner table. The .NET image button has Click handler and ClientClick handler. Click tells what to do on PostBack, and ClientClick passes on to JavaScript.
Apparently, even if I don't define a target function for Click, the page still does a Post-Back. Thus first the javascript works, and then the page does a post-back, messing up the page.
Solution: exchange ImageButton for a simple image with click-event for javascript.