简体   繁体   English

在OpenXML中复制先前已修改的工作表

[英]Copying a worksheet in OpenXML that has previously been modified

I have followed the routine used here to copy a worksheet in a workbook into the same workbook by using .AddPart<>() and a temporary workbook to serve as a middleman, but have come up with some issues. 我遵循此处使用的例程,通过使用.AddPart<>()和一个临时工作簿充当中间人,将工作簿中的工作表复制到同一工作簿中,但是出现了一些问题。 Prior to copying the worksheet, I have made modifications to it. 在复制工作表之前,我已经对其进行了修改。 However, the copied version of the worksheet retains the original sheet, not the modified one. 但是,工作表的复制版本保留原始表,而不是修改后的表。 Here's the code: 这是代码:

Document = SpreadsheetDocument.Open(filename, true);
SetupPages(0, nSections);
CopySheet(1);

SetupPages() simply gets a worksheet which has a table with only one row and then copies that row nSections - 1 times, so that the table ends up with nSections rows. SetupPages()只是获得一个工作表,该工作表的表只有一行,然后将该行复制nSections - 1次,以便该表以nSections行结尾。 This works. 这可行。

CopySheet() has the following code: CopySheet()具有以下代码:

private void CopySheet(int sNum)
{
    var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
    WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
    var part = Document.XGetWorkSheetPart(sNum);
    WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);
    var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);

    var sheets = Document.WorkbookPart.Workbook.GetFirstChild<Sheets>();
    var sheet = new Sheet();
    sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
    sheet.Name = "AAA";
    sheet.SheetId = (uint)sheets.ChildElements.Count + 1;
    sheets.Append(sheet);
}

This method gets the desired workSheetPart and uses tempSheet.AddPart<>() to perform a deep copy of the desired part and then uses it again to deep copy it back into the original document. 此方法获取所需的workSheetPart并使用tempSheet.AddPart<>()执行所需部分的深层副本,然后再次使用它来将其深层复制回原始文档中。 This way all the referenced objects contained within the desired workSheetPart are also copied. 这样,还复制了所需workSheetPart中包含的所有引用对象。

This works, in as much as I now have a copy of the workSheet in my original document. 就像我现在在原始文档中拥有workSheet的副本一样,此方法同样有效。 However, all the modifications made by SetupPages() prior to calling CopySheet() do not appear in the copied workSheet. 但是,所作的所有修改SetupPages()调用之前CopySheet()不会出现在复制工作表。 So I now have the original Sheet with (in this example) 11 rows and the copied Sheet with only 1 row. 因此,我现在有原始的工作表(在此示例中)有11行,而复制的工作表只有1行。

I have tried placing a Document.WorkBookPart.WorkBook.Save() between SetupPages() and CopySheet() , to see if "saving the changes" would make them available to be copied as well, but to no avail. 我试过在SetupPages()CopySheet() Document.WorkBookPart.WorkBook.Save()之间放置一个Document.WorkBookPart.WorkBook.Save() ,以查看是否“保存更改”会使它们也可以被复制,但无济于事。

Is there any OpenXML trick I am unaware of? 我没有意识到任何OpenXML技巧吗?

EDIT: Using the debugger I have just noticed that part.WorkSheet.ChildElements.Count = 15 (the expected number of rows after SetupPages ). 编辑:使用调试器,我刚刚注意到part.WorkSheet.ChildElements.Count = 15SetupPages之后的预期行SetupPages )。 However, tempWBP.WorkSheet.ChildElements.Count = 5 (the number of rows in the original sheet prior to the modifications of SetupPages ). 但是, tempWBP.WorkSheet.ChildElements.Count = 5 (在修改SetupPages之前,原始工作表中的行数)。 For whatever reason, the new Rows added by my program are not being deep-copied. 无论出于何种原因,我的程序添加的新行都不会被深复制。 Now this I just don't understand. 现在,我只是不明白。 Should it have something to do with some improper binding of the rows on my part or something, here's the definition of SetupPages() : 如果它与我部分上的行的某些不正确绑定有关或与此有关,这是SetupPages()的定义:

