private void ValidateRowVisualComplex( RowVisual rowVisual, IntPtr pfstablerow, int tableColumnCount, PTS.FSKUPDATE fskupdRow, CalculatedColumn[] calculatedColumns) { PTS.FSKUPDATE[] arrayUpdate; IntPtr[] arrayFsCell; PTS.FSTABLEKCELLMERGE[] arrayTableCellMerge; CellParaClientEntry[] arrayCellParaClients; VisualCollection cellVisualsCollection; int sourceIndex; QueryRowDetails( pfstablerow, out arrayFsCell, out arrayUpdate, out arrayTableCellMerge); // arrayFsCell lists cells in order different from one we want to maintain in visual collection. // before going to update visual collection it is necessary to reorder ascending by cell's column index. // knowing the following facts: // * total number of columns the row holds (including row spanned cells from previous rows) less or equal to tableColumnCount; // * total number of cells (including row spanned cells from previous rows) is less or equal to tableColumnCount; // * cells do not overlap - no two cells have the same column index; // * cells' column indices fall into the range [0, tableColumnCount - 1]; // it is possible to write custom and optimized sorting routine: // * iterate through arrayFsCell; // * for each item record its CellParaClient value into arrayCellParaClients[CellParaClient.ColumnIndex]; // once complete, arrayCellParaClients will contain CellParaClients in correct order. some entries however will be null // due to potential column spanning of cells. arrayCellParaClients = new CellParaClientEntry[tableColumnCount]; for (int iC = 0; iC < arrayFsCell.Length; ++iC) { CellParaClient cellParaClient; PTS.FSKUPDATE fskupdCell; int columnIndex; if (arrayFsCell[iC] == IntPtr.Zero) { // paginated case - cell may be null continue; } fskupdCell = (arrayUpdate[iC] != PTS.FSKUPDATE.fskupdInherited) ? arrayUpdate[iC] : fskupdRow; cellParaClient = (CellParaClient)(PtsContext.HandleToObject(arrayFsCell[iC])); columnIndex = cellParaClient.ColumnIndex; arrayCellParaClients[columnIndex].cellParaClient = cellParaClient; arrayCellParaClients[columnIndex].fskupdCell = fskupdCell; } cellVisualsCollection = rowVisual.Children; sourceIndex = 0; for (int columnIndex = 0; columnIndex < arrayCellParaClients.Length; ++columnIndex) { CellParaClient cellParaClient; double urCellOffset; PTS.FSKUPDATE fskupdCell; cellParaClient = arrayCellParaClients[columnIndex].cellParaClient; if (cellParaClient == null) { // paginated case - cell may be null continue; } fskupdCell = arrayCellParaClients[columnIndex].fskupdCell; if (fskupdCell != PTS.FSKUPDATE.fskupdNoChange) { urCellOffset = calculatedColumns[columnIndex].UrOffset; cellParaClient.ValidateVisual(); if (fskupdCell == PTS.FSKUPDATE.fskupdNew) { cellVisualsCollection.Insert(sourceIndex, cellParaClient.Visual); } else { Debug.Assert( cellParaClient.Visual != null // If the check below fails, then PTS cheats by reporting "ChangInside" for // a cell that in fact was re-Formatted. && VisualTreeHelper.GetParent(cellParaClient.Visual) != null ); SynchronizeCellVisualsCollection(cellVisualsCollection, sourceIndex, cellParaClient.Visual); } } sourceIndex++; } if (cellVisualsCollection.Count > sourceIndex) { cellVisualsCollection.RemoveRange( sourceIndex, cellVisualsCollection.Count - sourceIndex); } #if DEBUGDEBUG for (int columnIndex = 0, sourceIndex = 0; columnIndex < arrayCellParaClients.Length; ++columnIndex) { CellParaClient cellParaClient = arrayCellParaClients[columnIndex].cellParaClient; if (cellParaClient != null) { Debug.Assert(rowVisual.Children.IndexOf(cellParaClient.Visual) == sourceIndex); sourceIndex++; } } #endif // DEBUGDEBUG }
internal override void ValidateVisual(PTS.FSKUPDATE fskupdInherited) { Invariant.Assert( fskupdInherited != PTS.FSKUPDATE.fskupdInherited ); Invariant.Assert( TableParagraph.Table != null && CalculatedColumns != null ); PTS.FSTABLEROWDESCRIPTION[] arrayTableRowDesc; PTS.FSKUPDATE fskupdTable; PTS.FSRECT rect; Table table = TableParagraph.Table; Visual.Clip = new RectangleGeometry(_columnRect.FromTextDpi()); if (!QueryTableDetails(out arrayTableRowDesc, out fskupdTable, out rect)) { // table has no rows thus no cell to validate _visual.Children.Clear(); return; } MbpInfo mbpInfo = MbpInfo.FromElement(TableParagraph.Element); if (ThisFlowDirection != PageFlowDirection) { mbpInfo.MirrorBP(); } if (fskupdTable == PTS.FSKUPDATE.fskupdInherited) { fskupdTable = fskupdInherited; } if (fskupdTable == PTS.FSKUPDATE.fskupdNoChange) { // no need to arrange because nothing changed return; } if (fskupdTable == PTS.FSKUPDATE.fskupdShifted) { fskupdTable = PTS.FSKUPDATE.fskupdNew; } VisualCollection rowVisualsCollection = _visual.Children; if (fskupdTable == PTS.FSKUPDATE.fskupdNew) { rowVisualsCollection.Clear(); } // Draw border and background info. Brush backgroundBrush = (Brush)Paragraph.Element.GetValue(TextElement.BackgroundProperty); using (DrawingContext dc = _visual.RenderOpen()) { Rect tableContentRect = GetTableContentRect(mbpInfo).FromTextDpi(); _visual.DrawBackgroundAndBorderIntoContext(dc, backgroundBrush, mbpInfo.BorderBrush, mbpInfo.Border, _rect.FromTextDpi(), IsFirstChunk, IsLastChunk); DrawColumnBackgrounds(dc, tableContentRect); DrawRowGroupBackgrounds(dc, arrayTableRowDesc, tableContentRect, mbpInfo); DrawRowBackgrounds(dc, arrayTableRowDesc, tableContentRect, mbpInfo); } TableRow rowPrevious = null; for (int iR = 0; iR < arrayTableRowDesc.Length; ++iR) { PTS.FSKUPDATE fskupdRow; RowParagraph rowParagraph; TableRow row; fskupdRow = (arrayTableRowDesc[iR].fsupdinf.fskupd != PTS.FSKUPDATE.fskupdInherited) ? arrayTableRowDesc[iR].fsupdinf.fskupd : fskupdTable; rowParagraph = (RowParagraph)(PtsContext.HandleToObject(arrayTableRowDesc[iR].fsnmRow)); row = rowParagraph.Row; // // STEP 1 SYNCHRONIZATION // --------------------------------------------------------- // synchronize rowVisualCollection. // for newly created rows visual is inserted; // otherwise for removed rows (if any) corresponding visuals are removed // if (fskupdRow == PTS.FSKUPDATE.fskupdNew) { RowVisual rowVisual = new RowVisual(row); rowVisualsCollection.Insert(iR, rowVisual); } else { SynchronizeRowVisualsCollection(rowVisualsCollection, iR, row); } Invariant.Assert(((RowVisual)rowVisualsCollection[iR]).Row == row); // // STEP 2 CELL VISUALS VALIDATION // --------------------------------------------------------- // for new or changed rows go inside and validate cells // if ( fskupdRow == PTS.FSKUPDATE.fskupdNew || fskupdRow == PTS.FSKUPDATE.fskupdChangeInside ) { // paginated case - if first row of a given rowgroup for this para client has foreign cells, they need to // be rendered regardless of merge state if(rowParagraph.Row.HasForeignCells && (rowPrevious == null || rowPrevious.RowGroup != row.RowGroup)) { ValidateRowVisualComplex( (RowVisual)(rowVisualsCollection[iR]), arrayTableRowDesc[iR].pfstablerow, CalculatedColumns.Length, fskupdRow, CalculatedColumns); } else { ValidateRowVisualSimple( (RowVisual)(rowVisualsCollection[iR]), arrayTableRowDesc[iR].pfstablerow, fskupdRow, CalculatedColumns); } } rowPrevious = row; } // // STEP 4 if (rowVisualsCollection.Count > arrayTableRowDesc.Length) { rowVisualsCollection.RemoveRange( arrayTableRowDesc.Length, rowVisualsCollection.Count - arrayTableRowDesc.Length); } }
private void ValidateRowVisualSimple( RowVisual rowVisual, IntPtr pfstablerow, PTS.FSKUPDATE fskupdRow, CalculatedColumn[] calculatedColumns) { PTS.FSKUPDATE[] arrayUpdate; IntPtr[] arrayFsCell; PTS.FSTABLEKCELLMERGE[] arrayTableCellMerge; VisualCollection cellVisualsCollection; int sourceIndex; QueryRowDetails( pfstablerow, out arrayFsCell, out arrayUpdate, out arrayTableCellMerge); cellVisualsCollection = rowVisual.Children; sourceIndex = 0; for (int iC = 0; iC < arrayFsCell.Length; ++iC) { CellParaClient cellParaClient; double urCellOffset; PTS.FSKUPDATE fskupdCell; if ( // paginated case - cell may be null arrayFsCell[iC] == IntPtr.Zero // exclude hanging cells || arrayTableCellMerge[iC] == PTS.FSTABLEKCELLMERGE.fskcellmergeMiddle || arrayTableCellMerge[iC] == PTS.FSTABLEKCELLMERGE.fskcellmergeLast ) { continue; } fskupdCell = (arrayUpdate[iC] != PTS.FSKUPDATE.fskupdInherited) ? arrayUpdate[iC] : fskupdRow; if (fskupdCell != PTS.FSKUPDATE.fskupdNoChange) { cellParaClient = (CellParaClient)(PtsContext.HandleToObject(arrayFsCell[iC])); urCellOffset = calculatedColumns[cellParaClient.ColumnIndex].UrOffset; cellParaClient.ValidateVisual(); if ( fskupdCell == PTS.FSKUPDATE.fskupdNew // PTS bug is a suspect here - this is a temp workaround: || VisualTreeHelper.GetParent(cellParaClient.Visual) == null ) { Visual currentParent = VisualTreeHelper.GetParent(cellParaClient.Visual) as Visual; if(currentParent != null) { ContainerVisual parent = currentParent as ContainerVisual; Invariant.Assert(parent != null, "parent should always derives from ContainerVisual"); parent.Children.Remove(cellParaClient.Visual); } cellVisualsCollection.Insert(sourceIndex, cellParaClient.Visual); } else { Debug.Assert( cellParaClient.Visual != null // If the check below fails, then PTS cheats by reporting "ChangInside" for // a cell that in fact was re-Formatted. && VisualTreeHelper.GetParent(cellParaClient.Visual) != null ); SynchronizeCellVisualsCollection(cellVisualsCollection, sourceIndex, cellParaClient.Visual); } } sourceIndex++; } if (cellVisualsCollection.Count > sourceIndex) { cellVisualsCollection.RemoveRange( sourceIndex, cellVisualsCollection.Count - sourceIndex); } #if DEBUGDEBUG for (int iC = 0, sourceIndex = 0; iC < arrayFsCell.Length; ++iC) { if ( arrayFsCell[iC] != IntPtr.Zero && arrayTableCellMerge[iC] != PTS.FSTABLEKCELLMERGE.fskcellmergeMiddle && arrayTableCellMerge[iC] != PTS.FSTABLEKCELLMERGE.fskcellmergeLast ) { CellParaClient cellParaClient = (CellParaClient)(PtsContext.HandleToObject(arrayFsCell[iC])); Debug.Assert(rowVisual.Children.IndexOf(cellParaClient.Visual) == sourceIndex); sourceIndex++; } } #endif // DEBUGDEBUG }