以前の記事「セルの書式設定 - その2」を踏まえて、セルの背景色を操作します。


C:\Users\Public\Documents\openxmlsdk15.xlsx

セルA1からJ1にかけて、背景色をべた塗り(Solid)するコードを以下に示します。

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace OpenXMLSDK_Sample8 {
    class Program {
        static void Main(string[] args) {
            const string FILE = @"C:\Users\Public\Documents\openxmlsdk15.xlsx";
            const string SHEET_NAME = "Sheet1";

            using (SpreadsheetDocument excelDoc = SpreadsheetDocument.Open(FILE, true)) {
                WorkbookPart bookPart = excelDoc.WorkbookPart;

                Dictionary<string, string> colors = new Dictionary<string, string>();
                colors.Add("A1", "FFC00000");
                colors.Add("B1", "FFFF0000");
                colors.Add("C1", "FFFFC000");
                colors.Add("D1", "FFFFFF00");
                colors.Add("E1", "FF92D050");
                colors.Add("F1", "FF00B050");
                colors.Add("G1", "FF00B0F0");
                colors.Add("H1", "FF0070C0");
                colors.Add("I1", "FF002060");
                colors.Add("J1", "FF7030A0");

                foreach (KeyValuePair<string, string> cell_color in colors) {
                    SetCellBackgroundColor(bookPart, SHEET_NAME, cell_color.Key, new ForegroundColor() { Rgb = cell_color.Value });
                }

            }
            //ファイルを開く
            System.Diagnostics.Process.Start(FILE);
        }

        private static void SetCellBackgroundColor(WorkbookPart bookPart, string sheet_name, string cell_address, ForegroundColor bg_color) {
            int sheet_index = GetWorksheetIndex(bookPart, sheet_name);
            WorksheetPart sheet_part = GetWorksheetPart(bookPart, sheet_index);
            Cell target_cell = GetCell(sheet_part, cell_address);

            //指定された色と同じパターンのFillを探す
            Fill same_bg_fill = bookPart.WorkbookStylesPart.Stylesheet.Fills.Elements<Fill>()
                .FirstOrDefault(f => 
                f.PatternFill != null && f.PatternFill.ForegroundColor != null &&
                f.PatternFill.ForegroundColor.Rgb != null &&
                f.PatternFill.PatternType.Value == PatternValues.Solid &&
                f.PatternFill.ForegroundColor.Rgb.Value == bg_color.Rgb.Value);
            
            int same_bg_index; //FillのID
            //見つからない場合は新たに作成
            if (same_bg_fill == null) {
                same_bg_fill = new Fill() { PatternFill = new PatternFill() { ForegroundColor = bg_color } };
                same_bg_fill.PatternFill.PatternType = new EnumValue<PatternValues>(PatternValues.Solid);
                bookPart.WorkbookStylesPart.Stylesheet.Fills.AppendChild<Fill>(same_bg_fill);
                same_bg_index = bookPart.WorkbookStylesPart.Stylesheet.Fills.Count() - 1;

                //Count属性の更新
                bookPart.WorkbookStylesPart.Stylesheet.Fills.Count++;
            }else {
                same_bg_index = bookPart.WorkbookStylesPart.Stylesheet.Fills.ToList().IndexOf(same_bg_fill);
            }

            var cell_format_enumerable = bookPart.WorkbookStylesPart.Stylesheet.CellFormats.Elements<CellFormat>();

            CellFormat target_cell_format = null;
            if(target_cell.StyleIndex != null) {
                //背景色をセットするセルに現在セットされているCellFormatを取得
                target_cell_format = cell_format_enumerable.ElementAt(Convert.ToInt32(target_cell.StyleIndex.Value));
            } else {
                target_cell_format = new CellFormat();
                target_cell_format.FillId = new UInt32Value((uint)same_bg_index);
                target_cell_format.ApplyFill = true;
            }

            //同じ属性・ChildNodeをもち、かつ指定されたFillIDと同じ設定をもつCellFormatを探す
            CellFormat format_to = cell_format_enumerable.FirstOrDefault(
                r => r.GetAttributes().Where(f => f.LocalName != "fillId").SequenceEqual(target_cell_format.GetAttributes()
                .Where(f => f.LocalName != "fillId")) && r.FillId != null && r.FillId.Value == (uint)same_bg_index && r.InnerXml == target_cell_format.InnerXml);

            if (format_to != null) {
                target_cell.StyleIndex = new UInt32Value((uint)(cell_format_enumerable.ToList().IndexOf(format_to)));
            } else {
                if (target_cell.StyleIndex != null) {
                    format_to = target_cell_format.CloneNode(true) as CellFormat;
                    if (format_to.FillId == null) {
                        format_to.FillId = new UInt32Value((uint)same_bg_index);
                    } else {
                        format_to.FillId.Value = (uint)same_bg_index;
                    }
                } else {
                    format_to = target_cell_format;
                }
                bookPart.WorkbookStylesPart.Stylesheet.CellFormats.Append(format_to);
                target_cell.StyleIndex = new UInt32Value((uint)bookPart.WorkbookStylesPart.Stylesheet.CellFormats.Count() - 1);

                //Count属性を更新
                bookPart.WorkbookStylesPart.Stylesheet.CellFormats.Count++;
            }
        }
    // 以下省略...
    }
}

「以下省略」とした部分に定義されているメソッドについては「セルの書式設定 - 表示形式」など、以前の記事をご覧ください。

31行目のSetCellBackgroundColorによってセルそれぞれの背景色をセットします。

SetCellBackgroundColorでは、41行目で指定されたセルを取得します。

45行目から50行目で、指定された背景色を持つFill要素を検索し、52行目から64行目で、そのindexを取得します。

71行目で指定されたセルのStyleIndexを手掛かりに現在セットされているCellFormatを取得して、
79行目から81行目で「FillID以外の属性がこのCellFormatと同じであり、かつFillIDに指定された背景色を持つFill要素のindexがセットされているようなCellFormat」を探します。

もしもそのようなCellFormatが見つかれば指定されたセルのStyleIndexを、見つかったCellFormatを指し示すように変更します(84行目)。
もしも見つからなかったら指定されたセルのCellFormatの複製を作成し、FillIDを指定された背景色を持つFill要素のindexに変更したうえでCellFormatsに追加して、
指定されたセルのStyleIndexがこのCellFormatを指すように変更します(96、97行目)。

このコードを実行すると、セルA1からJ1の背景色が以下のように変わります。

次回はセルの罫線を設定するコードについて紹介します。