using ClosedXML.Extensions; using DocumentFormat.OpenXml.Office.Excel; using DocumentFormat.OpenXml.Office2010.Excel; using System.Collections.Generic; namespace ClosedXML.Excel { internal class XLCFDataBarConverterExtension : IXLCFConverterExtension { private static readonly IReadOnlyDictionary CFValueToTypeMap = new Dictionary { { DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues.Max, ConditionalFormattingValueObjectTypeValues.Max }, { DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues.Min, ConditionalFormattingValueObjectTypeValues.Min }, { DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues.Number, ConditionalFormattingValueObjectTypeValues.Numeric }, { DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues.Percent, ConditionalFormattingValueObjectTypeValues.Percent }, { DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues.Percentile, ConditionalFormattingValueObjectTypeValues.Percentile }, { DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues.Formula, ConditionalFormattingValueObjectTypeValues.Formula }, }; public ConditionalFormattingRule Convert(IXLConditionalFormat cf, XLWorkbook.SaveContext context) { ConditionalFormattingRule conditionalFormattingRule = new ConditionalFormattingRule() { Type = DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValues.DataBar, Id = ((XLConditionalFormat)cf).Id.WrapInBraces() }; DataBar dataBar = new DataBar() { MinLength = 0, MaxLength = 100, Gradient = true, ShowValue = !cf.ShowBarOnly }; var cfMin = BuildValueObject(cf, 1, ConditionalFormattingValueObjectTypeValues.AutoMin); var cfMax = BuildValueObject(cf, 2, ConditionalFormattingValueObjectTypeValues.AutoMax); var barAxisColor = new BarAxisColor { Rgb = XLColor.Black.Color.ToHex() }; var negativeFillColor = new NegativeFillColor { Rgb = cf.Colors[1].Color.ToHex() }; if (cf.Colors.Count == 2) { negativeFillColor = new NegativeFillColor { Rgb = cf.Colors[2].Color.ToHex() }; } dataBar.Append(cfMin); dataBar.Append(cfMax); dataBar.Append(negativeFillColor); dataBar.Append(barAxisColor); conditionalFormattingRule.Append(dataBar); return conditionalFormattingRule; } /// /// Builds a single x14 conditional formatting value object (cfvo) for a data bar threshold. /// /// The conditional format the data bar belongs to. /// 1-based threshold index (1 = minimum, 2 = maximum). /// /// Type emitted for an automatic bound: autoMin for the minimum, autoMax for the maximum. /// /// /// Automatic and min/max bounds are self-describing and carry no formula; only /// value based thresholds (num/percent/percentile/formula) emit an xm:f formula. /// private static ConditionalFormattingValueObject BuildValueObject(IXLConditionalFormat cf, int index, ConditionalFormattingValueObjectTypeValues automaticType) { cf.Values.TryGetValue(index, out var value); var formulaText = value?.Value; if (!cf.ContentTypes.TryGetValue(index, out var contentType)) { return new ConditionalFormattingValueObject { Type = automaticType }; } var type = GetCFType(contentType.ToOpenXml()); var valueObject = new ConditionalFormattingValueObject { Type = type }; if (type == ConditionalFormattingValueObjectTypeValues.Min || type == ConditionalFormattingValueObjectTypeValues.Max) { if (formulaText == null) { valueObject.Type = automaticType; } return valueObject; } if (formulaText != null) { valueObject.Append(new Formula { Text = formulaText }); } return valueObject; } private static ConditionalFormattingValueObjectTypeValues GetCFType(DocumentFormat.OpenXml.Spreadsheet.ConditionalFormatValueObjectValues value) { return CFValueToTypeMap[value]; } } }