如何使用 openxml 将现有的复杂行克隆到工作表

问题描述 投票:0回答:2

我需要动态地将现有行克隆到工作表中。前任。我想复制第 28、29 行并插入到第 30、31 或 32,33 行,或者更多,这取决于数据行。 从

如何在 openxml 中动态地做到这一点? 预先感谢。

c# excel openxml
2个回答
0
投票

最后,我使用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]);
    }

0
投票

在阅读了许多人说要插入行的帖子后,我发现这实际上在我的模板中造成了问题。插入行与在 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;
}
© www.soinside.com 2019 - 2024. All rights reserved.