Revert "[NWD] Further EPPlus fixes & improvements."
This reverts commit d0678ed0e8a7acc31363e9d08dc7d3899a8f2177.
Reason for revert: Workflow templates for xlsx files modify styling options in some cases.
Change-Id: Ief762b59af79be9071ff89753550b37c0da6bcbd
Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/epplus/+/207762
Reviewed-by: Hughes Hilton <hugheshilton@google.com>
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
index 91abb7d..99a44a1 100644
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
+++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
@@ -29,6 +29,8 @@
* Eyal Seagull Conditional Formatting Adaption 2012-04-03
*******************************************************************************/
+using System.Drawing;
+
namespace OfficeOpenXml.ConditionalFormatting.Contracts;
/// <summary>
@@ -49,4 +51,9 @@
/// Databar High Value
/// </summary>
ExcelConditionalFormattingIconDataBarValue HighValue { get; }
+
+ /// <summary>
+ /// The color of the databar
+ /// </summary>
+ Color Color { get; set; }
}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
index 770d75b..700ffd6 100644
--- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
+++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
@@ -44,4 +44,9 @@
/// ShowValue
/// </summary>
bool ShowValue { get; set; }
+
+ /// <summary>
+ /// IconSet (3, 4 ou 5 IconSet)
+ /// </summary>
+ T IconSet { get; set; }
}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs b/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
index bd84006..b2d99bf 100644
--- a/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
+++ b/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
@@ -29,6 +29,7 @@
* Eyal Seagull Conditional Formatting 2012-04-03
*******************************************************************************/
+using System.Drawing;
using OfficeOpenXml.ConditionalFormatting.Contracts;
namespace OfficeOpenXml.ConditionalFormatting;
@@ -283,4 +284,35 @@
/// </summary>
/// <returns></returns>
IExcelConditionalFormattingTwoColorScale AddTwoColorScale();
+
+ /// <summary>
+ /// Adds a <see cref="IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>"/> to the range
+ /// </summary>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet(
+ eExcelconditionalFormatting3IconsSetType iconSet);
+
+ /// <summary>
+ /// Adds a <see cref="IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>"/> to the range
+ /// </summary>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet(
+ eExcelconditionalFormatting4IconsSetType iconSet);
+
+ /// <summary>
+ /// Adds a <see cref="IExcelConditionalFormattingFiveIconSet"/> to the range
+ /// </summary>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ IExcelConditionalFormattingFiveIconSet AddFiveIconSet(
+ eExcelconditionalFormatting5IconsSetType iconSet);
+
+ /// <summary>
+ /// Adds a <see cref="IExcelConditionalFormattingDataBarGroup"/> to the range
+ /// </summary>
+ /// <param name="color"></param>
+ /// <returns></returns>
+ IExcelConditionalFormattingDataBarGroup AddDatabar(Color color);
}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
index 08605aa..8d0ecf1 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
@@ -29,8 +29,10 @@
* Eyal Seagull Conditional Formatting 2012-04-03
*******************************************************************************/
+using System;
using System.Collections;
using System.Collections.Generic;
+using System.Drawing;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
using OfficeOpenXml.Utils;
@@ -775,4 +777,66 @@
eExcelConditionalFormattingRuleType.TwoColorScale,
address);
}
+
+ /// <summary>
+ /// Add ThreeIconSet Rule
+ /// </summary>
+ /// <param name="address">The address</param>
+ /// <param name="iconSet">Type of iconset</param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet(
+ ExcelAddress address,
+ eExcelconditionalFormatting3IconsSetType iconSet) {
+ var icon =
+ (IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>)
+ AddRule(eExcelConditionalFormattingRuleType.ThreeIconSet, address);
+ icon.IconSet = iconSet;
+ return icon;
+ }
+
+ /// <summary>
+ /// Adds a FourIconSet rule
+ /// </summary>
+ /// <param name="address"></param>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet(
+ ExcelAddress address,
+ eExcelconditionalFormatting4IconsSetType iconSet) {
+ var icon =
+ (IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>)
+ AddRule(eExcelConditionalFormattingRuleType.FourIconSet, address);
+ icon.IconSet = iconSet;
+ return icon;
+ }
+
+ /// <summary>
+ /// Adds a FiveIconSet rule
+ /// </summary>
+ /// <param name="address"></param>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingFiveIconSet AddFiveIconSet(
+ ExcelAddress address,
+ eExcelconditionalFormatting5IconsSetType iconSet) {
+ var icon = (IExcelConditionalFormattingFiveIconSet)AddRule(
+ eExcelConditionalFormattingRuleType.FiveIconSet,
+ address);
+ icon.IconSet = iconSet;
+ return icon;
+ }
+
+ /// <summary>
+ /// Adds a databar rule
+ /// </summary>
+ /// <param name="address"></param>
+ /// <param name="color"></param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingDataBarGroup AddDatabar(ExcelAddress address, Color color) {
+ var dataBar = (IExcelConditionalFormattingDataBarGroup)AddRule(
+ eExcelConditionalFormattingRuleType.DataBar,
+ address);
+ dataBar.Color = color;
+ return dataBar;
+ }
}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
index 84d8fb1..a8585f0 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
@@ -30,6 +30,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Xml;
using OfficeOpenXml.Utils;
@@ -62,6 +63,7 @@
internal ExcelConditionalFormattingColorScaleValue(
eExcelConditionalFormattingValueObjectPosition position,
eExcelConditionalFormattingValueObjectType type,
+ Color color,
double value,
string formula,
eExcelConditionalFormattingRuleType ruleType,
@@ -130,6 +132,7 @@
Position = position;
RuleType = ruleType;
Type = type;
+ Color = color;
Value = value;
Formula = formula;
}
@@ -150,6 +153,7 @@
internal ExcelConditionalFormattingColorScaleValue(
eExcelConditionalFormattingValueObjectPosition position,
eExcelConditionalFormattingValueObjectType type,
+ Color color,
double value,
string formula,
eExcelConditionalFormattingRuleType ruleType,
@@ -160,6 +164,7 @@
: this(
position,
type,
+ color,
value,
formula,
ruleType,
@@ -183,6 +188,7 @@
internal ExcelConditionalFormattingColorScaleValue(
eExcelConditionalFormattingValueObjectPosition position,
eExcelConditionalFormattingValueObjectType type,
+ Color color,
eExcelConditionalFormattingRuleType ruleType,
ExcelAddress address,
int priority,
@@ -191,6 +197,7 @@
: this(
position,
type,
+ color,
0,
null,
ruleType,
@@ -344,6 +351,32 @@
}
/// <summary>
+ ///
+ /// </summary>
+ public Color Color {
+ get {
+ // Color Code like "FF5B34F2"
+ var colorCode = GetXmlNodeString(
+ string.Format(
+ "{0}[position()={1}]/{2}",
+ // {0}
+ ExcelConditionalFormattingConstants.Paths._color,
+ // {1}
+ GetNodeOrder(),
+ // {2}
+ ExcelConditionalFormattingConstants.Paths._rgbAttribute));
+
+ return ExcelConditionalFormattingHelper.ConvertFromColorCode(colorCode);
+ }
+ set =>
+ // Use the color code to store (Ex. "FF5B35F2")
+ CreateNodeByOrdem(
+ eExcelConditionalFormattingValueObjectNodeType.Color,
+ ExcelConditionalFormattingConstants.Paths._rgbAttribute,
+ value.ToArgb().ToString("x"));
+ }
+
+ /// <summary>
/// Get/Set the 'cfvo' node @val attribute
/// </summary>
public Double Value {
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
index ba97c3d..0ea9a45 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
@@ -30,6 +30,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Xml;
@@ -62,6 +63,20 @@
}
/// <summary>
+ /// Convert a color code to Color Object
+ /// </summary>
+ /// <param name="colorCode">Color Code (Ex. "#FFB43C53" or "FFB43C53")</param>
+ /// <returns></returns>
+ public static Color ConvertFromColorCode(string colorCode) {
+ try {
+ return Color.FromArgb(Int32.Parse(colorCode.Replace("#", ""), NumberStyles.HexNumber));
+ } catch {
+ // Assume white is the default color (instead of giving an error)
+ return Color.White;
+ }
+ }
+
+ /// <summary>
///
/// </summary>
/// <param name="node"></param>
diff --git a/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs b/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs
index 6fcc305..debf061 100644
--- a/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs
+++ b/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs
@@ -29,6 +29,7 @@
* Eyal Seagull Conditional Formatting 2012-04-03
*******************************************************************************/
+using System.Drawing;
using OfficeOpenXml.ConditionalFormatting.Contracts;
using OfficeOpenXml.Utils;
@@ -377,4 +378,61 @@
eExcelConditionalFormattingRuleType.TwoColorScale,
_address));
}
+
+ /// <summary>
+ /// Adds a ThreeIconSet rule
+ /// </summary>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet(
+ eExcelconditionalFormatting3IconsSetType iconSet) {
+ var rule =
+ (IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>)(_worksheet.ConditionalFormatting.AddRule(
+ eExcelConditionalFormattingRuleType.ThreeIconSet,
+ _address));
+ rule.IconSet = iconSet;
+ return rule;
+ }
+
+ /// <summary>
+ /// Adds a FourIconSet rule
+ /// </summary>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet(
+ eExcelconditionalFormatting4IconsSetType iconSet) {
+ var rule =
+ (IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>)(_worksheet.ConditionalFormatting.AddRule(
+ eExcelConditionalFormattingRuleType.FourIconSet,
+ _address));
+ rule.IconSet = iconSet;
+ return rule;
+ }
+
+ /// <summary>
+ /// Adds a FiveIconSet rule
+ /// </summary>
+ /// <param name="iconSet"></param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingFiveIconSet AddFiveIconSet(
+ eExcelconditionalFormatting5IconsSetType iconSet) {
+ var rule = (IExcelConditionalFormattingFiveIconSet)(_worksheet.ConditionalFormatting.AddRule(
+ eExcelConditionalFormattingRuleType.FiveIconSet,
+ _address));
+ rule.IconSet = iconSet;
+ return rule;
+ }
+
+ /// <summary>
+ /// Adds a Databar rule
+ /// </summary>
+ /// <param name="color">The color of the databar</param>
+ /// <returns></returns>
+ public IExcelConditionalFormattingDataBarGroup AddDatabar(Color color) {
+ var rule = (IExcelConditionalFormattingDataBarGroup)(_worksheet.ConditionalFormatting.AddRule(
+ eExcelConditionalFormattingRuleType.DataBar,
+ _address));
+ rule.Color = color;
+ return rule;
+ }
}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
index 8ca4be2..2a80337 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
@@ -29,6 +29,7 @@
* Eyal Seagull Added 2012-04-03
*******************************************************************************/
+using System.Drawing;
using System.Globalization;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
@@ -152,4 +153,17 @@
public ExcelConditionalFormattingIconDataBarValue LowValue { get; internal set; }
public ExcelConditionalFormattingIconDataBarValue HighValue { get; internal set; }
+
+ private const string _colorPath = "d:dataBar/d:color/@rgb";
+
+ public Color Color {
+ get {
+ var rgb = GetXmlNodeString(_colorPath);
+ if (!string.IsNullOrEmpty(rgb)) {
+ return Color.FromArgb(int.Parse(rgb, NumberStyles.HexNumber));
+ }
+ return Color.White;
+ }
+ set => SetXmlNodeString(_colorPath, value.ToArgb().ToString("X"));
+ }
}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
index 5700e10..fa0574e 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
@@ -71,6 +71,7 @@
LowValue = new(
eExcelConditionalFormattingValueObjectPosition.Low,
eExcelConditionalFormattingValueObjectType.Min,
+ ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoLowValue),
eExcelConditionalFormattingRuleType.ThreeColorScale,
address,
priority,
@@ -81,6 +82,7 @@
MiddleValue = new(
eExcelConditionalFormattingValueObjectPosition.Middle,
eExcelConditionalFormattingValueObjectType.Percent,
+ ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoMiddleValue),
50,
string.Empty,
eExcelConditionalFormattingRuleType.ThreeColorScale,
@@ -93,6 +95,7 @@
HighValue = new(
eExcelConditionalFormattingValueObjectPosition.High,
eExcelConditionalFormattingValueObjectType.Max,
+ ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoHighValue),
eExcelConditionalFormattingRuleType.ThreeColorScale,
address,
priority,
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
index bcf19e1..2b8b27e 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
@@ -223,6 +223,18 @@
private const string _iconSetPath = "d:iconSet/@iconSet";
+ /// <summary>
+ /// Type of iconset
+ /// </summary>
+ public T IconSet {
+ get {
+ var v = GetXmlNodeString(_iconSetPath);
+ v = v.Substring(1); //Skip first icon.
+ return (T)Enum.Parse(typeof(T), v, true);
+ }
+ set => SetXmlNodeString(_iconSetPath, GetIconSetString(value));
+ }
+
private string GetIconSetString(T value) {
if (Type == eExcelConditionalFormattingRuleType.FourIconSet) {
switch (value.ToString()) {
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
index ad7d79f..69ee8b1 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
@@ -81,6 +81,7 @@
LowValue = new(
eExcelConditionalFormattingValueObjectPosition.Low,
eExcelConditionalFormattingValueObjectType.Min,
+ ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoLowValue),
eExcelConditionalFormattingRuleType.TwoColorScale,
address,
priority,
@@ -91,6 +92,7 @@
HighValue = new(
eExcelConditionalFormattingValueObjectPosition.High,
eExcelConditionalFormattingValueObjectType.Max,
+ ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoHighValue),
eExcelConditionalFormattingRuleType.TwoColorScale,
address,
priority,
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs
index 7917008..44b5d3e 100644
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs
+++ b/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs
@@ -49,7 +49,7 @@
/// <summary>
/// Controls how Excel will handle invalid values.
/// </summary>
- ExcelDataValidationWarningStyle ErrorStyle { get; }
+ ExcelDataValidationWarningStyle ErrorStyle { get; set; }
/// <summary>
/// True if input message should be shown
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
index 2604079..48b06cb 100644
--- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
+++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
@@ -39,5 +39,5 @@
/// <summary>
/// Operator type
/// </summary>
- ExcelDataValidationOperator Operator { get; }
+ ExcelDataValidationOperator Operator { get; set; }
}
diff --git a/EPPlus/DataValidation/ExcelDataValidation.cs b/EPPlus/DataValidation/ExcelDataValidation.cs
index 88a60de..78b6259 100644
--- a/EPPlus/DataValidation/ExcelDataValidation.cs
+++ b/EPPlus/DataValidation/ExcelDataValidation.cs
@@ -199,9 +199,18 @@
public ExcelDataValidationOperator Operator {
get {
var operatorString = GetXmlNodeString(_operatorPath);
- return Enum.TryParse<ExcelDataValidationOperator>(operatorString, true, out var op)
- ? op
- : ExcelDataValidationOperator.Any;
+ if (!string.IsNullOrEmpty(operatorString)) {
+ return (ExcelDataValidationOperator)
+ Enum.Parse(typeof(ExcelDataValidationOperator), operatorString);
+ }
+ return default(ExcelDataValidationOperator);
+ }
+ set {
+ if (!ValidationType.AllowOperator) {
+ throw new InvalidOperationException(
+ "The current validation type does not allow operator to be set");
+ }
+ SetXmlNodeString(_operatorPath, value.ToString());
}
}
@@ -211,9 +220,17 @@
public ExcelDataValidationWarningStyle ErrorStyle {
get {
var errorStyleString = GetXmlNodeString(_errorStylePath);
- return Enum.TryParse<ExcelDataValidationWarningStyle>(errorStyleString, true, out var style)
- ? style
- : ExcelDataValidationWarningStyle.Undefined;
+ if (!string.IsNullOrEmpty(errorStyleString)) {
+ return (ExcelDataValidationWarningStyle)
+ Enum.Parse(typeof(ExcelDataValidationWarningStyle), errorStyleString);
+ }
+ return ExcelDataValidationWarningStyle.Undefined;
+ }
+ set {
+ if (value == ExcelDataValidationWarningStyle.Undefined) {
+ DeleteNode(_errorStylePath);
+ }
+ SetXmlNodeString(_errorStylePath, value.ToString());
}
}
diff --git a/EPPlus/DataValidation/ExcelDataValidationType.cs b/EPPlus/DataValidation/ExcelDataValidationType.cs
index cdcc99c..1c7465c 100644
--- a/EPPlus/DataValidation/ExcelDataValidationType.cs
+++ b/EPPlus/DataValidation/ExcelDataValidationType.cs
@@ -116,6 +116,34 @@
/// </summary>
internal bool AllowOperator { get; private set; }
+ /// <summary>
+ /// Returns a validation type by <see cref="eDataValidationType"/>
+ /// </summary>
+ /// <param name="type"></param>
+ /// <returns></returns>
+ internal static ExcelDataValidationType GetByValidationType(eDataValidationType type) {
+ switch (type) {
+ case eDataValidationType.Any:
+ return Any;
+ case eDataValidationType.Whole:
+ return Whole;
+ case eDataValidationType.List:
+ return List;
+ case eDataValidationType.Decimal:
+ return Decimal;
+ case eDataValidationType.TextLength:
+ return TextLength;
+ case eDataValidationType.DateTime:
+ return DateTime;
+ case eDataValidationType.Time:
+ return Time;
+ case eDataValidationType.Custom:
+ return Custom;
+ default:
+ throw new InvalidOperationException("Non supported Validationtype : " + type);
+ }
+ }
+
internal static ExcelDataValidationType GetBySchemaName(string schemaName) {
switch (schemaName) {
case DataValidationSchemaNames.Any:
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
index bd137cd..3392fc7 100644
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
+++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
@@ -30,6 +30,9 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
+using System;
+using System.Drawing;
+using System.Globalization;
using System.Xml;
namespace OfficeOpenXml.Drawing.Vml;
@@ -149,6 +152,179 @@
}
}
+ private const string _backgroundcolorPath = "@fillcolor";
+
+ /// <summary>
+ /// Background color
+ /// </summary>
+ public Color BackgroundColor {
+ get {
+ string col = GetXmlNodeString(_backgroundcolorPath);
+ if (col == "") {
+ return Color.FromArgb(0xff, 0xff, 0xe1);
+ }
+ if (col.StartsWith("#")) {
+ col = col.Substring(1, col.Length - 1);
+ }
+ if (int.TryParse(
+ col,
+ NumberStyles.AllowHexSpecifier,
+ CultureInfo.InvariantCulture,
+ out var res)) {
+ return Color.FromArgb(res);
+ }
+ return Color.Empty;
+ }
+ set {
+ string color = "#" + value.ToArgb().ToString("X").Substring(2, 6);
+ SetXmlNodeString(_backgroundcolorPath, color);
+ //SetXmlNode(BACKGROUNDCOLOR2_PATH, color);
+ }
+ }
+
+ private const string _linestylePath = "v:stroke/@dashstyle";
+ private const string _endcapPath = "v:stroke/@endcap";
+
+ /// <summary>
+ /// Linestyle for border
+ /// </summary>
+ public eLineStyleVml LineStyle {
+ get {
+ string v = GetXmlNodeString(_linestylePath);
+ if (v == "") {
+ return eLineStyleVml.Solid;
+ }
+ if (v == "1 1") {
+ v = GetXmlNodeString(_endcapPath);
+ return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true);
+ }
+ return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true);
+ }
+ set {
+ if (value == eLineStyleVml.Round || value == eLineStyleVml.Square) {
+ SetXmlNodeString(_linestylePath, "1 1");
+ if (value == eLineStyleVml.Round) {
+ SetXmlNodeString(_endcapPath, "round");
+ } else {
+ DeleteNode(_endcapPath);
+ }
+ } else {
+ string v = value.ToString();
+ v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1, v.Length - 1);
+ SetXmlNodeString(_linestylePath, v);
+ DeleteNode(_endcapPath);
+ }
+ }
+ }
+
+ private const string _linecolorPath = "@strokecolor";
+
+ /// <summary>
+ /// Line color
+ /// </summary>
+ public Color LineColor {
+ get {
+ string col = GetXmlNodeString(_linecolorPath);
+ if (col == "") {
+ return Color.Black;
+ }
+ if (col.StartsWith("#")) {
+ col = col.Substring(1, col.Length - 1);
+ }
+ if (int.TryParse(
+ col,
+ NumberStyles.AllowHexSpecifier,
+ CultureInfo.InvariantCulture,
+ out var res)) {
+ return Color.FromArgb(res);
+ }
+ return Color.Empty;
+ }
+ set {
+ string color = "#" + value.ToArgb().ToString("X").Substring(2, 6);
+ SetXmlNodeString(_linecolorPath, color);
+ }
+ }
+
+ private const string _linewidthPath = "@strokeweight";
+
+ /// <summary>
+ /// Width of the border
+ /// </summary>
+ public Single LineWidth {
+ get {
+ string wt = GetXmlNodeString(_linewidthPath);
+ if (wt == "") {
+ return (Single).75;
+ }
+ if (wt.EndsWith("pt")) {
+ wt = wt.Substring(0, wt.Length - 2);
+ }
+
+ if (Single.TryParse(wt, NumberStyles.Any, CultureInfo.InvariantCulture, out var ret)) {
+ return ret;
+ }
+ return 0;
+ }
+ set => SetXmlNodeString(_linewidthPath, value.ToString(CultureInfo.InvariantCulture) + "pt");
+ }
+
+ ///// <summary>
+ ///// Width of the Comment
+ ///// </summary>
+ //public Single Width
+ //{
+ // get
+ // {
+ // string v;
+ // GetStyle("width", out v);
+ // if(v.EndsWith("pt"))
+ // {
+ // v = v.Substring(0, v.Length - 2);
+ // }
+ // short ret;
+ // if (short.TryParse(v,System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
+ // {
+ // return ret;
+ // }
+ // else
+ // {
+ // return 0;
+ // }
+ // }
+ // set
+ // {
+ // SetStyle("width", value.ToString("N2",CultureInfo.InvariantCulture) + "pt");
+ // }
+ //}
+ ///// <summary>
+ ///// Height of the Comment
+ ///// </summary>
+ //public Single Height
+ //{
+ // get
+ // {
+ // string v;
+ // GetStyle("height", out v);
+ // if (v.EndsWith("pt"))
+ // {
+ // v = v.Substring(0, v.Length - 2);
+ // }
+ // short ret;
+ // if (short.TryParse(v, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret))
+ // {
+ // return ret;
+ // }
+ // else
+ // {
+ // return 0;
+ // }
+ // }
+ // set
+ // {
+ // SetStyle("height", value.ToString("N2", CultureInfo.InvariantCulture) + "pt");
+ // }
+ //}
private const string _textboxStylePath = "v:textbox/@style";
/// <summary>
diff --git a/EPPlus/EPPlusSDK.csproj b/EPPlus/EPPlusSDK.csproj
index 1941081..a26851d 100644
--- a/EPPlus/EPPlusSDK.csproj
+++ b/EPPlus/EPPlusSDK.csproj
@@ -4,6 +4,9 @@
<RootNamespace>OfficeOpenXml</RootNamespace>
<AssemblyName>EPPlus</AssemblyName>
<PackageId>Appsheet.EPPlus</PackageId>
- <Version>1.0.7</Version>
+ <Version>1.0.6</Version>
</PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="System.Drawing.Common" Version="6.0.0"/>
+ </ItemGroup>
</Project>
diff --git a/EPPlus/ExcelComment.cs b/EPPlus/ExcelComment.cs
index 3930bde..9e7409a 100644
--- a/EPPlus/ExcelComment.cs
+++ b/EPPlus/ExcelComment.cs
@@ -124,6 +124,7 @@
}
return _text;
}
+ set => RichText.Text = value;
}
/// <summary>
diff --git a/EPPlus/ExcelCommentCollection.cs b/EPPlus/ExcelCommentCollection.cs
index 9146df7..b4a60af 100644
--- a/EPPlus/ExcelCommentCollection.cs
+++ b/EPPlus/ExcelCommentCollection.cs
@@ -138,9 +138,79 @@
}
}
+ /// <summary>
+ /// Adds a comment to the top left cell of the range
+ /// </summary>
+ /// <param name="cell">The cell</param>
+ /// <param name="text">The comment text</param>
+ /// <param name="author">Author</param>
+ /// <returns>The comment</returns>
+ public ExcelComment Add(ExcelRangeBase cell, string text, string author) {
+ var elem = CommentXml.CreateElement("comment", ExcelPackage._schemaMain);
+ int ix = _comments.IndexOf(
+ ExcelCellBase.GetCellId(Worksheet.SheetID, cell._fromRow, cell._fromCol));
+ //Make sure the nodes come on order.
+ if (ix < 0 && (~ix < _comments.Count)) {
+ ix = ~ix;
+ var preComment = _comments[ix] as ExcelComment;
+ preComment._commentHelper.TopNode.ParentNode.InsertBefore(
+ elem,
+ preComment._commentHelper.TopNode);
+ } else {
+ CommentXml.SelectSingleNode("d:comments/d:commentList", NameSpaceManager).AppendChild(elem);
+ }
+ elem.SetAttribute("ref", cell.Start.Address);
+ ExcelComment comment = new ExcelComment(NameSpaceManager, elem, cell);
+ comment.RichText.Add(text);
+ if (author != "") {
+ comment.Author = author;
+ }
+ _comments.Add(comment);
+ //Check if a value exists otherwise add one so it is saved when the cells collection is iterated
+ if (!Worksheet._values.Exists(cell._fromRow, cell._fromCol)) {
+ Worksheet._values.SetValue(cell._fromRow, cell._fromCol, null);
+ }
+ return comment;
+ }
+
+ /// <summary>
+ /// Removes the comment
+ /// </summary>
+ /// <param name="comment">The comment to remove</param>
+ public void Remove(ExcelComment comment) {
+ ulong id = ExcelCellBase.GetCellId(
+ Worksheet.SheetID,
+ comment.Range._fromRow,
+ comment.Range._fromCol);
+ int ix = _comments.IndexOf(id);
+ if (ix >= 0 && comment == _comments[ix]) {
+ comment.TopNode.ParentNode.RemoveChild(comment.TopNode); //Remove VML
+ comment._commentHelper.TopNode.ParentNode.RemoveChild(comment._commentHelper.TopNode); //Remove Comment
+
+ Worksheet.VmlDrawingsComments._drawings.Delete(id);
+ _comments.Delete(id);
+ } else {
+ throw (new ArgumentException("Comment does not exist in the worksheet"));
+ }
+ }
+
void IDisposable.Dispose() {}
+ /// <summary>
+ /// Removes the comment at the specified position
+ /// </summary>
+ /// <param name="index">The index</param>
+ public void RemoveAt(int index) {
+ Remove(this[index]);
+ }
+
IEnumerator IEnumerable.GetEnumerator() {
return _comments;
}
+
+ internal void Clear() {
+ while (Count > 0) {
+ RemoveAt(0);
+ }
+ }
}
diff --git a/EPPlus/ExcelPrinterSettings.cs b/EPPlus/ExcelPrinterSettings.cs
new file mode 100644
index 0000000..dcdb541
--- /dev/null
+++ b/EPPlus/ExcelPrinterSettings.cs
@@ -0,0 +1,773 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011 Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author Change Date
+ * ******************************************************************************
+ * Jan Källman Initial Release 2009-10-01
+ * Jan Källman License changed GPL-->LGPL 2011-12-27
+ *******************************************************************************/
+
+using System;
+using System.Globalization;
+using System.Xml;
+
+namespace OfficeOpenXml;
+
+/// <summary>
+/// Printer orientation
+/// </summary>
+public enum eOrientation {
+ /// <summary>
+ /// Portrait orientation
+ /// </summary>
+ Portrait,
+
+ /// <summary>
+ /// Landscape orientation
+ /// </summary>
+ Landscape,
+}
+
+/// <summary>
+/// Papersize
+/// </summary>
+public enum ePaperSize {
+ /// <summary>
+ /// Letter paper (8.5 in. by 11 in.)
+ /// </summary>
+ Letter = 1,
+
+ /// <summary>
+ /// Letter small paper (8.5 in. by 11 in.)
+ /// </summary>
+ LetterSmall = 2,
+
+ /// <summary>
+ /// // Tabloid paper (11 in. by 17 in.)
+ /// </summary>
+ Tabloid = 3,
+
+ /// <summary>
+ /// Ledger paper (17 in. by 11 in.)
+ /// </summary>
+ Ledger = 4,
+
+ /// <summary>
+ /// Legal paper (8.5 in. by 14 in.)
+ /// </summary>
+ Legal = 5,
+
+ /// <summary>
+ /// Statement paper (5.5 in. by 8.5 in.)
+ /// </summary>
+ Statement = 6,
+
+ /// <summary>
+ /// Executive paper (7.25 in. by 10.5 in.)
+ /// </summary>
+ Executive = 7,
+
+ /// <summary>
+ /// A3 paper (297 mm by 420 mm)
+ /// </summary>
+ A3 = 8,
+
+ /// <summary>
+ /// A4 paper (210 mm by 297 mm)
+ /// </summary>
+ A4 = 9,
+
+ /// <summary>
+ /// A4 small paper (210 mm by 297 mm)
+ /// </summary>
+ A4Small = 10,
+
+ /// <summary>
+ /// A5 paper (148 mm by 210 mm)
+ /// </summary>
+ A5 = 11,
+
+ /// <summary>
+ /// B4 paper (250 mm by 353 mm)
+ /// </summary>
+ B4 = 12,
+
+ /// <summary>
+ /// B5 paper (176 mm by 250 mm)
+ /// </summary>
+ B5 = 13,
+
+ /// <summary>
+ /// Folio paper (8.5 in. by 13 in.)
+ /// </summary>
+ Folio = 14,
+
+ /// <summary>
+ /// Quarto paper (215 mm by 275 mm)
+ /// </summary>
+ Quarto = 15,
+
+ /// <summary>
+ /// Standard paper (10 in. by 14 in.)
+ /// </summary>
+ Standard1014 = 16,
+
+ /// <summary>
+ /// Standard paper (11 in. by 17 in.)
+ /// </summary>
+ Standard1117 = 17,
+
+ /// <summary>
+ /// Note paper (8.5 in. by 11 in.)
+ /// </summary>
+ Note = 18,
+
+ /// <summary>
+ /// #9 envelope (3.875 in. by 8.875 in.)
+ /// </summary>
+ Envelope9 = 19,
+
+ /// <summary>
+ /// #10 envelope (4.125 in. by 9.5 in.)
+ /// </summary>
+ Envelope10 = 20,
+
+ /// <summary>
+ /// #11 envelope (4.5 in. by 10.375 in.)
+ /// </summary>
+ Envelope11 = 21,
+
+ /// <summary>
+ /// #12 envelope (4.75 in. by 11 in.)
+ /// </summary>
+ Envelope12 = 22,
+
+ /// <summary>
+ /// #14 envelope (5 in. by 11.5 in.)
+ /// </summary>
+ Envelope14 = 23,
+
+ /// <summary>
+ /// C paper (17 in. by 22 in.)
+ /// </summary>
+ C = 24,
+
+ /// <summary>
+ /// D paper (22 in. by 34 in.)
+ /// </summary>
+ D = 25,
+
+ /// <summary>
+ /// E paper (34 in. by 44 in.)
+ /// </summary>
+ E = 26,
+
+ /// <summary>
+ /// DL envelope (110 mm by 220 mm)
+ /// </summary>
+ DlEnvelope = 27,
+
+ /// <summary>
+ /// C5 envelope (162 mm by 229 mm)
+ /// </summary>
+ C5Envelope = 28,
+
+ /// <summary>
+ /// C3 envelope (324 mm by 458 mm)
+ /// </summary>
+ C3Envelope = 29,
+
+ /// <summary>
+ /// C4 envelope (229 mm by 324 mm)
+ /// </summary>
+ C4Envelope = 30,
+
+ /// <summary>
+ /// C6 envelope (114 mm by 162 mm)
+ /// </summary>
+ C6Envelope = 31,
+
+ /// <summary>
+ /// C65 envelope (114 mm by 229 mm)
+ /// </summary>
+ C65Envelope = 32,
+
+ /// <summary>
+ /// B4 envelope (250 mm by 353 mm)
+ /// </summary>
+ B4Envelope = 33,
+
+ /// <summary>
+ /// B5 envelope (176 mm by 250 mm)
+ /// </summary>
+ B5Envelope = 34,
+
+ /// <summary>
+ /// B6 envelope (176 mm by 125 mm)
+ /// </summary>
+ B6Envelope = 35,
+
+ /// <summary>
+ /// Italy envelope (110 mm by 230 mm)
+ /// </summary>
+ ItalyEnvelope = 36,
+
+ /// <summary>
+ /// Monarch envelope (3.875 in. by 7.5 in.).
+ /// </summary>
+ MonarchEnvelope = 37,
+
+ /// <summary>
+ /// 6 3/4 envelope (3.625 in. by 6.5 in.)
+ /// </summary>
+ Six34Envelope = 38,
+
+ /// <summary>
+ /// US standard fanfold (14.875 in. by 11 in.)
+ /// </summary>
+ UsStandard = 39,
+
+ /// <summary>
+ /// German standard fanfold (8.5 in. by 12 in.)
+ /// </summary>
+ GermanStandard = 40,
+
+ /// <summary>
+ /// German legal fanfold (8.5 in. by 13 in.)
+ /// </summary>
+ GermanLegal = 41,
+
+ /// <summary>
+ /// ISO B4 (250 mm by 353 mm)
+ /// </summary>
+ Isob4 = 42,
+
+ /// <summary>
+ /// Japanese double postcard (200 mm by 148 mm)
+ /// </summary>
+ JapaneseDoublePostcard = 43,
+
+ /// <summary>
+ /// Standard paper (9 in. by 11 in.)
+ /// </summary>
+ Standard9 = 44,
+
+ /// <summary>
+ /// Standard paper (10 in. by 11 in.)
+ /// </summary>
+ Standard10 = 45,
+
+ /// <summary>
+ /// Standard paper (15 in. by 11 in.)
+ /// </summary>
+ Standard15 = 46,
+
+ /// <summary>
+ /// Invite envelope (220 mm by 220 mm)
+ /// </summary>
+ InviteEnvelope = 47,
+
+ /// <summary>
+ /// Letter extra paper (9.275 in. by 12 in.)
+ /// </summary>
+ LetterExtra = 50,
+
+ /// <summary>
+ /// Legal extra paper (9.275 in. by 15 in.)
+ /// </summary>
+ LegalExtra = 51,
+
+ /// <summary>
+ /// Tabloid extra paper (11.69 in. by 18 in.)
+ /// </summary>
+ TabloidExtra = 52,
+
+ /// <summary>
+ /// A4 extra paper (236 mm by 322 mm)
+ /// </summary>
+ A4Extra = 53,
+
+ /// <summary>
+ /// Letter transverse paper (8.275 in. by 11 in.)
+ /// </summary>
+ LetterTransverse = 54,
+
+ /// <summary>
+ /// A4 transverse paper (210 mm by 297 mm)
+ /// </summary>
+ A4Transverse = 55,
+
+ /// <summary>
+ /// Letter extra transverse paper (9.275 in. by 12 in.)
+ /// </summary>
+ LetterExtraTransverse = 56,
+
+ /// <summary>
+ /// SuperA/SuperA/A4 paper (227 mm by 356 mm)
+ /// </summary>
+ SuperA = 57,
+
+ /// <summary>
+ /// SuperB/SuperB/A3 paper (305 mm by 487 mm)
+ /// </summary>
+ SuperB = 58,
+
+ /// <summary>
+ /// Letter plus paper (8.5 in. by 12.69 in.)
+ /// </summary>
+ LetterPlus = 59,
+
+ /// <summary>
+ /// A4 plus paper (210 mm by 330 mm)
+ /// </summary>
+ A4Plus = 60,
+
+ /// <summary>
+ /// A5 transverse paper (148 mm by 210 mm)
+ /// </summary>
+ A5Transverse = 61,
+
+ /// <summary>
+ /// JIS B5 transverse paper (182 mm by 257 mm)
+ /// </summary>
+ Jisb5Transverse = 62,
+
+ /// <summary>
+ /// A3 extra paper (322 mm by 445 mm)
+ /// </summary>
+ A3Extra = 63,
+
+ /// <summary>
+ /// A5 extra paper (174 mm by 235 mm)
+ /// </summary>
+ A5Extra = 64,
+
+ /// <summary>
+ /// ISO B5 extra paper (201 mm by 276 mm)
+ /// </summary>
+ Isob5 = 65,
+
+ /// <summary>
+ /// A2 paper (420 mm by 594 mm)
+ /// </summary>
+ A2 = 66,
+
+ /// <summary>
+ /// A3 transverse paper (297 mm by 420 mm)
+ /// </summary>
+ A3Transverse = 67,
+
+ /// <summary>
+ /// A3 extra transverse paper (322 mm by 445 mm*/
+ /// </summary>
+ A3ExtraTransverse = 68,
+}
+
+/// <summary>
+/// Specifies printed page order
+/// </summary>
+public enum ePageOrder {
+ /// <summary>
+ /// Order pages vertically first, then move horizontally.
+ /// </summary>
+ DownThenOver,
+
+ /// <summary>
+ /// Order pages horizontally first, then move vertically
+ /// </summary>
+ OverThenDown,
+}
+
+/// <summary>
+/// Printer settings
+/// </summary>
+public sealed class ExcelPrinterSettings : XmlHelper {
+ private readonly ExcelWorksheet _ws;
+ private bool _marginsCreated;
+
+ internal ExcelPrinterSettings(XmlNamespaceManager ns, XmlNode topNode, ExcelWorksheet ws)
+ : base(ns, topNode) {
+ _ws = ws;
+ SchemaNodeOrder = ws.SchemaNodeOrder;
+ }
+
+ private const string _leftMarginPath = "d:pageMargins/@left";
+
+ /// <summary>
+ /// Left margin in inches
+ /// </summary>
+ public decimal LeftMargin {
+ get => GetXmlNodeDecimal(_leftMarginPath);
+ set {
+ CreateMargins();
+ SetXmlNodeString(_leftMarginPath, value.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ private const string _rightMarginPath = "d:pageMargins/@right";
+
+ /// <summary>
+ /// Right margin in inches
+ /// </summary>
+ public decimal RightMargin {
+ get => GetXmlNodeDecimal(_rightMarginPath);
+ set {
+ CreateMargins();
+ SetXmlNodeString(_rightMarginPath, value.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ private const string _topMarginPath = "d:pageMargins/@top";
+
+ /// <summary>
+ /// Top margin in inches
+ /// </summary>
+ public decimal TopMargin {
+ get => GetXmlNodeDecimal(_topMarginPath);
+ set {
+ CreateMargins();
+ SetXmlNodeString(_topMarginPath, value.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ private const string _bottomMarginPath = "d:pageMargins/@bottom";
+
+ /// <summary>
+ /// Bottom margin in inches
+ /// </summary>
+ public decimal BottomMargin {
+ get => GetXmlNodeDecimal(_bottomMarginPath);
+ set {
+ CreateMargins();
+ SetXmlNodeString(_bottomMarginPath, value.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ private const string _headerMarginPath = "d:pageMargins/@header";
+
+ /// <summary>
+ /// Header margin in inches
+ /// </summary>
+ public decimal HeaderMargin {
+ get => GetXmlNodeDecimal(_headerMarginPath);
+ set {
+ CreateMargins();
+ SetXmlNodeString(_headerMarginPath, value.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ private const string _footerMarginPath = "d:pageMargins/@footer";
+
+ /// <summary>
+ /// Footer margin in inches
+ /// </summary>
+ public decimal FooterMargin {
+ get => GetXmlNodeDecimal(_footerMarginPath);
+ set {
+ CreateMargins();
+ SetXmlNodeString(_footerMarginPath, value.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+
+ private const string _orientationPath = "d:pageSetup/@orientation";
+
+ /// <summary>
+ /// Orientation
+ /// Portrait or Landscape
+ /// </summary>
+ public eOrientation Orientation {
+ get => (eOrientation)Enum.Parse(typeof(eOrientation), GetXmlNodeString(_orientationPath), true);
+ set =>
+ SetXmlNodeString(_orientationPath, value.ToString().ToLower(CultureInfo.InvariantCulture));
+ }
+
+ private const string _fitToWidthPath = "d:pageSetup/@fitToWidth";
+
+ /// <summary>
+ /// Fit to Width in pages.
+ /// Set FitToPage to true when using this one.
+ /// 0 is automatic
+ /// </summary>
+ public int FitToWidth {
+ get => GetXmlNodeInt(_fitToWidthPath);
+ set => SetXmlNodeString(_fitToWidthPath, value.ToString());
+ }
+
+ private const string _fitToHeightPath = "d:pageSetup/@fitToHeight";
+
+ /// <summary>
+ /// Fit to height in pages.
+ /// Set FitToPage to true when using this one.
+ /// 0 is automatic
+ /// </summary>
+ public int FitToHeight {
+ get => GetXmlNodeInt(_fitToHeightPath);
+ set => SetXmlNodeString(_fitToHeightPath, value.ToString());
+ }
+
+ private const string _scalePath = "d:pageSetup/@scale";
+
+ /// <summary>
+ /// Print scale
+ /// </summary>
+ public int Scale {
+ get => GetXmlNodeInt(_scalePath);
+ set => SetXmlNodeString(_scalePath, value.ToString());
+ }
+
+ private const string _fitToPagePath = "d:sheetPr/d:pageSetUpPr/@fitToPage";
+
+ /// <summary>
+ /// Fit To Page.
+ /// </summary>
+ public bool FitToPage {
+ get => GetXmlNodeBool(_fitToPagePath);
+ set => SetXmlNodeString(_fitToPagePath, value ? "1" : "0");
+ }
+
+ private const string _headersPath = "d:printOptions/@headings";
+
+ /// <summary>
+ /// Print headings (column letter and row numbers)
+ /// </summary>
+ public bool ShowHeaders {
+ get => GetXmlNodeBool(_headersPath, false);
+ set => SetXmlNodeBool(_headersPath, value, false);
+ }
+
+ /// <summary>
+ /// Print titles
+ /// Rows to be repeated after each pagebreak.
+ /// The address must be a full row address (ex. 1:1)
+ /// </summary>
+ public ExcelAddress RepeatRows {
+ get {
+ if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) {
+ ExcelRangeBase r = _ws.Names["_xlnm.Print_Titles"];
+ if (r.Start.Column == 1 && r.End.Column == ExcelPackage.MaxColumns) {
+ return new(r.FirstAddress);
+ }
+ if (r._addresses != null
+ && r.Addresses[0].Start.Column == 1
+ && r.Addresses[0].End.Column == ExcelPackage.MaxColumns) {
+ return r._addresses[0];
+ }
+ return null;
+ }
+ return null;
+ }
+ set {
+ //Must span entire columns
+ if (!(value.Start.Column == 1 && value.End.Column == ExcelPackage.MaxColumns)) {
+ throw new InvalidOperationException(
+ "Address must span full columns only (for ex. Address=\"A:A\" for the first column).");
+ }
+
+ var vertAddr = RepeatColumns;
+ string addr;
+ if (vertAddr == null) {
+ addr = value.Address;
+ } else {
+ addr = vertAddr.Address + "," + value.Address;
+ }
+
+ if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) {
+ _ws.Names["_xlnm.Print_Titles"].Address = addr;
+ } else {
+ _ws.Names.Add("_xlnm.Print_Titles", new(_ws, addr));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Print titles
+ /// Columns to be repeated after each pagebreak.
+ /// The address must be a full column address (ex. A:A)
+ /// </summary>
+ public ExcelAddress RepeatColumns {
+ get {
+ if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) {
+ ExcelRangeBase r = _ws.Names["_xlnm.Print_Titles"];
+ if (r.Start.Row == 1 && r.End.Row == ExcelPackage.MaxRows) {
+ return new(r.FirstAddress);
+ }
+ if (r._addresses != null
+ && (r._addresses[0].Start.Row == 1
+ && r._addresses[0].End.Row == ExcelPackage.MaxRows)) {
+ return r._addresses[0];
+ }
+ return null;
+ }
+ return null;
+ }
+ set {
+ //Must span entire rows
+ if (!(value.Start.Row == 1 && value.End.Row == ExcelPackage.MaxRows)) {
+ throw new InvalidOperationException(
+ "Address must span rows only (for ex. Address=\"1:1\" for the first row).");
+ }
+
+ var horAddr = RepeatRows;
+ string addr;
+ if (horAddr == null) {
+ addr = value.Address;
+ } else {
+ addr = value.Address + "," + horAddr.Address;
+ }
+
+ if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) {
+ _ws.Names["_xlnm.Print_Titles"].Address = addr;
+ } else {
+ _ws.Names.Add("_xlnm.Print_Titles", new(_ws, addr));
+ }
+ }
+ }
+
+ /// <summary>
+ /// The printarea.
+ /// Null if no print area is set.
+ /// </summary>
+ public ExcelRangeBase PrintArea {
+ get {
+ if (_ws.Names.ContainsKey("_xlnm.Print_Area")) {
+ return _ws.Names["_xlnm.Print_Area"];
+ }
+ return null;
+ }
+ set {
+ if (value == null) {
+ _ws.Names.Remove("_xlnm.Print_Area");
+ } else if (_ws.Names.ContainsKey("_xlnm.Print_Area")) {
+ _ws.Names["_xlnm.Print_Area"].Address = value.Address;
+ } else {
+ _ws.Names.Add("_xlnm.Print_Area", value);
+ }
+ }
+ }
+
+ private const string _gridLinesPath = "d:printOptions/@gridLines";
+
+ /// <summary>
+ /// Print gridlines
+ /// </summary>
+ public bool ShowGridLines {
+ get => GetXmlNodeBool(_gridLinesPath, false);
+ set => SetXmlNodeBool(_gridLinesPath, value, false);
+ }
+
+ private const string _horizontalCenteredPath = "d:printOptions/@horizontalCentered";
+
+ /// <summary>
+ /// Horizontal centered when printing
+ /// </summary>w
+ public bool HorizontalCentered {
+ get => GetXmlNodeBool(_horizontalCenteredPath, false);
+ set => SetXmlNodeBool(_horizontalCenteredPath, value, false);
+ }
+
+ private const string _verticalCenteredPath = "d:printOptions/@verticalCentered";
+
+ /// <summary>
+ /// Vertical centered when printing
+ /// </summary>
+ public bool VerticalCentered {
+ get => GetXmlNodeBool(_verticalCenteredPath, false);
+ set => SetXmlNodeBool(_verticalCenteredPath, value, false);
+ }
+
+ private const string _pageOrderPath = "d:pageSetup/@pageOrder";
+
+ /// <summary>
+ /// Specifies printed page order
+ /// </summary>
+ public ePageOrder PageOrder {
+ get {
+ if (GetXmlNodeString(_pageOrderPath) == "overThenDown") {
+ return ePageOrder.OverThenDown;
+ }
+ return ePageOrder.DownThenOver;
+ }
+ set {
+ if (value == ePageOrder.OverThenDown) {
+ SetXmlNodeString(_pageOrderPath, "overThenDown");
+ } else {
+ DeleteNode(_pageOrderPath);
+ }
+ }
+ }
+
+ private const string _blackAndWhitePath = "d:pageSetup/@blackAndWhite";
+
+ /// <summary>
+ /// Print black and white
+ /// </summary>
+ public bool BlackAndWhite {
+ get => GetXmlNodeBool(_blackAndWhitePath, false);
+ set => SetXmlNodeBool(_blackAndWhitePath, value, false);
+ }
+
+ private const string _draftPath = "d:pageSetup/@draft";
+
+ /// <summary>
+ /// Print a draft
+ /// </summary>
+ public bool Draft {
+ get => GetXmlNodeBool(_draftPath, false);
+ set => SetXmlNodeBool(_draftPath, value, false);
+ }
+
+ private const string _paperSizePath = "d:pageSetup/@paperSize";
+
+ /// <summary>
+ /// Paper size
+ /// </summary>
+ public ePaperSize PaperSize {
+ get {
+ string s = GetXmlNodeString(_paperSizePath);
+ if (s != "") {
+ return (ePaperSize)int.Parse(s);
+ }
+ return ePaperSize.Letter;
+ }
+ set => SetXmlNodeString(_paperSizePath, ((int)value).ToString());
+ }
+
+ /// <summary>
+ /// All or none of the margin attributes must exist. Create all att ones.
+ /// </summary>
+ private void CreateMargins() {
+ if (_marginsCreated == false
+ && TopNode.SelectSingleNode(_leftMarginPath, NameSpaceManager) == null) {
+ _marginsCreated = true;
+ LeftMargin = 0.7087M;
+ RightMargin = 0.7087M;
+ TopMargin = 0.7480M;
+ BottomMargin = 0.7480M;
+ HeaderMargin = 0.315M;
+ FooterMargin = 0.315M;
+ }
+ }
+}
diff --git a/EPPlus/ExcelRangeBase.cs b/EPPlus/ExcelRangeBase.cs
index 686eb78..b4e48a8 100644
--- a/EPPlus/ExcelRangeBase.cs
+++ b/EPPlus/ExcelRangeBase.cs
@@ -349,6 +349,12 @@
}
}
+ private void Set_Comment(object value, int row, int col) {
+ string[] v = (string[])value;
+ Worksheet.Comments.Add(new(_worksheet, GetAddress(_fromRow, _fromCol)), v[0], v[1]);
+ // _worksheet.Cell(row, col).Comment = comment;
+ }
+
private void SetToSelectedRange() {
if (_worksheet.View.SelectedRange == "") {
Address = "A1";
@@ -1831,6 +1837,339 @@
}
/// <summary>
+ /// Adds a new comment for the range.
+ /// If this range contains more than one cell, the top left comment is returned by the method.
+ /// </summary>
+ /// <param name="text"></param>
+ /// <param name="author"></param>
+ /// <returns>A reference comment of the top left cell</returns>
+ public ExcelComment AddComment(string text, string author) {
+ if (string.IsNullOrEmpty(author)) {
+ author = Thread.CurrentPrincipal.Identity.Name;
+ }
+ //Check if any comments exists in the range and throw an exception
+ _changePropMethod(Exists_Comment, null);
+ //Create the comments
+ _changePropMethod(Set_Comment, new[] { text, author });
+
+ return _worksheet.Comments[new ExcelCellAddress(_fromRow, _fromCol)];
+ }
+
+ ///// <summary>
+ ///// Copies the range of cells to an other range
+ ///// </summary>
+ ///// <param name="Destination">The start cell where the range will be copied.</param>
+ public void Copy(ExcelRangeBase destination) {
+ bool sameWorkbook = destination._worksheet.Workbook == _worksheet.Workbook;
+ ExcelStyles sourceStyles = _worksheet.Workbook.Styles,
+ styles = destination._worksheet.Workbook.Styles;
+ Dictionary<int, int> styleCashe = new Dictionary<int, int>();
+
+ //Clear all existing cells;
+ int toRow = _toRow - _fromRow + 1,
+ toCol = _toCol - _fromCol + 1;
+
+ string s = "";
+ int i = 0;
+ object o = null;
+ byte flag = 0;
+ Uri hl = null;
+ ExcelComment comment = null;
+
+ var cse = new CellsStoreEnumerator<object>(
+ _worksheet._values,
+ _fromRow,
+ _fromCol,
+ _toRow,
+ _toCol);
+ var copiedValue = new List<CopiedCell>();
+ while (cse.Next()) {
+ var row = cse.Row;
+ var col = cse.Column; //Issue 15070
+ var cell = new CopiedCell {
+ Row = destination._fromRow + (row - _fromRow),
+ Column = destination._fromCol + (col - _fromCol),
+ Value = cse.Value,
+ };
+
+ //Destination._worksheet._values.SetValue(row, col, cse.Value);
+
+ if (_worksheet._types.Exists(row, col, ref s)) {
+ //Destination._worksheet._types.SetValue(row, col,s);
+ cell.Type = s;
+ }
+
+ if (_worksheet._formulas.Exists(row, col, ref o)) {
+ if (o is int) {
+ // Destination._worksheet._formulas.SetValue(row, col, _worksheet.GetFormula(cse.Row, cse.Column)); //Shared formulas, set the formula per cell to simplify
+ cell.Formula = _worksheet.GetFormula(cse.Row, cse.Column);
+ } else {
+ //Destination._worksheet._formulas.SetValue(row, col, o);
+ cell.Formula = o;
+ }
+ }
+ if (_worksheet._styles.Exists(row, col, ref i)) {
+ if (sameWorkbook) {
+ //Destination._worksheet._styles.SetValue(row, col, i);
+ cell.StyleID = i;
+ } else {
+ if (styleCashe.ContainsKey(i)) {
+ i = styleCashe[i];
+ } else {
+ var oldStyleId = i;
+ i = styles.CloneStyle(sourceStyles, i);
+ styleCashe.Add(oldStyleId, i);
+ }
+ //Destination._worksheet._styles.SetValue(row, col, i);
+ cell.StyleID = i;
+ }
+ }
+
+ if (_worksheet._hyperLinks.Exists(row, col, ref hl)) {
+ //Destination._worksheet._hyperLinks.SetValue(row, col, hl);
+ cell.HyperLink = hl;
+ }
+
+ if (_worksheet._commentsStore.Exists(row, col, ref comment)) {
+ cell.Comment = comment;
+ }
+
+ if (_worksheet._flags.Exists(row, col, ref flag)) {
+ cell.Flag = flag;
+ }
+ copiedValue.Add(cell);
+ }
+
+ //Copy styles with no cell value
+ var cses = new CellsStoreEnumerator<int>(
+ _worksheet._styles,
+ _fromRow,
+ _fromCol,
+ _toRow,
+ _toCol);
+ while (cses.Next()) {
+ if (!_worksheet._values.Exists(cses.Row, cses.Column)) {
+ var row = destination._fromRow + (cses.Row - _fromRow);
+ var col = destination._fromCol + (cses.Column - _fromCol);
+ var cell = new CopiedCell {
+ Row = row,
+ Column = col,
+ Value = null,
+ };
+
+ i = cses.Value;
+ if (sameWorkbook) {
+ cell.StyleID = i;
+ } else {
+ if (styleCashe.ContainsKey(i)) {
+ i = styleCashe[i];
+ } else {
+ var oldStyleId = i;
+ i = styles.CloneStyle(sourceStyles, i);
+ styleCashe.Add(oldStyleId, i);
+ }
+ //Destination._worksheet._styles.SetValue(row, col, i);
+ cell.StyleID = i;
+ }
+ copiedValue.Add(cell);
+ }
+ }
+ var copiedMergedCells = new Dictionary<int, ExcelAddress>();
+ //Merged cells
+ var csem = new CellsStoreEnumerator<int>(
+ _worksheet.MergedCells._cells,
+ _fromRow,
+ _fromCol,
+ _toRow,
+ _toCol);
+ while (csem.Next()) {
+ if (!copiedMergedCells.ContainsKey(csem.Value)) {
+ var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[csem.Value]);
+ if (Collide(adr) == eAddressCollition.Inside) {
+ copiedMergedCells.Add(
+ csem.Value,
+ new(
+ destination._fromRow + (adr.Start.Row - _fromRow),
+ destination._fromCol + (adr.Start.Column - _fromCol),
+ destination._fromRow + (adr.End.Row - _fromRow),
+ destination._fromCol + (adr.End.Column - _fromCol)));
+ } else {
+ //Partial merge of the address ignore.
+ copiedMergedCells.Add(csem.Value, null);
+ }
+ }
+ }
+
+ destination._worksheet.MergedCells.Clear(
+ new(
+ destination._fromRow,
+ destination._fromCol,
+ destination._fromRow + toRow - 1,
+ destination._fromCol + toCol - 1));
+
+ destination._worksheet._values.Clear(destination._fromRow, destination._fromCol, toRow, toCol);
+ destination._worksheet._formulas.Clear(
+ destination._fromRow,
+ destination._fromCol,
+ toRow,
+ toCol);
+ destination._worksheet._styles.Clear(destination._fromRow, destination._fromCol, toRow, toCol);
+ destination._worksheet._types.Clear(destination._fromRow, destination._fromCol, toRow, toCol);
+ destination._worksheet._hyperLinks.Clear(
+ destination._fromRow,
+ destination._fromCol,
+ toRow,
+ toCol);
+ destination._worksheet._flags.Clear(destination._fromRow, destination._fromCol, toRow, toCol);
+ destination._worksheet._commentsStore.Clear(
+ destination._fromRow,
+ destination._fromCol,
+ toRow,
+ toCol);
+
+ foreach (var cell in copiedValue) {
+ destination._worksheet._values.SetValue(cell.Row, cell.Column, cell.Value);
+
+ if (cell.Type != null) {
+ destination._worksheet._types.SetValue(cell.Row, cell.Column, cell.Type);
+ }
+
+ if (cell.StyleID != null) {
+ destination._worksheet._styles.SetValue(cell.Row, cell.Column, cell.StyleID.Value);
+ }
+
+ if (cell.Formula != null) {
+ cell.Formula = UpdateFormulaReferences(
+ cell.Formula.ToString(),
+ destination._fromRow - _fromRow,
+ destination._fromCol - _fromCol,
+ 0,
+ 0,
+ true);
+ destination._worksheet._formulas.SetValue(cell.Row, cell.Column, cell.Formula);
+ }
+ if (cell.HyperLink != null) {
+ destination._worksheet._hyperLinks.SetValue(cell.Row, cell.Column, cell.HyperLink);
+ }
+
+ if (cell.Comment != null) {
+ //Destination._worksheet._commentsStore.SetValue(cell.Row, cell.Column, cell.Comment);
+ }
+ if (cell.Flag != 0) {
+ destination._worksheet._flags.SetValue(cell.Row, cell.Column, cell.Flag);
+ }
+ }
+
+ //Add merged cells
+ foreach (var m in copiedMergedCells.Values) {
+ if (m != null) {
+ destination._worksheet.MergedCells.Add(m, true);
+ }
+ }
+
+ //Clone the cell
+ //var copiedCell = (_worksheet._cells[GetCellID(_worksheet.SheetID, cell._fromRow, cell.column)] as ExcelCell);
+
+ //var newCell = copiedCell.Clone(Destination._worksheet,
+ // Destination._fromRow + (copiedCell.Row - _fromRow),
+ // Destination.column + (copiedCell.Column - column));
+
+ // newCell.MergeId = _worksheet.GetMergeCellId(copiedCell.Row, copiedCell.Column);
+
+ // if (!string.IsNullOrEmpty(newCell.Formula))
+ // {
+ // newCell.Formula = ExcelCell.UpdateFormulaReferences(newCell.Formula, newCell.Row - copiedCell.Row, (newCell.Column - copiedCell.Column), 1, 1);
+ // }
+
+ // //If its not the same workbook we must copy the styles to the new workbook.
+ // if (!sameWorkbook)
+ // {
+ // if (styleCashe.ContainsKey(cell.StyleID))
+ // {
+ // newCell.StyleID = styleCashe[cell.StyleID];
+ // }
+ // else
+ // {
+ // newCell.StyleID = styles.CloneStyle(sourceStyles, cell.StyleID);
+ // styleCashe.Add(cell.StyleID, newCell.StyleID);
+ // }
+ // }
+ // newCells.Add(newCell);
+ // if (newCell.Merge) mergedCells.Add(newCell.CellID, newCell);
+ // }
+
+ // //Now clear the destination.
+ // Destination.Offset(0, 0, (_toRow - _fromRow) + 1, (_toCol - column) + 1).Clear();
+
+ // //And last add the new cells to the worksheet
+ // foreach (var cell in newCells)
+ // {
+ // Destination.Worksheet._cells.Add(cell);
+ // }
+ // //Add merged cells
+ // if (mergedCells.Count > 0)
+ // {
+ // List<ExcelAddressBase> mergedAddresses = new List<ExcelAddressBase>();
+ // foreach (var cell in mergedCells.Values)
+ // {
+ // if (!IsAdded(cell, mergedAddresses))
+ // {
+ // int startRow = cell.Row, startCol = cell.Column, endRow = cell.Row, endCol = cell.Column + 1;
+ // while (mergedCells.ContainsKey(ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)))
+ // {
+ // ExcelCell next = mergedCells[ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)];
+ // if (cell.MergeId != next.MergeId)
+ // {
+ // break;
+ // }
+ // endCol++;
+ // }
+
+ // while (IsMerged(mergedCells, Destination.Worksheet, endRow, startCol, endCol - 1, cell))
+ // {
+ // endRow++;
+ // }
+
+ // mergedAddresses.Add(new ExcelAddressBase(startRow, startCol, endRow - 1, endCol - 1));
+ // }
+ // }
+ // Destination.Worksheet.MergedCells.List.AddRange((from r in mergedAddresses select r.Address));
+ // }
+ //}
+
+ //private bool IsAdded(ExcelCell cell, List<ExcelAddressBase> mergedAddresses)
+ //{
+ // foreach (var address in mergedAddresses)
+ // {
+ // if (address.Collide(new ExcelAddressBase(cell.CellAddress)) == eAddressCollition.Inside)
+ // {
+ // return true;
+ // }
+ // }
+ // return false;
+ //}
+
+ //private bool IsMerged(Dictionary<ulong, ExcelCell> mergedCells, ExcelWorksheet worksheet, int row, int startCol, int endCol, ExcelCell cell)
+ //{
+ // for (int col = startCol; col <= endCol; col++)
+ // {
+ // if (!mergedCells.ContainsKey(ExcelCell.GetCellID(worksheet.SheetID, row, col)))
+ // {
+ // return false;
+ // }
+ // else
+ // {
+ // ExcelCell next = mergedCells[ExcelCell.GetCellID(worksheet.SheetID, row, col)];
+ // if (cell.MergeId != next.MergeId)
+ // {
+ // return false;
+ // }
+ // }
+ // }
+ // return true;
+ }
+
+ /// <summary>
/// Clear all cells
/// </summary>
public void Clear() {
diff --git a/EPPlus/ExcelStyles.cs b/EPPlus/ExcelStyles.cs
index 0fd1fb3..9f1b283 100644
--- a/EPPlus/ExcelStyles.cs
+++ b/EPPlus/ExcelStyles.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting;
@@ -162,7 +163,215 @@
if (id < 0) {
id = 0;
}
- return new(this, positionId, address, id);
+ return new(this, PropertyChange, positionId, address, id);
+ }
+
+ /// <summary>
+ /// Handels changes of properties on the style objects
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ /// <returns></returns>
+ internal int PropertyChange(StyleBase sender, StyleChangeEventArgs e) {
+ var address = new ExcelAddressBase(e.Address);
+ var ws = _wb.Worksheets[e.PositionID];
+ Dictionary<int, int> styleCashe = new Dictionary<int, int>();
+ //Set single address
+ lock (ws._styles) {
+ SetStyleAddress(sender, e, address, ws, ref styleCashe);
+ if (address.Addresses != null) {
+ //Handle multiaddresses
+ foreach (var innerAddress in address.Addresses) {
+ SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe);
+ }
+ }
+ }
+ return 0;
+ }
+
+ private void SetStyleAddress(
+ StyleBase sender,
+ StyleChangeEventArgs e,
+ ExcelAddressBase address,
+ ExcelWorksheet ws,
+ ref Dictionary<int, int> styleCashe) {
+ if (address.Start.Column == 0 || address.Start.Row == 0) {
+ throw (new("error address"));
+ }
+ //Columns
+ if (address.Start.Row == 1 && address.End.Row == ExcelPackage.MaxRows) {
+ ExcelColumn column;
+ int col = address.Start.Column,
+ row = 0;
+ //Get the startcolumn
+ if (!ws._values.Exists(0, address.Start.Column)) {
+ column = ws.Column(address.Start.Column);
+ } else {
+ column = (ExcelColumn)ws._values.GetValue(0, address.Start.Column);
+ }
+
+ while (column.ColumnMin <= address.End.Column) {
+ if (column.ColumnMax > address.End.Column) {
+ var newCol = ws.CopyColumn(column, address.End.Column + 1, column.ColumnMax);
+ column.ColumnMax = address.End.Column;
+ }
+ var s = ws._styles.GetValue(0, column.ColumnMin);
+ if (styleCashe.ContainsKey(s)) {
+ ws.SetStyle(0, column.ColumnMin, styleCashe[s]);
+ } else {
+ ExcelXfs st = CellXfs[s];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(s, newId);
+ ws.SetStyle(0, column.ColumnMin, newId);
+ }
+
+ //index++;
+
+ if (!ws._values.NextCell(ref row, ref col) || row > 0) {
+ column._columnMax = address.End.Column;
+ break;
+ }
+ column = (ws._values.GetValue(0, col) as ExcelColumn);
+ }
+
+ if (column._columnMax < address.End.Column) {
+ var newCol = ws.Column(column._columnMax + 1);
+ newCol._columnMax = address.End.Column;
+
+ var s = ws._styles.GetValue(0, column.ColumnMin);
+ if (styleCashe.ContainsKey(s)) {
+ ws.SetStyle(0, column.ColumnMin, styleCashe[s]);
+ } else {
+ ExcelXfs st = CellXfs[s];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(s, newId);
+ ws.SetStyle(0, column.ColumnMin, newId);
+ }
+
+ column._columnMax = address.End.Column;
+ }
+
+ //Set for individual cells in the span. We loop all cells here since the cells are sorted with columns first.
+ var cse = new CellsStoreEnumerator<int>(
+ ws._styles,
+ 1,
+ address._fromCol,
+ address._toRow,
+ address._toCol);
+ while (cse.Next()) {
+ if (cse.Column >= address.Start.Column && cse.Column <= address.End.Column) {
+ if (styleCashe.ContainsKey(cse.Value)) {
+ ws.SetStyle(cse.Row, cse.Column, styleCashe[cse.Value]);
+ } else {
+ ExcelXfs st = CellXfs[cse.Value];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(cse.Value, newId);
+ cse.Value = newId;
+ //ws.SetStyle(cse.Row, cse.Column, newId);
+ }
+ }
+ }
+
+ //Update cells with styled columns
+ cse = new(ws._styles, 1, 0, address._toRow, 0);
+ while (cse.Next()) {
+ for (int c = address._fromRow; c <= address._toCol; c++) {
+ if (!ws._styles.Exists(cse.Row, c)) {
+ if (styleCashe.ContainsKey(cse.Value)) {
+ ws.SetStyle(cse.Row, c, styleCashe[cse.Value]);
+ } else {
+ ExcelXfs st = CellXfs[cse.Value];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(cse.Value, newId);
+ ws.SetStyle(cse.Row, c, newId);
+ }
+ }
+ }
+ }
+ }
+ //Rows
+ else if (address.Start.Column == 1 && address.End.Column == ExcelPackage.MaxColumns) {
+ for (int rowNum = address.Start.Row; rowNum <= address.End.Row; rowNum++) {
+ var s = ws._styles.GetValue(rowNum, 0);
+ if (s == 0) {
+ //iterate all columns and set the row to the style of the last column
+ var cse = new CellsStoreEnumerator<int>(ws._styles, 0, 1, 0, ExcelPackage.MaxColumns);
+ while (cse.Next()) {
+ s = cse.Value;
+ var c = ws._values.GetValue(cse.Row, cse.Column) as ExcelColumn;
+ if (c != null && c.ColumnMax < ExcelPackage.MaxColumns) {
+ for (int col = c.ColumnMin; col < c.ColumnMax; col++) {
+ if (!ws._styles.Exists(rowNum, col)) {
+ ws._styles.SetValue(rowNum, col, s);
+ }
+ }
+ }
+ }
+ ws.SetStyle(rowNum, 0, s);
+ }
+ if (styleCashe.ContainsKey(s)) {
+ ws.SetStyle(rowNum, 0, styleCashe[s]);
+ } else {
+ ExcelXfs st = CellXfs[s];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(s, newId);
+ ws._styles.SetValue(rowNum, 0, newId);
+ ws.SetStyle(rowNum, 0, newId);
+ }
+ }
+
+ //Update individual cells
+ var cse2 = new CellsStoreEnumerator<int>(
+ ws._styles,
+ address._fromRow,
+ address._fromCol,
+ address._toRow,
+ address._toCol);
+ while (cse2.Next()) {
+ var s = cse2.Value;
+ if (styleCashe.ContainsKey(s)) {
+ ws.SetStyle(cse2.Row, cse2.Column, styleCashe[s]);
+ } else {
+ ExcelXfs st = CellXfs[s];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(s, newId);
+ cse2.Value = newId;
+ }
+ }
+
+ //Update cells with styled rows
+ cse2 = new(ws._styles, 0, 1, 0, address._toCol);
+ while (cse2.Next()) {
+ for (int r = address._fromRow; r <= address._toRow; r++) {
+ if (!ws._styles.Exists(r, cse2.Column)) {
+ var s = cse2.Value;
+ if (styleCashe.ContainsKey(s)) {
+ ws.SetStyle(r, cse2.Column, styleCashe[s]);
+ } else {
+ ExcelXfs st = CellXfs[s];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(s, newId);
+ ws.SetStyle(r, cse2.Column, newId);
+ }
+ }
+ }
+ }
+ } else //Cellrange
+ {
+ for (int col = address.Start.Column; col <= address.End.Column; col++) {
+ for (int row = address.Start.Row; row <= address.End.Row; row++) {
+ var s = GetStyleId(ws, row, col);
+ if (styleCashe.ContainsKey(s)) {
+ ws.SetStyle(row, col, styleCashe[s]);
+ } else {
+ ExcelXfs st = CellXfs[s];
+ int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ styleCashe.Add(s, newId);
+ ws.SetStyle(row, col, newId);
+ }
+ }
+ }
+ }
}
internal int GetStyleId(ExcelWorksheet ws, int row, int col) {
@@ -195,6 +404,31 @@
return 0;
}
+ /// <summary>
+ /// Handles property changes on Named styles.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ /// <returns></returns>
+ internal int NamedStylePropertyChange(StyleBase sender, StyleChangeEventArgs e) {
+ int index = NamedStyles.FindIndexById(e.Address);
+ if (index >= 0) {
+ int newId = CellStyleXfs[NamedStyles[index].StyleXfId]
+ .GetNewId(CellStyleXfs, sender, e.StyleClass, e.StyleProperty, e.Value);
+ int prevIx = NamedStyles[index].StyleXfId;
+ NamedStyles[index].StyleXfId = newId;
+ NamedStyles[index].Style.Index = newId;
+
+ NamedStyles[index].XfId = int.MinValue;
+ foreach (var style in CellXfs) {
+ if (style.XfId == prevIx) {
+ style.XfId = newId;
+ }
+ }
+ }
+ return 0;
+ }
+
public ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats = new();
public ExcelStyleCollection<ExcelFontXml> Fonts = new();
public ExcelStyleCollection<ExcelFillXml> Fills = new();
@@ -244,7 +478,7 @@
CellStyleXfs[styleXfId].XfId = CellStyleXfs.Count - 1;
int xfid = CloneStyle(styles, xfIdCopy, false, true); //Always add a new style (We create a new named style here)
CellXfs[xfid].XfId = styleXfId;
- style.Style = new(this, positionId, name, styleXfId);
+ style.Style = new(this, NamedStylePropertyChange, positionId, name, styleXfId);
style.StyleXfId = styleXfId;
style.Name = name;
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs
index 33d2dd8..c561c33 100644
--- a/EPPlus/ExcelWorksheet.cs
+++ b/EPPlus/ExcelWorksheet.cs
@@ -1514,6 +1514,17 @@
}
}
+ /// <summary>
+ /// Printer settings
+ /// </summary>
+ public ExcelPrinterSettings PrinterSettings {
+ get {
+ var ps = new ExcelPrinterSettings(NameSpaceManager, TopNode, this);
+ ps.SchemaNodeOrder = SchemaNodeOrder;
+ return ps;
+ }
+ }
+
///// <summary>
///// Provides access to an individual cell within the worksheet.
///// </summary>
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
index 90693ee..2545f6a 100644
--- a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
+++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
@@ -107,7 +107,9 @@
|| DataType == DataType.Boolean
|| DataType == DataType.Date;
- public bool IsNumericString => DataType == DataType.String && ConvertUtil.IsNumericString(Result);
+ public bool IsNumericString {
+ get { return DataType == DataType.String && ConvertUtil.IsNumericString(Result); }
+ }
public bool IsResultOfSubtotal { get; set; }
diff --git a/EPPlus/RangeCollection.cs b/EPPlus/RangeCollection.cs
index c7f8218..5dfb567 100644
--- a/EPPlus/RangeCollection.cs
+++ b/EPPlus/RangeCollection.cs
@@ -103,7 +103,9 @@
/// <returns></returns>
internal IRangeId this[int index] => _cells[_cellIndex[index].ListPointer];
- internal int Count => _cells.Count;
+ internal int Count {
+ get { return _cells.Count; }
+ }
internal void Add(IRangeId cell) {
var ix = IndexOf(cell.RangeID);
diff --git a/EPPlus/Style/Dxf/DxfStyleBase.cs b/EPPlus/Style/Dxf/DxfStyleBase.cs
index 0c73cb0..7bbbcd0 100644
--- a/EPPlus/Style/Dxf/DxfStyleBase.cs
+++ b/EPPlus/Style/Dxf/DxfStyleBase.cs
@@ -21,8 +21,8 @@
protected void SetValueColor(XmlHelper helper, string path, ExcelDxfColor color) {
if (color != null && color.HasValue) {
- if (color.Rgb != null) {
- SetValue(helper, path + "/@rgb", color.Rgb);
+ if (color.Color != null) {
+ SetValue(helper, path + "/@rgb", color.Color.Value.ToArgb().ToString("x"));
} else if (color.Auto != null) {
SetValueBool(helper, path + "/@auto", color.Auto);
} else if (color.Theme != null) {
@@ -68,7 +68,7 @@
}
}
- protected string GetAsString(object v) {
+ protected internal string GetAsString(object v) {
return (v ?? "").ToString();
}
diff --git a/EPPlus/Style/Dxf/ExcelDxfColor.cs b/EPPlus/Style/Dxf/ExcelDxfColor.cs
index d22a7f9..4e6c4f9 100644
--- a/EPPlus/Style/Dxf/ExcelDxfColor.cs
+++ b/EPPlus/Style/Dxf/ExcelDxfColor.cs
@@ -1,4 +1,5 @@
using System;
+using System.Drawing;
namespace OfficeOpenXml.Style.Dxf;
@@ -14,7 +15,7 @@
public double? Tint { get; set; }
- public string Rgb { get; set; }
+ public Color? Color { get; set; }
protected internal override string Id =>
GetAsString(Theme)
@@ -25,20 +26,20 @@
+ "|"
+ GetAsString(Tint)
+ "|"
- + GetAsString(Rgb);
+ + GetAsString(Color == null ? "" : Color.Value.ToArgb().ToString("x"));
protected internal override ExcelDxfColor Clone() {
return new(_styles) {
Theme = Theme,
Index = Index,
- Rgb = Rgb,
+ Color = Color,
Auto = Auto,
Tint = Tint,
};
}
protected internal override bool HasValue =>
- Theme != null || Index != null || Auto != null || Tint != null || Rgb != null;
+ Theme != null || Index != null || Auto != null || Tint != null || Color != null;
protected internal override void CreateNodes(XmlHelper helper, string path) {
throw new NotImplementedException();
diff --git a/EPPlus/Style/Dxf/ExcelDxfStyle.cs b/EPPlus/Style/Dxf/ExcelDxfStyle.cs
index 325d5b1..7180b21 100644
--- a/EPPlus/Style/Dxf/ExcelDxfStyle.cs
+++ b/EPPlus/Style/Dxf/ExcelDxfStyle.cs
@@ -1,4 +1,5 @@
using System;
+using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -52,17 +53,46 @@
return bi;
}
- private ExcelBorderStyle GetBorderStyleEnum(string style) =>
- Enum.TryParse<ExcelBorderStyle>(style, true, out var result) ? result : ExcelBorderStyle.None;
+ private ExcelBorderStyle GetBorderStyleEnum(string style) {
+ if (style == "") {
+ return ExcelBorderStyle.None;
+ }
+ string sInStyle =
+ style.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture)
+ + style.Substring(1, style.Length - 1);
+ try {
+ return (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), sInStyle);
+ } catch {
+ return ExcelBorderStyle.None;
+ }
+ }
- private ExcelFillStyle GetPatternTypeEnum(string patternType) =>
- Enum.TryParse<ExcelFillStyle>(patternType, true, out var result) ? result : ExcelFillStyle.None;
+ private ExcelFillStyle GetPatternTypeEnum(string patternType) {
+ if (patternType == "") {
+ return ExcelFillStyle.None;
+ }
+ patternType =
+ patternType.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture)
+ + patternType.Substring(1, patternType.Length - 1);
+ try {
+ return (ExcelFillStyle)Enum.Parse(typeof(ExcelFillStyle), patternType);
+ } catch {
+ return ExcelFillStyle.None;
+ }
+ }
private ExcelDxfColor GetColor(XmlHelperInstance helper, string path) {
ExcelDxfColor ret = new ExcelDxfColor(_styles);
ret.Theme = helper.GetXmlNodeIntNull(path + "/@theme");
ret.Index = helper.GetXmlNodeIntNull(path + "/@indexed");
- ret.Rgb = helper.GetXmlNodeString(path + "/@rgb");
+ string rgb = helper.GetXmlNodeString(path + "/@rgb");
+ if (rgb != "") {
+ ret.Color = Color.FromArgb(
+ int.Parse(rgb.Substring(0, 2), NumberStyles.AllowHexSpecifier),
+ int.Parse(rgb.Substring(2, 2), NumberStyles.AllowHexSpecifier),
+ int.Parse(rgb.Substring(4, 2), NumberStyles.AllowHexSpecifier),
+ int.Parse(rgb.Substring(6, 2), NumberStyles.AllowHexSpecifier));
+ }
ret.Auto = helper.GetXmlNodeBoolNullable(path + "/@auto");
ret.Tint = helper.GetXmlNodeDoubleNull(path + "/@tint");
return ret;
diff --git a/EPPlus/Style/ExcelBorder.cs b/EPPlus/Style/ExcelBorder.cs
index 7784e20..bf07432 100644
--- a/EPPlus/Style/ExcelBorder.cs
+++ b/EPPlus/Style/ExcelBorder.cs
@@ -30,44 +30,53 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
+using System.Drawing;
+
namespace OfficeOpenXml.Style;
/// <summary>
/// Cell Border style
/// </summary>
public sealed class Border : StyleBase {
- internal Border(ExcelStyles styles, int positionId, string address, int index)
- : base(styles, positionId, address) {
+ internal Border(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address,
+ int index)
+ : base(styles, changedEvent, positionId, address) {
Index = index;
}
/// <summary>
/// Left border style
/// </summary>
- public ExcelBorderItem Left => new(_styles, _positionID, _address, eStyleClass.BorderLeft, this);
+ public ExcelBorderItem Left =>
+ new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderLeft, this);
/// <summary>
/// Right border style
/// </summary>
public ExcelBorderItem Right =>
- new(_styles, _positionID, _address, eStyleClass.BorderRight, this);
+ new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderRight, this);
/// <summary>
/// Top border style
/// </summary>
- public ExcelBorderItem Top => new(_styles, _positionID, _address, eStyleClass.BorderTop, this);
+ public ExcelBorderItem Top =>
+ new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderTop, this);
/// <summary>
/// Bottom border style
/// </summary>
public ExcelBorderItem Bottom =>
- new(_styles, _positionID, _address, eStyleClass.BorderBottom, this);
+ new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderBottom, this);
/// <summary>
/// 0Diagonal border style
/// </summary>
public ExcelBorderItem Diagonal =>
- new(_styles, _positionID, _address, eStyleClass.BorderDiagonal, this);
+ new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderDiagonal, this);
/// <summary>
/// A diagonal from the bottom left to top right of the cell
@@ -79,6 +88,10 @@
}
return false;
}
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Border, eStyleProperty.BorderDiagonalUp, value, _positionID, _address));
}
/// <summary>
@@ -91,8 +104,99 @@
}
return false;
}
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Border, eStyleProperty.BorderDiagonalDown, value, _positionID, _address));
}
internal override string Id =>
Top.Id + Bottom.Id + Left.Id + Right.Id + Diagonal.Id + DiagonalUp + DiagonalDown;
+
+ /// <summary>
+ /// Set the border style around the range.
+ /// </summary>
+ /// <param name="style">The border style</param>
+ public void BorderAround(ExcelBorderStyle style) {
+ var addr = new ExcelAddress(_address);
+ SetBorderAroundStyle(style, addr);
+ }
+
+ /// <summary>
+ /// Set the border style around the range.
+ /// </summary>
+ /// <param name="style">The border style</param>
+ /// <param name="color">The color of the border</param>
+ public void BorderAround(ExcelBorderStyle style, Color color) {
+ var addr = new ExcelAddress(_address);
+ SetBorderAroundStyle(style, addr);
+
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderTop,
+ eStyleProperty.Color,
+ color.ToArgb().ToString("X"),
+ _positionID,
+ new ExcelAddress(addr._fromRow, addr._fromCol, addr._fromRow, addr._toCol).Address));
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderBottom,
+ eStyleProperty.Color,
+ color.ToArgb().ToString("X"),
+ _positionID,
+ new ExcelAddress(addr._toRow, addr._fromCol, addr._toRow, addr._toCol).Address));
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderLeft,
+ eStyleProperty.Color,
+ color.ToArgb().ToString("X"),
+ _positionID,
+ new ExcelAddress(addr._fromRow, addr._fromCol, addr._toRow, addr._fromCol).Address));
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderRight,
+ eStyleProperty.Color,
+ color.ToArgb().ToString("X"),
+ _positionID,
+ new ExcelAddress(addr._fromRow, addr._toCol, addr._toRow, addr._toCol).Address));
+ }
+
+ private void SetBorderAroundStyle(ExcelBorderStyle style, ExcelAddress addr) {
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderTop,
+ eStyleProperty.Style,
+ style,
+ _positionID,
+ new ExcelAddress(addr._fromRow, addr._fromCol, addr._fromRow, addr._toCol).Address));
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderBottom,
+ eStyleProperty.Style,
+ style,
+ _positionID,
+ new ExcelAddress(addr._toRow, addr._fromCol, addr._toRow, addr._toCol).Address));
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderLeft,
+ eStyleProperty.Style,
+ style,
+ _positionID,
+ new ExcelAddress(addr._fromRow, addr._fromCol, addr._toRow, addr._fromCol).Address));
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.BorderRight,
+ eStyleProperty.Style,
+ style,
+ _positionID,
+ new ExcelAddress(addr._fromRow, addr._toCol, addr._toRow, addr._toCol).Address));
+ }
}
diff --git a/EPPlus/Style/ExcelBorderItem.cs b/EPPlus/Style/ExcelBorderItem.cs
index c8922d2..7708ab9 100644
--- a/EPPlus/Style/ExcelBorderItem.cs
+++ b/EPPlus/Style/ExcelBorderItem.cs
@@ -44,11 +44,12 @@
internal ExcelBorderItem(
ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
int worksheetId,
string address,
eStyleClass cls,
StyleBase parent)
- : base(styles, worksheetId, address) {
+ : base(styles, changedEvent, worksheetId, address) {
_cls = cls;
_parent = parent;
}
@@ -56,7 +57,10 @@
/// <summary>
/// The line style of the border
/// </summary>
- public ExcelBorderStyle Style => GetSource().Style;
+ public ExcelBorderStyle Style {
+ get => GetSource().Style;
+ set => _ChangedEvent(this, new(_cls, eStyleProperty.Style, value, _positionID, _address));
+ }
private ExcelColor _color;
@@ -66,7 +70,7 @@
public ExcelColor Color {
get {
if (_color == null) {
- _color = new(_styles, _positionID, _address, _cls, _parent);
+ _color = new(_styles, _ChangedEvent, _positionID, _address, _cls, _parent);
}
return _color;
}
diff --git a/EPPlus/Style/ExcelColor.cs b/EPPlus/Style/ExcelColor.cs
index 2050f50..e673510 100644
--- a/EPPlus/Style/ExcelColor.cs
+++ b/EPPlus/Style/ExcelColor.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using OfficeOpenXml.Style.XmlAccess;
namespace OfficeOpenXml.Style;
@@ -44,11 +45,12 @@
internal ExcelColor(
ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
int worksheetId,
string address,
eStyleClass cls,
StyleBase parent)
- : base(styles, worksheetId, address) {
+ : base(styles, changedEvent, worksheetId, address) {
_parent = parent;
_cls = cls;
}
@@ -61,17 +63,41 @@
/// <summary>
/// The tint value
/// </summary>
- public decimal Tint => GetSource().Tint;
+ public decimal Tint {
+ get => GetSource().Tint;
+ set {
+ if (value > 1 || value < -1) {
+ throw (new ArgumentOutOfRangeException("Value must be between -1 and 1"));
+ }
+ _ChangedEvent(this, new(_cls, eStyleProperty.Tint, value, _positionID, _address));
+ }
+ }
/// <summary>
/// The RGB value
/// </summary>
- public string Rgb => GetSource().Rgb;
+ public string Rgb {
+ get => GetSource().Rgb;
+ internal set =>
+ _ChangedEvent(this, new(_cls, eStyleProperty.Color, value, _positionID, _address));
+ }
/// <summary>
/// The indexed color number.
/// </summary>
- public int Indexed => GetSource().Indexed;
+ public int Indexed {
+ get => GetSource().Indexed;
+ set =>
+ _ChangedEvent(this, new(_cls, eStyleProperty.IndexedColor, value, _positionID, _address));
+ }
+
+ /// <summary>
+ /// Set the color of the object
+ /// </summary>
+ /// <param name="color">The color</param>
+ public void SetColor(Color color) {
+ Rgb = color.ToArgb().ToString("X");
+ }
internal override string Id => Theme + Tint + Rgb + Indexed;
diff --git a/EPPlus/Style/ExcelFill.cs b/EPPlus/Style/ExcelFill.cs
index e6cc1b2..d1a5ea6 100644
--- a/EPPlus/Style/ExcelFill.cs
+++ b/EPPlus/Style/ExcelFill.cs
@@ -36,8 +36,13 @@
/// The background fill of a cell
/// </summary>
public class ExcelFill : StyleBase {
- internal ExcelFill(ExcelStyles styles, int positionId, string address, int index)
- : base(styles, positionId, address) {
+ internal ExcelFill(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address,
+ int index)
+ : base(styles, changedEvent, positionId, address) {
Index = index;
}
@@ -51,6 +56,14 @@
}
return _styles.Fills[Index].PatternType;
}
+ set {
+ if (_gradient != null) {
+ _gradient = null;
+ }
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Fill, eStyleProperty.PatternType, value, _positionID, _address));
+ }
}
private ExcelColor _patternColor;
@@ -61,7 +74,13 @@
public ExcelColor PatternColor {
get {
if (_patternColor == null) {
- _patternColor = new(_styles, _positionID, _address, eStyleClass.FillPatternColor, this);
+ _patternColor = new(
+ _styles,
+ _ChangedEvent,
+ _positionID,
+ _address,
+ eStyleClass.FillPatternColor,
+ this);
if (_gradient != null) {
_gradient = null;
}
@@ -80,6 +99,7 @@
if (_backgroundColor == null) {
_backgroundColor = new(
_styles,
+ _ChangedEvent,
_positionID,
_address,
eStyleClass.FillBackgroundColor,
@@ -100,7 +120,7 @@
public ExcelGradientFill Gradient {
get {
if (_gradient == null) {
- _gradient = new(_styles, _positionID, _address, Index);
+ _gradient = new(_styles, _ChangedEvent, _positionID, _address, Index);
_backgroundColor = null;
_patternColor = null;
}
diff --git a/EPPlus/Style/ExcelFont.cs b/EPPlus/Style/ExcelFont.cs
index 2cb6d5c..36beb83 100644
--- a/EPPlus/Style/ExcelFont.cs
+++ b/EPPlus/Style/ExcelFont.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
namespace OfficeOpenXml.Style;
@@ -38,68 +39,146 @@
/// Cell style Font
/// </summary>
public sealed class ExcelFont : StyleBase {
- internal ExcelFont(ExcelStyles styles, int positionId, string address, int index)
- : base(styles, positionId, address) {
+ internal ExcelFont(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address,
+ int index)
+ : base(styles, changedEvent, positionId, address) {
Index = index;
}
/// <summary>
/// The name of the font
/// </summary>
- public string Name => _styles.Fonts[Index].Name;
+ public string Name {
+ get => _styles.Fonts[Index].Name;
+ set =>
+ _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Name, value, _positionID, _address));
+ }
/// <summary>
/// The Size of the font
/// </summary>
- public float Size => _styles.Fonts[Index].Size;
+ public float Size {
+ get => _styles.Fonts[Index].Size;
+ set =>
+ _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Size, value, _positionID, _address));
+ }
/// <summary>
/// Font family
/// </summary>
- public int Family => _styles.Fonts[Index].Family;
+ public int Family {
+ get => _styles.Fonts[Index].Family;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Font, eStyleProperty.Family, value, _positionID, _address));
+ }
/// <summary>
/// Cell color
/// </summary>
- public ExcelColor Color => new(_styles, _positionID, _address, eStyleClass.Font, this);
+ public ExcelColor Color =>
+ new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.Font, this);
/// <summary>
/// Scheme
/// </summary>
- public string Scheme => _styles.Fonts[Index].Scheme;
+ public string Scheme {
+ get => _styles.Fonts[Index].Scheme;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Font, eStyleProperty.Scheme, value, _positionID, _address));
+ }
/// <summary>
/// Font-bold
/// </summary>
- public bool Bold => _styles.Fonts[Index].Bold;
+ public bool Bold {
+ get => _styles.Fonts[Index].Bold;
+ set =>
+ _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Bold, value, _positionID, _address));
+ }
/// <summary>
/// Font-italic
/// </summary>
- public bool Italic => _styles.Fonts[Index].Italic;
+ public bool Italic {
+ get => _styles.Fonts[Index].Italic;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Font, eStyleProperty.Italic, value, _positionID, _address));
+ }
/// <summary>
/// Font-Strikeout
/// </summary>
- public bool Strike => _styles.Fonts[Index].Strike;
+ public bool Strike {
+ get => _styles.Fonts[Index].Strike;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Font, eStyleProperty.Strike, value, _positionID, _address));
+ }
/// <summary>
/// Font-Underline
/// </summary>
- public bool UnderLine => _styles.Fonts[Index].UnderLine;
+ public bool UnderLine {
+ get => _styles.Fonts[Index].UnderLine;
+ set {
+ if (value) {
+ UnderLineType = ExcelUnderLineType.Single;
+ } else {
+ UnderLineType = ExcelUnderLineType.None;
+ }
+ //_ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.UnderlineType, value, _positionID, _address));
+ }
+ }
- public ExcelUnderLineType UnderLineType => _styles.Fonts[Index].UnderLineType;
+ public ExcelUnderLineType UnderLineType {
+ get => _styles.Fonts[Index].UnderLineType;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Font, eStyleProperty.UnderlineType, value, _positionID, _address));
+ }
/// <summary>
/// Font-Vertical Align
/// </summary>
- public ExcelVerticalAlignmentFont VerticalAlign =>
- Enum.TryParse<ExcelVerticalAlignmentFont>(
- _styles.Fonts[Index].VerticalAlign,
- true,
- out var result)
- ? result
- : ExcelVerticalAlignmentFont.None;
+ public ExcelVerticalAlignmentFont VerticalAlign {
+ get {
+ if (_styles.Fonts[Index].VerticalAlign == "") {
+ return ExcelVerticalAlignmentFont.None;
+ }
+ return (ExcelVerticalAlignmentFont)
+ Enum.Parse(typeof(ExcelVerticalAlignmentFont), _styles.Fonts[Index].VerticalAlign, true);
+ }
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Font, eStyleProperty.VerticalAlign, value, _positionID, _address));
+ }
+
+ /// <summary>
+ /// Set the font from a Font object
+ /// </summary>
+ /// <param name="font"></param>
+ public void SetFromFont(Font font) {
+ Name = font.Name;
+ //Family=fnt.FontFamily.;
+ Size = (int)font.Size;
+ Strike = font.Strikeout;
+ Bold = font.Bold;
+ UnderLine = font.Underline;
+ Italic = font.Italic;
+ }
internal override string Id =>
Name
diff --git a/EPPlus/Style/ExcelGradientFill.cs b/EPPlus/Style/ExcelGradientFill.cs
index 508a1f7..16e73c8 100644
--- a/EPPlus/Style/ExcelGradientFill.cs
+++ b/EPPlus/Style/ExcelGradientFill.cs
@@ -39,40 +39,112 @@
/// The background fill of a cell
/// </summary>
public class ExcelGradientFill : StyleBase {
- internal ExcelGradientFill(ExcelStyles styles, int positionId, string address, int index)
- : base(styles, positionId, address) {
+ internal ExcelGradientFill(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address,
+ int index)
+ : base(styles, changedEvent, positionId, address) {
Index = index;
}
/// <summary>
/// Angle of the linear gradient
/// </summary>
- public double Degree => ((ExcelGradientFillXml)_styles.Fills[Index]).Degree;
+ public double Degree {
+ get => ((ExcelGradientFillXml)_styles.Fills[Index]).Degree;
+ set =>
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.GradientFill,
+ eStyleProperty.GradientDegree,
+ value,
+ _positionID,
+ _address));
+ }
/// <summary>
/// Linear or Path gradient
/// </summary>
- public ExcelFillGradientType Type => ((ExcelGradientFillXml)_styles.Fills[Index]).Type;
+ public ExcelFillGradientType Type {
+ get => ((ExcelGradientFillXml)_styles.Fills[Index]).Type;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.GradientFill, eStyleProperty.GradientType, value, _positionID, _address));
+ }
/// <summary>
/// Specifies in percentage format(from the top to the bottom) the position of the top edge of the inner rectangle (color 1). For top, 0 means the top edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. (applies to From Corner and From Center gradients).
/// </summary>
- public double Top => ((ExcelGradientFillXml)_styles.Fills[Index]).Top;
+ public double Top {
+ get => ((ExcelGradientFillXml)_styles.Fills[Index]).Top;
+ set {
+ if (value < 0 | value > 1) {
+ throw (new ArgumentOutOfRangeException("Value must be between 0 and 1"));
+ }
+ _ChangedEvent(
+ this,
+ new(eStyleClass.GradientFill, eStyleProperty.GradientTop, value, _positionID, _address));
+ }
+ }
/// <summary>
/// Specifies in percentage format (from the top to the bottom) the position of the bottom edge of the inner rectangle (color 1). For bottom, 0 means the bottom edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell.
/// </summary>
- public double Bottom => ((ExcelGradientFillXml)_styles.Fills[Index]).Bottom;
+ public double Bottom {
+ get => ((ExcelGradientFillXml)_styles.Fills[Index]).Bottom;
+ set {
+ if (value < 0 | value > 1) {
+ throw (new ArgumentOutOfRangeException("Value must be between 0 and 1"));
+ }
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.GradientFill,
+ eStyleProperty.GradientBottom,
+ value,
+ _positionID,
+ _address));
+ }
+ }
/// <summary>
/// Specifies in percentage format (from the left to the right) the position of the left edge of the inner rectangle (color 1). For left, 0 means the left edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients).
/// </summary>
- public double Left => ((ExcelGradientFillXml)_styles.Fills[Index]).Left;
+ public double Left {
+ get => ((ExcelGradientFillXml)_styles.Fills[Index]).Left;
+ set {
+ if (value < 0 | value > 1) {
+ throw (new ArgumentOutOfRangeException("Value must be between 0 and 1"));
+ }
+ _ChangedEvent(
+ this,
+ new(eStyleClass.GradientFill, eStyleProperty.GradientLeft, value, _positionID, _address));
+ }
+ }
/// <summary>
/// Specifies in percentage format (from the left to the right) the position of the right edge of the inner rectangle (color 1). For right, 0 means the right edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients).
/// </summary>
- public double Right => ((ExcelGradientFillXml)_styles.Fills[Index]).Right;
+ public double Right {
+ get => ((ExcelGradientFillXml)_styles.Fills[Index]).Right;
+ set {
+ if (value < 0 | value > 1) {
+ throw (new ArgumentOutOfRangeException("Value must be between 0 and 1"));
+ }
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.GradientFill,
+ eStyleProperty.GradientRight,
+ value,
+ _positionID,
+ _address));
+ }
+ }
private ExcelColor _gradientColor1;
@@ -82,7 +154,13 @@
public ExcelColor Color1 {
get {
if (_gradientColor1 == null) {
- _gradientColor1 = new(_styles, _positionID, _address, eStyleClass.FillGradientColor1, this);
+ _gradientColor1 = new(
+ _styles,
+ _ChangedEvent,
+ _positionID,
+ _address,
+ eStyleClass.FillGradientColor1,
+ this);
}
return _gradientColor1;
}
@@ -96,7 +174,13 @@
public ExcelColor Color2 {
get {
if (_gradientColor2 == null) {
- _gradientColor2 = new(_styles, _positionID, _address, eStyleClass.FillGradientColor2, this);
+ _gradientColor2 = new(
+ _styles,
+ _ChangedEvent,
+ _positionID,
+ _address,
+ eStyleClass.FillGradientColor2,
+ this);
}
return _gradientColor2;
}
diff --git a/EPPlus/Style/ExcelNumberFormat.cs b/EPPlus/Style/ExcelNumberFormat.cs
index b971e7c..d1841df 100644
--- a/EPPlus/Style/ExcelNumberFormat.cs
+++ b/EPPlus/Style/ExcelNumberFormat.cs
@@ -36,8 +36,13 @@
/// The numberformat of the cell
/// </summary>
public sealed class ExcelNumberFormat : StyleBase {
- internal ExcelNumberFormat(ExcelStyles styles, int positionId, string address, int index)
- : base(styles, positionId, address) {
+ internal ExcelNumberFormat(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address,
+ int index)
+ : base(styles, changedEvent, positionId, address) {
Index = index;
}
@@ -46,6 +51,10 @@
/// </summary>
public int NumFmtID => Index;
+ //set
+ //{
+ // _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Numberformat, "NumFmtID", value, _workSheetID, _address));
+ //}
/// <summary>
/// The numberformat
/// </summary>
@@ -58,6 +67,15 @@
}
return "general";
}
+ set =>
+ _ChangedEvent(
+ this,
+ new(
+ eStyleClass.Numberformat,
+ eStyleProperty.Format,
+ (string.IsNullOrEmpty(value) ? "General" : value),
+ _positionID,
+ _address));
}
internal override string Id => Format;
diff --git a/EPPlus/Style/ExcelRichText.cs b/EPPlus/Style/ExcelRichText.cs
index 969dccc..2207656 100644
--- a/EPPlus/Style/ExcelRichText.cs
+++ b/EPPlus/Style/ExcelRichText.cs
@@ -33,6 +33,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -215,13 +216,33 @@
/// <summary>
/// Vertical Alignment
/// </summary>
- public ExcelVerticalAlignmentFont VerticalAlign =>
- Enum.TryParse<ExcelVerticalAlignmentFont>(
- GetXmlNodeString(TopNode, _vertAlignPath),
- true,
- out var result)
- ? result
- : ExcelVerticalAlignmentFont.None;
+ public ExcelVerticalAlignmentFont VerticalAlign {
+ get {
+ string v = GetXmlNodeString(_vertAlignPath);
+ if (v == "") {
+ return ExcelVerticalAlignmentFont.None;
+ }
+ try {
+ return (ExcelVerticalAlignmentFont)Enum.Parse(typeof(ExcelVerticalAlignmentFont), v, true);
+ } catch {
+ return ExcelVerticalAlignmentFont.None;
+ }
+ }
+ set {
+ _collection.ConvertRichtext();
+ if (value == ExcelVerticalAlignmentFont.None) {
+ // If Excel 2010 encounters a vertical align value of blank, it will not load
+ // the spreadsheet. So if None is specified, delete the node, it will be
+ // recreated if a new value is applied later.
+ DeleteNode(_vertAlignPath);
+ } else {
+ SetXmlNodeString(_vertAlignPath, value.ToString().ToLowerInvariant());
+ }
+ if (_callback != null) {
+ _callback();
+ }
+ }
+ }
private const string _sizePath = "d:rPr/d:sz/@val";
@@ -257,5 +278,30 @@
private const string _colorPath = "d:rPr/d:color/@rgb";
+ /// <summary>
+ /// Text color
+ /// </summary>
+ public Color Color {
+ get {
+ string col = GetXmlNodeString(_colorPath);
+ if (col == "") {
+ return Color.Empty;
+ }
+ return Color.FromArgb(int.Parse(col, NumberStyles.AllowHexSpecifier));
+ }
+ set {
+ _collection.ConvertRichtext();
+ SetXmlNodeString(
+ _colorPath,
+ value
+ .ToArgb()
+ .ToString(
+ "X") /*.Substring(2, 6)*/);
+ if (_callback != null) {
+ _callback();
+ }
+ }
+ }
+
public ExcelRichTextCollection _collection { get; set; }
}
diff --git a/EPPlus/Style/ExcelRichTextCollection.cs b/EPPlus/Style/ExcelRichTextCollection.cs
index 7cd4867..5e87c4b 100644
--- a/EPPlus/Style/ExcelRichTextCollection.cs
+++ b/EPPlus/Style/ExcelRichTextCollection.cs
@@ -32,6 +32,7 @@
using System.Collections;
using System.Collections.Generic;
+using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
@@ -81,6 +82,56 @@
/// </summary>
public int Count => _list.Count;
+ /// <summary>
+ /// Add a rich text string
+ /// </summary>
+ /// <param name="text">The text to add</param>
+ /// <returns></returns>
+ public ExcelRichText Add(string text) {
+ ConvertRichtext();
+ XmlDocument doc;
+ if (TopNode is XmlDocument document) {
+ doc = document;
+ } else {
+ doc = TopNode.OwnerDocument;
+ }
+ var node = doc.CreateElement("d", "r", ExcelPackage._schemaMain);
+ TopNode.AppendChild(node);
+ var rt = new ExcelRichText(NameSpaceManager, node, this);
+ if (_list.Count > 0) {
+ ExcelRichText prevItem = _list[_list.Count - 1];
+ rt.FontName = prevItem.FontName;
+ rt.Size = prevItem.Size;
+ if (prevItem.Color.IsEmpty) {
+ rt.Color = Color.Black;
+ } else {
+ rt.Color = prevItem.Color;
+ }
+ rt.PreserveSpace = rt.PreserveSpace;
+ rt.Bold = prevItem.Bold;
+ rt.Italic = prevItem.Italic;
+ rt.UnderLine = prevItem.UnderLine;
+ } else if (_cells == null) {
+ rt.FontName = "Calibri";
+ rt.Size = 11;
+ } else {
+ var style = _cells.Offset(0, 0).Style;
+ rt.FontName = style.Font.Name;
+ rt.Size = style.Font.Size;
+ rt.Bold = style.Font.Bold;
+ rt.Italic = style.Font.Italic;
+ _cells.IsRichText = true;
+ }
+ rt.Text = text;
+ rt.PreserveSpace = true;
+ if (_cells != null) {
+ rt.SetCallback(UpdateCells);
+ UpdateCells();
+ }
+ _list.Add(rt);
+ return rt;
+ }
+
internal void ConvertRichtext() {
if (_cells == null) {
return;
@@ -109,6 +160,11 @@
this[0].Italic = fnt.Italic;
this[0].Size = fnt.Size;
this[0].UnderLine = fnt.UnderLine;
+
+ if (fnt.Color.Rgb != ""
+ && int.TryParse(fnt.Color.Rgb, NumberStyles.HexNumber, null, out var hex)) {
+ this[0].Color = Color.FromArgb(hex);
+ }
}
}
@@ -117,6 +173,18 @@
}
/// <summary>
+ /// Clear the collection
+ /// </summary>
+ public void Clear() {
+ _list.Clear();
+ TopNode.RemoveAll();
+ UpdateCells();
+ if (_cells != null) {
+ _cells.IsRichText = false;
+ }
+ }
+
+ /// <summary>
/// Removes an item at the specific index
/// </summary>
/// <param name="index"></param>
@@ -156,6 +224,16 @@
}
return sb.ToString();
}
+ set {
+ if (Count == 0) {
+ Add(value);
+ } else {
+ this[0].Text = value;
+ for (int ix = 1; ix < Count; ix++) {
+ RemoveAt(ix);
+ }
+ }
+ }
}
IEnumerator<ExcelRichText> IEnumerable<ExcelRichText>.GetEnumerator() {
diff --git a/EPPlus/Style/ExcelRichTextHtmlUtility.cs b/EPPlus/Style/ExcelRichTextHtmlUtility.cs
new file mode 100644
index 0000000..83e37c6
--- /dev/null
+++ b/EPPlus/Style/ExcelRichTextHtmlUtility.cs
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * You may amend and distribute as you like, but don't remove this header!
+ *
+ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
+ * See http://www.codeplex.com/EPPlus for details.
+ *
+ * Copyright (C) 2011 Jan Källman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
+ * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
+ *
+ * All code and executables are provided "as is" with no warranty either express or implied.
+ * The author accepts no liability for any damage or loss of business that this product may cause.
+ *
+ * Code change notes:
+ *
+ * Author Change Date
+ * ******************************************************************************
+ * Richard Tallent Initial Release 2012-08-13
+ *******************************************************************************/
+
+using System;
+using System.Text.RegularExpressions;
+using System.Web;
+
+namespace OfficeOpenXml.Style;
+
+public class ExcelRichTextHtmlUtility {
+ /// <summary>
+ /// Provides basic HTML support by converting well-behaved HTML into appropriate RichText blocks.
+ /// HTML support is limited, and does not include font colors, sizes, or typefaces at this time,
+ /// and also does not support CSS style attributes. It does support line breaks using the BR tag.
+ ///
+ /// This routine parses the HTML into RegEx pairings of an HTML tag and the text until the NEXT
+ /// tag (if any). The tag is parsed to determine the setting change to be applied to the last set
+ /// of settings, and if the text is not blank, a new block is added to rich text.
+ /// </summary>
+ /// <param name="range"></param>
+ /// <param name="html">The HTML to parse into RichText</param>
+ /// <param name="defaultFontName"></param>
+ /// <param name="defaultFontSize"></param>
+ public static void SetRichTextFromHtml(
+ ExcelRange range,
+ string html,
+ string defaultFontName,
+ short defaultFontSize) {
+ // Reset the cell value, just in case there is an existing RichText value.
+ range.Value = "";
+
+ // Sanity check for blank values, skips creating Regex objects for performance.
+ if (String.IsNullOrEmpty(html)) {
+ range.IsRichText = false;
+ return;
+ }
+
+ // Change all BR tags to line breaks. http://epplus.codeplex.com/discussions/238692/
+ // Cells with line breaks aren't necessarily considered rich text, so this is performed
+ // before parsing the HTML tags.
+ html = Regex.Replace(
+ html,
+ "<br[^>]*>",
+ "\r\n",
+ RegexOptions.Compiled | RegexOptions.IgnoreCase);
+
+ string tag;
+ string text;
+ ExcelRichText thisrt = null;
+ bool isFirst = true;
+
+ // Get all pairs of legitimate tags and the text between them. This loop will
+ // only execute if there is at least one start or end tag.
+ foreach (Match m in Regex.Matches(
+ html,
+ @"<(/?[a-z]+)[^<>]*>([\s\S]*?)(?=</?[a-z]+[^<>]*>|$)",
+ RegexOptions.Compiled | RegexOptions.IgnoreCase)) {
+ if (isFirst) {
+ // On the very first match, set up the initial rich text object with
+ // the defaults for the text BEFORE the match.
+ range.IsRichText = true;
+ thisrt = range.RichText.Add(CleanText(html.Substring(0, m.Index))); // May be 0-length
+ thisrt.Size = defaultFontSize; // Set the default font size
+ thisrt.FontName = defaultFontName; // Set the default font name
+ isFirst = false;
+ }
+ // Get the tag and the block of text until the NEXT tag or EOS. If there are HTML entities
+ // encoded, unencode them, they should be passed to RichText as normal characters (other
+ // than non-breaking spaces, which should be replaced with normal spaces, they break Excel.
+ tag = m.Groups[1].Captures[0].Value;
+ text = CleanText(m.Groups[2].Captures[0].Value);
+
+ if (thisrt.Text == "") {
+ // The most recent rich text block wasn't *actually* used last time around, so update
+ // the text and keep it as the "current" block. This happens with the first block if
+ // it starts with a tag, and may happen later if tags come one right after the other.
+ thisrt.Text = text;
+ } else {
+ // The current rich text block has some text, so create a new one. RichText.Add()
+ // automatically applies the settings from the previous block, other than vertical
+ // alignment.
+ thisrt = range.RichText.Add(text);
+ }
+ // Override the settings based on the current tag, keep all other settings.
+ SetStyleFromTag(tag, thisrt);
+ }
+
+ if (thisrt == null) {
+ // No HTML tags were found, so treat this as a normal text value.
+ range.IsRichText = false;
+ range.Value = CleanText(html);
+ } else if (String.IsNullOrEmpty(thisrt.Text)) {
+ // Rich text was found, but the last node contains no text, so remove it. This can happen if,
+ // say, the end of the string is an end tag or unsupported tag (common).
+ range.RichText.Remove(thisrt);
+
+ // Failsafe -- the HTML may be just tags, no text, in which case there may be no rich text
+ // directives that remain. If that is the case, turn off rich text and treat this like a blank
+ // cell value.
+ if (range.RichText.Count == 0) {
+ range.IsRichText = false;
+ range.Value = "";
+ }
+ }
+ }
+
+ private static void SetStyleFromTag(string tag, ExcelRichText settings) {
+ switch (tag.ToLower()) {
+ case "b":
+ case "strong":
+ settings.Bold = true;
+ break;
+ case "i":
+ case "em":
+ settings.Italic = true;
+ break;
+ case "u":
+ settings.UnderLine = true;
+ break;
+ case "s":
+ case "strike":
+ settings.Strike = true;
+ break;
+ case "sup":
+ settings.VerticalAlign = ExcelVerticalAlignmentFont.Superscript;
+ break;
+ case "sub":
+ settings.VerticalAlign = ExcelVerticalAlignmentFont.Subscript;
+ break;
+ case "/b":
+ case "/strong":
+ settings.Bold = false;
+ break;
+ case "/i":
+ case "/em":
+ settings.Italic = false;
+ break;
+ case "/u":
+ settings.UnderLine = false;
+ break;
+ case "/s":
+ case "/strike":
+ settings.Strike = false;
+ break;
+ case "/sup":
+ case "/sub":
+ settings.VerticalAlign = ExcelVerticalAlignmentFont.None;
+ break;
+ }
+ }
+
+ private static string CleanText(string s) {
+ // Need to convert HTML entities (named or numbered) into actual Unicode characters
+ s = HttpUtility.HtmlDecode(s);
+ // Remove any non-breaking spaces, kills Excel
+ s = s.Replace("\u00A0", " ");
+ return s;
+ }
+}
diff --git a/EPPlus/Style/ExcelStyle.cs b/EPPlus/Style/ExcelStyle.cs
index f7b60f9..9c2509a 100644
--- a/EPPlus/Style/ExcelStyle.cs
+++ b/EPPlus/Style/ExcelStyle.cs
@@ -39,8 +39,13 @@
/// Toplevel class for cell styling
/// </summary>
public sealed class ExcelStyle : StyleBase {
- internal ExcelStyle(ExcelStyles styles, int positionId, string address, int xfsId)
- : base(styles, positionId, address) {
+ internal ExcelStyle(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address,
+ int xfsId)
+ : base(styles, changedEvent, positionId, address) {
Index = xfsId;
ExcelXfs xfs;
if (positionId > -1) {
@@ -50,10 +55,10 @@
}
Styles = styles;
PositionID = positionId;
- Numberformat = new(styles, PositionID, address, xfs.NumberFormatId);
- Font = new(styles, PositionID, address, xfs.FontId);
- Fill = new(styles, PositionID, address, xfs.FillId);
- Border = new(styles, PositionID, address, xfs.BorderId);
+ Numberformat = new(styles, changedEvent, PositionID, address, xfs.NumberFormatId);
+ Font = new(styles, changedEvent, PositionID, address, xfs.FontId);
+ Fill = new(styles, changedEvent, PositionID, address, xfs.FillId);
+ Border = new(styles, changedEvent, PositionID, address, xfs.BorderId);
}
/// <summary>
@@ -79,54 +84,122 @@
/// <summary>
/// The horizontal alignment in the cell
/// </summary>
- public ExcelHorizontalAlignment HorizontalAlignment => _styles.CellXfs[Index].HorizontalAlignment;
+ public ExcelHorizontalAlignment HorizontalAlignment {
+ get => _styles.CellXfs[Index].HorizontalAlignment;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.HorizontalAlign, value, _positionID, _address));
+ }
/// <summary>
/// The vertical alignment in the cell
/// </summary>
- public ExcelVerticalAlignment VerticalAlignment => _styles.CellXfs[Index].VerticalAlignment;
+ public ExcelVerticalAlignment VerticalAlignment {
+ get => _styles.CellXfs[Index].VerticalAlignment;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.VerticalAlign, value, _positionID, _address));
+ }
/// <summary>
/// Wrap the text
/// </summary>
- public bool WrapText => _styles.CellXfs[Index].WrapText;
+ public bool WrapText {
+ get => _styles.CellXfs[Index].WrapText;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.WrapText, value, _positionID, _address));
+ }
/// <summary>
/// Readingorder
/// </summary>
- public ExcelReadingOrder ReadingOrder => _styles.CellXfs[Index].ReadingOrder;
+ public ExcelReadingOrder ReadingOrder {
+ get => _styles.CellXfs[Index].ReadingOrder;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.ReadingOrder, value, _positionID, _address));
+ }
/// <summary>
/// Shrink the text to fit
/// </summary>
- public bool ShrinkToFit => _styles.CellXfs[Index].ShrinkToFit;
+ public bool ShrinkToFit {
+ get => _styles.CellXfs[Index].ShrinkToFit;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.ShrinkToFit, value, _positionID, _address));
+ }
/// <summary>
/// The margin between the border and the text
/// </summary>
- public int Indent => _styles.CellXfs[Index].Indent;
+ public int Indent {
+ get => _styles.CellXfs[Index].Indent;
+ set {
+ if (value < 0 || value > 250) {
+ throw (new ArgumentOutOfRangeException("Indent must be between 0 and 250"));
+ }
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.Indent, value, _positionID, _address));
+ }
+ }
/// <summary>
/// Text orientation in degrees. Values range from 0 to 180.
/// </summary>
- public int TextRotation => _styles.CellXfs[Index].TextRotation;
+ public int TextRotation {
+ get => _styles.CellXfs[Index].TextRotation;
+ set {
+ if (value < 0 || value > 180) {
+ throw new ArgumentOutOfRangeException("TextRotation out of range.");
+ }
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.TextRotation, value, _positionID, _address));
+ }
+ }
/// <summary>
/// If true the cell is locked for editing when the sheet is protected
/// <seealso cref="ExcelWorksheet.Protection"/>
/// </summary>
- public bool Locked => _styles.CellXfs[Index].Locked;
+ public bool Locked {
+ get => _styles.CellXfs[Index].Locked;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.Locked, value, _positionID, _address));
+ }
/// <summary>
/// If true the formula is hidden when the sheet is protected.
/// <seealso cref="ExcelWorksheet.Protection"/>
/// </summary>
- public bool Hidden => _styles.CellXfs[Index].Hidden;
+ public bool Hidden {
+ get => _styles.CellXfs[Index].Hidden;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.Hidden, value, _positionID, _address));
+ }
/// <summary>
/// The index in the style collection
/// </summary>
- public int XfId => _styles.CellXfs[Index].XfId;
+ public int XfId {
+ get => _styles.CellXfs[Index].XfId;
+ set =>
+ _ChangedEvent(
+ this,
+ new(eStyleClass.Style, eStyleProperty.XfId, value, _positionID, _address));
+ }
internal int PositionID { get; set; }
diff --git a/EPPlus/Style/ExcelTextFont.cs b/EPPlus/Style/ExcelTextFont.cs
index 9252413..f098072 100644
--- a/EPPlus/Style/ExcelTextFont.cs
+++ b/EPPlus/Style/ExcelTextFont.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -140,6 +141,22 @@
}
}
+ private readonly string _underLineColorPath = "a:uFill/a:solidFill/a:srgbClr/@val";
+
+ public Color UnderLineColor {
+ get {
+ string col = GetXmlNodeString(_underLineColorPath);
+ if (col == "") {
+ return Color.Empty;
+ }
+ return Color.FromArgb(int.Parse(col, NumberStyles.AllowHexSpecifier));
+ }
+ set {
+ CreateTopNode();
+ SetXmlNodeString(_underLineColorPath, value.ToArgb().ToString("X").Substring(2, 6));
+ }
+ }
+
private readonly string _italicPath = "@i";
public bool Italic {
@@ -170,6 +187,22 @@
}
}
+ private readonly string _colorPath = "a:solidFill/a:srgbClr/@val";
+
+ public Color Color {
+ get {
+ string col = GetXmlNodeString(_colorPath);
+ if (col == "") {
+ return Color.Empty;
+ }
+ return Color.FromArgb(int.Parse(col, NumberStyles.AllowHexSpecifier));
+ }
+ set {
+ CreateTopNode();
+ SetXmlNodeString(_colorPath, value.ToArgb().ToString("X").Substring(2, 6));
+ }
+ }
+
private eUnderLineType TranslateUnderline(string text) {
switch (text) {
case "sng":
@@ -179,9 +212,7 @@
case "":
return eUnderLineType.None;
default:
- return Enum.TryParse<eUnderLineType>(text, true, out var result)
- ? result
- : eUnderLineType.None;
+ return (eUnderLineType)Enum.Parse(typeof(eUnderLineType), text);
}
}
@@ -219,4 +250,26 @@
return "noStrike";
}
}
+
+ /// <summary>
+ /// Set the font style from a font object
+ /// </summary>
+ /// <param name="font"></param>
+ public void SetFromFont(Font font) {
+ LatinFont = font.Name;
+ ComplexFont = font.Name;
+ Size = font.Size;
+ if (font.Bold) {
+ Bold = font.Bold;
+ }
+ if (font.Italic) {
+ Italic = font.Italic;
+ }
+ if (font.Underline) {
+ UnderLine = eUnderLineType.Single;
+ }
+ if (font.Strikeout) {
+ Strike = eStrikeType.Single;
+ }
+ }
}
diff --git a/EPPlus/Style/StyleBase.cs b/EPPlus/Style/StyleBase.cs
index ec560a5..fa1b390 100644
--- a/EPPlus/Style/StyleBase.cs
+++ b/EPPlus/Style/StyleBase.cs
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*******************************************************************************
* You may amend and distribute as you like, but don't remove this header!
*
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
@@ -163,11 +163,17 @@
public abstract class StyleBase {
protected ExcelStyles _styles;
+ internal XmlHelper.ChangedEventHandler _ChangedEvent;
protected int _positionID;
protected string _address;
- internal StyleBase(ExcelStyles styles, int positionId, string address) {
+ internal StyleBase(
+ ExcelStyles styles,
+ XmlHelper.ChangedEventHandler changedEvent,
+ int positionId,
+ string address) {
_styles = styles;
+ _ChangedEvent = changedEvent;
_address = address;
_positionID = positionId;
}
diff --git a/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs b/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs
index 9c0de5e..7e94481 100644
--- a/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs
@@ -61,9 +61,14 @@
if (style == "") {
return ExcelBorderStyle.None;
}
- return Enum.TryParse<ExcelBorderStyle>(style, true, out var result)
- ? result
- : ExcelBorderStyle.None;
+ string sInStyle =
+ style.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture)
+ + style.Substring(1, style.Length - 1);
+ try {
+ return (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), sInStyle);
+ } catch {
+ return ExcelBorderStyle.None;
+ }
}
private ExcelBorderStyle _borderStyle = ExcelBorderStyle.None;
diff --git a/EPPlus/Style/XmlAccess/ExcelColorXml.cs b/EPPlus/Style/XmlAccess/ExcelColorXml.cs
index 7a6d024..ba1fd11 100644
--- a/EPPlus/Style/XmlAccess/ExcelColorXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelColorXml.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -141,6 +142,11 @@
_auto = false;
}
+ public void SetColor(Color color) {
+ Clear();
+ _rgb = color.ToArgb().ToString("X");
+ }
+
internal ExcelColorXml Copy() {
return new(NameSpaceManager) {
_indexed = _indexed,
diff --git a/EPPlus/Style/XmlAccess/ExcelFillXml.cs b/EPPlus/Style/XmlAccess/ExcelFillXml.cs
index cf43d0e..98b7c9d 100644
--- a/EPPlus/Style/XmlAccess/ExcelFillXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelFillXml.cs
@@ -55,9 +55,17 @@
}
private ExcelFillStyle GetPatternType(string patternType) {
- return Enum.TryParse<ExcelFillStyle>(patternType, true, out var result)
- ? result
- : ExcelFillStyle.None;
+ if (patternType == "") {
+ return ExcelFillStyle.None;
+ }
+ patternType =
+ patternType.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture)
+ + patternType.Substring(1, patternType.Length - 1);
+ try {
+ return (ExcelFillStyle)Enum.Parse(typeof(ExcelFillStyle), patternType);
+ } catch {
+ return ExcelFillStyle.None;
+ }
}
internal override string Id => PatternType + PatternColor.Id + BackgroundColor.Id;
diff --git a/EPPlus/Style/XmlAccess/ExcelFontXml.cs b/EPPlus/Style/XmlAccess/ExcelFontXml.cs
index 2d90c95..88ab554 100644
--- a/EPPlus/Style/XmlAccess/ExcelFontXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelFontXml.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -70,9 +71,7 @@
if (ut == "") {
_underlineType = ExcelUnderLineType.Single;
} else {
- if (!Enum.TryParse(ut, true, out _underlineType)) {
- _underlineType = ExcelUnderLineType.Single;
- }
+ _underlineType = (ExcelUnderLineType)Enum.Parse(typeof(ExcelUnderLineType), ut, true);
}
} else {
_underlineType = ExcelUnderLineType.None;
@@ -223,6 +222,16 @@
set => _verticalAlign = value;
}
+ public void SetFromFont(Font font) {
+ Name = font.Name;
+ //Family=fnt.FontFamily.;
+ Size = (int)font.Size;
+ Strike = font.Strikeout;
+ Bold = font.Bold;
+ UnderLine = font.Underline;
+ Italic = font.Italic;
+ }
+
internal ExcelFontXml Copy() {
ExcelFontXml newFont = new ExcelFontXml(NameSpaceManager);
newFont.Name = _name;
diff --git a/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs b/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs
index 356e90f..8004056 100644
--- a/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs
@@ -57,7 +57,7 @@
CustomBuildin = GetXmlNodeBool(_customBuiltinPath);
_styles = styles;
- _style = new(styles, -1, Name, _styleXfId);
+ _style = new(styles, styles.NamedStylePropertyChange, -1, Name, _styleXfId);
}
internal override string Id => Name;
diff --git a/EPPlus/Style/XmlAccess/ExcelXfsXml.cs b/EPPlus/Style/XmlAccess/ExcelXfsXml.cs
index 9761ea1..d00ed0e 100644
--- a/EPPlus/Style/XmlAccess/ExcelXfsXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelXfsXml.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -81,15 +82,45 @@
}
}
- private ExcelHorizontalAlignment GetHorizontalAlign(string align) =>
- Enum.TryParse<ExcelHorizontalAlignment>(align, true, out var result)
- ? result
- : ExcelHorizontalAlignment.General;
+ private ExcelHorizontalAlignment GetHorizontalAlign(string align) {
+ if (align == "") {
+ return ExcelHorizontalAlignment.General;
+ }
+ align =
+ align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture)
+ + align.Substring(1, align.Length - 1);
+ try {
+ return (ExcelHorizontalAlignment)Enum.Parse(typeof(ExcelHorizontalAlignment), align);
+ } catch {
+ return ExcelHorizontalAlignment.General;
+ }
+ }
- private ExcelVerticalAlignment GetVerticalAlign(string align) =>
- Enum.TryParse<ExcelVerticalAlignment>(align, true, out var result)
- ? result
- : ExcelVerticalAlignment.Bottom;
+ private ExcelVerticalAlignment GetVerticalAlign(string align) {
+ if (align == "") {
+ return ExcelVerticalAlignment.Bottom;
+ }
+ align =
+ align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture)
+ + align.Substring(1, align.Length - 1);
+ try {
+ return (ExcelVerticalAlignment)Enum.Parse(typeof(ExcelVerticalAlignment), align);
+ } catch {
+ return ExcelVerticalAlignment.Bottom;
+ }
+ }
+
+ internal void Xf_ChangedEvent(object sender, EventArgs e) {
+ //if (_cell != null)
+ //{
+ // if (!Styles.ChangedCells.ContainsKey(_cell.Id))
+ // {
+ // //_cell.Style = "";
+ // _cell.SetNewStyleID(int.MinValue.ToString());
+ // Styles.ChangedCells.Add(_cell.Id, _cell);
+ // }
+ //}
+ }
private int _xfID;
@@ -320,6 +351,327 @@
return newXf;
}
+ internal int GetNewId(
+ ExcelStyleCollection<ExcelXfs> xfsCol,
+ StyleBase styleObject,
+ eStyleClass styleClass,
+ eStyleProperty styleProperty,
+ object value) {
+ ExcelXfs newXfs = Copy();
+ switch (styleClass) {
+ case eStyleClass.Numberformat:
+ newXfs.NumberFormatId = GetIdNumberFormat(styleProperty, value);
+ styleObject.SetIndex(newXfs.NumberFormatId);
+ break;
+ case eStyleClass.Font: {
+ newXfs.FontId = GetIdFont(styleProperty, value);
+ styleObject.SetIndex(newXfs.FontId);
+ break;
+ }
+ case eStyleClass.Fill:
+ case eStyleClass.FillBackgroundColor:
+ case eStyleClass.FillPatternColor:
+ newXfs.FillId = GetIdFill(styleClass, styleProperty, value);
+ styleObject.SetIndex(newXfs.FillId);
+ break;
+ case eStyleClass.GradientFill:
+ case eStyleClass.FillGradientColor1:
+ case eStyleClass.FillGradientColor2:
+ newXfs.FillId = GetIdGradientFill(styleClass, styleProperty, value);
+ styleObject.SetIndex(newXfs.FillId);
+ break;
+ case eStyleClass.Border:
+ case eStyleClass.BorderBottom:
+ case eStyleClass.BorderDiagonal:
+ case eStyleClass.BorderLeft:
+ case eStyleClass.BorderRight:
+ case eStyleClass.BorderTop:
+ newXfs.BorderId = GetIdBorder(styleClass, styleProperty, value);
+ styleObject.SetIndex(newXfs.BorderId);
+ break;
+ case eStyleClass.Style:
+ switch (styleProperty) {
+ case eStyleProperty.XfId:
+ newXfs.XfId = (int)value;
+ break;
+ case eStyleProperty.HorizontalAlign:
+ newXfs.HorizontalAlignment = (ExcelHorizontalAlignment)value;
+ break;
+ case eStyleProperty.VerticalAlign:
+ newXfs.VerticalAlignment = (ExcelVerticalAlignment)value;
+ break;
+ case eStyleProperty.WrapText:
+ newXfs.WrapText = (bool)value;
+ break;
+ case eStyleProperty.ReadingOrder:
+ newXfs.ReadingOrder = (ExcelReadingOrder)value;
+ break;
+ case eStyleProperty.ShrinkToFit:
+ newXfs.ShrinkToFit = (bool)value;
+ break;
+ case eStyleProperty.Indent:
+ newXfs.Indent = (int)value;
+ break;
+ case eStyleProperty.TextRotation:
+ newXfs.TextRotation = (int)value;
+ break;
+ case eStyleProperty.Locked:
+ newXfs.Locked = (bool)value;
+ break;
+ case eStyleProperty.Hidden:
+ newXfs.Hidden = (bool)value;
+ break;
+ default:
+ throw (new("Invalid property for class style."));
+ }
+ break;
+ }
+ int id = xfsCol.FindIndexById(newXfs.Id);
+ if (id < 0) {
+ return xfsCol.Add(newXfs.Id, newXfs);
+ }
+ return id;
+ }
+
+ private int GetIdBorder(eStyleClass styleClass, eStyleProperty styleProperty, object value) {
+ ExcelBorderXml border = Border.Copy();
+
+ switch (styleClass) {
+ case eStyleClass.BorderBottom:
+ SetBorderItem(border.Bottom, styleProperty, value);
+ break;
+ case eStyleClass.BorderDiagonal:
+ SetBorderItem(border.Diagonal, styleProperty, value);
+ break;
+ case eStyleClass.BorderLeft:
+ SetBorderItem(border.Left, styleProperty, value);
+ break;
+ case eStyleClass.BorderRight:
+ SetBorderItem(border.Right, styleProperty, value);
+ break;
+ case eStyleClass.BorderTop:
+ SetBorderItem(border.Top, styleProperty, value);
+ break;
+ case eStyleClass.Border:
+ if (styleProperty == eStyleProperty.BorderDiagonalUp) {
+ border.DiagonalUp = (bool)value;
+ } else if (styleProperty == eStyleProperty.BorderDiagonalDown) {
+ border.DiagonalDown = (bool)value;
+ } else {
+ throw (new("Invalid property for class Border."));
+ }
+ break;
+ default:
+ throw (new("Invalid class/property for class Border."));
+ }
+ int subId;
+ string id = border.Id;
+ subId = _styles.Borders.FindIndexById(id);
+ if (subId == int.MinValue) {
+ return _styles.Borders.Add(id, border);
+ }
+ return subId;
+ }
+
+ private void SetBorderItem(
+ ExcelBorderItemXml excelBorderItem,
+ eStyleProperty styleProperty,
+ object value) {
+ if (styleProperty == eStyleProperty.Style) {
+ excelBorderItem.Style = (ExcelBorderStyle)value;
+ } else if (styleProperty == eStyleProperty.Color
+ || styleProperty == eStyleProperty.Tint
+ || styleProperty == eStyleProperty.IndexedColor) {
+ if (excelBorderItem.Style == ExcelBorderStyle.None) {
+ throw (new("Can't set bordercolor when style is not set."));
+ }
+ excelBorderItem.Color.Rgb = value.ToString();
+ }
+ }
+
+ private int GetIdFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) {
+ ExcelFillXml fill = Fill.Copy();
+
+ switch (styleProperty) {
+ case eStyleProperty.PatternType:
+ if (fill is ExcelGradientFillXml) {
+ fill = new(NameSpaceManager);
+ }
+ fill.PatternType = (ExcelFillStyle)value;
+ break;
+ case eStyleProperty.Color:
+ case eStyleProperty.Tint:
+ case eStyleProperty.IndexedColor:
+ case eStyleProperty.AutoColor:
+ if (fill is ExcelGradientFillXml) {
+ fill = new(NameSpaceManager);
+ }
+ if (fill.PatternType == ExcelFillStyle.None) {
+ throw (new ArgumentException("Can't set color when patterntype is not set."));
+ }
+ ExcelColorXml destColor;
+ if (styleClass == eStyleClass.FillPatternColor) {
+ destColor = fill.PatternColor;
+ } else {
+ destColor = fill.BackgroundColor;
+ }
+
+ if (styleProperty == eStyleProperty.Color) {
+ destColor.Rgb = value.ToString();
+ } else if (styleProperty == eStyleProperty.Tint) {
+ destColor.Tint = (decimal)value;
+ } else if (styleProperty == eStyleProperty.IndexedColor) {
+ destColor.Indexed = (int)value;
+ } else {
+ destColor.Auto = (bool)value;
+ }
+
+ break;
+ default:
+ throw (new ArgumentException("Invalid class/property for class Fill."));
+ }
+ int subId;
+ string id = fill.Id;
+ subId = _styles.Fills.FindIndexById(id);
+ if (subId == int.MinValue) {
+ return _styles.Fills.Add(id, fill);
+ }
+ return subId;
+ }
+
+ private int GetIdGradientFill(
+ eStyleClass styleClass,
+ eStyleProperty styleProperty,
+ object value) {
+ ExcelGradientFillXml fill;
+ if (Fill is ExcelGradientFillXml) {
+ fill = (ExcelGradientFillXml)Fill.Copy();
+ } else {
+ fill = new(Fill.NameSpaceManager);
+ fill.GradientColor1.SetColor(Color.White);
+ fill.GradientColor2.SetColor(Color.FromArgb(79, 129, 189));
+ fill.Type = ExcelFillGradientType.Linear;
+ fill.Degree = 90;
+ fill.Top = double.NaN;
+ fill.Bottom = double.NaN;
+ fill.Left = double.NaN;
+ fill.Right = double.NaN;
+ }
+
+ switch (styleProperty) {
+ case eStyleProperty.GradientType:
+ fill.Type = (ExcelFillGradientType)value;
+ break;
+ case eStyleProperty.GradientDegree:
+ fill.Degree = (double)value;
+ break;
+ case eStyleProperty.GradientTop:
+ fill.Top = (double)value;
+ break;
+ case eStyleProperty.GradientBottom:
+ fill.Bottom = (double)value;
+ break;
+ case eStyleProperty.GradientLeft:
+ fill.Left = (double)value;
+ break;
+ case eStyleProperty.GradientRight:
+ fill.Right = (double)value;
+ break;
+ case eStyleProperty.Color:
+ case eStyleProperty.Tint:
+ case eStyleProperty.IndexedColor:
+ case eStyleProperty.AutoColor:
+ ExcelColorXml destColor;
+
+ if (styleClass == eStyleClass.FillGradientColor1) {
+ destColor = fill.GradientColor1;
+ } else {
+ destColor = fill.GradientColor2;
+ }
+
+ if (styleProperty == eStyleProperty.Color) {
+ destColor.Rgb = value.ToString();
+ } else if (styleProperty == eStyleProperty.Tint) {
+ destColor.Tint = (decimal)value;
+ } else if (styleProperty == eStyleProperty.IndexedColor) {
+ destColor.Indexed = (int)value;
+ } else {
+ destColor.Auto = (bool)value;
+ }
+ break;
+ default:
+ throw (new ArgumentException("Invalid class/property for class Fill."));
+ }
+ int subId;
+ string id = fill.Id;
+ subId = _styles.Fills.FindIndexById(id);
+ if (subId == int.MinValue) {
+ return _styles.Fills.Add(id, fill);
+ }
+ return subId;
+ }
+
+ private int GetIdNumberFormat(eStyleProperty styleProperty, object value) {
+ if (styleProperty == eStyleProperty.Format) {
+ ExcelNumberFormatXml item = null;
+ if (!_styles.NumberFormats.FindById(value.ToString(), ref item)) {
+ item = new(NameSpaceManager) {
+ Format = value.ToString(),
+ NumFmtId = _styles.NumberFormats.NextId++,
+ };
+ _styles.NumberFormats.Add(value.ToString(), item);
+ }
+ return item.NumFmtId;
+ }
+ throw (new("Invalid property for class Numberformat"));
+ }
+
+ private int GetIdFont(eStyleProperty styleProperty, object value) {
+ ExcelFontXml fnt = Font.Copy();
+
+ switch (styleProperty) {
+ case eStyleProperty.Name:
+ fnt.Name = value.ToString();
+ break;
+ case eStyleProperty.Size:
+ fnt.Size = (float)value;
+ break;
+ case eStyleProperty.Family:
+ fnt.Family = (int)value;
+ break;
+ case eStyleProperty.Bold:
+ fnt.Bold = (bool)value;
+ break;
+ case eStyleProperty.Italic:
+ fnt.Italic = (bool)value;
+ break;
+ case eStyleProperty.Strike:
+ fnt.Strike = (bool)value;
+ break;
+ case eStyleProperty.UnderlineType:
+ fnt.UnderLineType = (ExcelUnderLineType)value;
+ break;
+ case eStyleProperty.Color:
+ fnt.Color.Rgb = value.ToString();
+ break;
+ case eStyleProperty.VerticalAlign:
+ fnt.VerticalAlign =
+ ((ExcelVerticalAlignmentFont)value) == ExcelVerticalAlignmentFont.None
+ ? ""
+ : value.ToString().ToLower(CultureInfo.InvariantCulture);
+ break;
+ default:
+ throw (new("Invalid property for class Font"));
+ }
+ int subId;
+ string id = fnt.Id;
+ subId = _styles.Fonts.FindIndexById(id);
+ if (subId == int.MinValue) {
+ return _styles.Fonts.Add(id, fnt);
+ }
+ return subId;
+ }
+
internal override XmlNode CreateXmlNode(XmlNode topNode) {
return CreateXmlNode(topNode, false);
}
diff --git a/NetCoreTests/ExcelPackageTest.cs b/NetCoreTests/ExcelPackageTest.cs
index 369e55a..8785d5d 100644
--- a/NetCoreTests/ExcelPackageTest.cs
+++ b/NetCoreTests/ExcelPackageTest.cs
@@ -3,7 +3,6 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OfficeOpenXml;
-using OfficeOpenXml.DataValidation;
namespace NetCoreTests;
@@ -33,20 +32,6 @@
worksheet.Name.Should().Be("pusum11a");
}
- [TestMethod]
- public void TestGetAsByteArray_DataValidation() {
- var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("DataValidation.xlsx")));
- var data = package.GetAsByteArray();
-
- // Verify that we can reload
- var newPackage = new ExcelPackage(new MemoryStream(data, false));
- newPackage.Workbook.Worksheets.Count.Should().Be(1);
- var worksheet = newPackage.Workbook.Worksheets.First();
- worksheet.Name.Should().Be("Sheet1");
- worksheet.DataValidations.Should().HaveCount(31);
- worksheet.DataValidations[1].ValidationType.Should().Be(ExcelDataValidationType.Whole);
- }
-
private static string GetTestWorkbookPath(string filename) {
var assemblyPath = Path.GetDirectoryName(typeof(ExcelPackageTest).Assembly.Location)!;
return Path.Combine(assemblyPath, "TestWorkbooks", filename);
diff --git a/NetCoreTests/TestWorkbooks/DataValidation.xlsx b/NetCoreTests/TestWorkbooks/DataValidation.xlsx
deleted file mode 100644
index 78d508c..0000000
--- a/NetCoreTests/TestWorkbooks/DataValidation.xlsx
+++ /dev/null
Binary files differ