From 93d59be3aac1ea7e7c5e7c5d7e5ff6258c99ee81 Mon Sep 17 00:00:00 2001 From: Angelo Dejaeghere Date: Fri, 8 Dec 2017 16:20:18 +0100 Subject: [PATCH] Added Excel Fromula to the openXMLwriter + added Builder pattern to the project --- src/DoddleReport.Builder/DoddleExporter.cs | 82 +++++++++++++++++ .../DoddleReport.Builder.csproj | 59 ++++++++++++ src/DoddleReport.Builder/ExportBuilder.cs | 78 ++++++++++++++++ src/DoddleReport.Builder/ExportColumn.cs | 43 +++++++++ .../Extentions/ExtensionsForIEnumerable.cs | 12 +++ .../Extentions/ExtensionsForMemberInfo.cs | 28 ++++++ src/DoddleReport.Builder/IExportColumn.cs | 11 +++ .../Properties/AssemblyInfo.cs | 36 ++++++++ src/DoddleReport.OpenXml/ExcelReportWriter.cs | 89 +++++++++++++++---- .../Controllers/BuilderPaternController.cs | 60 +++++++++++++ .../DoddleReport.Sample.Web.csproj | 6 ++ src/DoddleReport.sln | 21 ++++- src/DoddleReport/ReportField.cs | 5 +- src/DoddleReport/RowField.cs | 3 + 14 files changed, 512 insertions(+), 21 deletions(-) create mode 100644 src/DoddleReport.Builder/DoddleExporter.cs create mode 100644 src/DoddleReport.Builder/DoddleReport.Builder.csproj create mode 100644 src/DoddleReport.Builder/ExportBuilder.cs create mode 100644 src/DoddleReport.Builder/ExportColumn.cs create mode 100644 src/DoddleReport.Builder/Extentions/ExtensionsForIEnumerable.cs create mode 100644 src/DoddleReport.Builder/Extentions/ExtensionsForMemberInfo.cs create mode 100644 src/DoddleReport.Builder/IExportColumn.cs create mode 100644 src/DoddleReport.Builder/Properties/AssemblyInfo.cs create mode 100644 src/DoddleReport.Sample.Web/Controllers/BuilderPaternController.cs diff --git a/src/DoddleReport.Builder/DoddleExporter.cs b/src/DoddleReport.Builder/DoddleExporter.cs new file mode 100644 index 0000000..7317610 --- /dev/null +++ b/src/DoddleReport.Builder/DoddleExporter.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Xml; +using System.Xml.Linq; + +namespace DoddleReport.Builder +{ + public static class DoddleExporter + { + /// + /// Converts an enumerable of dictionaries to a report source + /// + /// + /// The type of values in the dictionaries + /// + /// + /// An enumerable of elements + /// + /// + /// The report source that was created from the elements + public static IReportSource ToReportSource(IEnumerable> elements) + { + var elementsArray = elements.ToArray(); + if (!elementsArray.Any()) + throw new ArgumentException("Can't export empty list of elements"); + return ToReportSource(elementsArray, elementsArray.First().Keys.ToArray(), + (element, key) => element.ContainsKey(key) ? element[key] : default(TValue)); + } + + /// + /// Converts an enumerable of XElement to a report source + /// + /// + /// The xml root elements that contain the values + /// + /// + /// They keys that can be used to fetch values from each root element + /// + /// The report source that was created from the elements + public static IReportSource ToReportSource(IEnumerable rootElements, string[] keys) + { + return ToReportSource(rootElements, keys, delegate (XElement element, string key) + { + var value = element.Element(XmlConvert.EncodeLocalName(key)); + return value != null ? value.Value : null; + }); + } + + /// + /// Converts a list of elements to a report source + /// + /// + /// An enumerable of elements + /// + /// + /// They keys with which the values can be fetched from one element + /// + /// + /// The function with which one value can be fetched given one key and one element + /// + /// The report source that was created from the elements + public static IReportSource ToReportSource(IEnumerable elements, string[] keys, + Func valueSelector) + { + var expandos = new List(); + foreach (var element in elements) + { + var expando = new ExpandoObject(); + var expandoDictionary = (IDictionary)expando; + foreach (var key in keys) + { + var value = valueSelector(element, key); + expandoDictionary[key] = value; + } + expandos.Add(expando); + } + return expandos.ToReportSource(); + } + } +} diff --git a/src/DoddleReport.Builder/DoddleReport.Builder.csproj b/src/DoddleReport.Builder/DoddleReport.Builder.csproj new file mode 100644 index 0000000..6a8c9b3 --- /dev/null +++ b/src/DoddleReport.Builder/DoddleReport.Builder.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D} + Library + Properties + DoddleReport.Builder + DoddleReport.Builder + v4.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {F08B2994-4D05-423E-A8FE-7D1E8A63472B} + DoddleReport + + + + \ No newline at end of file diff --git a/src/DoddleReport.Builder/ExportBuilder.cs b/src/DoddleReport.Builder/ExportBuilder.cs new file mode 100644 index 0000000..2fb1c3f --- /dev/null +++ b/src/DoddleReport.Builder/ExportBuilder.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Linq.Expressions; +using DoddleReport.Builder.Extentions; + +namespace DoddleReport.Builder +{ + public class ExportBuilder where TModel : class + { + private readonly IEnumerable _models; + private readonly ICollection> _columns; + + /// + /// Initializes a new instance of the class. + /// + private ExportBuilder(IEnumerable models) + { + _models = models; + _columns = new List>(); + } + + public static ExportBuilder Create(IEnumerable models) + { + return new ExportBuilder(models); + } + + public ExportBuilder Column(Expression> display) + { + if (!(display.Body is MemberExpression)) + throw new ArgumentException(display + " is not a property!"); + + var memberInfo = ((MemberExpression)display.Body).Member; + if (!memberInfo.HasAttribute()) + throw new ArgumentException(display + " does not have a [Display] attribute"); + var displayAttribute = ExtensionsForMemberInfo.GetAttribute(memberInfo); + + _columns.Add(new ExportColumn(displayAttribute.DisplayName, display)); + return this; + } + + public ExportBuilder Column(string header, Expression> property) + { + _columns.Add(new ExportColumn(header, property)); + return this; + + } + + + public IReportSource ToReportSource() + { + if (_models.Any()) + { + return DoddleExporter.ToReportSource(_models.Select(model => _columns.ToDictionary(c => c.Header, c => c.Display(model)))); + } + var result = _columns + .ToDictionary(a => a.Header, a => string.Empty); + return DoddleExporter.ToReportSource(new[] { result }); + } + + public Report ToReport(IEnumerable> headers, IReportWriter writer = null) + { + headers = headers ?? Enumerable.Empty>(); + var report = new Report(ToReportSource(), writer); + //report.TextFields.Footer = string.Format(@"Aangemaakt op: {0}", DateTime.Now.ToString(DataFormatStrings.Date)); + var headersArray = headers as KeyValuePair[] ?? headers.ToArray(); + if (headersArray.Any()) + { + report.TextFields.Header = headersArray.Aggregate(string.Empty, + (currentHeaders, header) => string.Format("{0}{3}{1} : {2}", currentHeaders, header.Key, header.Value, Environment.NewLine)); + } + + return report; + } + } + +} diff --git a/src/DoddleReport.Builder/ExportColumn.cs b/src/DoddleReport.Builder/ExportColumn.cs new file mode 100644 index 0000000..6896991 --- /dev/null +++ b/src/DoddleReport.Builder/ExportColumn.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq.Expressions; + +namespace DoddleReport.Builder +{ + public class ExportColumn : IExportColumn where TModel : class + { + private readonly string _header; + private readonly Expression> _display; + private string _formula; + + public string Header => _header; + public string Formula => _formula; + public Func Display { get { return model => _display.Compile().Invoke(model); } } + + /// + /// Initializes a new instance of the class. + /// + public ExportColumn(string header, Expression> display) + { + _header = header; + _display = display; ; + } + + public ExportColumn(string header, Expression> property, string formula) + { + _header = header; + _display = property; + _formula = formula; + } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + public override string ToString() + { + return $"Header: {_header}, Display: {_display}"; + } + } +} diff --git a/src/DoddleReport.Builder/Extentions/ExtensionsForIEnumerable.cs b/src/DoddleReport.Builder/Extentions/ExtensionsForIEnumerable.cs new file mode 100644 index 0000000..4553dac --- /dev/null +++ b/src/DoddleReport.Builder/Extentions/ExtensionsForIEnumerable.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace DoddleReport.Builder.Extentions +{ + public static class ExtensionsForIEnumerable + { + public static ExportBuilder Export(this IEnumerable models) where TModel : class + { + return ExportBuilder.Create(models); + } + } +} diff --git a/src/DoddleReport.Builder/Extentions/ExtensionsForMemberInfo.cs b/src/DoddleReport.Builder/Extentions/ExtensionsForMemberInfo.cs new file mode 100644 index 0000000..c658097 --- /dev/null +++ b/src/DoddleReport.Builder/Extentions/ExtensionsForMemberInfo.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace DoddleReport.Builder.Extentions +{ + public static class ExtensionsForMemberInfo + { + public static bool HasAttribute(this MemberInfo @this) + { + return HasAttribute(@this, typeof(TAttribute)); + } + + public static bool HasAttribute(this MemberInfo @this, Type attributeType) + { + return Attribute.GetCustomAttributes(@this, attributeType).Any(); + } + + public static TAttribute GetAttribute(this MemberInfo @this) where TAttribute : Attribute + { + if (!@this.HasAttribute(typeof(TAttribute))) + throw new InvalidOperationException($"Member {@this} has no attribute of type {typeof(TAttribute)}"); + return (TAttribute)@this.GetCustomAttribute(typeof(TAttribute)); + } + + + } +} diff --git a/src/DoddleReport.Builder/IExportColumn.cs b/src/DoddleReport.Builder/IExportColumn.cs new file mode 100644 index 0000000..de9e669 --- /dev/null +++ b/src/DoddleReport.Builder/IExportColumn.cs @@ -0,0 +1,11 @@ +using System; + +namespace DoddleReport.Builder +{ + public interface IExportColumn where TModel : class + { + string Header { get; } + string Formula { get; } + Func Display { get; } + } +} diff --git a/src/DoddleReport.Builder/Properties/AssemblyInfo.cs b/src/DoddleReport.Builder/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e6d6b0f --- /dev/null +++ b/src/DoddleReport.Builder/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DoddleReport.Builder")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DoddleReport.Builder")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("10fae193-e8eb-4239-8579-97e2adc28f9d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/DoddleReport.OpenXml/ExcelReportWriter.cs b/src/DoddleReport.OpenXml/ExcelReportWriter.cs index 20a4334..2805366 100644 --- a/src/DoddleReport.OpenXml/ExcelReportWriter.cs +++ b/src/DoddleReport.OpenXml/ExcelReportWriter.cs @@ -16,6 +16,8 @@ public class ExcelReportWriter : IReportWriter public const string FooterStyle = "FooterStyle"; public const string PaperSize = "PaperSize"; public const string AdjustColumnWidthToContents = "AdjustColumnWidthToContents"; + public const string Password = "Password"; + public const string CustomProperties = "CustomProperties"; /// /// This Dictionary maps standard .NET format strings (like {0:c}) to OpenXML Format strings like "$ #,##0.00" @@ -138,7 +140,7 @@ protected virtual int RenderHeader(IXLWorksheet worksheet, int fieldsCount, Repo /// The row it last wrote on. private static int RenderTextItem(IXLWorksheet worksheet, int fieldsCount, string itemText, int currentRow, ReportStyle reportStyle) { - foreach (var s in itemText.Split(new[] { "\r\n"}, StringSplitOptions.None)) + foreach (var s in itemText.Split(new[] { "\r\n" }, StringSplitOptions.None)) { currentRow++; var row = worksheet.Row(currentRow); @@ -172,9 +174,22 @@ protected virtual void RenderRow(int rowCount, ReportRow reportRow, IXLRow dataR } else if (reportRow.RowType == ReportRowType.DataRow) { + var cell = dataRow.Cell(colCount); field.DataStyle.CopyToXlStyle(cell.Style); - if (field.DataType == typeof(bool)) + if (!string.IsNullOrWhiteSpace(field.ExcelFormula)) + { + cell.FormulaA1 = field.ExcelFormula.Replace("#ROW#", rowCount.ToString()); + if (field.DataType.IsNumericType()) + { + cell.SetDataType(XLCellValues.Number); + if (!string.Equals("{0}", field.DataFormatString)) + { + cell.Style.NumberFormat.Format = GetOpenXmlDataFormatString(field.DataFormatString); + } + } + } + else if (field.DataType == typeof(bool)) { cell.SetDataType(XLCellValues.Boolean); cell.Value = reportRow[field]; @@ -202,11 +217,11 @@ protected virtual void RenderRow(int rowCount, ReportRow reportRow, IXLRow dataR cell.Value = reportRow.GetFormattedValue(field); } - var url = reportRow.GetUrlString(field); - if (url != null) - { - cell.Hyperlink = new XLHyperlink(url); - } + var url = reportRow.GetUrlString(field); + if (url != null) + { + cell.Hyperlink = new XLHyperlink(url); + } } else if (reportRow.RowType == ReportRowType.FooterRow) { @@ -307,6 +322,9 @@ private static ReportStyle GetDefaultFooterStyle() private void WriteReport(Report report, XLWorkbook workbook) { var sheetName = report.RenderHints[SheetName] as string ?? "Data"; + var customProperties = report.RenderHints[CustomProperties] as Dictionary ?? + new Dictionary(); + var password = report.RenderHints[Password] as string ?? ""; IXLWorksheet worksheet; int duplicateNameCount = 0; var originalSheetName = sheetName; @@ -320,11 +338,14 @@ private void WriteReport(Report report, XLWorkbook workbook) var orientation = report.RenderHints.Orientation == ReportOrientation.Portrait ? XLPageOrientation.Portrait : XLPageOrientation.Landscape; worksheet.PageSetup.PageOrientation = orientation; + // Password protext the worksheet + PassordProtext(password, worksheet); + + // Add custom properties if any. + AddCustomProperties(workbook, customProperties); + // Set the paper size to what the render hint is set to - if (report.RenderHints[PaperSize] != null) - { - worksheet.PageSetup.PaperSize = (XLPaperSize)Enum.Parse(typeof(XLPaperSize), report.RenderHints[PaperSize].ToString()); - } + SetPaperSize(report, worksheet); if (report.RenderHints.FreezePanes) worksheet.SheetView.Freeze(report.RenderHints.FreezeRows, report.RenderHints.FreezeColumns); @@ -334,12 +355,7 @@ private void WriteReport(Report report, XLWorkbook workbook) int rowCount = RenderHeader(worksheet, fieldsCount, report.TextFields, report.RenderHints); // Render all the rows - foreach (var row in report.GetRows()) - { - rowCount++; - var dataRow = worksheet.Row(rowCount); - RenderRow(rowCount, row, dataRow); - } + rowCount = AddRows(report, rowCount, worksheet); // Render the footer RenderFooter(worksheet, fieldsCount, report.TextFields, report.RenderHints, rowCount); @@ -383,5 +399,44 @@ private void WriteReport(Report report, XLWorkbook workbook) } } } + + private int AddRows(Report report, int rowCount, IXLWorksheet worksheet) + { + foreach (var row in report.GetRows()) + { + rowCount++; + var dataRow = worksheet.Row(rowCount); + RenderRow(rowCount, row, dataRow); + } + return rowCount; + } + + private void SetPaperSize(Report report, IXLWorksheet worksheet) + { + if (report.RenderHints[PaperSize] != null) + { + worksheet.PageSetup.PaperSize = + (XLPaperSize)Enum.Parse(typeof(XLPaperSize), report.RenderHints[PaperSize].ToString()); + } + } + + private void AddCustomProperties(XLWorkbook workbook, Dictionary customProperties) + { + if (customProperties.Any()) + { + foreach (var property in customProperties) + { + workbook.CustomProperties.Add(property.Key, property.Value); + } + } + } + + private void PassordProtext(string password, IXLWorksheet worksheet) + { + if (!string.IsNullOrWhiteSpace(password)) + { + worksheet.Protect(password); + } + } } } diff --git a/src/DoddleReport.Sample.Web/Controllers/BuilderPaternController.cs b/src/DoddleReport.Sample.Web/Controllers/BuilderPaternController.cs new file mode 100644 index 0000000..20f3be1 --- /dev/null +++ b/src/DoddleReport.Sample.Web/Controllers/BuilderPaternController.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using System.Web.Mvc; +using DoddleReport.Sample.Web.Models; +using DoddleReport.Builder.Extentions; +using DoddleReport.OpenXml; +using DoddleReport.Web; + +namespace DoddleReport.Sample.Web.Controllers +{ + public class BuilderPaternController : Controller + { + // GET + public ActionResult Index() + { + var query = DoddleProductRepository.GetAll(); + var totalProducts = query.Count; + var totalOrders = query.Sum(p => p.OrderCount); + + var report = query.Export() + .Column("Id", x => x.Id) + .Column("Description", x => x.Description) + .Column("Price", x => x.Price) + .Column("Calculation", x => 0) + .Column("Formula", x => 0) + .Column("Text formula", x => string.Empty) + .ToReport(null); + + report.TextFields.Title = "Products Report"; + report.TextFields.SubTitle = "This is a sample report showing how Doddle Report works"; + report.TextFields.Footer = "Copyright 2011 (c) The Doddle Project"; + report.TextFields.Header = string.Format(@" + Report Generated: {0} + Total Products: {1} + Total Orders: {2} + Total Sales: {3:c}", DateTime.Now, totalProducts, totalOrders, totalProducts * totalOrders); + + report.RenderHints.FreezeRows = 5; + report.RenderHints.FreezeColumns = 1; + + report.DataFields["Price"].DataFormatString = "{0:c}"; + report.DataFields["Price"].ShowTotals = true; + + report.DataFields["Calculation"].DataFormatString = "{0:c}"; + report.DataFields["Calculation"].ExcelFormula = "=2*C#ROW#"; + + report.DataFields["Formula"].ShowTotals = true; + report.DataFields["Formula"].DataFormatString = "{0:c}"; + report.DataFields["Formula"].ExcelFormula = "=C#ROW#+D#ROW#"; + + report.DataFields["Text formula"].ExcelFormula = "=LEFT(B#ROW#, 30)"; + + + + report.RenderHints[ExcelReportWriter.Password] = "password"; + + return new ReportResult(report, new ExcelReportWriter(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + } + } +} \ No newline at end of file diff --git a/src/DoddleReport.Sample.Web/DoddleReport.Sample.Web.csproj b/src/DoddleReport.Sample.Web/DoddleReport.Sample.Web.csproj index 846e1f9..8827b1c 100644 --- a/src/DoddleReport.Sample.Web/DoddleReport.Sample.Web.csproj +++ b/src/DoddleReport.Sample.Web/DoddleReport.Sample.Web.csproj @@ -36,6 +36,7 @@ true + true @@ -110,6 +111,7 @@ + @@ -172,6 +174,10 @@ {355CAFF3-F806-4194-BE54-2F7640463CED} DoddleReport.AbcPdf + + {10fae193-e8eb-4239-8579-97e2adc28f9d} + DoddleReport.Builder + {347D0716-0297-4866-9FD5-5E019B51C408} DoddleReport.iTextSharp diff --git a/src/DoddleReport.sln b/src/DoddleReport.sln index 58dcb81..bc00aed 100644 --- a/src/DoddleReport.sln +++ b/src/DoddleReport.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2010 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{0E73989A-FF31-4542-88F9-DAC6F9C40FE2}" ProjectSection(SolutionItems) = preProject @@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoddleReport.Web", "DoddleR EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoddleReport.iTextSharp", "DoddleReport.iTextSharp\DoddleReport.iTextSharp.csproj", "{347D0716-0297-4866-9FD5-5E019B51C408}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DoddleReport.Builder", "DoddleReport.Builder\DoddleReport.Builder.csproj", "{10FAE193-E8EB-4239-8579-97E2ADC28F9D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -106,6 +108,18 @@ Global {347D0716-0297-4866-9FD5-5E019B51C408}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {347D0716-0297-4866-9FD5-5E019B51C408}.Release|Mixed Platforms.Build.0 = Release|Any CPU {347D0716-0297-4866-9FD5-5E019B51C408}.Release|x86.ActiveCfg = Release|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Debug|x86.ActiveCfg = Debug|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Debug|x86.Build.0 = Debug|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Release|Any CPU.Build.0 = Release|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Release|x86.ActiveCfg = Release|Any CPU + {10FAE193-E8EB-4239-8579-97E2ADC28F9D}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -114,6 +128,9 @@ Global {28FBF83C-A8A3-418B-A32E-3A725BD37A5C} = {2E920538-21EC-49E6-BF72-75E82B2E49E2} {12A17D7F-C168-4086-8D6A-DFE311E9EE90} = {2E920538-21EC-49E6-BF72-75E82B2E49E2} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {242821AC-AF59-467C-B09A-94A890D1780A} + EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = DoddleReport.vsmdi EndGlobalSection diff --git a/src/DoddleReport/ReportField.cs b/src/DoddleReport/ReportField.cs index d388441..ca73419 100644 --- a/src/DoddleReport/ReportField.cs +++ b/src/DoddleReport/ReportField.cs @@ -74,8 +74,9 @@ public string DataFormatString internal Delegate FormatAsDelegate { get; private set; } internal Delegate UrlDelegate { get; private set; } - - public ReportField(string fieldName) + public string ExcelFormula { get; set; } + + public ReportField(string fieldName) : this(fieldName, typeof(object)) {} public ReportField(string fieldName, Type dataType) diff --git a/src/DoddleReport/RowField.cs b/src/DoddleReport/RowField.cs index caaeb0b..290ce7f 100644 --- a/src/DoddleReport/RowField.cs +++ b/src/DoddleReport/RowField.cs @@ -43,6 +43,8 @@ public string DataFormatString public bool Hidden { get; private set; } + public string ExcelFormula { get; set; } + public ReportStyle DataStyle { get; private set; } public ReportStyle HeaderStyle { get; private set; } public ReportStyle FooterStyle { get; private set; } @@ -67,6 +69,7 @@ public RowField(ReportRow row, ReportField field) HeaderStyle = field.HeaderStyle; ShowTotals = field.ShowTotals; UrlDelegate = field.UrlDelegate; + ExcelFormula = field.ExcelFormula; } public void FormatAs(Func formatAsDelegate)