首页 > 解决方案 > 在 Excel 中更改 CellValue 中文本的字体颜色 - OpenXml

问题描述

如何更改 Excel 中 CellValue 的文本颜色?我可以更改单元格的前景色,但它会更改单元格内所有文本的颜色,这是我不想要的。我只想突出显示单元格内的特定文本,即 CellValue 文本。

我正在使用下面的代码突出显示单元格文本,如何为 CellValue 完成?

foreach (DocumentFormat.OpenXml.Spreadsheet.Cell currentCell in allCells)
{    
Fill fill = new Fill()
    {
         PatternFill = new PatternFill
         {
             PatternType = PatternValues.Solid,
             ForegroundColor = new ForegroundColor() { Rgb = "FFFF00" }
          }
    };
    styleSheet.Fills.AppendChild(fill);

   //Adding the  CellFormat which uses the Fill element 
    CellFormats cellFormats = styleSheet.CellFormats;
    CellFormat cf = new CellFormat();
    cf.FillId = styleSheet.Fills.Count;
    cellFormats.AppendChild(cf);
    currentCell.StyleIndex = styleSheet.CellFormats.Count;
}

我在 CellValue 中没有看到 Style 的任何属性

CellValue currentCellValue = currentCell.GetFirstChild<CellValue>();
if (currentCell.DataType == CellValues.SharedString) // cell has a cell value that is a string, thus, stored else where
    {
             data = doc.WorkbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault().SharedStringTable.ElementAt(int.Parse(currentCellValue.Text)).InnerText;
    }

从 OpenXML 工具生成的代码 -

SharedStringTable sharedStringTable1 = new SharedStringTable(){ Count = (UInt32Value)1U, UniqueCount = (UInt32Value)1U };

            SharedStringItem sharedStringItem1 = new SharedStringItem();

            Run run1 = new Run();

            RunProperties runProperties1 = new RunProperties();
            FontSize fontSize3 = new FontSize(){ Val = 11D };
            Color color3 = new Color(){ Rgb = "FFFF0000" };
            RunFont runFont1 = new RunFont(){ Val = "Calibri" };
            FontFamily fontFamily1 = new FontFamily(){ Val = 2 };
            FontScheme fontScheme4 = new FontScheme(){ Val = FontSchemeValues.Minor };

            runProperties1.Append(fontSize3);
            runProperties1.Append(color3);
            runProperties1.Append(runFont1);
            runProperties1.Append(fontFamily1);
            runProperties1.Append(fontScheme4);
            Text text1 = new Text();
            text1.Text = "Microsoft";

            run1.Append(runProperties1);
            run1.Append(text1);

            Run run2 = new Run();

            RunProperties runProperties2 = new RunProperties();
            FontSize fontSize4 = new FontSize(){ Val = 11D };
            Color color4 = new Color(){ Theme = (UInt32Value)1U };
            RunFont runFont2 = new RunFont(){ Val = "Calibri" };
            FontFamily fontFamily2 = new FontFamily(){ Val = 2 };
            FontScheme fontScheme5 = new FontScheme(){ Val = FontSchemeValues.Minor };

            runProperties2.Append(fontSize4);
            runProperties2.Append(color4);
            runProperties2.Append(runFont2);
            runProperties2.Append(fontFamily2);
            runProperties2.Append(fontScheme5);
            Text text2 = new Text(){ Space = SpaceProcessingModeValues.Preserve };
            text2.Text = " is great";

            run2.Append(runProperties2);
            run2.Append(text2);

            sharedStringItem1.Append(run1);
            sharedStringItem1.Append(run2);

            sharedStringTable1.Append(sharedStringItem1);

            sharedStringTablePart1.SharedStringTable = sharedStringTable1;

标签: c#excelopenxml

解决方案


你必须通过SharedStringItem元素。
这样的一个SharedStringItem 可以包含Run元素。您在此元素
上应用样式。Run

重要的是,您的代码还涵盖 aSharedStringItem不包含任何子Run元素的情况。当单元格仅包含文本而没有任何格式化的子元素时就是这种情况。
在这里,您必须创建一个新的 Run 才能应用样式。

下面的代码使用 Excel 文件将第一行中的单元格的单词 RED 的颜色设置为红色,如下图所示。
单元格A1包含Run元素,单元格B1不包含。

输入

最终结果看起来像

结果

