C# 在Excel-OpenXML中插入页脚时出现问题

C# 在Excel-OpenXML中插入页脚时出现问题,c#,excel,ms-office,openxml,openxml-sdk,C#,Excel,Ms Office,Openxml,Openxml Sdk,我将Excel文件作为内存流发送,编辑它们,然后将它们发送回浏览器,以便它们在客户端office程序(Microsoft Excel)中打开。在编辑过程中,我在工作簿中的所有excel工作表上添加页脚。页脚的插入在大多数情况下都能正常工作,但如果我编辑的Excel文件中有许多“复杂”的表格,其中有图表等,则插入页脚会失败。这是我用来插入页脚的代码 // Adds footer to all sheets in the workbook except the one inserted by cod

我将Excel文件作为内存流发送,编辑它们,然后将它们发送回浏览器,以便它们在客户端office程序(Microsoft Excel)中打开。在编辑过程中,我在工作簿中的所有excel工作表上添加页脚。页脚的插入在大多数情况下都能正常工作,但如果我编辑的Excel文件中有许多“复杂”的表格,其中有图表等,则插入页脚会失败。这是我用来插入页脚的代码

// Adds footer to all sheets in the workbook except the one inserted by code       
private static void AddFooterToAllSheets(SpreadsheetDocument spreadSheetDocument, string footerText, string sheetTitle)
{
    var workbookPart = spreadSheetDocument.WorkbookPart;
    var workbook = spreadSheetDocument.WorkbookPart.Workbook;
    var sheetIndex = 0;

    //variable worksheetpart is not used in code, but added here because of looping
    foreach (var worksheetpart in workbook.WorkbookPart.WorksheetParts)
    {
        string sheetName = workbookPart.Workbook.Descendants<Sheet>().ElementAt(sheetIndex).Name;
        if (sheetName.Equals(sheetTitle))
        {
            sheetIndex++;
            continue;
        }

        InsertHeaderFooter(spreadSheetDocument, sheetName, footerText, HeaderType.AllFooter);
        sheetIndex++;
    }
}