public void SetupPages(int p, int nSections)
{
    Regex rn = new Regex("[0-9]+");
    Regex rs = new Regex("[A-Z]+");
    SheetData sData = Document.XGet<SheetData>(2 * p + 1);
    for (uint i = 1; i < nSections; i++)
    {
        var r = sData.ChildElements.GetItem(4).Clone() as Row;
        r.RowIndex.Value += i;
        foreach (OpenXmlElement _c in r.ChildElements)
        {
            var c = _c as Cell;
            Match mn = rn.Match(c.CellReference.Value);
            Match ms = rs.Match(c.CellReference.Value);
            string str = (int.Parse(mn.Value) + i).ToString();
            c.CellReference.Value = ms.Value + str;
        }
        (r.FirstChild as Cell).CellValue = new CellValue((i + 1).ToString());
        sData.Append(r);
    }
}

EDIT 2: I've been able to make the copy work fully, but it's very unelegant and doesn't fix what is clearly an error in the code, but merely an emergency measure to pretend that there isn't a problem. 编辑2:我已经能够使副本完全正常工作,但是它非常不确定,并且不能解决代码中明显的错误,而只是一种应急措施,以假装没有问题。 I basically get a clone of the original SheetData (which contains the modifications done in SetupPages ) and set it as the SheetData of the copied Sheet . 我基本上得到了原始SheetData (其中包含在SetupPages完成的修改),并将其设置为复制的SheetSheetData I'm just posting this here for information purposes, but if someone could still please point out what is wrong in the code that I'm not seeing, I'll be quite thankful. 我只是在此处发布此信息,以供参考,但是如果仍然有人可以指出我没有看到的代码中的错误,我将非常感激。 Here's the "hacked" version of CopySheet() , if anyone is interested. 如果有人感兴趣,这是CopySheet()的“被黑”版本。

private void CopySheet(int sNum)
{
    var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
    WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
    var part = Document.XGetWorkSheetPart(sNum);
    var b = part.Worksheet.ChildElements[5].Clone() as SheetData;
    WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);

    var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);
    copy.Worksheet.RemoveChild<SheetData>(copy.Worksheet.ChildElements[5] as SheetData);
    copy.Worksheet.InsertAt<SheetData>(b, 5);

    var sheets = Document.WorkbookPart.Workbook.GetFirstChild<Sheets>();
    var sheet = new Sheet();
    sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
    sheet.Name = "AAA";
    sheet.SheetId = (uint)sheets.ChildElements.Count + 1;
    sheets.Append(sheet);
}

I've solved this as best I can (and from what I've gathered from other forums I've asked, as best "they" can) by closing and opening the file prior to creating the copies. 我已通过在创建副本之前关闭和打开文件来尽可能地解决这个问题(以及从我从其他要求的论坛收集来的,最好的“他们”可以解决的问题)。 This makes the changes permanent and then, when copied, the changes are copied, too. 这使更改成为永久更改,然后在复制时也复制更改。 With this, the "hack" described above becomes unnecessary. 这样,上述“黑客”就变得不必要了。 The final version of the code therefore became (with a change to avoid SheetID and Sheet.Name conflicts): 因此,代码的最终版本变成了(为避免SheetIDSheet.Name发生冲突而进行了更改):

private void CopySheet(int sNum, int pNum, string type)
{
    var tempSheet = SpreadsheetDocument.Create(new MemoryStream(), SpreadsheetDocumentType.Workbook);
    WorkbookPart tempWBP = tempSheet.AddWorkbookPart();
    var part = Document.XGetWorkSheetPart(sNum);
    WorksheetPart tempWSP = tempWBP.AddPart<WorksheetPart>(part);
    var copy = Document.WorkbookPart.AddPart<WorksheetPart>(tempWSP);
    var sheets = Document.WorkbookPart.Workbook.GetFirstChild<Sheets>();
    var sheet = new Sheet();
    sheet.Id = Document.WorkbookPart.GetIdOfPart(copy);
    sheet.Name = "Phase " + pNum + " " + type;
    uint id = 1;
    bool valid = false;
    while (!valid)
    {
        uint temp = id;
        foreach (OpenXmlElement e in sheets.ChildElements)
        {
            var s = e as Sheet;
            if (id == s.SheetId.Value)
            {
                id++;
                break;
            }
        }
        if (temp == id)
            valid = true;
    }
    sheet.SheetId = id;
    sheets.Append(sheet);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM