【问题标题】:OpenXML How to add hyperlink that points to another sheetOpenXML如何添加指向另一个工作表的超链接
【发布时间】:2017-12-12 01:49:24
【问题描述】:

我正在寻找如何向单元格添加超链接的示例。 似乎并不像添加文本那么容易。

我得到了生成正确 XML 但在 excel 中没有出现链接的代码

    private SheetData PopulateSheetWithData(SheetData sheetData, IList<Event> events, SpreadsheetDocument document)
    {
        int errorIndex = 0;
        foreach (var @event in events)
        {
            errorIndex++;

            Hyperlinks hyperlinks = new Hyperlinks();
            Hyperlink hyperlink = new Hyperlink()
            {
                Location = "UniqueError_" + errorIndex + "!A1",
                Display = @event.LOG_CORR_KEY,
                Reference = "A"+(errorIndex+1),
                Id = "UniqueError_" + errorIndex
            };
            hyperlinks.AppendChild(hyperlink);
            sheetData.AppendChild(hyperlinks);
        }
        return sheetData;
    }

我做错了吗? 我找到了this 文章如何添加超链接,但它看起来太复杂了。这个问题有什么帮助吗?

【问题讨论】:

    标签: c# .net excel hyperlink openxml


    【解决方案1】:

    所以经过一段时间的努力,我决定专注于我的 OpenXML Excell 调查,我成功了!

    我找到了一个关于如何将超链接插入到 excel 文件的解决方案,甚至更多,现在我的程序可以创建多个工作表,这些工作表的数量取决于我的 dataObject。 我很兴奋,我想与大家分享我的成就。

    首先,您需要创建 SpreadSheetDocument,因此我创建了一个方法 CreatePackage 并作为参数传递 filePath 以及我的 DataObject

    public void CreatePackage(string filePath, List<DataObject> data)
    {
        using (SpreadsheetDocument document = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook)
        )
        {
            CreateParts(document, data);
        }
     }
    

    CreateParts 方法接受 SpreadsheetDocumentDataObject

    private void CreateParts(SpreadsheetDocument document, List<DataObject> data)
        {
            ExtendedFilePropertiesPart extendedFilePropertiesPart = document.AddNewPart<ExtendedFilePropertiesPart>();
            extendedFilePropertiesPart.Properties = new Properties();
    
            WorkbookPart workbookPart = document.AddWorkbookPart();
            //Create new sheet for every Unique error
            GenerateWorkbookPart(workbookPart,data.Count);
            //generates new SheetPart for every sheet
            GenerateWorkSheetsParts(workbookPart,data);
    
        }
    

    我无法找到 ExtendedFilePropertiesPart 依赖 Excel 中 HyperLink 的原因和方式,但我确信没有此超链接将无法工作,即使 Excell 文件生成时也会损坏。

    接下来,我们需要为 WorkBookPart 创建一个 workbook 也为 workbook 我们需要创建一个 Sheets它将容纳所有 工作表。对于每个 sheet,我们还需要创建 WorkSheetPart,但对此,我稍后会回来。现在:

    private void GenerateWorkbookPart(WorkbookPart workbookPart, int dataCount)
            {
    
                Workbook workbook = new Workbook();
                Sheets sheets = new Sheets();
                Sheet sheet = new Sheet();
                for (int i = 1; i < dataCount+2; i++)
                {
                    var relId = "rId" + i;
                    if (i == 1)
                    {
                        sheet = new Sheet()
                        {
                            Name = "Main",
                            SheetId = (uint) i,
                            Id = relId
                        };
                    }
                    else
                    {
                        sheet = new Sheet()
                        {
                            Name = "Unique" + (i-1),
                            SheetId = (uint)i,
                            Id = relId
                        };
                    }
    
                    sheets.AppendChild(sheet);
                }
                workbook.AppendChild(sheets);
                workbookPart.Workbook = workbook;
            }
    

    为什么我要在总数中加上 +2?因为首先,由于某种原因,工作表的RelationshipId(Id)不能为0,所以我需要从1开始,第二,我的excel中的第一页是导航页所以我也跳过它。

    为我的文档创建 WorkBookPart 后,我​​将开始为每个 Sheet 创建 WorkSheetPart 并用数据填充它。

    private void GenerateWorkSheetsParts(WorkbookPart workbookPart, List<DataObject> data)
            {
                for (int i = 1; i < data.Count+2; i++)
                {
                    var relId = "rId" + i;
                    if (i == 1)
                    {
                        WorksheetPart workSheetPart = workbookPart.AddNewPart<WorksheetPart>(relId);
                        GenerateWorkSheetPartContent(workSheetPart, i, data);
                    }
                    else
                    {
                        WorksheetPart workSheetPart = workbookPart.AddNewPart<WorksheetPart>(relId);
                        GenerateWorkSheetPartContent(workSheetPart, i, data[i-2].NestedObject);
                    }
    
                }
            }
    
     private void GenerateWorkSheetPartContent(WorksheetPart worksheetPart,int indexer, List<NestedObject> data)
            {
    
                Worksheet worksheet = new Worksheet();
                SheetData sheetData = new SheetData();
                Hyperlinks hyperlinks = new Hyperlinks();
    
                if (indexer == 1)
                {
                    sheetData.AppendChild(ConstructHeader("Unique errors", "Count"));
                    
                    foreach (var @event in data)
                    {
                        indexer++;
                        Row row = new Row();
                        row.Append(ConstructCell(@event.ErrorMessage, "A" + indexer, CellValues.String), ConstructCell(@event.ListOfErrorsObject.Count.ToString(), CellValues.Number));
                        sheetData.AppendChild(row);
                        Hyperlink hyperlink = new Hyperlink()
                        {
                            Reference = "A" + indexer,
                            Location = "Unique" + (indexer - 1)+"!A1",
                            Display = "Unique" + indexer
                        };
                        hyperlinks.AppendChild(hyperlink);
                    }
                    worksheet.Append(sheetData, hyperlinks);
                    worksheetPart.Worksheet = worksheet;
                }
                else
                {
                    worksheet.AppendChild(sheetData);
                    worksheetPart.Worksheet = worksheet;
                }
            }
    

    Indexer - 当我的对象一个接一个地移动时,我可以确保 Indexer 与 rId 编号相同,并且也等于第一列的行号。 p>

    我还做了一些帮助器ConstructHeader,它在第一行构造标题,它需要String和ConstructCell的参数,这有助于更快地构造我可以附加到的单元格排。它还有一个重载,用于构造一个应该带有超链接的单元格。

            private Row ConstructHeader(params string[] headers)
        {
            Row row = new Row();
            foreach (var header in headers)
            {
                row.AppendChild(ConstructCell(header, CellValues.String));
            }
            return row;
        }
    
        private Cell ConstructCell(string value, CellValues dataType)
        {
            return new Cell()
            {
                CellValue = new CellValue(value),
                DataType = new EnumValue<CellValues>(dataType),
            };
        }
        private Cell ConstructCell(string value, string cellReference, CellValues dataType)
        {
            return new Cell()
            {
                CellReference = cellReference,
                CellValue = new CellValue(value),
                DataType = dataType,
            };
        }
    

    总结: 此代码将创建一个 Excel 文档,其中第一个工作表作为导航,其他工作表包含来自 DataObject 的填充数据。我希望这会对某人有所帮助。 另外,如果您有任何 cmets 或反馈 - 请分享我想听听。

    【讨论】:

    • 好帖子!这正是我所寻找的。谢谢!但是你的List&lt;DataObjects&gt; 是如何构建的?我在 NestedObject 部分苦苦挣扎。
    • @crank 我记得它有字符串结构和相关ID列表
    【解决方案2】:

    这对我有用,并将“test.xlsx”的 Sheet1 中的 C1 链接到 Sheet2 中的 A10

    static void AddHyperlink()
        {
    
            var filePath = "test.xlsx";
    
            // C1 in Sheet1
            var sheetName1 = "Sheet1";
            var column = "C";
            var row = 1;
    
            // Link to A10 in Sheet2
            var pathToOtherFile = filePath;
            var sheetName2 = "Sheet2";
            var cellRef = "A10";
    
            using (var document = SpreadsheetDocument.Open(filePath, true))
            {
                WorkbookPart wbPart = document.WorkbookPart;
    
    
    
                var sheets = document.WorkbookPart.Workbook.Sheets.Cast<Sheet>().ToList();
    
    
    
                var sheet = sheets.Where(x => x.Name == sheetName1).FirstOrDefault();
    
                string relationshipId = sheets.First().Id.Value;
                //get the worksheetpart by Id
                WorksheetPart worksheetPart = (WorksheetPart)wbPart.GetPartById(relationshipId);
                var worksheet = worksheetPart.Worksheet;
    
    
                Cell cell = GetCell(worksheet, column, row);
                var s = cell.LastChild;
    
                var cell1 = cell;
    
                CellFormula cellFormula1 = new CellFormula() { Space = SpaceProcessingModeValues.Preserve };
                cellFormula1.Text = $"HYPERLINK(\"[{pathToOtherFile}]{sheetName2}!{cellRef}\", \"Radio Clash\")";
                cell1.CellFormula = cellFormula1;
    
            }
    
        }
    
    
        private static Cell GetCell(Worksheet worksheet, string columnName, int rowIndex)
        {
            Row row = GetRow(worksheet, rowIndex);
    
            if (row == null)
                return null;
    
            return row.Elements<Cell>().Where(c => string.Compare
                   (c.CellReference.Value, columnName +
                   rowIndex, true) == 0).First();
        }
    
    
        // Given a worksheet and a row index, return the row.
        private static Row GetRow(Worksheet worksheet, int rowIndex)
        {
            return worksheet.GetFirstChild<SheetData>().
              Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
        }
    

    如果你想使用自引用(不引用另一个文件),你可以使用:

        cellFormula1.Text = $"=HYPERLINK(\"[\" & MID(CELL(\"filename\"),SEARCH(\"[\",CELL(\"filename\"))+1, SEARCH(\"]\",CELL(\"filename\"))-SEARCH(\"[\",CELL(\"filename\"))-1) &\"]{sheetName2}!{cellRef}\", \"Radio Clash\")";
    

    代替:

    cellFormula1.Text = $"HYPERLINK(\"[{pathToOtherFile}]{sheetName2}!{cellRef}\", \"Radio Clash\")";
    

    【讨论】:

      猜你喜欢
      • 2020-03-04
      • 1970-01-01
      • 1970-01-01
      • 2012-06-30
      • 2015-09-22
      • 1970-01-01
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      相关资源
      最近更新 更多