From e9dda4b96f54cc6de2993394984998791c3c480a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Par=C3=A9?= Date: Fri, 6 Dec 2019 08:53:36 -0500 Subject: [PATCH] Dynamic Properties (#27) --- .../Dexiom.EPPlusExporter.Net45.csproj | 6 + .../Dexiom.EPPlusExporter.csproj | 2 + Dexiom.EPPlusExporter/DisplayField.cs | 52 ++++++++ Dexiom.EPPlusExporter/DynamicProp.cs | 22 ++++ Dexiom.EPPlusExporter/DynamicProperty.cs | 30 +++++ Dexiom.EPPlusExporter/EnumerableExporter.cs | 113 ++++++++++++------ .../Interfaces/ITableOutputCustomization.cs | 32 +++-- Dexiom.EPPlusExporter/TableExporter.cs | 77 ++++++------ .../EnumerableExporterTests.cs | 44 +++++-- 9 files changed, 282 insertions(+), 96 deletions(-) create mode 100644 Dexiom.EPPlusExporter/DisplayField.cs create mode 100644 Dexiom.EPPlusExporter/DynamicProp.cs create mode 100644 Dexiom.EPPlusExporter/DynamicProperty.cs diff --git a/Dexiom.EPPlusExporter.Net45/Dexiom.EPPlusExporter.Net45.csproj b/Dexiom.EPPlusExporter.Net45/Dexiom.EPPlusExporter.Net45.csproj index cb6af31..a6a0964 100644 --- a/Dexiom.EPPlusExporter.Net45/Dexiom.EPPlusExporter.Net45.csproj +++ b/Dexiom.EPPlusExporter.Net45/Dexiom.EPPlusExporter.Net45.csproj @@ -56,6 +56,12 @@ ColumnHeaderConfiguration.cs + + DisplayField.cs + + + DynamicProperty.cs + EnumerableExporter.cs diff --git a/Dexiom.EPPlusExporter/Dexiom.EPPlusExporter.csproj b/Dexiom.EPPlusExporter/Dexiom.EPPlusExporter.csproj index 200db88..50e4907 100644 --- a/Dexiom.EPPlusExporter/Dexiom.EPPlusExporter.csproj +++ b/Dexiom.EPPlusExporter/Dexiom.EPPlusExporter.csproj @@ -46,6 +46,8 @@ + + diff --git a/Dexiom.EPPlusExporter/DisplayField.cs b/Dexiom.EPPlusExporter/DisplayField.cs new file mode 100644 index 0000000..363d3ef --- /dev/null +++ b/Dexiom.EPPlusExporter/DisplayField.cs @@ -0,0 +1,52 @@ +using System; +using System.ComponentModel; +using System.Reflection; +using Dexiom.EPPlusExporter.Helpers; + +namespace Dexiom.EPPlusExporter +{ + public class DisplayField where T : class + { + private readonly PropertyInfo _propertyInfo; + private readonly DynamicProperty _dynamicProperty; + + public DisplayField(PropertyInfo propertyInfo) + { + _propertyInfo = propertyInfo; + + Name = _propertyInfo.Name; + DisplayName = ReflectionHelper.GetPropertyDisplayName(_propertyInfo); + Type = _propertyInfo.PropertyType; + } + + public DisplayField(DynamicProperty dynamicProperty) + { + _dynamicProperty = dynamicProperty; + + Name = _dynamicProperty.Name; + DisplayName = _dynamicProperty.DisplayName; + Type = _dynamicProperty.ValueType; + } + + #region Properties + public string Name { get; set; } + public string DisplayName { get; set; } + public Type Type { get; set; } + #endregion + + public object GetValue(T item) + { + if (_propertyInfo != null) + { +#if NET4 + return _propertyInfo.GetValue(item, null); +#endif +#if NET45 || NET46 + return _propertyInfo.GetValue(item); +#endif + } + + return _dynamicProperty.GetValue(item); + } + } +} \ No newline at end of file diff --git a/Dexiom.EPPlusExporter/DynamicProp.cs b/Dexiom.EPPlusExporter/DynamicProp.cs new file mode 100644 index 0000000..71180b9 --- /dev/null +++ b/Dexiom.EPPlusExporter/DynamicProp.cs @@ -0,0 +1,22 @@ +using System; + +namespace Dexiom.EPPlusExporter +{ + public static class DynamicProperty + { + public static DynamicProp Create(Func getValue, Type valueType) where T : class => new DynamicProp(getValue, valueType); + } + + public class DynamicProp + { + public DynamicProp(Func getValue, Type valueType) + { + ValueType = valueType; + GetValue = getValue; + } + + + public Type ValueType { get; set; } + public Func GetValue { get; set; } + } +} \ No newline at end of file diff --git a/Dexiom.EPPlusExporter/DynamicProperty.cs b/Dexiom.EPPlusExporter/DynamicProperty.cs new file mode 100644 index 0000000..b5f90db --- /dev/null +++ b/Dexiom.EPPlusExporter/DynamicProperty.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace Dexiom.EPPlusExporter +{ + #region Create Method (using type inference) + public static class DynamicProperty + { + public static DynamicProperty Create(IEnumerable data, string name, string displayName, Type valueType, Func getValue) where T : class + { + return new DynamicProperty() + { + Name = name, + DisplayName = displayName, + ValueType = valueType, + GetValue = getValue + }; + } + } + #endregion + + public class DynamicProperty + where T : class + { + public string Name { get; set; } + public string DisplayName { get; set; } + public Type ValueType { get; set; } + public Func GetValue { get; set; } + } +} \ No newline at end of file diff --git a/Dexiom.EPPlusExporter/EnumerableExporter.cs b/Dexiom.EPPlusExporter/EnumerableExporter.cs index aace3a9..0d5dbb7 100644 --- a/Dexiom.EPPlusExporter/EnumerableExporter.cs +++ b/Dexiom.EPPlusExporter/EnumerableExporter.cs @@ -1,40 +1,43 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using System.Linq.Expressions; +using System.Net.Configuration; using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Dexiom.EPPlusExporter.Extensions; using Dexiom.EPPlusExporter.Helpers; using OfficeOpenXml; -using OfficeOpenXml.Style; using OfficeOpenXml.Table; namespace Dexiom.EPPlusExporter { -#region Create Method (using type inference) - public class EnumerableExporter + #region Create Method (using type inference) + public static class EnumerableExporter { public static EnumerableExporter Create(IEnumerable data, TableStyles tableStyles = TableStyles.Medium4) where T : class => new EnumerableExporter(data) { TableStyle = tableStyles }; + public static EnumerableExporter Create(IEnumerable data, IEnumerable> dynamicProperties, TableStyles tableStyles = TableStyles.Medium4) where T : class => new EnumerableExporter(data, dynamicProperties) { TableStyle = tableStyles }; } -#endregion + #endregion public class EnumerableExporter : TableExporter where T : class { public IEnumerable Data { get; set; } + public IEnumerable> DynamicProperties { get; set; } -#region Constructors + #region Constructors public EnumerableExporter(IEnumerable data) { Data = data; } -#endregion -#region Protected + public EnumerableExporter(IEnumerable data, IEnumerable> dynamicProperties) + { + Data = data; + DynamicProperties = dynamicProperties; + } + #endregion + + #region Protected protected override ExcelRange AddWorksheet(ExcelPackage package) { const int headerFirstRow = 1; @@ -46,17 +49,51 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) return null; //let's avoid multiple enumeration - var myData = Data as IList ?? Data.ToList(); + var data = Data as IList ?? Data.ToList(); + IList> dynamicProperties = null; + if (DynamicProperties != null) + dynamicProperties = DynamicProperties as IList> ?? DynamicProperties.ToList(); //get available properties - var properties = ReflectionHelper.GetBaseTypeOfEnumerable(Data).GetProperties() - .Where(p => !IgnoredProperties.Contains(p.Name)); + var properties = ReflectionHelper.GetBaseTypeOfEnumerable(data).GetProperties() + .Where(p => !IgnoredProperties.Contains(p.Name)) + .ToList(); //resolve displayed properties - var displayedProperties = DisplayedProperties?.Select(propName => properties.FirstOrDefault(n => n.Name == propName)).Where(propInfo => propInfo != null).ToList() ?? properties.ToList(); + HashSet allPropertyNames; + if (DisplayedProperties != null) + { + allPropertyNames = DisplayedProperties; + } + else + { + allPropertyNames = new HashSet(properties.Select(n => n.Name)); + if (dynamicProperties != null) + { + foreach (var dynamicPropertyName in dynamicProperties.Select(n => n.Name)) + allPropertyNames.Add(dynamicPropertyName); + } + } + + var displayFields = new List>(); + foreach (var propertyName in allPropertyNames) + { + var property = properties.FirstOrDefault(n => n.Name == propertyName); + if (property != null) + { + //displayedProperties.Add(property); //todo: delete me + displayFields.Add(new DisplayField(property)); + } + else + { + var dynamicProperty = DynamicProperties?.FirstOrDefault(n => n.Name == propertyName); + if (dynamicProperty != null) + displayFields.Add(new DisplayField(dynamicProperty)); + } + } //init the configurations - var columnConfigurations = GetColumnConfigurations(displayedProperties.Select(n => n.Name)); + var columnConfigurations = GetColumnConfigurations(displayFields.Select(n => n.Name)); //create the worksheet var worksheet = package.Workbook.Worksheets.Add(WorksheetName); @@ -64,11 +101,11 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) //Create table header { var col = headerFirstCol; - foreach (var property in displayedProperties) + foreach (var displayField in displayFields) { - var colConfig = columnConfigurations[property.Name]; + var colConfig = columnConfigurations[displayField.Name]; var cell = worksheet.Cells[headerFirstRow, col]; - cell.Value = string.IsNullOrEmpty(colConfig.Header.Text) ? ReflectionHelper.GetPropertyDisplayName(property) : colConfig.Header.Text; + cell.Value = string.IsNullOrEmpty(colConfig.Header.Text) ? displayField.DisplayName : colConfig.Header.Text; colConfig.Header.SetStyle(cell.Style); col++; @@ -77,13 +114,13 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) //Add rows var row = dataFirstRow; - foreach (var item in myData) + foreach (var item in data) { var iCol = dataFirstCol; - foreach (var property in displayedProperties) + foreach (var displayField in displayFields) { var cell = worksheet.Cells[row, iCol]; - cell.Value = GetPropertyValue(property, item); + cell.Value = ApplyTextFormat(displayField.Name, displayField.GetValue(item)); iCol++; } @@ -91,8 +128,8 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) } //get bottom & right bounds - var dataLastCol = dataFirstCol + displayedProperties.Count - 1; - var dataLastRow = dataFirstRow + Math.Max(myData.Count, 1) - 1; //make sure to have at least 1 data line (for table format) + var dataLastCol = dataFirstCol + displayFields.Count - 1; + var dataLastRow = dataFirstRow + Math.Max(data.Count, 1) - 1; //make sure to have at least 1 data line (for table format) var tableRange = worksheet.Cells[headerFirstRow, headerFirstCol, dataLastRow, dataLastCol]; WorksheetHelper.FormatAsTable(tableRange, TableStyle, WorksheetName, false); @@ -100,14 +137,14 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) //apply configurations { var iCol = dataFirstCol; - foreach (var property in displayedProperties) + foreach (var displayField in displayFields) { - var colConfig = columnConfigurations[property.Name]; + var colConfig = columnConfigurations[displayField.Name]; var columnRange = worksheet.Cells[dataFirstRow, iCol, dataLastRow, iCol]; //apply default number format - if (DefaultNumberFormats.ContainsKey(property.PropertyType)) - columnRange.Style.Numberformat.Format = DefaultNumberFormats[property.PropertyType]; + if (DefaultNumberFormats.ContainsKey(displayField.Type)) + columnRange.Style.Numberformat.Format = DefaultNumberFormats[displayField.Type]; //apply number format if (colConfig.Content.NumberFormat != null) @@ -129,14 +166,14 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) //apply conditional styles { var iCol = dataFirstCol; - foreach (var property in displayedProperties) + foreach (var displayField in displayFields) { - if (ConditionalStyles.ContainsKey(property.Name)) + if (ConditionalStyles.ContainsKey(displayField.Name)) { - var conditionalStyle = ConditionalStyles[property.Name]; + var conditionalStyle = ConditionalStyles[displayField.Name]; var iRow = dataFirstRow; - foreach (var item in myData) + foreach (var item in data) { var cell = worksheet.Cells[iRow, iCol]; conditionalStyle(item, cell.Style); //apply style on cell @@ -151,14 +188,14 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) //apply conditional styles { var iCol = dataFirstCol; - foreach (var property in displayedProperties) + foreach (var displayField in displayFields) { - if (Formulas.ContainsKey(property.Name)) + if (Formulas.ContainsKey(displayField.Name)) { - var formulaFormat = Formulas[property.Name]; + var formulaFormat = Formulas[displayField.Name]; var iRow = dataFirstRow; - foreach (var item in myData) + foreach (var item in data) { var cell = worksheet.Cells[iRow, iCol]; var formula = formulaFormat(item, cell.Value); //apply style on cell @@ -176,6 +213,6 @@ protected override ExcelRange AddWorksheet(ExcelPackage package) return tableRange; } -#endregion + #endregion } } diff --git a/Dexiom.EPPlusExporter/Interfaces/ITableOutputCustomization.cs b/Dexiom.EPPlusExporter/Interfaces/ITableOutputCustomization.cs index dbe52dd..5bcd912 100644 --- a/Dexiom.EPPlusExporter/Interfaces/ITableOutputCustomization.cs +++ b/Dexiom.EPPlusExporter/Interfaces/ITableOutputCustomization.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq.Expressions; using OfficeOpenXml; using OfficeOpenXml.Style; @@ -8,33 +9,44 @@ namespace Dexiom.EPPlusExporter.Interfaces public interface ITableOutputCustomization where T : class { - TableExporter Configure(Expression> property, Action column); + TableExporter Configure(Expression> properties, Action column); + TableExporter Configure(IEnumerable propertyNames, Action column); TableExporter CustomizeTable(Action applyCustomization); #region Shorthands for configure - TableExporter StyleFor(Expression> property, Action setStyle); + TableExporter StyleFor(Expression> properties, Action setStyle); + TableExporter StyleFor(IEnumerable propertyNames, Action setStyle); - TableExporter HeaderStyleFor(Expression> property, Action setStyle); + TableExporter HeaderStyleFor(Expression> properties, Action setStyle); + TableExporter HeaderStyleFor(IEnumerable propertyNames, Action setStyle); - TableExporter NumberFormatFor(Expression> property, string numberFormat); + TableExporter NumberFormatFor(Expression> properties, string numberFormat); + TableExporter NumberFormatFor(IEnumerable propertyNames, string numberFormat); #endregion #region Misc + TableExporter DefaultNumberFormat(Type type, string numberFormat); - TableExporter Display(Expression> property); + TableExporter Display(Expression> properties); + TableExporter Display(IEnumerable propertyNames); - TableExporter Ignore(Expression> property); + TableExporter Ignore(Expression> properties); + TableExporter Ignore(IEnumerable propertyNames); - TableExporter DefaultNumberFormat(Type type, string numberFormat); - TableExporter TextFormatFor(Expression> property, string format); - - TableExporter ConditionalStyleFor(Expression> property, Action setStyle); + TableExporter TextFormatFor(Expression> properties, string format); + TableExporter TextFormatFor(IEnumerable propertyNames, string format); + + TableExporter ConditionalStyleFor(Expression> properties, Action setStyle); + TableExporter ConditionalStyleFor(IEnumerable propertyNames, Action setStyle); + + TableExporter FormulaFor(Expression> properties, Func formulaFormat); + TableExporter FormulaFor(IEnumerable propertyNames, Func formulaFormat); #endregion } diff --git a/Dexiom.EPPlusExporter/TableExporter.cs b/Dexiom.EPPlusExporter/TableExporter.cs index 4af8150..691fa8a 100644 --- a/Dexiom.EPPlusExporter/TableExporter.cs +++ b/Dexiom.EPPlusExporter/TableExporter.cs @@ -58,38 +58,35 @@ public ExcelWorksheet AppendToExcelPackage(ExcelPackage package) #region ITableOutputCustomization - public TableExporter Configure(Expression> property, Action column) + public TableExporter Configure(Expression> properties, Action column) => Configure(PropertyNames.For(properties), column); + public TableExporter Configure(IEnumerable propertyNames, Action column) { - foreach (var propName in PropertyNames.For(property)) + foreach (var propName in propertyNames) _columnAlterations.Add(new KeyValuePair>(propName, column)); return this; } - + public TableExporter CustomizeTable(Action applyCustomization) { _tableCustomizations.Add(applyCustomization); return this; } - public TableExporter StyleFor(Expression> property, Action setStyle) - { - Configure(property, c => c.Content.SetStyle = setStyle); - return this; - } - public TableExporter HeaderStyleFor(Expression> property, Action setStyle) - { - Configure(property, c => c.Header.SetStyle = setStyle); - return this; - } + public TableExporter StyleFor(Expression> properties, Action setStyle) => StyleFor(PropertyNames.For(properties), setStyle); + public TableExporter StyleFor(IEnumerable propertyNames, Action setStyle) => Configure(propertyNames, c => c.Content.SetStyle = setStyle); - public TableExporter NumberFormatFor(Expression> property, string numberFormat) - { - Configure(property, c => c.Content.NumberFormat = numberFormat); - return this; - } + public TableExporter HeaderStyleFor(Expression> properties, Action setStyle) => HeaderStyleFor(PropertyNames.For(properties), setStyle); + public TableExporter HeaderStyleFor(IEnumerable propertyNames, Action setStyle) => Configure(propertyNames, c => c.Header.SetStyle = setStyle); + + + public TableExporter NumberFormatFor(Expression> properties, string numberFormat) => NumberFormatFor(PropertyNames.For(properties), numberFormat); + public TableExporter NumberFormatFor(IEnumerable propertyNames, string numberFormat) => Configure(propertyNames, c => c.Content.NumberFormat = numberFormat); + + + public TableExporter Display(Expression> properties) => Display(PropertyNames.For(properties)); public TableExporter Display(IEnumerable propertyNames) { if (DisplayedProperties == null) @@ -100,14 +97,9 @@ public TableExporter Display(IEnumerable propertyNames) return this; } - - public TableExporter Display(Expression> properties) - { - Display(PropertyNames.For(properties)); - return this; - } + public TableExporter Ignore(Expression> properties) => Ignore(PropertyNames.For(properties)); public TableExporter Ignore(IEnumerable propertyNames) { foreach (var propName in propertyNames) @@ -116,11 +108,6 @@ public TableExporter Ignore(IEnumerable propertyNames) return this; } - public TableExporter Ignore(Expression> properties) - { - Ignore(PropertyNames.For(properties)); - return this; - } public TableExporter DefaultNumberFormat(Type type, string numberFormat) { @@ -128,31 +115,35 @@ public TableExporter DefaultNumberFormat(Type type, string numberFormat) return this; } - public TableExporter TextFormatFor(Expression> property, string format) + + public TableExporter TextFormatFor(Expression> properties, string format) => TextFormatFor(PropertyNames.For(properties), format); + public TableExporter TextFormatFor(IEnumerable propertyNames, string format) { - foreach (var propName in PropertyNames.For(property)) + foreach (var propName in propertyNames) TextFormats.AddOrUpdate(propName, format); return this; } - - public TableExporter ConditionalStyleFor(Expression> property, Action setStyle) + + public TableExporter ConditionalStyleFor(Expression> properties, Action setStyle) => ConditionalStyleFor(PropertyNames.For(properties), setStyle); + public TableExporter ConditionalStyleFor(IEnumerable propertyNames, Action setStyle) { - foreach (var propName in PropertyNames.For(property)) + foreach (var propName in propertyNames) ConditionalStyles.AddOrUpdate(propName, setStyle); return this; } - - public TableExporter FormulaFor(Expression> property, Func formulaFormat) + + public TableExporter FormulaFor(Expression> properties, Func formulaFormat) => FormulaFor(PropertyNames.For(properties), formulaFormat); + public TableExporter FormulaFor(IEnumerable propertyNames, Func formulaFormat) { - foreach (var propName in PropertyNames.For(property)) + foreach (var propName in propertyNames) Formulas.AddOrUpdate(propName, formulaFormat); return this; } #endregion - + #region Protected protected Dictionary TextFormats { get; } = new Dictionary(); @@ -178,8 +169,14 @@ protected object GetPropertyValue(PropertyInfo property, object item) #if NET45 || NET46 var value = property.GetValue(item); #endif - if (value != null && TextFormats.ContainsKey(property.Name)) - return string.Format(TextFormats[property.Name], value); + + return ApplyTextFormat(property.Name, value); + } + + protected object ApplyTextFormat(string propertyName, object value) + { + if (value != null && TextFormats.ContainsKey(propertyName)) + return string.Format(TextFormats[propertyName], value); return value; } diff --git a/Dexiom.EPPlusExporterTests/EnumerableExporterTests.cs b/Dexiom.EPPlusExporterTests/EnumerableExporterTests.cs index 765745c..38e7b5b 100644 --- a/Dexiom.EPPlusExporterTests/EnumerableExporterTests.cs +++ b/Dexiom.EPPlusExporterTests/EnumerableExporterTests.cs @@ -86,7 +86,13 @@ public void ConfigureTest() new { TextValue = "SomeText", DateValue = DateTime.Now, DoubleValue = 10.2, IntValue = 5} }; - var excelPackage = EnumerableExporter.Create(data) + var dynamicProperties = new[] + { + DynamicProperty.Create(data, "DynamicColumn1", "Display Name 1", typeof(DateTime?), n => DateTime.Now.AddDays(n.IntValue - 4)), + DynamicProperty.Create(data, "DynamicColumn2", "Display Name 2", typeof(double), n => n.DoubleValue - 0.2) + }; + + var excelPackage = EnumerableExporter.Create(data, dynamicProperties) .Configure(n => n.IntValue, configuration => { configuration.Header.Text = ""; @@ -105,6 +111,14 @@ public void ConfigureTest() style.Border.Right.Style = ExcelBorderStyle.Dashed; }; }) + .Configure(new []{ "DynamicColumn1", "IntValue" }, n => + { + n.Header.SetStyle = style => + { + style.Font.Bold = true; + style.Font.Color.SetColor(Color.Black); + }; + }) .CustomizeTable(range => { var newRange = range.Worksheet.Cells[range.End.Row, range.Start.Column, range.End.Row, range.End.Column]; @@ -113,7 +127,7 @@ public void ConfigureTest() }) .CreateExcelPackage(); - //TestHelper.OpenDocument(excelPackage); + TestHelper.OpenDocument(excelPackage); var excelWorksheet = excelPackage.Workbook.Worksheets.First(); @@ -166,18 +180,31 @@ public void DefaultNumberFormatTest() new { TextValue = "SomeText", DateValue = DateTime.Now, DoubleValue = 10.2, IntValue = 5} }; - var excelWorksheet = EnumerableExporter.Create(data) - .DefaultNumberFormat(typeof(DateTime), "DATE: yyyy-MM-dd") + var dynamicProperties = new[] + { + DynamicProperty.Create(data, "DynamicColumn1", "Display Name 1", typeof(DateTime?), n => DateTime.Now.AddDays(n.IntValue - 4)), + DynamicProperty.Create(data, "DynamicColumn2", "Display Name 2", typeof(double), n => n.DoubleValue - 0.2) + }; + + + var excelPackage = EnumerableExporter.Create(data, dynamicProperties) + .DefaultNumberFormat(typeof(DateTime), "| yyyy-MM-dd") + .DefaultNumberFormat(typeof(DateTime?), "|| yyyy-MM-dd") .DefaultNumberFormat(typeof(double), "0.00 $") .DefaultNumberFormat(typeof(int), "00") - .CreateExcelPackage() - .Workbook.Worksheets.First(); + .CreateExcelPackage(); + var excelWorksheet = excelPackage.Workbook.Worksheets.First(); + + //TestHelper.OpenDocument(excelPackage); string numberDecimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; - - Assert.IsTrue(excelWorksheet.Cells[2, 2].Text == DateTime.Today.ToString("DATE: yyyy-MM-dd")); //DateValue + + Assert.IsTrue(excelWorksheet.Cells[2, 2].Text == DateTime.Today.ToString("| yyyy-MM-dd")); //DateValue Assert.IsTrue(excelWorksheet.Cells[2, 3].Text == $"10{numberDecimalSeparator}20 $"); //DoubleValue Assert.IsTrue(excelWorksheet.Cells[2, 4].Text == "05"); //IntValue + Assert.IsTrue(excelWorksheet.Cells[2, 5].Text == DateTime.Today.AddDays(1).ToString("|| yyyy-MM-dd")); //DynamicColumn1 + Assert.IsTrue(excelWorksheet.Cells[2, 6].Text == $"10{numberDecimalSeparator}00 $"); //DynamicColumn2 + } [TestMethod()] @@ -250,6 +277,7 @@ public void TextFormatForTest() new { TextValue = "SomeText", DateValue = DateTime.Now, DoubleValue = 10.2, IntValue = 5} }; + const string textFormat = "Prefix: {0}"; const string dateFormat = "{0:yyyy-MM-dd HH:mm}"; var exporter = EnumerableExporter.Create(data)