| using System; |
| using System.Collections.Generic; |
| using System.Diagnostics; |
| using System.Linq; |
| using System.Web; |
| using System.Web.UI; |
| using System.Web.UI.WebControls; |
| using Telerik.Web.UI; |
| |
| namespace gridTest |
| { |
| public class RadGridEx : RadGrid |
| { |
| protected override void ControlPreRender() |
| { |
| EnsureColumnsOrder(); |
| base.ControlPreRender(); |
| } |
| |
| /// <summary> |
| /// Method checks columns sequence and re-orders columns if needed to make them |
| /// all appear within the group they belong. This required in case columns order does not |
| /// much their groupping |
| /// </summary> |
| private void EnsureColumnsOrder() |
| { |
| var groupingColumns = GetGroupingColumns(); |
| foreach (var groupColumn in groupingColumns) |
| { |
| List<GridColumn> columns = new List<GridColumn>(groupColumn.ColumnNames.Length); |
| foreach (string column in groupColumn.ColumnNames) |
| columns.Add(MasterTableView.Columns.FindByDataField(column)); |
| columns.Sort((x, y) => x.OrderIndex.CompareTo(y.OrderIndex)); |
| int minOrder = columns.Min(x => x.OrderIndex); |
| for (int i = 0; i < columns.Count; ++i) |
| { |
| int newIndex = minOrder + i; |
| if (columns[i].OrderIndex != newIndex) |
| { |
| // To change column's order we need to increment order of |
| // following columns |
| Array.ForEach( |
| Array.FindAll(MasterTableView.RenderColumns, x => x != columns[i] && x.OrderIndex >= newIndex), |
| x => ++x.OrderIndex); |
| columns[i].OrderIndex = newIndex; |
| } |
| } |
| } |
| // Apply re-ordering |
| MasterTableView.SetLevelRequiresBinding(); |
| } |
| |
| protected override void RenderContents(HtmlTextWriter writer) |
| { |
| if (ContainsGroupingColumn()) |
| AddGroupingRow(); |
| base.RenderContents(writer); |
| } |
| |
| private bool ContainsGroupingColumn() |
| { |
| return MasterTableView.RenderColumns.Any(x => x is GridGroupingColumn); |
| } |
| |
| /// <summary> |
| /// Addds an additional row from the top for grouping columns |
| /// </summary> |
| private void AddGroupingRow() |
| { |
| var groupingColumns = GetGroupingColumns(); |
| var renderColumns = MasterTableView.RenderColumns; |
| var columnGroupsMapping = new Dictionary<string, GridGroupingColumn>(renderColumns.Length); |
| //Map columns to their groups |
| foreach (var groupColumn in groupingColumns) |
| { |
| foreach (string column in groupColumn.ColumnNames) |
| { |
| Debug.Assert(!columnGroupsMapping.ContainsKey(column), |
| string.Format("Column '{0}' alredy belons to another group'", column)); |
| columnGroupsMapping[column] = groupColumn; |
| } |
| groupColumn.ColSpan = groupColumn.ColumnNames.Length; |
| } |
| |
| // Now every ungrouped column will belong to an "empty" group |
| // which will gather sequence of such columns. For the columns with groups |
| // appropriate group columns will be added to the table head |
| List<GridGroupingColumn> headGroupingColumns = new List<GridGroupingColumn>(); |
| int ungroupedCount = 0; |
| GridGroupingColumn currentGroup = null; |
| foreach (var column in renderColumns) |
| { |
| if (!column.Visible) |
| continue; |
| string columnName = GetColumnName(column); |
| if (!columnGroupsMapping.ContainsKey(columnName)) |
| { |
| //Count number of ungrouped columns in a sequence |
| // this is needed to assign ColSpan to the empty group column |
| ++ungroupedCount; |
| |
| if (currentGroup != null) |
| { |
| headGroupingColumns.Add(currentGroup); |
| currentGroup = null; |
| } |
| |
| } |
| else |
| { |
| if (ungroupedCount > 0) |
| { |
| // Create "dummy" group for ungrouped sequence of columns |
| GridGroupingColumn empty = new GridGroupingColumn(); |
| empty.ColSpan = ungroupedCount; |
| headGroupingColumns.Add(empty); |
| ungroupedCount = 0; |
| } |
| |
| if (currentGroup != columnGroupsMapping[columnName]) |
| { |
| if (currentGroup != null) |
| headGroupingColumns.Add(currentGroup); |
| currentGroup = columnGroupsMapping[columnName]; |
| } |
| } |
| } |
| // Ensure we finilize all groups |
| if (ungroupedCount > 0) |
| { |
| GridGroupingColumn empty = new GridGroupingColumn(); |
| empty.ColSpan = ungroupedCount; |
| headGroupingColumns.Add(empty); |
| } |
| else if (currentGroup != null) |
| { |
| if (headGroupingColumns.Count == 0 || currentGroup != headGroupingColumns[headGroupingColumns.Count - 1]) |
| headGroupingColumns.Add(currentGroup); |
| } |
| |
| //Insert grouping item to the grid root |
| // Note: this is a little bit of "hack" because we are |
| // intruding into RadGrid controls structure which |
| // may be changed in farther releases |
| var table = (Table)MasterTableView.Controls[0]; |
| var tHead = (GridTHead)table.Rows[0]; |
| var headerItem = new GridHeaderItem(MasterTableView, 0, 0); |
| headerItem.Initialize(headGroupingColumns.ToArray()); |
| tHead.Controls.AddAt(0, headerItem); |
| } |
| |
| /// <summary> |
| /// Returns column name which can be used to identify column. |
| /// If UniqueName is not specified then function checks column type |
| /// and gets most allowable uniq name equivalent |
| /// </summary> |
| /// <param name="column">Grid column</param> |
| /// <returns>Uniq name</returns> |
| private string GetColumnName(GridColumn column) |
| { |
| if (!string.IsNullOrEmpty(column.UniqueName)) |
| return column.UniqueName; |
| if (column is GridBoundColumn) |
| return ((GridBoundColumn)column).DataField; |
| if (column is GridButtonColumn) |
| return ((GridButtonColumn)column).CommandName; |
| if (column is GridTemplateColumn) |
| return ((GridTemplateColumn)column).DataField; |
| return string.Empty; |
| } |
| |
| private GridGroupingColumn[] GetGroupingColumns() |
| { |
| List<GridGroupingColumn> cols = new List<GridGroupingColumn>(); |
| foreach (var col in MasterTableView.Columns) |
| if (col is GridGroupingColumn) |
| cols.Add((GridGroupingColumn)col); |
| return cols.ToArray(); |
| } |
| |
| } |
| public class GridGroupingColumn : GridColumn |
| { |
| private string[] columnNames; |
| private string groupingColumns; |
| internal int ColSpan { get; set; } |
| |
| public override bool Visible |
| { |
| get { return false; } |
| } |
| public string[] ColumnNames |
| { |
| get { return columnNames; } |
| } |
| |
| public string GroupingColumns |
| { |
| get { return groupingColumns; } |
| set |
| { |
| groupingColumns = value; |
| columnNames = value.Split(','); |
| for (int i = 0; i < columnNames.Length; ++i) |
| columnNames[i] = columnNames[i].Trim(); |
| } |
| } |
| |
| public override void InitializeCell(TableCell cell, int columnIndex, GridItem inItem) |
| { |
| if (Owner != null) |
| { |
| base.InitializeCell(cell, columnIndex, inItem); |
| //This is just to make sure column is formed well |
| cell.Style.Add(HtmlTextWriterStyle.BorderColor, "#000000"); |
| cell.Style.Add(HtmlTextWriterStyle.BorderWidth, "1px"); |
| cell.Style.Add(HtmlTextWriterStyle.BorderStyle, "solid"); |
| } |
| |
| cell.CssClass = "rgHeader"; |
| cell.Text = HeaderText; |
| cell.Controls.Add(new LiteralControl(HeaderText)); |
| |
| cell.ColumnSpan = ColSpan; |
| cell.HorizontalAlign = HorizontalAlign.Center; |
| } |
| |
| |
| public override GridColumn Clone() |
| { |
| var c = new GridGroupingColumn(); |
| c.CopyBaseProperties(this); |
| return c; |
| } |
| } |
| } |
| |