我需要动态地将现有行克隆到工作表中。前任。我想复制第 28、29 行并插入到第 30、31 或 32,33 行,或者更多,这取决于数据行。 从
如何在 openxml 中动态地做到这一点? 预先感谢。
最后,我使用EPplus而不是OpenXML, 只需 2 行即可解决我的问题。
private void AddRows(ExcelWorksheet sheet, int rowFrom, int colFrom, int rowTo, int colTo)
{
sheet.InsertRow(rowFrom,2);
sheet.Cells[28, 1, 29, 46].Copy(sheet.Cells[rowFrom, colFrom, rowTo, colTo]);
}
在阅读了许多人说要插入行的帖子后,我发现这实际上在我的模板中造成了问题。插入行与在 excel 中插入不同/ 您实际上是在 xml 文件中插入一行,这意味着如果您不小心,行索引可能会乱序。以下代码是我用于模板的代码,我相信您可以修改它以满足您的需求。我会根据索引找到现有行并将其替换为我要复制的行。修改此代码以允许在找不到行时插入行,但我的模板没有问题,因此不需要比这更进一步。
希望这对像我一样被困在这个问题上几个小时的人有所帮助。
public static class GenerateJobHoursReport
{
private static string file;
public static string File
{ get { return file; } set { file = value; } }
public static void CreatePackage(string JobID)
{
//Get the data to insert
DataTable dataTable = SQL_Commands.Get_Data_Table($"select * from [index].GetHoursBreakOut({JobID});");
if(dataTable.Rows.Count == 0 ) { MessageBox.Show("No Hours have been entered", "Error No Hours", MessageBoxButtons.OK, MessageBoxIcon.Error); File = ""; return; }
//generate a tempfile name
string docName = System.IO.Path.GetTempFileName();
docName = docName.Replace(Path.GetFileName(docName), JobID + " Job Hours Report.xlsx");
//if the file exists delete it
if (System.IO.File.Exists(docName)) { System.IO.File.Delete(docName); }
//write the template from resource to the file location
System.IO.File.WriteAllBytes(docName, Properties.Resources.Job_Hours_Report);
//save the file location to open the file once it has been created
File = docName;
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
{
//Get the workbookpart
WorkbookPart workbookPart = spreadSheet.WorkbookPart;
//get the work sheet
string relationshipId = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name.Equals("Hours Breakout"))?.Id;
WorksheetPart worksheet = ((WorksheetPart)workbookPart.GetPartById(relationshipId));
//get the table on the worksheet
Table table = (Table)worksheet.TableDefinitionParts.FirstOrDefault(t => t.Table.Name == "HoursTable")?.Table;
//get the worksheet sheetdata
SheetData sheetData = worksheet.Worksheet.Elements<SheetData>().First();
//split the table reference to get the rows and columns
string[] tableRef = table.Reference.Value.Split(':');
uint rowIndex = uint.Parse(Regex.Match(tableRef[0], @"\d+").Value) + 1;
char[] refColumns = Array.ConvertAll(tableRef, x => x = Regex.Replace(x, @"\d+", "")).Select(s => char.Parse(s)).ToArray();
char[] columns = new char[(refColumns[refColumns.Length - 1] - refColumns[0]) + 1];
int ltr = 0;
for (char letter = refColumns[0]; letter <= refColumns[refColumns.Length - 1]; letter++)
{
columns[ltr] = letter;
ltr++;
}
// Add blank rows to the template
AddRows(workbookPart, sheetData, table.Reference, dataTable.Rows.Count);
// Save the worksheet
worksheet.Worksheet.Save();
// Modify the table reference
table.Reference = $"{refColumns[0]}{rowIndex - 1}:{refColumns[1]}{rowIndex + dataTable.Rows.Count}";
// insert the data into the blank rows
foreach (DataRow dataRow in dataTable.Rows)
{
// get the row by index
Row row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault();
// loop through the column letters
for (char letter = columns[0]; letter <= columns[columns.Length - 1]; letter++)
{
//get the cell by it's cell reference
Cell cell = row.Elements<Cell>().Where(c => c.CellReference == $"{letter.ToString()}{rowIndex}").FirstOrDefault();
//set the cell datatype by the datacolumm datatype
cell.DataType = CreateExcel.GetColumnCellValue(dataTable.Columns[Array.IndexOf(columns, letter)]);
// set the cellvalue
cell.CellValue = new CellValue(dataRow[Array.IndexOf(columns, letter)].ToString());
}
rowIndex++;
}
// get the second worksheet
relationshipId = workbookPart.Workbook.Descendants<Sheet>().FirstOrDefault(s => s.Name.Equals("Hours Chart"))?.Id;
WorksheetPart worksheet2 = ((WorksheetPart)workbookPart.GetPartById(relationshipId));
// get the pivot table
PivotTablePart pivotTable = worksheet2.PivotTableParts.FirstOrDefault();
PivotCacheDefinition pivotCacheDefinition = pivotTable.PivotTableCacheDefinitionPart.PivotCacheDefinition;
pivotCacheDefinition.RefreshOnLoad = true;
// set the work book to calculate on open
spreadSheet.WorkbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;
spreadSheet.WorkbookPart.Workbook.CalculationProperties.FullCalculationOnLoad = true;
}
}
private static void AddRows(WorkbookPart workbookPart, SheetData sheetData, StringValue tableReference, int rows)
{
// split the table reference to get the row data
string[] tableRef = tableReference.Value.Split(':');
uint LastRow = uint.Parse(Regex.Match(tableRef[1], @"\d+").Value);
// copy the last row to the new location
CopyRow(workbookPart, sheetData, LastRow, LastRow + (uint)rows - 1);
// copy table rows
for (uint i = 0; i < rows - 1; i++)
{
CopyRow(workbookPart, sheetData, LastRow + i - 1, LastRow + i);
}
}
private static void CopyRow(WorkbookPart workbookPart, SheetData sheetData, uint oldRow, uint newRow)
{
// get the row to copy
Row currentRow = sheetData.Descendants<Row>().FirstOrDefault(r => r.RowIndex == oldRow);
// clone the row
Row cloneRow = (Row)currentRow.CloneNode(true);
// set the clone rows new index
cloneRow.RowIndex = newRow;
// loop through the row cells
foreach (Cell child in currentRow.Elements<Cell>())
{
// get the cell to copy
Cell currentCell = cloneRow.Elements<Cell>().Where(x => x.CellReference == child.CellReference).FirstOrDefault();
// clone the cell
Cell cloneCell = (Cell)currentCell.CloneNode(true);
// modify the cell refernce
cloneCell.CellReference = cloneCell.CellReference.Value.Replace(oldRow.ToString(), newRow.ToString());
// check if the cell has a formula
var form = cloneCell.CellFormula;
if (form != null)
{
// get the calulation cell based on the cell reference
CalculationCell calculationCell = workbookPart.CalculationChainPart.CalculationChain.Descendants<CalculationCell>().Where(x => x.CellReference == child.CellReference).FirstOrDefault();
// modify the calculation cell reference
calculationCell.CellReference = calculationCell.CellReference.Value.Replace(oldRow.ToString(), newRow.ToString());
}
// replace the clone row cell
cloneRow.ReplaceChild<Cell>(cloneCell, currentCell);
}
// get the row to replace
Row replaceRow = sheetData.Descendants<Row>().FirstOrDefault(r => r.RowIndex == newRow);
// replace the row with the cloned row
sheetData.ReplaceChild<Row>(cloneRow, replaceRow);
}
}
public static CellValues GetColumnCellValue(System.Data.DataColumn dataColumn)
{
CellValues cellValues = new CellValues();
if (dataColumn.DataType == typeof(string))
{
cellValues = CellValues.String;
}
else if (dataColumn.DataType == typeof(int))
{
cellValues = CellValues.Number;
}
else if (dataColumn.DataType == typeof(decimal))
{
cellValues = CellValues.Number;
}
else if (dataColumn.DataType == typeof(DateTime))
{
cellValues = CellValues.Date;
}
else if (dataColumn.DataType == typeof(TimeSpan))
{
cellValues = CellValues.Number;
}
else if (dataColumn.DataType == typeof(Boolean))
{
cellValues = CellValues.Boolean;
}
else
{
cellValues = CellValues.InlineString;
}
return cellValues;
}