using System; using System.Collections; using System.Configuration; using System.Data; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Globalization; using System.Text; using System.Collections.Generic; public partial class FrozenGridHeader_Solution3 : System.Web.UI.Page { #region Variables private string[] _dateFormats = { "dd/MM/yyyy", "yyyyMMdd" }; private static DataProvider _controller; /// <summary> /// Stores the identifications of buttons. /// <para>Will be used to enable/disable all buttons.</para> /// </summary> System.Collections.Generic.LinkedList<String> _buttons; /// <summary> /// Number of visible columns /// </summary> private int _VisibleColumns = -1; private static DateTime? _from; private static DateTime? _to; #endregion #region Properties /// <summary> /// Number of visible columns /// </summary> private int VisibleColumns { get { if (_VisibleColumns == -1) { _VisibleColumns = 0; for (int i = 0; i < gridOrders.Columns.Count; i++) { if (gridOrders.Columns[i].Visible) _VisibleColumns++; } } return _VisibleColumns; } } #endregion #region Page Events protected void Page_Init(object sender, EventArgs e) { btnSearch.Click += new EventHandler(btnSearch_Click); } protected void Page_Load(object sender, EventArgs e) { PrepareExpandableLines(); SetupGridHeaderFreezing(); } private void SetupGridHeaderFreezing() { HeaderFreezeParameters parentGridPara = new HeaderFreezeParameters(); parentGridPara.GridCss_Class = "gridview_style"; parentGridPara.HeaderRowOnSight_CssClass = "parentgrid_header_row"; parentGridPara.FreezingPosition = 0; //Freeze table at the top of browser parentGridPara.ShowTableFreezingIcon = true; //Show the freezing icon HeaderFreezeParameters childGridPara = new HeaderFreezeParameters(); childGridPara.GridCss_Class = "childgridview_style"; childGridPara.HeaderRowOnSight_CssClass = "HeaderRowOnSight"; childGridPara.HeaderRowOutOfSight_CssClass = "HeaderRowOutOfSight"; childGridPara.FreezingPosition = 80; //80 is the height of header rows of parent grid. Child grid will freeze at the point which is under the top of browser as "80px". childGridPara.ShowTableFreezingIcon = true; List<HeaderFreezeParameters> objGridHeaderFreezeSettingList = new List<HeaderFreezeParameters>(); objGridHeaderFreezeSettingList.Add(parentGridPara); objGridHeaderFreezeSettingList.Add(childGridPara); GridHelper.FreezeTableHeader(objGridHeaderFreezeSettingList); } /// <summary> /// Releases allocated memory /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Page_UnLoad(object sender, EventArgs e) { if (_controller != null) { _controller.Dispose(); _controller = null; } } #endregion #region Grid Events /// <summary> /// Function : AddMergedCells /// Purpose: Adds merged cell in the header /// </summary> /// <param name="objgridviewrow"></param> /// <param name="objtablecell"></param> /// <param name="colspan"></param> /// <param name="celltext"></param> private static void AddMergedCells(GridViewRow objgridviewrow, TableCell objtablecell, int colspan, string celltext) { objtablecell.ColumnSpan = colspan; if(celltext != "") objtablecell.Text = celltext; objgridviewrow.Cells.Add(objtablecell); } protected void gridOrders_RowCreated(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.Header) { //e.Row.Cells[0].RowSpan = 2; //e.Row.Cells[1].RowSpan = 2; //e.Row.Cells[2].RowSpan = 2; //e.Row.Cells[3].RowSpan = 2; //e.Row.Cells[4].RowSpan = 2; ////TableCell mergeCell = new TableCell(); ////mergeCell.Text = "Ship Information"; ////mergeCell.ColumnSpan = 2; //e.Row.Cells[5].ColumnSpan = 2; ////Creating a gridview row object //GridViewRow objgridviewrow = new GridVieRow(1, 0, DataControlRowType.Header, DataControlRowState.Insert); ////Creating a table cell object //TableCell objtablecell; //objtablecell = e.Row.Cells[6]; //AddMergedCells(objgridviewrow, objtablecell, 1); ////e.Row.Cells.RemoveAt(6); //objtablecell = e.Row.Cells[7]; //AddMergedCells(objgridviewrow, objtablecell, 1); ////e.Row.Cells.RemoveAt(7); //e.Row.Cells[6].RowSpan = 2; //e.Row.Cells[7].RowSpan = 2; //gridOrders.Controls[0].Controls.AddAt(0, objgridviewrow); //Creating a gridview row object GridViewRow objgridviewrow = new GridViewRow(1, 0, DataControlRowType.Header, DataControlRowState.Insert); objgridviewrow.CssClass = "parentgrid_header_row"; //Creating a table cell object TableCell objtablecell = new TableHeaderCell(); objtablecell.RowSpan = 2; objtablecell.Text = e.Row.Cells[0].Text; objtablecell.ApplyStyle(e.Row.Cells[0].ControlStyle); AddMergedCells(objgridviewrow, objtablecell, 1, ""); objtablecell = new TableHeaderCell(); objtablecell.RowSpan = 2; objtablecell.Text = e.Row.Cells[1].Text; objtablecell.ApplyStyle(e.Row.Cells[0].ControlStyle); AddMergedCells(objgridviewrow, objtablecell, 1, ""); objtablecell = new TableHeaderCell(); objtablecell.ApplyStyle(e.Row.Cells[0].ControlStyle); AddMergedCells(objgridviewrow, objtablecell, 3, "Basic Information"); objtablecell = new TableHeaderCell(); objtablecell.ApplyStyle(e.Row.Cells[0].ControlStyle); AddMergedCells(objgridviewrow, objtablecell, 2, "Ship Information"); objtablecell = new TableHeaderCell(); objtablecell.RowSpan = 2; objtablecell.Text = e.Row.Cells[7].Text; objtablecell.ApplyStyle(e.Row.Cells[0].ControlStyle); AddMergedCells(objgridviewrow, objtablecell, 1, ""); objtablecell = new TableHeaderCell(); objtablecell.RowSpan = 2; objtablecell.ApplyStyle(e.Row.Cells[0].ControlStyle); AddMergedCells(objgridviewrow, objtablecell, 1, ""); gridOrders.Controls[0].Controls.AddAt(0, objgridviewrow); e.Row.Cells.RemoveAt(0); //Remove the first column e.Row.Cells.RemoveAt(0); //Remove the second column e.Row.Cells.RemoveAt(5); //Remove the 7th column e.Row.Cells.RemoveAt(5); //Remove the 8th column } if (e.Row.RowType == DataControlRowType.DataRow) { Label lblRowNo = (Label)(e.Row.Cells[0].Controls[0]); //Set Label text equal to the rowIndex +1 lblRowNo.Text = (e.Row.RowIndex + 1).ToString(); } } /// <summary> /// Called after the main grid was bound /// <para>Will create a Javascrip array, used to enable/disable the buttons</para> /// <para>See function EnableExpandButtons in ExpandPanel.js</para> /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void gridOrders_DataBound(object sender, EventArgs e) { if (_buttons != null && _buttons.Count > 0) { foreach (string element in _buttons) { ScriptManager.RegisterArrayDeclaration( this.Page, "ExpandButtons", // The array's name String.Format(CultureInfo.InvariantCulture, "'{0}'", element)); // The button ID } } //String arrValue = "\"10284\", \"11077\", \"10251\""; ScriptManager.RegisterArrayDeclaration(this, "amoutCells", _arrAmountCells); //Re setup Freezing function //SetupFrozenGridHeaderRow(); SetupGridHeaderFreezing(); } private string _arrAmountCells = ""; //private string[] _arrCellWidth = new string[20]; /// <summary> /// Called for each row of the main grid, calls a method to prepare the details /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void gridOrders_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType != DataControlRowType.DataRow) return; try { //if (e.Row.RowIndex == 0) //{ // for (int j = 0; j < e.Row.Cells.Count; j++) // { // _arrCellWidth[j] = e.Row.Cells[j].Style["width"]; // } //} //if (e.Row.RowIndex == 1) //{ // for (int j = 0; j < e.Row.Cells.Count; j++) // { // e.Row.Cells[j].Style.Add("width", _arrCellWidth[j]); // } //} Order orderRow = e.Row.DataItem as Order; GridViewRow gridRow = e.Row; Label lblOrderAmount = gridRow.FindControl("lblOrderAmount") as Label; _arrAmountCells = string.Format("{0}\"{1}:{2}\"", (_arrAmountCells == "" ? "" : _arrAmountCells + ","), lblOrderAmount.ClientID, orderRow.OrderID); lblOrderAmount.ID = orderRow.OrderID.ToString(); lblOrderAmount.Text = String.Format("{0:#,##0;($#,##0);Zero}", _controller.SumOrderAmount(orderRow.OrderID)); BuildNestedPanel(gridRow, orderRow); } catch (System.Exception ex) { ShowErrorMessage(ex.Message); } } #endregion #region ObjectDataSource Events /// <summary> /// Instantiates the business logic layer object, in order to fill the main grid /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void odsOrders_ObjectCreating(object sender, ObjectDataSourceEventArgs e) { try { _controller = new DataProvider(); e.ObjectInstance = _controller; } catch (System.Exception ex) { ShowErrorMessage(ex.Message); } } /// <summary> /// Select simulated or data base stored data /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void odsOrders_Selecting(object sender, ObjectDataSourceSelectingEventArgs e) { btnSearch_Click(null, null); if (e.ExecutingSelectCount) return; e.InputParameters["from"] = _from; e.InputParameters["to"] = _to; } /// <summary> /// This method is called when the object odsStores releases memory used by the business logic layer object. /// <para>If some error was found when reading from database, this method will show the error message.</para> /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void odsOrders_ObjectDisposing(object sender, ObjectDataSourceDisposingEventArgs e) { DataProvider controller = e.ObjectInstance as DataProvider; if (controller != null && controller.Error) { ShowErrorMessage(controller.Exception); gridOrders.Visible = false; } e.Cancel = true; } #endregion #region Control Events protected void btnSearch_Click(object sender, EventArgs e) { try { //Parameters Handling: //Parse parameters and pass on to the underlying ObjectDataSource txtFromDate.Text = txtFromDate.Text.Replace("__/__/____", ""); txtToDate.Text = txtToDate.Text.Replace("__/__/____", ""); if (string.IsNullOrEmpty(txtFromDate.Text)) _from = null; else _from = DateTime.ParseExact(txtFromDate.Text, _dateFormats, CultureInfo.CurrentCulture, DateTimeStyles.None); if (string.IsNullOrEmpty(txtToDate.Text)) _to = null; else _to = DateTime.ParseExact(txtToDate.Text, _dateFormats, CultureInfo.CurrentCulture, DateTimeStyles.None); //End Of Parameters Handling PrepareExpandableLines(); } catch (System.Exception ex) { ShowErrorMessage(ex.Message); } } #endregion #region Private Methods #region Dynamically populate data on demand /// <summary> /// Register the script to expand/contract details in order to show order details /// </summary> private void PrepareExpandableLines() { // First, handle some specifics from Firefox // Reference : IE/Firefox show/hide/colspan // http://forums.codewalkers.com/client-side-things-82/ie-firefox-show-hide-colspan-902435.html string StyleDisplayBlock = "block"; if (this.Request.Browser.Browser.ToLower() == "firefox") { StyleDisplayBlock = "table-row"; } //Added by Henry Truong, 2012/10/30 if (Request.UserAgent.ToLower().IndexOf("chrome") > 0) { StyleDisplayBlock = "table-row"; } string js = String.Format(CultureInfo.InvariantCulture, "var StyleDisplayBlock = '{0}';\n;"+ "var ExpandableLines = '{1}';\n", StyleDisplayBlock, pnlExpandableLines.ClientID); ScriptManager.RegisterClientScriptBlock(this.Page, this.Page.GetType(), "StyleDisplayBlock", js, true); // Then, include the script ScriptManager.RegisterClientScriptInclude( this.Page, this.Page.GetType(), "expand_models", "JS/ExpandPanel.js"); } /// <summary> /// Builds a string to populate the expanded line with the models /// </summary> /// <param name="contextKey">CustomerId + radSimulatedData.Checked, separated by '-'</param> /// <returns>HTML table filled with drilled down data</returns> [System.Web.Services.WebMethod(CacheDuration = 45, Description = "Get data")] [System.Web.Script.Services.ScriptMethod] public static string DataDrillDownService(string contextKey) { #if DEBUG // Small delay to provide time to show 'loading.gif' System.Threading.Thread.Sleep(1000); #endif StringBuilder sb = new StringBuilder(); System.Collections.Generic.List<OrderDetail> objOrderDetails = null; // Extracts OrderID and 'chkCachedData.Checked' from the context key string[] keys = contextKey.Split('-'); bool cachedData = (keys[1][0] == '1'); int orderID = 0; bool hasError = false; if (!Int32.TryParse(keys[0], out orderID)) { // TODO: Error LOG hasError = true; sb.Append("<span class=\"error-models\">ERROR : Can not load the detail data</span>"); } else { try { objOrderDetails = (System.Collections.Generic.List<OrderDetail>)(new DataProvider()).GetOrderDetails(orderID); } catch (System.Exception ex) { // TODO: Error LOG hasError = true; sb.Append("<span class=\"error-models\">ERROR : Can not get the data. Details: " + ex.Message + "</span>"); } if (!hasError) { if (objOrderDetails == null || objOrderDetails.Count == 0) { sb.Append("<span class=\"notfound-models\">Order details do not found for this order.</span>"); } else { sb.Append(PopulateDetailsTable(objOrderDetails)); } } } if (objOrderDetails != null) { objOrderDetails = null; } return sb.ToString(); ; } /// <summary> /// Populates a HTML table with the order detail data /// </summary> /// <param name="topModels">Data about the order detail</param> /// <returns>HTML table filled with order details</returns> private static string PopulateDetailsTable(System.Collections.Generic.List<OrderDetail> objOrderDetails) { StringBuilder sb = new StringBuilder("<table id='tblDrillDown' class = 'childgridview_style'> \n" + "<tr height='40px' class='HeaderRowOnSight'> \n" + "<th>ProductName</th> \n" + "<th>Unit Price</th> \n" + "<th>Quantity</th> \n" + "<th>Discount</th> \n" + "</tr> \n", objOrderDetails.Count * 180); foreach (OrderDetail orderDetail in objOrderDetails) { sb.Append("<tr> \n"); sb.AppendFormat(CultureInfo.CurrentCulture, "<td>{0}</td> ", orderDetail.ProductName); sb.AppendFormat(CultureInfo.CurrentCulture, "<td class=\"cellright\">{0}</td> ", orderDetail.UnitPrice); sb.AppendFormat(CultureInfo.CurrentCulture, "<td class=\"cellright\">{0:n2}</td> ", orderDetail.Quantity); sb.AppendFormat(CultureInfo.CurrentCulture, "<td class=\"cellcenter\">{0}</td> ", orderDetail.Discount); sb.Append("</tr> \n"); } sb.Append("</table> \n"); return sb.ToString(); } /// <summary> /// Shows a generic error message to the user /// </summary> private void ShowErrorMessage(string message) { lblMsgErroTitulo.Text = "ERROR"; lblMsgErro.Text = "Can not query the database. Error: " + message; popupMsgErro.Show(); } /// <summary> /// Prepares to show the details for one order. /// <para>A new hidden row is inserted below the current row in the grid.</para> /// <para>That row will have only one cell, spanned to the entire row.</para> /// <para>Inside the new row, a panel is inserted as a simple HTML 'fieldset', just to show a border and some header.</para> /// <para>Inside the fieldset, a new panel is inserted. That panel will be filled with details when the user click the button.</para> /// </summary> /// <param name="gridViewRow">One row from the main grid</param> /// <param name="orderRow">One order</param> private void BuildNestedPanel(GridViewRow gridViewRow, Order orderRow) { // Gets the index for the new row Table htmlTab = gridOrders.Controls[0] as Table; int newRowIndex = htmlTab.Rows.GetRowIndex(gridViewRow) + 1; // Creates two panels : external and internal // External panel : A simple <fieldset> System.Web.UI.WebControls.Panel externalPanel = new Panel(); externalPanel.EnableViewState = false; externalPanel.GroupingText = "Order Detail"; externalPanel.ID = String.Format(CultureInfo.InvariantCulture, "pDrillDownE_{0}", newRowIndex); externalPanel.CssClass = "expand-panel"; // Internal panel : A <div> as a container for the nested grid System.Web.UI.WebControls.Panel internalPanel = new Panel(); internalPanel.EnableViewState = false; internalPanel.ID = String.Format(CultureInfo.InvariantCulture, "pDrillDown_{0}", newRowIndex); externalPanel.Controls.Add(internalPanel); // Inserts the panels in one cell TableCell cell = new TableCell(); //cell.HorizontalAlign = HorizontalAlign.Left; cell.BorderStyle = BorderStyle.None; cell.Controls.Add(externalPanel); cell.ColumnSpan = VisibleColumns; // Inserts the cell in a collection of cell (only one cell) TableCell[] cells = new TableCell[1]; cells[0] = cell; // Inserts one row under the current row GridViewRow newRow = new GridViewRow( newRowIndex, newRowIndex, DataControlRowType.DataRow, DataControlRowState.Normal); newRow.ID = String.Format(CultureInfo.InvariantCulture, "linM_{0}", newRowIndex); newRow.Style.Add(HtmlTextWriterStyle.Display, "none"); // Inserts the cell in the new row newRow.Cells.AddRange(cells); // Inserts the new row in the controls collection of the table (grid) htmlTab.Controls.AddAt(newRowIndex, newRow); string contextKey = String.Format(CultureInfo.InvariantCulture, "{0}-{1}", orderRow.OrderID, (chkCachedData.Checked ? 1 : 0)); // Locates the button and prepares the 'onclick' event Image btn = gridViewRow.FindControl("imgModel") as Image; //CssClass = "shadowed" btn.Attributes.Add("onmouseover", "this.classList.add('shadowed')"); btn.Attributes.Add("onmouseout", "this.classList.remove('shadowed')"); //btn.Attributes.Add("onmouseover", "if(this.src.endsWith('Images/expand.gif')) this.src='Images/expand_mouseover.gif'"); //btn.Attributes.Add("onmouseout", "if(this.src.endsWith('Images/expand_mouseover.gif')) this.src='Images/expand.gif'"); btn.Attributes["onClick"] = String.Format(CultureInfo.InvariantCulture, "ExpandDetails('{0}', '{1}', '{2}', '{3}');", contextKey, newRow.ClientID, internalPanel.ClientID, btn.ClientID); // Insert the ID into the buttons list if (_buttons == null) _buttons = new System.Collections.Generic.LinkedList<string>(); _buttons.AddLast(btn.ClientID); } #endregion #endregion }
By viewing downloads associated with this article you agree to the Terms of use and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
Skills that self-taught computer programmers lack