void RadPivotGrid1_CellDataBound(object sender, PivotGridCellDataBoundEventArgs e) { PivotGridDataCell cell = e.Cell as PivotGridDataCell; if (cell != null) { // We do not need to attach onclick event on cell which does not have values if (cell.DataItem != null) { string argument = GetCommandArguments(cell); string script = string.Format("OpenDetailsWindow('{0}')", argument); cell.Attributes.Add("onclick", script); } index++; } }<script type="text/javascript"> function OpenDetailsWindow(argument) { $find("<%= RadAjaxPanel1.ClientID %>").ajaxRequest(argument); }</script>private void AdjustRowAndColumnIndexes(PivotGridDataCell cell, ref int rowIndexesCount, ref int columnIndexesCount){ //if aggregates are more than one additional cells are rendered, so we need to exclude their values from the query if (aggregateFields.Count > 1) { if (RadPivotGrid1.AggregatesPosition == PivotGridAxis.Columns) { if (cell.CellType == PivotGridDataCellType.DataCell || cell.CellType == PivotGridDataCellType.RowTotalDataCell || cell.CellType == PivotGridDataCellType.RowAndColumnTotal || cell.CellType == PivotGridDataCellType.RowGrandTotalDataCell || cell.CellType == PivotGridDataCellType.ColumnGrandTotalRowTotal) { columnIndexesCount--; } } else { if (cell.CellType != PivotGridDataCellType.RowTotalDataCell && cell.CellType != PivotGridDataCellType.ColumnGrandTotalRowTotal) { rowIndexesCount--; } } } // if row total or grand total cell is hit we need to escape its values from query if (cell.CellType == PivotGridDataCellType.RowTotalDataCell || cell.CellType == PivotGridDataCellType.ColumnGrandTotalRowTotal || cell.CellType == PivotGridDataCellType.RowGrandTotalDataCell) { rowIndexesCount--; } // if column total or grand total cell is hit we need to escape its values from query if (cell.CellType == PivotGridDataCellType.ColumnTotalDataCell || cell.CellType == PivotGridDataCellType.ColumnGrandTotalDataCell || cell.CellType == PivotGridDataCellType.RowGrandTotalColumnTotal || cell.CellType == PivotGridDataCellType.RowAndColumnTotal || cell.CellType == PivotGridDataCellType.ColumnGrandTotalRowTotal) { columnIndexesCount--; } }int index = 0;int[] allFakeColumnCells = null;bool isFirstDataCell = true;int countOfFakeRowCells = 0;int cellsCount = 0;string firstRowID = string.Empty;string currentRowID = string.Empty;int key = 0;void RadPivotGrid1_CellDataBound(object sender, PivotGridCellDataBoundEventArgs e){ PivotGridDataCell cell = e.Cell as PivotGridDataCell; if (cell != null) { // If this is the first data cell we need to populate the collection whith fake columns cells count if (isFirstDataCell) { PopulateFakeColumnsCellCollection(cell); isFirstDataCell = false; } // We do not need to attach onclick event on cell which does not have values if (cell.DataItem != null) { string argument = GetCommandArguments(cell); string script = string.Format("OpenDetailsWindow('{0}')", argument); cell.Attributes.Add("onclick", script); } index++; }}// This methos is executed only for the first cell from the first rowprivate void PopulateFakeColumnsCellCollection(PivotGridDataCell cell){ PivotGridDataItem item = cell.NamingContainer as PivotGridDataItem; cellsCount = item.Cells.Count; allFakeColumnCells = new int[cellsCount]; firstRowID = item.UniqueID; for (int i = 0; i < cellsCount; i++) { int countOfFakeCells = GetCountOfFakeColumnCells(item.Cells[i] as PivotGridDataCell); allFakeColumnCells[i] = countOfFakeCells; }}private int GetCountOfFakeRowCells(PivotGridDataCell cell){ int count = 0; //if aggregates are more than one additional cells are rendered, so we need to exclude their values from the query if (aggregateFields.Count > 1) { if (RadPivotGrid1.AggregatesPosition == PivotGridAxis.Rows) { if (cell.CellType != PivotGridDataCellType.RowTotalDataCell && cell.CellType != PivotGridDataCellType.ColumnGrandTotalRowTotal) { count++; } } } // if row total or grand total cell is hit we need to escape its values from query if (cell.CellType == PivotGridDataCellType.RowTotalDataCell || cell.CellType == PivotGridDataCellType.ColumnGrandTotalRowTotal || cell.CellType == PivotGridDataCellType.RowGrandTotalDataCell) { count++; } return count;}public string GetCommandArguments(PivotGridDataCell cell){ // True when first cell of each row is hit if (currentRowID != cell.NamingContainer.UniqueID) { index = 0; currentRowID = cell.NamingContainer.UniqueID; countOfFakeRowCells = GetCountOfFakeRowCells(cell); } object[] rowIndexes = cell.ParentRowIndexes; object[] columnIndexes = cell.ParentColumnIndexes; int rowIndexesCount = rowIndexes.Count(); int columnIndexesCount = columnIndexes.Count(); int countOfFakeColumnCells = allFakeColumnCells[index]; rowIndexesCount -= countOfFakeRowCells; columnIndexesCount -= countOfFakeColumnCells; StringBuilder buider = BuildArguments(rowIndexes, columnIndexes, rowIndexesCount, columnIndexesCount); return buider.ToString();}private int GetCountOfFakeColumnCells(PivotGridDataCell cell){ int count = 0; if (aggregateFields.Count > 1) { if (RadPivotGrid1.AggregatesPosition == PivotGridAxis.Columns) { if (cell.CellType == PivotGridDataCellType.DataCell || cell.CellType == PivotGridDataCellType.RowTotalDataCell || cell.CellType == PivotGridDataCellType.RowAndColumnTotal || cell.CellType == PivotGridDataCellType.RowGrandTotalDataCell || cell.CellType == PivotGridDataCellType.ColumnGrandTotalRowTotal) { count++; } } } // if column total or grand total cell is hit we need to escape its values from query if (cell.CellType == PivotGridDataCellType.ColumnTotalDataCell || cell.CellType == PivotGridDataCellType.RowAndColumnTotal || cell.CellType == PivotGridDataCellType.ColumnGrandTotalRowTotal || cell.CellType == PivotGridDataCellType.ColumnGrandTotalDataCell || cell.CellType == PivotGridDataCellType.RowGrandTotalColumnTotal) { count++; } return count;}public Dictionary<int, string> Arguments{ get { if (Session["Arguments"] == null) { Session["Arguments"] = new Dictionary<int, string>(); } return Session["Arguments"] as Dictionary<int, string>; } set { Session["Arguments"] = value; }}public string GetCommandArguments(PivotGridDataCell cell) { … StringBuilder buider = BuildArguments(rowIndexes, columnIndexes, rowIndexesCount, columnIndexesCount); return buider.ToString(); }private StringBuilder BuildArguments(object[] rowIndexes, object[] columnIndexes, int rowIndexesCount, int columnIndexesCount) { StringBuilder buider = new StringBuilder(); ReplaceArgumentsWithNumbers(rowIndexes, rowFields, rowIndexesCount, buider); ReplaceArgumentsWithNumbers(columnIndexes, columnFields, columnIndexesCount, buider); // Remove the semicolon in the end if (buider.Length > 1) { buider.Remove(buider.Length - 1, 1); } return buider; } private void ReplaceArgumentsWithNumbers(object[] cellIndexes, List<PivotGridField> fields, int indexesCount, StringBuilder buider) { for (int i = 0; i < indexesCount; i++) { string firstPart = fields[i].DataField; string secondPart = cellIndexes[i].ToString(); if (Arguments.ContainsValue(firstPart)) { buider.Append(Arguments.FirstOrDefault(a => a.Value == firstPart).Key); AppendSecondParts(buider, secondPart); } else { Arguments.Add(key, firstPart); buider.Append(string.Format("{0}", key.ToString())); key++; AppendSecondParts(buider, secondPart); } } } private void AppendSecondParts(StringBuilder buider, string secondPart) { if (Arguments.ContainsValue(secondPart)) { buider.Append(string.Format("~{0};", Arguments.FirstOrDefault(a => a.Value == secondPart).Key)); } else { Arguments.Add(key, secondPart); buider.Append(string.Format("~{0};", key.ToString())); key++; } }void RadAjaxPanel1_AjaxRequest(object sender, AjaxRequestEventArgs e) { StringBuilder whereClause = new StringBuilder(); if (!string.IsNullOrEmpty(e.Argument.ToString())) { string[] elements = e.Argument.ToString().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var element in elements) { var group = element.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries); int firstPart = Convert.ToInt32(group[0]); int secondPart = Convert.ToInt32(group[1]); whereClause.Append(string.Format("{0} = '{1}' AND ", Arguments[firstPart], Arguments[secondPart])); } … }Radoslav Kirilov is a software developer at one of Telerik’s ASP.NET AJAX teams. Ever since he joined the company in 2009, he has been working on the data-bound and date-picker controls. His interests are primarily concentrated on ASP.NET, AJAX, MVC, SQL and best practices.