/// <summary> /// Throws exception for the row other DataRow/UnBound Row that tries to span /// </summary> /// <param name="range"></param> internal void ContainsRow(CoveredCellInfo range) { var rows = dataGrid.RowGenerator.Items.Where(row => row.RowIndex >= range.Top && row.RowIndex <= range.Bottom); if (!(rows.Any())) { return; } rows.ForEach(row => { if (range.ContainsRow(row.RowIndex) && (row.RowType != RowType.DefaultRow && row.RowType != RowType.UnBoundRow || row.RowType == RowType.AddNewRow)) { throw new Exception(string.Format("Given range {0} is not valid with the row type {1}", range, row.RowType)); } // Throw exception when the invalid parent row merges. if (this.dataGrid.DetailsViewDefinition.Count > 0 && this.dataGrid.IsInDetailsViewIndex(row.RowIndex + this.dataGrid.DetailsViewDefinition.Count)) { foreach (var viewDefinition in this.dataGrid.DetailsViewDefinition) { var itemSource = this.dataGrid.DetailsViewManager.GetChildSource(row.RowData, viewDefinition.RelationalColumn); if (DetailsViewHelper.GetChildSourceCount(itemSource) > 0) { throw new Exception(string.Format("Given range {0} is not valid with the details view row", range)); } } } }); }
/// <summary> /// Check whther any othe childview contains records /// </summary> /// <param name="record">RecordEntry</param> /// <returns>true if any child contains record</returns> internal static bool HasChildSource(this DetailsViewManager manager, RecordEntry record) { var provider = manager.DataGrid.View.GetPropertyAccessProvider(); foreach (var definition in manager.DataGrid.DetailsViewDefinition) { var childSource = provider.GetValue(record.Data, definition.RelationalColumn) as IEnumerable; if (childSource != null && DetailsViewHelper.GetChildSourceCount(childSource) > 0) { return(true); } } return(false); }
/// <summary> /// Decides whether to merge the adjacent parent rows based on child source of row data. /// </summary> /// <param name="dataGrid">The SfDataGrid.</param> /// <param name="rowData">Specifies the data object to find the child items source.</param> /// <returns> /// Returns <b>true</b> if the DetialsViewDataGrid has items source; otherwise, <b>false</b>. /// </returns> public static bool CanMergeNextRows(this SfDataGrid dataGrid, object rowData) { if (!dataGrid.HideEmptyGridViewDefinition) { return(false); } foreach (var viewDefinition in dataGrid.DetailsViewDefinition) { var itemSource = dataGrid.DetailsViewManager.GetChildSource(rowData, viewDefinition.RelationalColumn); if (DetailsViewHelper.GetChildSourceCount(itemSource) > 0) { return(false); } } return(true); }
internal static int GetChildSourceCount(object source) { //(WPF -37043) To avoid break the below method is called here. return(DetailsViewHelper.GetChildSourceCount(source)); }
internal override List <int> ExpandDetailsView(int rowIndex, RecordEntry record, Dictionary <string, IEnumerable> detailsViewItemsSource) { var actualRowIndex = rowIndex; record.IsExpanded = true; ResetExpandedLevel(this.DataGrid); var count = 0; var updateDataRow = new List <int>(); var DetailsViewDefinition = this.DataGrid.DetailsViewDefinition; // If the grid is DetailsViewDataGrid, need to access SourceDataGrid's DetailsViewDefinition(Since NotifyListener is assigned for SourceDataGrid's DetailsViewDefinition only) if (this.DataGrid is DetailsViewDataGrid && this.DataGrid.NotifyListener != null) { DetailsViewDefinition = this.DataGrid.NotifyListener.SourceDataGrid.DetailsViewDefinition; } foreach (var detailsView in DetailsViewDefinition) { actualRowIndex++; var gridViewDefinition = detailsView as GridViewDefinition; IEnumerable itemsSource; if (detailsViewItemsSource.TryGetValue(gridViewDefinition.RelationalColumn, out itemsSource) && itemsSource != null) { CreateOrUpdateDetailsViewDataRow(this.DataGrid.RowGenerator.Items, actualRowIndex, record, detailsView, count, itemsSource); } else if (!this.DataGrid.HideEmptyGridViewDefinition) { CreateOrUpdateDetailsViewDataRow(this.DataGrid.RowGenerator.Items, actualRowIndex, record, detailsView, count, null); } // WPF-20080 - When HideEmptyGridViewDefinition is true and there is no records in details view, need to hide DetailsViewDataRow else { // WPF-19997 - Create childView only if HideEmptyGridViewDefinition if (!record.ChildViews.ContainsKey(gridViewDefinition.RelationalColumn)) { record.ChildViews.Add(gridViewDefinition.RelationalColumn, new NestedRecordEntry(record, record.Level) { NestedLevel = (actualRowIndex - rowIndex) - 1 }); ResetTopLevelGroupCache(); } count++; updateDataRow.Add(actualRowIndex); this.DataGrid.VisualContainer.RowHeights.SetHidden(actualRowIndex, actualRowIndex, true); continue; } updateDataRow.Add(actualRowIndex); var view = record.ChildViews[gridViewDefinition.RelationalColumn]; if (view != null && !this.DataGrid.HideEmptyGridViewDefinition) { this.DataGrid.VisualContainer.RowHeights.SetHidden(actualRowIndex, actualRowIndex, false); } else if (view != null && DetailsViewHelper.GetChildSourceCount(view.View.SourceCollection) > 0) { this.DataGrid.VisualContainer.RowHeights.SetHidden(actualRowIndex, actualRowIndex, false); } else { this.DataGrid.VisualContainer.RowHeights.SetHidden(actualRowIndex, actualRowIndex, true); } count++; } if (this.DataGrid.HideEmptyGridViewDefinition) { if (record.ChildViews.Count == this.DataGrid.DetailsViewDefinition.Count) { var isExpanded = record.ChildViews.Any(view => view.Value.View != null && DetailsViewHelper.GetChildSourceCount(view.Value.View.SourceCollection) > 0); if (!isExpanded) { var recordIndex = this.DataGrid.ResolveToRecordIndex(rowIndex); this.DataGrid.DetailsViewManager.CollapseDetailsViewAt(recordIndex); } } } return(updateDataRow); }
internal override void ExpandNestedLinesofRecord(IEnumerable itemsSource, LineSizeCollection lines, GridViewDefinition gridViewDefinition, RecordEntry recordEntry, int level) { if (gridViewDefinition.DataGrid.DetailsViewDefinition != null && gridViewDefinition.DataGrid.DetailsViewDefinition.Any()) { var rowIndex = 1; foreach (var item in itemsSource) { var actualRowIndex = rowIndex; int index = 0; foreach (var nestedViewDefinition in gridViewDefinition.DataGrid.DetailsViewDefinition) { if (nestedViewDefinition is GridViewDefinition) { index++; var nestedgridViewDefinition = nestedViewDefinition as GridViewDefinition; actualRowIndex++; int repeatValueCount; var isHidden = lines.GetHidden(actualRowIndex, out repeatValueCount); LineSizeCollection nestedLines = null; if (!isHidden) { nestedLines = lines.GetNestedLines(actualRowIndex) as LineSizeCollection; } int nestedLevel = recordEntry != null && recordEntry.ChildViews != null && recordEntry.ChildViews.ContainsKey(gridViewDefinition.RelationalColumn) ? recordEntry.ChildViews[gridViewDefinition.RelationalColumn].ExpandedLevel : level; if (nestedLines == null) { var detailsViewLinesitemsource = GetChildSource((item is RecordEntry) ? (item as RecordEntry).Data : item, nestedgridViewDefinition.RelationalColumn); int count = 0; // If need to expand inner levels also, DetailsViewDefinition count is added with SourceCollection count if (nestedLevel > this.DataGrid.DetailsViewManager.GetDefinitionLevel(nestedgridViewDefinition) || nestedLevel == -1) { count = detailsViewLinesitemsource != null?DetailsViewHelper.GetChildSourceCount(detailsViewLinesitemsource) * (nestedgridViewDefinition.DataGrid.DetailsViewDefinition.Count + 1) : 0; } else { count = detailsViewLinesitemsource != null?DetailsViewHelper.GetChildSourceCount(detailsViewLinesitemsource) : 0; } // While creating lines, LineCount is set by considering DetailsViewDataRow also. But if we HideEmptyGridViewDefintion is true, we need to hide it(RowHeight = 0) if (nestedgridViewDefinition.DataGrid.HideEmptyGridViewDefinition && count == 0) { lines.SetHidden(actualRowIndex, actualRowIndex, true); continue; } //AddNewRow, StackedHeaders, UnBoundRows and TableSummaryRows count added here count += nestedgridViewDefinition.DataGrid.StackedHeaderRows != null ? nestedgridViewDefinition.DataGrid.StackedHeaderRows.Count : 0; count += nestedgridViewDefinition.DataGrid.UnBoundRows != null ? nestedgridViewDefinition.DataGrid.UnBoundRows.Count : 0; count += nestedgridViewDefinition.DataGrid.TableSummaryRows != null ? nestedgridViewDefinition.DataGrid.TableSummaryRows.Count : 0; count += nestedgridViewDefinition.DataGrid.AddNewRowPosition != AddNewRowPosition.None ? 1 : 0; nestedLines = new LineSizeCollection { LineCount = count + 1, DefaultLineSize = nestedgridViewDefinition.DataGrid.RowHeight }; } // Below code is to set the PaddingDistance based on GridViewDefintion level if (nestedgridViewDefinition.DataGrid.AllowDetailsViewPadding) { SetDetailsViewPadding(nestedLines, (item is RecordEntry) ? (item as RecordEntry).Data : item, rowIndex, actualRowIndex, gridViewDefinition.DataGrid); } if (nestedLevel > this.DataGrid.DetailsViewManager.GetDefinitionLevel(nestedgridViewDefinition) || nestedLevel == -1) { ExpandNestedLines((item is RecordEntry) ? (item as RecordEntry).Data : item, nestedLines, nestedgridViewDefinition, (item is RecordEntry) ? item as RecordEntry : null, nestedLevel); } lines.SetNestedLines(actualRowIndex, nestedLines); lines.SetHidden(actualRowIndex, actualRowIndex, false); } } rowIndex += gridViewDefinition.DataGrid.DetailsViewDefinition.Count + 1; } } }
internal override void ExpandAllDetailsViewOfRecord(int level, RecordEntry record, int rowIndex) { var actualRowIndex = rowIndex; int index = 0; foreach (var viewDefinition in this.DataGrid.DetailsViewDefinition) { actualRowIndex++; if (viewDefinition is GridViewDefinition) { index++; var gridViewDefinition = viewDefinition as GridViewDefinition; int repeatValueCount; var isHidden = this.DataGrid.VisualContainer.RowHeights.GetHidden(actualRowIndex, out repeatValueCount); LineSizeCollection lines = null; if (!isHidden) { lines = this.DataGrid.VisualContainer.RowHeights.GetNestedLines(actualRowIndex) as LineSizeCollection; } //WPF-18239 - If nested lines are reset, lines will be null(even though it is visible). // Below code is added to create nested lines if (lines == null) { var itemsource = GetChildSource(record.Data, gridViewDefinition.RelationalColumn); int count = 0; // If need to expand inner levels also, DetailsViewDefinition count is added with SourceCollection count if (level > 1 || level == -1) { count = itemsource != null?DetailsViewHelper.GetChildSourceCount(itemsource) * (gridViewDefinition.DataGrid.DetailsViewDefinition.Count + 1) : 0; } else { count = itemsource != null?DetailsViewHelper.GetChildSourceCount(itemsource) : 0; } if (this.DataGrid.HideEmptyGridViewDefinition && count == 0) { // WPF-19997 - Create childView only if HideEmptyGridViewDefinition if (!record.ChildViews.ContainsKey(gridViewDefinition.RelationalColumn)) { record.ChildViews.Add(gridViewDefinition.RelationalColumn, new NestedRecordEntry(record, record.Level) { NestedLevel = (actualRowIndex - rowIndex) - 1 }); this.ResetTopLevelGroupCache(); } continue; } // AddNewRow, StackedHeaders, UnBoundRows and TableSummaryRows count added here count += gridViewDefinition.DataGrid.StackedHeaderRows != null ? gridViewDefinition.DataGrid.StackedHeaderRows.Count : 0; count += gridViewDefinition.DataGrid.UnBoundRows != null ? gridViewDefinition.DataGrid.UnBoundRows.Count : 0; count += gridViewDefinition.DataGrid.TableSummaryRows != null ? gridViewDefinition.DataGrid.TableSummaryRows.Count : 0; count += gridViewDefinition.DataGrid.AddNewRowPosition != AddNewRowPosition.None ? 1 : 0; count += gridViewDefinition.DataGrid.FilterRowPosition != FilterRowPosition.None ? 1 : 0; // DefaultLineSize should be set based on the SourceDataGrid's RowHeight lines = new LineSizeCollection { LineCount = count + 1, DefaultLineSize = gridViewDefinition.DataGrid.RowHeight }; } // Below code is to set the PaddingDistance based on GridViewDefintion level if (this.DataGrid.AllowDetailsViewPadding) { SetDetailsViewPadding(lines, record.Data, rowIndex, actualRowIndex, this.DataGrid); } // Need to expand nested lines also if level is greater than 1 or need to expand all records (level is -1) if (level > 1 || level == -1) { ExpandNestedLines(record.Data, lines, gridViewDefinition, record, level); } this.DataGrid.VisualContainer.RowHeights.SetNestedLines(actualRowIndex, lines); this.DataGrid.VisualContainer.RowHeights.SetHidden(actualRowIndex, actualRowIndex, false); if (!record.ChildViews.ContainsKey(gridViewDefinition.RelationalColumn)) { record.ChildViews.Add(gridViewDefinition.RelationalColumn, new NestedRecordEntry(record, record.Level) { NestedLevel = (actualRowIndex - rowIndex) - 1 }); ResetTopLevelGroupCache(); } record.ChildViews[gridViewDefinition.RelationalColumn].ExpandedLevel = level; // Set IsNestedLevelExpanded if level is -1 (ExpandAllDetailsView is called) if (level == -1) { record.ChildViews[gridViewDefinition.RelationalColumn].IsNestedLevelExpanded = true; } else { record.ChildViews[gridViewDefinition.RelationalColumn].IsNestedLevelExpanded = false; } } } }
/// <summary> /// Refresh the merged row within the range. /// </summary> /// <param name="dr"></param> internal void RefreshMergedRows(DataRowBase dr) { var coveredCellInfoCollection = this.dataGrid.CoveredCells.GetCoveredCellsRange(dr); if (coveredCellInfoCollection.Count == 0) { return; } foreach (var coveredRange in coveredCellInfoCollection) { var invalidateRows = this.dataGrid.RowGenerator.Items.FindAll(item => item.RowIndex <= coveredRange.Bottom && item.RowIndex >= coveredRange.Top && (item.RowType == RowType.DefaultRow || item.RowType == RowType.UnBoundRow)); foreach (var invalidateRow in invalidateRows) { if (invalidateRow.RowType == RowType.AddNewRow && (invalidateRow.RowIndex == coveredRange.Top || invalidateRow.RowIndex == coveredRange.Bottom)) { throw new Exception(String.Format("AddNewRow cells cannot be merged {0}", coveredRange)); } if (!invalidateRow.IsSpannedRow) { this.InitializeMergedRow(invalidateRow); } invalidateRow.VisibleColumns.ForEach(r => { var detailsViewDefinitionCount = this.dataGrid.DetailsViewDefinition.Count; if (detailsViewDefinitionCount != 0 && this.dataGrid.IsInDetailsViewIndex(invalidateRow.RowIndex + detailsViewDefinitionCount)) { var throwException = false; foreach (var viewDefinition in this.dataGrid.DetailsViewDefinition) { var itemSource = this.dataGrid.DetailsViewManager.GetChildSource(dr.RowData, viewDefinition.RelationalColumn); if (DetailsViewHelper.GetChildSourceCount(itemSource) > 0) { throwException = true; break; } } if (invalidateRow.RowIndex != coveredRange.Bottom && (throwException || !dataGrid.HideEmptyGridViewDefinition)) { throw new Exception(String.Format("Given range is not valid {0} with the details view row", coveredRange)); } } if (r.ColumnIndex >= coveredRange.Left && r.ColumnIndex <= coveredRange.Right && r.GridColumn != null && !r.GridColumn.IsHidden) { if (r.ColumnVisibility == Visibility.Collapsed) { r.ColumnVisibility = Visibility.Visible; } } } ); if (!this.dataGrid.IsInDetailsViewIndex(invalidateRow.RowIndex)) { invalidateRow.WholeRowElement.ItemsPanel.InvalidateMeasure(); invalidateRow.WholeRowElement.ItemsPanel.InvalidateArrange(); #if WPF if (this.dataGrid.useDrawing) { invalidateRow.WholeRowElement.ItemsPanel.InvalidateVisual(); } #endif } } } }