internal static void Reuse(Worksheet sheet, CellPosition fromPosition, RangePosition toRange) { fromPosition = sheet.FixPos(fromPosition); toRange = sheet.FixRange(toRange); var cell = sheet.cells[fromPosition.Row, fromPosition.Col]; #region Arguments Check if (cell == null || string.IsNullOrEmpty(cell.InnerFormula) || cell.FormulaTree == null) { throw new InvalidOperationException("cannot found formula from specified position, try reset formula for the cell again"); } if (cell.formulaStatus != Formula.FormulaStatus.Normal) { throw new InvalidOperationException("formula in specified cell contains errors, correct the formula firstly"); } if (toRange.Contains(fromPosition)) { throw new ArgumentException("toRange should not contain the position of the formula to be reused"); } #endregion // Arguments Check var rs = new ReplacableString(cell.InnerFormula); STNode node = cell.FormulaTree; Stack <List <Cell> > dirtyCells = new Stack <List <Cell> >(); for (int r = toRange.Row; r <= toRange.EndRow; r++) { for (int c = toRange.Col; c <= toRange.EndCol;) { var toCell = sheet.CreateAndGetCell(r, c); if (toCell.Colspan <= 0) { c++; continue; } FormulaRefactor.CopyFormula(fromPosition, node, toCell, rs, dirtyCells); c += cell.Colspan; } } }
internal static void CopyFormula(CellPosition fromPosition, STNode fromNode, Cell toCell, ReplacableString rs, Stack <List <Cell> > dirtyCells) { var sheet = toCell.Worksheet; STNode node2 = (STNode)fromNode.Clone(); int r = toCell.Row; int c = toCell.Column; rs.Restore(); #region Rebuilt Formula STNode.RecursivelyIterate(node2, n => { switch (n.Type) { case STNodeType.CELL: #region Cell Offset { var refCellNode = (STCellNode)n; var newPos = refCellNode.Position; #region Calc Offset // B2: =A1 // B3: =A2 if (newPos.RowProperty == PositionProperty.Relative) { newPos.Row += r - fromPosition.Row; } if (newPos.ColumnProperty == PositionProperty.Relative) { newPos.Col += c - fromPosition.Col; } #endregion // Calc Offset if (newPos.Row < 0 || newPos.Col < 0 || newPos.Row >= sheet.rows.Count || newPos.Col >= sheet.cols.Count) { toCell.formulaStatus = FormulaStatus.InvalidReference; } refCellNode.Position = newPos; n.Start += rs.Offset; int diff = rs.Replace(n.Start, n.Length, newPos.ToAddress()); n.Length += diff; } break; #endregion // Cell Offset case STNodeType.RANGE: #region Range Offset { var refRangeNode = (STRangeNode)n; var newRange = refRangeNode.Range; #region Calc Offset int diffRow = r - fromPosition.Row; int diffCol = c - fromPosition.Col; if (newRange.StartRowProperty == PositionProperty.Relative) { newRange.Row += diffRow; } if (newRange.StartColumnProperty == PositionProperty.Relative) { newRange.Col += diffCol; } //if (newRange.EndRowProperty == PositionProperty.Relative) //{ // newRange.EndRow += diffRow; //} //if (newRange.EndColumnProperty == PositionProperty.Relative) //{ // newRange.EndCol += diffCol; //} #endregion // Calc Offset if (newRange.Row < 0 || newRange.Col < 0 || newRange.Row >= sheet.rows.Count || newRange.Col >= sheet.cols.Count || newRange.EndRow < 0 || newRange.EndCol < 0 || newRange.EndRow >= sheet.rows.Count || newRange.EndCol >= sheet.cols.Count) { toCell.formulaStatus = FormulaStatus.InvalidReference; } refRangeNode.Range = newRange; n.Start += rs.Offset; int diff = rs.Replace(n.Start, n.Length, newRange.ToAddress()); n.Length += diff; } break; #endregion // Range Offset } }); #endregion // Rebuilt Formula #region Update To New Cell toCell.InnerFormula = rs.ToString(); #if FORMULA_FORMAT toCell.InnerFormula = Generate(cell.InnerFormula, node2); #endif // FORMULA_FORMAT sheet.SetCellFormula(toCell, node2); if (toCell.formulaStatus == FormulaStatus.Normal) { sheet.RecalcCell(toCell, dirtyCells); } #endregion // Update To New Cell }