public static void InsertHeaderFooter(SpreadsheetDocument document, string sheetName, string textToInsert, HeaderType type)
{
    var wbPart = document.WorkbookPart;

    // Find the sheet with the supplied name, and then use 
    // that Sheet object to retrieve a reference to 
    // the appropriate worksheet.
    var theSheet = wbPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).FirstOrDefault();
    if (theSheet == null)
    {
        return;
    }
    var wsPart = (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
    var ws = wsPart.Worksheet;

    // Worksheet is nothing? You have a damaged workbook!
    if (ws == null)
    {
        return;
    }

    // Retrieve a reference to the header/footer node, if it exists.
    var hf = ws.Descendants<HeaderFooter>().FirstOrDefault();
    if (hf == null)
    {
        hf = new HeaderFooter();
        ws.AppendChild<HeaderFooter>(hf);
    }

    // The HeaderFooter node should be there, at this point!
    if (hf != null)
    {
        // You've found the node. Now add the header or footer.
        // Deal with the attributes first:
        switch (type)
        {
            case HeaderType.EvenHeader:
            case HeaderType.EvenFooter:
            case HeaderType.OddHeader:
            case HeaderType.OddFooter:
                // Even or odd only? Add a differentOddEven attribute and set 
                // it to "1".
                hf.DifferentOddEven = true;
                break;

            case HeaderType.FirstFooter:
            case HeaderType.FirstHeader:
                hf.DifferentFirst = true;
                break;
        }

        switch (type)
        {
            // This code creates new header elements, even if they
            // already exist. Either way, you end up with a 
            // "fresh" element.
            case HeaderType.AllHeader:
                hf.EvenHeader = new EvenHeader { Text = textToInsert };

                hf.OddHeader = new OddHeader { Text = textToInsert };
                break;

            case HeaderType.AllFooter:
                hf.EvenFooter = new EvenFooter { Text = textToInsert };

                hf.OddFooter = new OddFooter { Text = textToInsert };
                break;

            case HeaderType.EvenFooter:
                hf.EvenFooter = new EvenFooter { Text = textToInsert };
                break;

            case HeaderType.EvenHeader:
                hf.EvenHeader = new EvenHeader { Text = textToInsert };
                break;

            case HeaderType.OddFooter:
                hf.OddFooter = new OddFooter { Text = textToInsert };
                break;

            case HeaderType.OddHeader:
                hf.OddHeader = new OddHeader { Text = textToInsert };
                break;

            case HeaderType.FirstHeader:
                hf.FirstHeader = new FirstHeader { Text = textToInsert };
                break;

            case HeaderType.FirstFooter:
                hf.FirstFooter = new FirstFooter { Text = textToInsert };
                break;
        }
    }
    ws.Save();
}
//将页脚添加到工作簿中的所有工作表中,由代码插入的工作表除外
专用静态void AddFooterToAllSheets(电子表格文档电子表格文档、字符串footerText、字符串sheetTitle)
{
var workbookPart=spreadSheetDocument.workbookPart;
var工作簿=电子表格文档.WorkbookPart.workbook;
var指数=0;
//代码中未使用变量worksheetpart,但由于循环,因此在此处添加了变量worksheetpart
foreach(工作簿中的var工作表部件。工作簿部件。工作表部件)
{
string sheetName=workbookPart.Workbook.subjections().ElementAt(sheetIndex.Name);
if(sheetName.Equals(sheetTitle))
{
索引++;
继续;
}
插入HeaderFooter(电子表格文档、表格名称、页脚文本、页眉类型.AllFooter);
索引++;
}
}
public static void InsertHeaderFooter(电子表格文档、字符串sheetName、字符串textToInsert、HeaderType类型)
{
var wbPart=document.WorkbookPart;
//找到具有提供名称的工作表,然后使用
//要检索引用的图纸对象
//适当的工作表。
var theSheet=wbbart.Workbook.subjections(),其中(s=>s.Name==sheetName.FirstOrDefault();
如果(表==null)
{
返回;
}
var wsPart=(工作表部分)(wbPart.GetPartById(theSheet.Id));
var ws=wsPart.Worksheet;
//工作表什么都不是?您的工作簿已损坏!
如果(ws==null)
{
返回;
}
//检索对页眉/页脚节点的引用(如果存在)。
var hf=ws.subjects().FirstOrDefault();
if(hf==null)
{
hf=新的头部足迹();
ws.AppendChild(hf);
}
//此时,HeaderFooter节点应该在那里!
如果(hf!=null)
{
//您已找到节点。现在添加页眉或页脚。
//首先处理属性:
开关(类型)
{
案例标题Type.EvenHeader:
案例标题Type.EvenFooter:
案例标题Type.OddHeader:
案例标题Type.OddFooter:
//仅偶数还是奇数?添加一个不同的TodDeven属性并设置
//把它改为“1”。
hf.differentitodeven=真;
打破
案例标题Type.FirstFooter:
案例标题Type.FirstHeader:
hf.DifferentFirst=真;
打破
}
开关(类型)
{
//此代码创建新的标头元素,即使它们
//已经存在了。不管怎样,你最终会得到一个
//“新鲜”元素。
案例标题Type.AllHeader:
hf.EvenHeader=newevenheader{Text=textToInsert};
hf.OddHeader=newoddheader{Text=textToInsert};
打破
案例标题类型.AllFooter:
hf.EvenFooter=newevenfooter{Text=textToInsert};
hf.OddFooter=newoddfooter{Text=textToInsert};
打破
案例标题Type.EvenFooter:
hf.EvenFooter=newevenfooter{Text=textToInsert};
打破
案例标题Type.EvenHeader:
hf.EvenHeader=newevenheader{Text=textToInsert};
打破
案例标题Type.OddFooter:
hf.OddFooter=newoddfooter{Text=textToInsert};
打破
案例标题Type.OddHeader:
hf.OddHeader=newoddheader{Text=textToInsert};
打破
案例标题Type.FirstHeader:
hf.FirstHeader=newfirstheader{Text=textToInsert};
打破
案例标题Type.FirstFooter:
hf.FirstFooter=newfirstfooter{Text=textToInsert};
打破
}
}
ws.Save();
}
试图打开文档时,会显示一条消息,说明Excel文件已损坏。验证损坏文件时,我在Open XML SDK 2.5 Productivity Tool中遇到的错误如下:

错误节点类型:工作表 错误部分:/xl/worksheets/sheet2.xml 错误节点路径:/x:工作表[1] 相关节点类型:HeaderFooter

描述:元素具有意外的子元素“”。

请尝试此操作

using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System;

namespace WindowsFormsApplication2
{
    public class GeneratedClass
    {
        private static System.Collections.Generic.IDictionary<System.String, OpenXmlPart> UriPartDictionary = new System.Collections.Generic.Dictionary<System.String, OpenXmlPart>();
        private static System.Collections.Generic.IDictionary<System.String, DataPart> UriNewDataPartDictionary = new System.Collections.Generic.Dictionary<System.String, DataPart>();
        private static SpreadsheetDocument document;

        public static void ChangePackage(string filePath)
        {
            using (document = SpreadsheetDocument.Open(filePath, true))
            {
                ChangeParts();
            }
        }

        private static void ChangeParts()
        {
            //Stores the referrences to all the parts in a dictionary.
            BuildUriPartDictionary();
            //Adds new parts or new relationships.
            AddParts();
            //Changes the contents of the specified parts.
            ChangeCoreFilePropertiesPart1(((CoreFilePropertiesPart)UriPartDictionary["/docProps/core.xml"]));
            ChangeWorksheetPart1(((WorksheetPart)UriPartDictionary["/xl/worksheets/sheet1.xml"]));
        }

        /// <summary>
        /// Stores the references to all the parts in the package.
        /// They could be retrieved by their URIs later.
        /// </summary>
        private static void BuildUriPartDictionary()
        {
            System.Collections.Generic.Queue<OpenXmlPartContainer> queue = new System.Collections.Generic.Queue<OpenXmlPartContainer>();
            queue.Enqueue(document);
            while (queue.Count > 0)
            {
                foreach (var part in queue.Dequeue().Parts)
                {
                    if (!UriPartDictionary.Keys.Contains(part.OpenXmlPart.Uri.ToString()))
                    {
                        UriPartDictionary.Add(part.OpenXmlPart.Uri.ToString(), part.OpenXmlPart);
                        queue.Enqueue(part.OpenXmlPart);
                    }
                }
            }
        }

        /// <summary>
        /// Adds new parts or new relationship between parts.
        /// </summary>
        private static void AddParts()
        {
            //Generate new parts.
            VmlDrawingPart vmlDrawingPart1 = UriPartDictionary["/xl/worksheets/sheet1.xml"].AddNewPart<VmlDrawingPart>("rId2");
            GenerateVmlDrawingPart1Content(vmlDrawingPart1);

            ImagePart imagePart1 = vmlDrawingPart1.AddNewPart<ImagePart>("image/png", "rId1");
            GenerateImagePart1Content(imagePart1);

        }

        private static void GenerateVmlDrawingPart1Content(VmlDrawingPart vmlDrawingPart1)
        {
            System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(vmlDrawingPart1.GetStream(System.IO.FileMode.Create), System.Text.Encoding.UTF8);
            writer.WriteRaw("<xml xmlns:v=\"urn:schemas-microsoft-com:vml\"\r\n xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n <o:shapelayout v:ext=\"edit\">\r\n  <o:idmap v:ext=\"edit\" data=\"1\"/>\r\n </o:shapelayout><v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" o:spt=\"75\"\r\n  o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\">\r\n  <v:stroke joinstyle=\"miter\"/>\r\n  <v:formulas>\r\n   <v:f eqn=\"if lineDrawn pixelLineWidth 0\"/>\r\n   <v:f eqn=\"sum @0 1 0\"/>\r\n   <v:f eqn=\"sum 0 0 @1\"/>\r\n   <v:f eqn=\"prod @2 1 2\"/>\r\n   <v:f eqn=\"prod @3 21600 pixelWidth\"/>\r\n   <v:f eqn=\"prod @3 21600 pixelHeight\"/>\r\n   <v:f eqn=\"sum @0 0 1\"/>\r\n   <v:f eqn=\"prod @6 1 2\"/>\r\n   <v:f eqn=\"prod @7 21600 pixelWidth\"/>\r\n   <v:f eqn=\"sum @8 21600 0\"/>\r\n   <v:f eqn=\"prod @7 21600 pixelHeight\"/>\r\n   <v:f eqn=\"sum @10 21600 0\"/>\r\n  </v:formulas>\r\n  <v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\"/>\r\n  <o:lock v:ext=\"edit\" aspectratio=\"t\"/>\r\n </v:shapetype><v:shape id=\"LH\" o:spid=\"_x0000_s1025\" type=\"#_x0000_t75\"\r\n  style=\';margin-left:0;margin-top:0;width:207pt;height:156pt;\r\n  z-index:1\'>\r\n  <v:imagedata o:relid=\"rId1\" o:title=\"WOPI\"/>\r\n  <o:lock v:ext=\"edit\" rotation=\"t\"/>\r\n </v:shape></xml>");
            writer.Flush();
            writer.Close();
        }

        private static void GenerateImagePart1Content(ImagePart imagePart1)
        {
            Image image = Image.FromFile(@"C:\Users\Administrator\Desktop\Capture.PNG");
            using (MemoryStream stream = new MemoryStream())
            {
                // Save image to stream.
                image.Save(stream, ImageFormat.Png);
                string imagePart1Data = Convert.ToBase64String(stream.ToArray());
                System.IO.Stream data = GetBinaryDataStream(imagePart1Data);
                imagePart1.FeedData(data);
                data.Close();
            }    

        }

        private static void ChangeCoreFilePropertiesPart1(CoreFilePropertiesPart coreFilePropertiesPart1)
        {
            var package = coreFilePropertiesPart1.OpenXmlPackage;
            package.PackageProperties.Modified = System.Xml.XmlConvert.ToDateTime("2015-07-30T03:03:22Z", System.Xml.XmlDateTimeSerializationMode.RoundtripKind);
        }

        private static void ChangeWorksheetPart1(WorksheetPart worksheetPart1)
        {
            Worksheet worksheet1 = worksheetPart1.Worksheet;

            HeaderFooter headerFooter1 = new HeaderFooter();
            OddHeader oddHeader1 = new OddHeader();
            oddHeader1.Text = "&L&G";

            headerFooter1.Append(oddHeader1);
            worksheet1.Append(headerFooter1);

            LegacyDrawingHeaderFooter legacyDrawingHeaderFooter1 = new LegacyDrawingHeaderFooter() { Id = "rId2" };
            worksheet1.Append(legacyDrawingHeaderFooter1);
        }

            private static System.IO.Stream GetBinaryDataStream(string base64String)
        {
            return new System.IO.MemoryStream(System.Convert.FromBase64String(base64String));
        }



    }
}
使用System.Linq;
使用DocumentFormat.OpenXml.Packaging;
使用DocumentFormat.OpenXml.Spreadsheet;
使用DocumentFormat.OpenXml;
使用系统图;
使用System.IO;
使用系统、绘图、成像;
使用制度;
命名空间Windows窗体应用程序2
{
公共类生成类
{
private static System.Collections.Generic.IDictionary UriPartDictionary=new System.Collections.Generic.Dictionary();
私有静态System.Collections.Generic.IDictionary UriNewDataPartDictionary=new System.Collections.Generic.Dictionary();
私有静态电子表格文档;
公共静态void ChangePackage(字符串文件路径)
{
使用(document=SpreadsheetDocument.Open(filePath,true))
{
更换零件();
}
}
私有静态void ChangeParts()
{
//在字典中存储对所有部分的引用。
BuildUriPartDictionary();
//添加新零件或新关系。
添加部件();
//更改指定部分的内容。
ChangeCoreFilePropertiesPart1(((CoreFilePropertiesPart)UriPartDictionary[“/docProps/core.xml]”);
    var hf = ws.GetFirstChild<HeaderFooter>();
    if (hf == null)
    {
        hf = new HeaderFooter();

        var drawing = ws.GetFirstChild<Drawing>();
        if (drawing != null)
        {
            ws.InsertBefore(hf, drawing);
        }
        else
        {
            ws.AppendChild(hf);
        }
    }