String pathToYourExcelFile = @"C:\Folder\ExcelFile.xlsx";
using (SpreadsheetDocument document = SpreadsheetDocument.Open(pathToYourExcelFile, true))
{
    WorkbookPart workbook =  document.WorkbookPart;                
    WorksheetPart firstWorksheet = document.WorkbookPart.WorksheetParts.FirstOrDefault();
    SharedStringTablePart stringTable = workbook.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();                              

    IEnumerable<Row> rows = firstWorksheet.Worksheet.GetFirstChild<SheetData>().Elements<Row>();
    Row firstRow = rows.FirstOrDefault();

    foreach (Cell cell in firstRow.Elements<Cell>())
    {                    
        foreach (CellValue cellValue in cell.Elements<CellValue>())
        {   
            IEnumerable<SharedStringItem> sharedStrings = 
                stringTable.SharedStringTable.Elements<SharedStringItem>()
                    .Where((o, i) => i == Convert.ToInt32(cellValue.InnerText));

            foreach (SharedStringItem sharedString in sharedStrings)
            { 
                IEnumerable<Run> runs = sharedString.Elements<Run>();
                if (runs.Count() > 0)
                {                                
                    foreach (Run run in runs)
                    {
                        if (run.InnerText == "RED")
                        {
                            RunProperties properties = run.RunProperties ?? new RunProperties();
                            Color color = properties.Elements<Color>().FirstOrDefault();
                            if (color != null)
                            {
                                properties.RemoveChild<Color>(color);
                            }

                            properties.Append(new Color { Rgb = "FFFF0000" }) ;
                        }
                    }
                }
                else
                {       
                    // No Runs, only text; create a Run.                                                     
                    Text text = new Text(sharedString.InnerText);                                
                    sharedString.RemoveAllChildren();
                    Run run = new Run();
                    run.Append(text);
                    run.RunProperties = new RunProperties();
                    run.RunProperties.Append(new Color { Rgb = "FFFF0000" }) ;
                    sharedString.Append(run);
                }
            }
        }
    }

    document.Save();

我将把上面代码中的清理和异常处理留给你……


编辑

对于您的特定情况,具有单元格值“Microsoft 很棒”,您必须将此字符串拆分为单独的部分并Run为每个部分创建一个。仅在具有文本值“Microsoft”的部分上应用自定义字体颜色。

下面的简约代码显示了这个概念。
此代码可以使用一些改进,因为最好不要拆分为单独的单词,但你明白了......

// No Runs, only text.              

const String MS = "Microsoft";
String innerText = sharedString.InnerText;
if (innerText.IndexOf(MS, StringComparison.OrdinalIgnoreCase) >= 0)
{ 
    sharedString.RemoveAllChildren();

    String[] parts = innerText.Split(' ');
    for (Int32 i = 0; i < parts.Length; i++)
    {
        String part = parts[i];
        Text text = new Text((i > 0 ? " " : String.Empty) + part);
        text.Space = SpaceProcessingModeValues.Preserve;         

        Run run = new Run();                                        
        run.Append(text);

        if (part.Equals(MS, StringComparison.OrdinalIgnoreCase))
        {
            run.RunProperties = new RunProperties();
            run.RunProperties.Append(new Color { Rgb = "FFFF0000" }) ;
        }

        sharedString.Append(run);                                        
    }

下图显示了之前和之后。

之前和之后


编辑

回应您关于如何遍历 Excel 文档中所有单元格的评论;请参阅下面的代码。

String pathToYourExcelFile = @"C:\Folder\ExcelFile.xlsx";
using (SpreadsheetDocument document = SpreadsheetDocument.Open(pathToYourExcelFile, true))
{
    WorkbookPart workbook =  document.WorkbookPart;

    // Loop over all worksheets.
    IEnumerable<WorksheetPart> worksheets = document.WorkbookPart.WorksheetParts;
    foreach (WorksheetPart worksheet in worksheets)
    {
        // Loop over all rows.
        IEnumerable<Row> rows = worksheet.Worksheet.GetFirstChild<SheetData>().Elements<Row>();   
        foreach (Row row in rows) 
        {
            // Loop over all cells.
            foreach (Cell cell in row.Elements<Cell>())
            {
                // Loop over all cell values.
                foreach (CellValue cellValue in cell.Elements<CellValue>())
                {
                    // Apply content formatting as in code above ...
                }
            }
        }
    }
}

推荐阅读