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)