diff --git a/src/EPPlus/CellPictures/CellPicturesManager.cs b/src/EPPlus/CellPictures/CellPicturesManager.cs
index 158b5eb22..9cc2a526d 100644
--- a/src/EPPlus/CellPictures/CellPicturesManager.cs
+++ b/src/EPPlus/CellPictures/CellPicturesManager.cs
@@ -358,6 +358,11 @@ private void AddNewWebPicture(int row, int col, Uri imageUri, Uri addressUri, st
}
}
+ internal void ReadAndAddReference(PictureCacheKey key, uint vmId)
+ {
+ _referenceCache.Add(key, vmId);
+ }
+
private void AddReferenceToPicture(int row, int col, PictureCacheKey key, uint vmId)
{
var rv = _richDataStore.GetRichValue(vmId);
diff --git a/src/EPPlus/Drawing/Chart/ExcelBarChartSerie.cs b/src/EPPlus/Drawing/Chart/ExcelBarChartSerie.cs
index feb80bdd6..ce0cf5296 100644
--- a/src/EPPlus/Drawing/Chart/ExcelBarChartSerie.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelBarChartSerie.cs
@@ -44,7 +44,7 @@ public ExcelChartSerieDataLabel DataLabel
{
if (_dataLabel == null)
{
- if (ExcelChartDataLabelStandard.ForbiddDataLabelPosition(_chart) == false)
+ if (ExcelChartDataLabelStandard.IsDataLabelPositionForbidden(_chart) == false)
{
_dataLabel = new ExcelChartSerieDataLabel(_chart, NameSpaceManager, TopNode, SchemaNodeOrder);
}
diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs
index 1b6cec48d..7e5300bfb 100644
--- a/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelChartDataLabel.cs
@@ -26,7 +26,7 @@ public abstract class ExcelChartDataLabel : XmlHelper, IDrawingStyle
{
internal ExcelChart _chart;
internal string _nodeName;
- private string _nsPrefix;
+ internal protected string NsPrefix { private set; get; }
private readonly string _formatPath;
private readonly string _sourceLinkedPath;
@@ -35,7 +35,7 @@ internal ExcelChartDataLabel(ExcelChart chart, XmlNamespaceManager ns, XmlNode n
{
_nodeName = nodeName;
_chart = chart;
- _nsPrefix = nsPrefix;
+ NsPrefix = nsPrefix;
_formatPath = $"{nsPrefix}:numFmt/@formatCode";
_sourceLinkedPath = $"{nsPrefix}:numFmt/@sourceLinked";
}
@@ -157,7 +157,7 @@ public ExcelDrawingFill Fill
{
if (_fill == null)
{
- _fill = new ExcelDrawingFill(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:spPr", SchemaNodeOrder);
+ _fill = new ExcelDrawingFill(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:spPr", SchemaNodeOrder);
}
return _fill;
}
@@ -172,7 +172,7 @@ public ExcelDrawingBorder Border
{
if (_border == null)
{
- _border = new ExcelDrawingBorder(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:spPr/a:ln", SchemaNodeOrder);
+ _border = new ExcelDrawingBorder(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:spPr/a:ln", SchemaNodeOrder);
}
return _border;
}
@@ -187,7 +187,7 @@ public ExcelDrawingEffectStyle Effect
{
if (_effect == null)
{
- _effect = new ExcelDrawingEffectStyle(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:spPr/a:effectLst", SchemaNodeOrder);
+ _effect = new ExcelDrawingEffectStyle(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:spPr/a:effectLst", SchemaNodeOrder);
}
return _effect;
}
@@ -202,7 +202,7 @@ public ExcelDrawing3D ThreeD
{
if (_threeD == null)
{
- _threeD = new ExcelDrawing3D(NameSpaceManager, TopNode, $"{_nsPrefix}:spPr", SchemaNodeOrder);
+ _threeD = new ExcelDrawing3D(NameSpaceManager, TopNode, $"{NsPrefix}:spPr", SchemaNodeOrder);
}
return _threeD;
}
@@ -218,7 +218,7 @@ public ExcelTextFont Font
{
if (_font == null)
{
- _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder, CreateDefaultText);
+ _font = new ExcelTextFont(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder, CreateDefaultText);
}
return _font;
}
@@ -233,7 +233,7 @@ public ExcelDrawingTextSettings TextSettings
{
if (_textSettings == null)
{
- _textSettings = new ExcelDrawingTextSettings(_chart, NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder);
+ _textSettings = new ExcelDrawingTextSettings(_chart, NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:p/a:pPr/a:defRPr", SchemaNodeOrder);
}
return _textSettings;
}
@@ -245,14 +245,14 @@ void IDrawingStyleBase.CreatespPr()
private void CreateDefaultText()
{
- if (TopNode.SelectSingleNode($"{_nsPrefix}:txPr", NameSpaceManager) == null)
+ if (TopNode.SelectSingleNode($"{NsPrefix}:txPr", NameSpaceManager) == null)
{
- if (!ExistsNode($"{_nsPrefix}:spPr"))
+ if (!ExistsNode($"{NsPrefix}:spPr"))
{
- var spNode = CreateNode($"{_nsPrefix}:spPr");
+ var spNode = CreateNode($"{NsPrefix}:spPr");
spNode.InnerXml = "";
}
- var node = CreateNode($"{_nsPrefix}:txPr");
+ var node = CreateNode($"{NsPrefix}:txPr");
node.InnerXml = "";
}
@@ -268,7 +268,7 @@ public ExcelTextBody TextBody
{
if (_textBody == null)
{
- _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"{_nsPrefix}:txPr/a:bodyPr", SchemaNodeOrder, Font.CreateTopNode);
+ _textBody = new ExcelTextBody(NameSpaceManager, TopNode, $"{NsPrefix}:txPr/a:bodyPr", SchemaNodeOrder, Font.CreateTopNode);
}
return _textBody;
}
diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelCollection.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelCollection.cs
index 8b2b2a0a2..613500be9 100644
--- a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelCollection.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelCollection.cs
@@ -13,7 +13,8 @@ Date Author Change
using System;
using System.Collections;
using System.Collections.Generic;
-using System.Reflection.Emit;
+using System.ComponentModel;
+using System.Data;
using System.Xml;
namespace OfficeOpenXml.Drawing.Chart
@@ -31,14 +32,25 @@ internal ExcelChartDataLabelCollection(ExcelChart chart, XmlNamespaceManager ns,
{
SchemaNodeOrder = schemaNodeOrder;
_list = new List();
- foreach (XmlNode dataLabelNode in TopNode.SelectNodes("c:dLbl", ns))
+ var existingDataLabelNodes = TopNode.SelectNodes("c:dLbl", ns);
+ foreach (XmlNode dataLabelNode in existingDataLabelNodes)
{
_list.Add(new ExcelChartDataLabelItem(chart, ns, dataLabelNode, "", schemaNodeOrder));
}
parentDatalabel = parent;
_chart = chart;
+
}
+
+ internal void InitializeDataLabelsXml()
+ {
+ if(_list.Count == 0)
+ {
+ var seriesNode = TopNode.ParentNode;
+ }
+ }
+
///
/// Adds a new chart label to the collection
///
@@ -72,7 +84,7 @@ private ExcelChartDataLabelItem CreateDataLabel(int idx)
dl.ShowLegendKey = parentDatalabel.ShowLegendKey;
dl.ShowLeaderLines = true;
dl.ShowValue = true;
- dl.Position = eLabelPosition.Center;
+ dl.Position = parentDatalabel.Position;
if (idx < _list.Count)
{
diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelItem.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelItem.cs
index 8e0d06e5c..417c05e04 100644
--- a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelItem.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelItem.cs
@@ -10,6 +10,10 @@ Date Author Change
*************************************************************************************************
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*************************************************************************************************/
+using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions;
+using OfficeOpenXml.Style;
+using System.Collections.Generic;
using System.Globalization;
using System.Xml;
@@ -20,10 +24,12 @@ namespace OfficeOpenXml.Drawing.Chart
///
public class ExcelChartDataLabelItem : ExcelChartDataLabelStandard
{
+ string _fontPropertiesPath = "";
internal ExcelChartDataLabelItem(ExcelChart chart, XmlNamespaceManager ns, XmlNode node, string nodeName, string[] schemaNodeOrder)
: base(chart, ns, node, nodeName, schemaNodeOrder)
{
Layout = new ExcelLayout(NameSpaceManager, TopNode, $"c:layout","c:extLst/c:ext[1]/c15:layout", SchemaNodeOrder);
+ _fontPropertiesPath = $"{NsPrefix}:tx/{NsPrefix}:rich";
}
///
@@ -31,6 +37,37 @@ internal ExcelChartDataLabelItem(ExcelChart chart, XmlNamespaceManager ns, XmlNo
///
public ExcelLayout Layout { get; private set; }
+ ExcelParagraphCollection _paragraphs = null;
+
+ ///
+ /// Access to text body properties
+ ///
+ private ExcelParagraphCollection ParagraphCollection
+ {
+ get
+ {
+ if (_paragraphs == null)
+ {
+ _paragraphs = new ExcelParagraphCollection(_chart, NameSpaceManager, TopNode, _fontPropertiesPath + "/a:p", SchemaNodeOrder);
+ }
+ return _paragraphs;
+ }
+ }
+
+ ///
+ /// Replace datalabel text
+ ///
+ ///
+ public void SetText(string replacementText)
+ {
+ ParagraphCollection.Clear();
+ ParagraphCollection.Add(replacementText, true);
+ }
+
+ internal List> GetExistingParagraphStrings()
+ {
+ return ParagraphCollection.GetParagraphTextLists();
+ }
///
/// The index of an individual datalabel
///
@@ -45,5 +82,7 @@ public int Index
SetXmlNodeString("c:idx/@val", value.ToString(CultureInfo.InvariantCulture));
}
}
+
+ internal ExcelAddressBase SingleCellAddressFromSeries;
}
}
diff --git a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs
index 5552436b1..0bbe7e621 100644
--- a/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelChartDataLabelStandard.cs
@@ -77,7 +77,10 @@ internal ExcelChartDataLabelStandard(ExcelChart chart, XmlNamespaceManager ns, X
const string positionPath = "c:dLblPos/@val";
///
/// Position of the labels
- /// Note: Only Center, InEnd and InBase are allowed for dataLabels on stacked columns
+ ///
BE AWARE! For SERIES labels and all underlying labels:
+ /// Setting a position not available for this label in the Excel UI May cause a corrupt file.
+ /// Note: Only Center, InEnd and InBase are allowed for dataLabels on stacked columns
+ /// (Same applies to most BarCharts but they allow OutEnd)
///
public override eLabelPosition Position
{
@@ -87,14 +90,19 @@ public override eLabelPosition Position
}
set
{
- if (ForbiddDataLabelPosition(_chart))
+ if (IsDataLabelPositionForbidden(_chart))
{
throw new InvalidOperationException("Can't set data label position on a 3D-chart");
}
+ if(_chart.ChartType == eChartType.ColumnClustered && value == eLabelPosition.Top)
+ {
+ throw new InvalidOperationException($"DataLabelPosition: '{value}' is not allowed on chart of type: '{_chart.ChartType}' \n " +
+ $"because it would cause a corrupt file");
+ }
SetXmlNodeString(positionPath, GetPosText(value));
}
}
- internal static bool ForbiddDataLabelPosition(ExcelChart _chart)
+ internal static bool IsDataLabelPositionForbidden(ExcelChart _chart)
{
return _chart.IsType3D() && !_chart.IsTypePie() && _chart.ChartType != eChartType.Line3D
|| _chart.IsTypeDoughnut();
@@ -144,7 +152,7 @@ public override bool ShowSeriesName
SetXmlNodeString(showSerPath, value ? "1" : "0");
}
}
- const string showPerentPath = "c:showPercent/@val";
+ const string showPercentPath = "c:showPercent/@val";
///
/// Show percent values
///
@@ -152,11 +160,11 @@ public override bool ShowPercent
{
get
{
- return GetXmlNodeBool(showPerentPath);
+ return GetXmlNodeBool(showPercentPath);
}
set
{
- SetXmlNodeString(showPerentPath, value ? "1" : "0");
+ SetXmlNodeString(showPercentPath, value ? "1" : "0");
}
}
const string showLeaderLinesPath = "c:showLeaderLines/@val";
@@ -254,5 +262,28 @@ public override string Separator
}
}
}
+
+ internal void AddExtFieldTableEmpty()
+ {
+ CreateNode($"{extPath}/c15:dlblFieldTable");
+ }
+
+
+ internal bool ShowDatalabelsRange
+ {
+ get
+ {
+ return GetXmlNodeBool($"{extPath}/c15:showDataLabelsRange");
+ }
+ set
+ {
+ var rangePath = $"{extPath}/c15:showDataLabelsRange";
+ if(ExistsNode(rangePath) == false)
+ {
+ CreateNode(rangePath);
+ }
+ SetXmlNodeBool(rangePath+"/@val", value);
+ }
+ }
}
}
diff --git a/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs b/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs
index ce8b6c61e..c9bfa044e 100644
--- a/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelChartSerieDataLabel.cs
@@ -10,13 +10,17 @@ Date Author Change
*************************************************************************************************
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*************************************************************************************************/
+using OfficeOpenXml.Drawing.Interfaces;
+using OfficeOpenXml.Drawing.Style.Effect;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
+using OfficeOpenXml.Style;
using System;
using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Net;
using System.Text;
using System.Xml;
-using OfficeOpenXml.Drawing.Interfaces;
-using OfficeOpenXml.Drawing.Style.Effect;
-using OfficeOpenXml.Style;
namespace OfficeOpenXml.Drawing.Chart
{
@@ -26,9 +30,16 @@ namespace OfficeOpenXml.Drawing.Chart
public sealed class ExcelChartSerieDataLabel : ExcelChartDataLabelStandard
{
internal ExcelChartSerieDataLabel(ExcelChart chart, XmlNamespaceManager ns, XmlNode node, string[] schemaNodeOrder)
- : base(chart, ns,node,"dLbls", schemaNodeOrder)
+ : base(chart, ns, node, "dLbls", schemaNodeOrder)
{
Position = eLabelPosition.Center;
+ var parentSeries = GetParentSeries();
+
+ var address = parentSeries.GetDataLabelRange();
+ if (string.IsNullOrEmpty(address) == false)
+ {
+ DataLabelRange = chart.WorkSheet.Cells[address];
+ }
}
ExcelChartDataLabelCollection _dataLabels = null;
///
@@ -41,9 +52,111 @@ public ExcelChartDataLabelCollection DataLabels
if (_dataLabels == null)
{
_dataLabels = new ExcelChartDataLabelCollection(_chart, NameSpaceManager, TopNode, SchemaNodeOrder, this as ExcelChartDataLabelStandard);
+
+ //Fill datalabel addresses
+ if(DataLabelRange != null)
+ {
+ var address = DataLabelRange;
+ for(int i = 0; i< _dataLabels.Count(); i++)
+ {
+ if (address.Rows > address.Columns)
+ {
+ _dataLabels[i].SingleCellAddressFromSeries = address.TakeSingleCell(i, 0);
+ }
+ else
+ {
+ _dataLabels[i].SingleCellAddressFromSeries = address.TakeSingleCell(0, i);
+ }
+ }
+ }
}
return _dataLabels;
}
}
+
+ ///
+ /// Does the datalabels of this chart contain
+ /// Value From Cells
+ ///
+ public bool ValueFromCells { get { return DataLabelRange != null; } }
+
+ internal ExcelRangeBase DataLabelRange { get; private set; } = null;
+
+
+ ExcelChartStandardSerie GetParentSeries()
+ {
+ //TODO: The way we aquire the Series instance here is clumsy.
+ //Fix as part of datalabel refactor?
+ //Perhaps the series of a series label should be part of its constructor.
+ //Or use an eventhandler
+ //For a single case however that feels overkill.
+
+ //Has to get the series index:
+ var idxNode = (XmlElement)TopNode.ParentNode.SelectSingleNode($"{NsPrefix}:idx", NameSpaceManager);
+ var idxNodeValue = int.Parse(idxNode.GetAttribute("val"));
+ //Get the series this datalabel is on
+ return (ExcelChartStandardSerie)_chart.Series[idxNodeValue];
+ }
+
+ ///
+ /// Select datalabel range for
+ /// Value From Cells
+ ///
+ /// must be a single; cell, row or column
+ /// Thrown when input is not a cell, a row or a column
+ public void SelectRange(ExcelRangeBase address)
+ {
+ //TODO: Arguably this is just another series with a series cache.
+ //Same as Cat or Val except that it is added in Ext on the Serie node
+ //ShowValue property essentially changes the datalabels in the same way.
+ //This could be unified somehow so that all serie ranges; Cat, Val and DataLabelRange are handled the same way.
+
+ bool moreThanOneRow = address.Rows > 1;
+ bool moreThanOneColumn = address.Columns > 1;
+
+ if (moreThanOneRow && moreThanOneColumn)
+ {
+ throw new InvalidExpressionException($"DataLabelRange cannot be set to invalid range: '{address.Address}'\n" +
+ $"The range must be a single cell, a single row or a single column");
+ }
+
+ DataLabelRange = address;
+
+ var currentSeries = GetParentSeries();
+ //Set the ext data needed in the Series node
+ currentSeries.SetDataLabelRange(address);
+
+ //Create the Datalabels if they do not exist
+ if (DataLabels.Count < currentSeries.NumberOfItems)
+ {
+ for (int i = 0; i < currentSeries.NumberOfItems; i++)
+ {
+ ExcelChartDataLabelItem currentLabel;
+ if (DataLabels.Count - 1 < i)
+ {
+ currentLabel = DataLabels.Add(i);
+ }
+ else
+ {
+ currentLabel = DataLabels[i];
+ }
+ currentLabel.AddExtFieldTableEmpty();
+ currentLabel.ShowDatalabelsRange = true;
+
+ if (address.Rows > address.Columns)
+ {
+ currentLabel.SingleCellAddressFromSeries = address.TakeSingleCell(i, 0);
+ }
+ else
+ {
+ currentLabel.SingleCellAddressFromSeries = address.TakeSingleCell(0, i);
+ }
+
+ ////Adds field CellRange to the paragraph of the label
+ ///For backwards compatability if opened in excel versions prior to Excel 2013
+ //currentLabel.AddField("CELLRANGE");
+ }
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs b/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs
index 06c03b88d..52c5c6cc2 100644
--- a/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelChartStandardSerie.cs
@@ -19,6 +19,8 @@ Date Author Change
using System.Globalization;
using System.Runtime.CompilerServices;
using System.IO;
+using OfficeOpenXml.FormulaParsing.Utilities;
+
namespace OfficeOpenXml.Drawing.Chart
{
///
@@ -28,26 +30,28 @@ public class ExcelChartStandardSerie : ExcelChartSerie
{
private readonly bool _isPivot;
-
double[] _NumberLiteralsY = null;
double[] _NumberLiteralsX = null;
string[] _StringLiteralsX = null;
string[] _StringLiteralsY = null;
+ const string extPath = "c:extLst/c:ext";
+ const string dlblRangePath = "c:extLst/c:ext/c15:datalabelsRange";
+
///
/// Literals for the Y serie, if the literal values are numeric
///
- public override double[] NumberLiteralsY
- {
- get
+ public override double[] NumberLiteralsY
+ {
+ get
{
- if(string.IsNullOrEmpty(_seriesNumLitPath) == false && GetNode(_seriesNumLitPath) != null)
+ if (string.IsNullOrEmpty(_seriesNumLitPath) == false && GetNode(_seriesNumLitPath) != null)
{
ReadNumLiterals(_seriesNumLitPath, out _NumberLiteralsY);
return _NumberLiteralsY;
}
return _NumberLiteralsY;
- }
+ }
protected set
{
_NumberLiteralsY = value;
@@ -56,7 +60,7 @@ protected set
///
/// Literals for the X serie, if the literal values are numeric
///
- public override double[] NumberLiteralsX
+ public override double[] NumberLiteralsX
{
get
{
@@ -121,25 +125,25 @@ protected set
/// Is pivotchart
internal ExcelChartStandardSerie(ExcelChart chart, XmlNamespaceManager ns, XmlNode node, bool isPivot)
: base(chart, ns, node)
- {
- _chart = chart;
- _isPivot = isPivot;
- SchemaNodeOrder = new string[] { "idx", "order", "tx", "spPr", "marker", "invertIfNegative", "pictureOptions", "explosion", "dPt", "dLbls", "trendline","errBars", "cat", "val", "xVal", "yVal", "smooth","shape", "bubbleSize", "bubble3D", "numRef", "numLit", "strRef", "strLit", "formatCode", "ptCount", "pt" };
-
- if (_chart.ChartNode.LocalName=="scatterChart" ||
- _chart.ChartNode.LocalName.StartsWith("bubble", StringComparison.OrdinalIgnoreCase))
- {
- _seriesTopPath = "c:yVal";
- _xSeriesTopPath = "c:xVal";
- }
- else
- {
- _seriesTopPath = "c:val";
- _xSeriesTopPath = "c:cat";
- }
-
- _seriesPath = string.Format(_seriesPath, _seriesTopPath);
- _numCachePath = string.Format(_numCachePath, _seriesTopPath);
+ {
+ _chart = chart;
+ _isPivot = isPivot;
+ SchemaNodeOrder = new string[] { "idx", "order", "tx", "spPr", "marker", "invertIfNegative", "pictureOptions", "explosion", "dPt", "dLbls", "trendline", "errBars", "cat", "val", "xVal", "yVal", "smooth", "shape", "bubbleSize", "bubble3D", "numRef", "numLit", "strRef", "strLit", "formatCode", "ptCount", "pt" };
+
+ if (_chart.ChartNode.LocalName == "scatterChart" ||
+ _chart.ChartNode.LocalName.StartsWith("bubble", StringComparison.OrdinalIgnoreCase))
+ {
+ _seriesTopPath = "c:yVal";
+ _xSeriesTopPath = "c:xVal";
+ }
+ else
+ {
+ _seriesTopPath = "c:val";
+ _xSeriesTopPath = "c:cat";
+ }
+
+ _seriesPath = string.Format(_seriesPath, _seriesTopPath);
+ _numCachePath = string.Format(_numCachePath, _seriesTopPath);
var np = string.Format(_xSeriesParentPath, _xSeriesTopPath, isPivot ? "c:multiLvlStrRef" : "c:numRef");
var sp = string.Format(_xSeriesParentPath, _xSeriesTopPath, isPivot ? "c:multiLvlStrRef" : "c:strRef");
@@ -157,54 +161,118 @@ internal ExcelChartStandardSerie(ExcelChart chart, XmlNamespaceManager ns, XmlNo
_xSeriesStrLitPath = string.Format("{0}/c:strLit", _xSeriesTopPath);
_xSeriesNumLitPath = string.Format("{0}/c:numLit", _xSeriesTopPath);
- }
- internal override void SetID(string id)
- {
- SetXmlNodeString("c:idx/@val",id);
- SetXmlNodeString("c:order/@val", id);
- }
- const string headerPath="c:tx/c:v";
- ///
- /// Header for the serie.
- ///
- public override string Header
- {
- get
- {
+ }
+ internal override void SetID(string id)
+ {
+ SetXmlNodeString("c:idx/@val", id);
+ SetXmlNodeString("c:order/@val", id);
+ }
+
+ internal bool HasDataLabelRange()
+ {
+ return ExistsNode(dlblRangePath);
+ }
+
+ internal string GetDataLabelRange()
+ {
+ if(ExistsNode($"{dlblRangePath}/c15:f"))
+ {
+ return GetXmlNodeString($"{dlblRangePath}/c15:f");
+ }
+ return null;
+ }
+
+ internal void AddExtLstXml()
+ {
+ NameSpaceManager.AddNamespace("c15", ExcelPackage.schemaChart2012);
+ NameSpaceManager.AddNamespace("c16", ExcelPackage.schemaChart2014);
+
+ XmlElement ext15Node;
+
+ var c15Uri = "{02D57815-91ED-43cb-92C2-25804820EDAC}";
+
+ //Only add node if it doesn't already exist
+ if (ExistsNode(extPath + $"[@uri='{c15Uri}']") == false)
+ {
+ XmlElement el = (XmlElement)CreateNode($"{extPath}");
+ el.SetAttribute("xmlns:c15", ExcelPackage.schemaChart2012);
+ SetXmlNodeString($"{extPath}/@uri", $"{c15Uri}");
+ ext15Node = el;
+ }
+ else
+ {
+ ext15Node = (XmlElement)GetNode($"{extPath}");
+ }
+
+ //Only add node if it doesn't already exist
+ if (ExistsNode($"{extPath}[2]") == false)
+ {
+ XmlElement element = (XmlElement)CreateNode($"{extPath}", false, true);
+ element.SetAttribute("xmlns:c16", ExcelPackage.schemaChart2014);
+ SetXmlNodeString($"{extPath}[2]/@uri", "{C3380CC4-5D6E-409C-BE32-E72D297353CC}");
+ var _guidId = Guid.NewGuid();
+
+ var extNode2 = GetNode($"{extPath}[2]");
+ var uniqueIdNode = (XmlElement)CreateNode(extNode2, "c16:uniqueID");
+ uniqueIdNode.SetAttribute("val", $"{{{_guidId}}}");
+ }
+ }
+
+
+ internal void SetDataLabelRange(ExcelRangeBase address)
+ {
+ AddExtLstXml();
+
+ var datalabelsRange = CreateNode(dlblRangePath);
+ var formulaNode = CreateNode($"{dlblRangePath}/c15:f");
+ formulaNode.InnerText = address.AddressAbsolute;
+
+ var rangeNode = CreateNode($"{dlblRangePath}/c15:dlblRangeCache");
+ CreateCache(address.FullAddressAbsolute, rangeNode);
+ }
+
+ const string headerPath = "c:tx/c:v";
+ ///
+ /// Header for the serie.
+ ///
+ public override string Header
+ {
+ get
+ {
return GetXmlNodeString(headerPath);
}
set
{
Cleartx();
- SetXmlNodeString(headerPath, value);
+ SetXmlNodeString(headerPath, value);
}
}
- private void Cleartx()
- {
- var n = TopNode.SelectSingleNode("c:tx", NameSpaceManager);
- if (n != null)
- {
- n.InnerXml = "";
- }
- }
- const string headerAddressPath = "c:tx/c:strRef/c:f";
+ private void Cleartx()
+ {
+ var n = TopNode.SelectSingleNode("c:tx", NameSpaceManager);
+ if (n != null)
+ {
+ n.InnerXml = "";
+ }
+ }
+ const string headerAddressPath = "c:tx/c:strRef/c:f";
///
- /// Header address for the serie.
- ///
- public override ExcelAddressBase HeaderAddress
- {
- get
- {
- string address = GetXmlNodeString(headerAddressPath);
- if (address == "")
- {
- return null;
- }
- else
- {
- return new ExcelAddressBase(address);
- }
+ /// Header address for the serie.
+ ///
+ public override ExcelAddressBase HeaderAddress
+ {
+ get
+ {
+ string address = GetXmlNodeString(headerAddressPath);
+ if (address == "")
+ {
+ return null;
+ }
+ else
+ {
+ return new ExcelAddressBase(address);
+ }
}
set
{
@@ -217,7 +285,7 @@ public override ExcelAddressBase HeaderAddress
SetXmlNodeString(headerAddressPath, ExcelCellBase.GetFullAddress(value.WorkSheetName, value.Address));
SetXmlNodeString("c:tx/c:strRef/c:strCache/c:ptCount/@val", "0");
}
- }
+ }
string _seriesTopPath;
string _seriesPath = "{0}/c:numRef/c:f";
string _numCachePath = "{0}/c:numRef/c:numCache";
@@ -227,18 +295,18 @@ public override ExcelAddressBase HeaderAddress
///
public override string Series
{
- get
- {
- return GetXmlNodeString(_seriesPath);
- }
- set
- {
+ get
+ {
+ return GetXmlNodeString(_seriesPath);
+ }
+ set
+ {
value = value.Trim();
if (value.StartsWith("=", StringComparison.OrdinalIgnoreCase)) value = value.Substring(1);
if (value.StartsWith("{", StringComparison.OrdinalIgnoreCase) && value.EndsWith("}", StringComparison.OrdinalIgnoreCase))
{
GetLitValues(value, out double[] numLit, out string[] strLit);
- if(strLit!=null)
+ if (strLit != null)
{
throw (new ArgumentException("Value series can't contain strings"));
}
@@ -255,22 +323,22 @@ public override string Series
}
- string _xSeries=null;
- string _xSeriesTopPath;
- string _xSeriesParentPath = "{0}/{1}";
- string _xSeriesPath = "{0}/{1}/c:f";
- string _xSeriesStrLitPath, _xSeriesNumLitPath;
+ string _xSeries = null;
+ string _xSeriesTopPath;
+ string _xSeriesParentPath = "{0}/{1}";
+ string _xSeriesPath = "{0}/{1}/c:f";
+ string _xSeriesStrLitPath, _xSeriesNumLitPath;
///
/// Set an address for the horisontal labels
///
- public override string XSeries
- {
- get
- {
- return GetXmlNodeString(_xSeriesPath);
- }
- set
- {
+ public override string XSeries
+ {
+ get
+ {
+ return GetXmlNodeString(_xSeriesPath);
+ }
+ set
+ {
_xSeries = value.Trim();
if (_xSeries.StartsWith("=", StringComparison.OrdinalIgnoreCase)) _xSeries = _xSeries.Substring(1);
if (value.StartsWith("{", StringComparison.OrdinalIgnoreCase) && value.EndsWith("}", StringComparison.OrdinalIgnoreCase))
@@ -285,7 +353,7 @@ public override string XSeries
NumberLiteralsX = null;
StringLiteralsX = null;
CreateNode(_xSeriesPath, true);
- if(ExcelCellBase.IsValidAddress(_xSeries))
+ if (ExcelCellBase.IsValidAddress(_xSeries))
{
SetXmlNodeString(_xSeriesPath, ExcelCellBase.GetFullAddress(_chart.WorkSheet.Name, _xSeries));
}
@@ -296,7 +364,7 @@ public override string XSeries
SetXSerieFunction();
}
}
- }
+ }
private void ReadNumLiterals(string path, out double[] numberLiterals)
{
@@ -306,9 +374,9 @@ private void ReadNumLiterals(string path, out double[] numberLiterals)
foreach (XmlNode node in childNodes)
{
- if(node.NodeType==XmlNodeType.Element && node.LocalName == "pt")
+ if (node.NodeType == XmlNodeType.Element && node.LocalName == "pt")
{
- if(double.TryParse(node.InnerText, NumberStyles.Any, CultureInfo.InvariantCulture, out double numLit) == false)
+ if (double.TryParse(node.InnerText, NumberStyles.Any, CultureInfo.InvariantCulture, out double numLit) == false)
{
throw new InvalidDataException($"numberLiteral in xml node:'{node.Name}' in chart:'{_chart.Name}' with value:'{node.InnerText}' could not be parsed as double. Chart cannot be read.");
}
@@ -323,7 +391,7 @@ private void ReadStringLiterals(string path, out string[] stringLiterals)
var parentNode = GetNode(path);
List strLits = new();
- if(parentNode != null)
+ if (parentNode != null)
{
var childNodes = parentNode.ChildNodes;
@@ -465,12 +533,12 @@ private void SetXSerieFunction()
}
private void SetLits(double[] numLit, string[] strLit, string numLitPath, string strLitPath)
{
- if(strLit!=null)
+ if (strLit != null)
{
XmlNode lit = CreateNode(strLitPath);
SetLitArray(lit, strLit);
}
- else if(numLit!=null)
+ else if (numLit != null)
{
XmlNode lit = CreateNode(numLitPath);
SetLitArray(lit, numLit);
@@ -506,7 +574,7 @@ private void SetLitArray(XmlNode lit, string[] strLit)
{
//Remove previous child nodes
var previousPt = lit.SelectNodes("c:pt", NameSpaceManager);
- if(previousPt != null)
+ if (previousPt != null)
{
for (int i = 0; i < previousPt.Count; i++)
{
@@ -535,9 +603,9 @@ private void AddCount(XmlNode lit, int count)
}
ExcelChartTrendlineCollection _trendLines = null;
- ///
- /// Access to the trendline collection
- ///
+ ///
+ /// Access to the trendline collection
+ ///
public override ExcelChartTrendlineCollection TrendLines
{
get
@@ -556,7 +624,7 @@ public override int NumberOfItems
{
get
{
- if(ExcelCellBase.IsValidAddress(Series))
+ if (ExcelCellBase.IsValidAddress(Series))
{
var a = new ExcelAddressBase(Series);
return a.Rows;
@@ -574,16 +642,16 @@ public override int NumberOfItems
///
public void CreateCache()
{
- if (_isPivot) throw(new NotImplementedException("Cache for pivotcharts has not been implemented yet."));
+ if (_isPivot) throw (new NotImplementedException("Cache for pivotcharts has not been implemented yet."));
if (!string.IsNullOrEmpty(Series))
{
- if(new ExcelRangeBase(_chart.WorkSheet, Series).Columns > 1)
+ if (new ExcelRangeBase(_chart.WorkSheet, Series).Columns > 1)
{
throw (new InvalidOperationException("A serie cannot be multiple columns. Please add one serie per column to create a cache"));
}
var node = GetTopNode(Series, _seriesTopPath);
-
+
CreateCache(Series, node);
}
@@ -598,8 +666,9 @@ public void CreateCache()
CreateCache(XSeries, node);
}
+
}
- private void CreateCache(string address, XmlNode node)
+ internal void CreateCache(string address, XmlNode node)
{
//var ws = _chart.WorkSheet;
var wb = _chart.WorkSheet.Workbook;
@@ -633,7 +702,7 @@ private void CreateCache(string address, XmlNode node)
}
CreateCacheFromRange(node, ws.Cells[address]);
}
-
+
}
private void CreateCacheFromRange(XmlNode node, ExcelRangeBase range)
@@ -641,17 +710,27 @@ private void CreateCacheFromRange(XmlNode node, ExcelRangeBase range)
if (range == null) return;
var startRow = range._fromRow;
var items = 0;
- var cse = new CellStoreEnumerator(range.Worksheet._values, startRow,range._fromCol, range._toRow, range._toCol);
+ var cse = new CellStoreEnumerator(range.Worksheet._values, startRow, range._fromCol, range._toRow, range._toCol);
while (cse.Next())
{
var v = cse.Value._value;
if (v != null)
{
- var d = Utils.TypeConversion.ConvertUtil.GetValueDouble(v);
+ string xmlValue = "";
+ if (v.IsNumeric())
+ {
+ var d = Utils.TypeConversion.ConvertUtil.GetValueDouble(v);
+ xmlValue = Utils.TypeConversion.ConvertUtil.GetValueForXml(d, range.Worksheet.Workbook.Date1904);
+ }
+ else
+ {
+ xmlValue = string.Format(CultureInfo.InvariantCulture, v.ToString());
+ }
+
var ptNode = node.OwnerDocument.CreateElement("c", "pt", ExcelPackage.schemaChart);
node.AppendChild(ptNode);
ptNode.SetAttribute("idx", (cse.Row - startRow).ToString(CultureInfo.InvariantCulture));
- ptNode.InnerXml = $"{Utils.TypeConversion.ConvertUtil.GetValueForXml(d, range.Worksheet.Workbook.Date1904)}";
+ ptNode.InnerXml = $"{xmlValue}";
items++;
}
}
@@ -700,10 +779,10 @@ private XmlNode GetTopNode(string address, string seriesTopPath)
if (addr.IsExternal)
{
var erIx = wb.ExternalLinks.GetExternalLink(addr._wb);
- if(erIx>=0)
+ if (erIx >= 0)
{
var er = wb.ExternalLinks[erIx].As.ExternalWorkbook;
- if(er.Package!=null)
+ if (er.Package != null)
{
var ws = er.Package.Workbook.Worksheets[addr.WorkSheetName];
var range = ws.Cells[addr.LocalAddress];
@@ -712,7 +791,7 @@ private XmlNode GetTopNode(string address, string seriesTopPath)
else
{
var ws = er.CachedWorksheets[addr.WorkSheetName];
- if(ws==null)
+ if (ws == null)
{
v = null;
}
@@ -728,7 +807,7 @@ private XmlNode GetTopNode(string address, string seriesTopPath)
v = null;
}
}
- else
+ else
{
ExcelWorksheet ws;
if (string.IsNullOrEmpty(addr.WorkSheetName))
@@ -752,22 +831,22 @@ private XmlNode GetTopNode(string address, string seriesTopPath)
string cachePath;
bool isNum;
- if(Utils.TypeConversion.ConvertUtil.IsNumericOrDate(v) || v is null)
+ if (Utils.TypeConversion.ConvertUtil.IsNumericOrDate(v) || v is null)
{
cachePath = string.Format("{0}/c:numRef/c:numCache", seriesTopPath);
isNum = true;
}
else
{
- cachePath=string.Format("{0}/c:strRef/c:strCache", seriesTopPath);
+ cachePath = string.Format("{0}/c:strRef/c:strCache", seriesTopPath);
isNum = false;
}
var node = CreateNode(cachePath);
if (node.HasChildNodes)
{
- if(isNum)
+ if (isNum)
{
- if(node.FirstChild.LocalName== "formatCode")
+ if (node.FirstChild.LocalName == "formatCode")
{
node.InnerXml = node.FirstChild.OuterXml;
}
@@ -778,7 +857,7 @@ private XmlNode GetTopNode(string address, string seriesTopPath)
}
else
{
- node.InnerXml = "";
+ node.InnerXml = "";
}
}
CreateNode($"{cachePath}/c:ptCount");
@@ -796,14 +875,14 @@ internal static XmlElement CreateSerieElement(ExcelChart chart)
//If the chart is added from a chart template, then use the chart templates series xml
if (chart._drawings._seriesTemplateXml != null)
{
- if(chart._drawings._seriesTemplateXml.Count != 0)
+ if (chart._drawings._seriesTemplateXml.Count != 0)
{
ser.InnerXml = chart._drawings._seriesTemplateXml[0];
return ser;
}
}
- int idx = FindIndex(chart._topChart??chart);
+ int idx = FindIndex(chart._topChart ?? chart);
ser.InnerXml = string.Format("{2}{5}{0}{3}{4}", AddExplosion(chart.ChartType), idx, AddSpPrAndScatterPoint(chart.ChartType), AddAxisNodes(chart.ChartType), AddSmooth(chart.ChartType), AddMarker(chart.ChartType));
return ser;
}
diff --git a/src/EPPlus/Drawing/Chart/ExcelLineChartSerie.cs b/src/EPPlus/Drawing/Chart/ExcelLineChartSerie.cs
index f1e5f8ad6..d5f78979d 100644
--- a/src/EPPlus/Drawing/Chart/ExcelLineChartSerie.cs
+++ b/src/EPPlus/Drawing/Chart/ExcelLineChartSerie.cs
@@ -10,13 +10,14 @@ Date Author Change
*************************************************************************************************
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*************************************************************************************************/
+using OfficeOpenXml.Drawing.Interfaces;
using System;
using System.Collections.Generic;
+using System.Data;
+using System.Drawing;
using System.Globalization;
using System.Text;
using System.Xml;
-using System.Drawing;
-using OfficeOpenXml.Drawing.Interfaces;
namespace OfficeOpenXml.Drawing.Chart
{
diff --git a/src/EPPlus/Style/RichText/ExcelParagraph.cs b/src/EPPlus/Style/RichText/ExcelParagraph.cs
index 841314f29..e90136448 100644
--- a/src/EPPlus/Style/RichText/ExcelParagraph.cs
+++ b/src/EPPlus/Style/RichText/ExcelParagraph.cs
@@ -12,6 +12,7 @@ Date Author Change
*************************************************************************************************/
using OfficeOpenXml.Drawing;
using OfficeOpenXml.Drawing.Interfaces;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using System;
using System.Collections.Generic;
using System.Text;
@@ -30,6 +31,7 @@ internal ExcelParagraph(IPictureRelationDocument pictureRelationDocument, XmlNam
}
const string TextPath = "../a:t";
+ const string FldPath = "../a:fld";
///
/// Text
///
diff --git a/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs b/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs
index 0c75e93be..841b5081a 100644
--- a/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs
+++ b/src/EPPlus/Style/RichText/ExcelParagraphCollection.cs
@@ -10,14 +10,15 @@ Date Author Change
*************************************************************************************************
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*************************************************************************************************/
+using OfficeOpenXml.Drawing;
using System;
using System.Collections.Generic;
-using System.Text;
-using System.Xml;
-using OfficeOpenXml.Drawing;
using System.Drawing;
-using System.Linq;
using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml;
namespace OfficeOpenXml.Style
{
@@ -213,6 +214,30 @@ public string Text
}
}
}
+
+ internal List> GetParagraphTextLists()
+ {
+ List> strings = new List>();
+ var pars = TopNode.SelectNodes(_path, NameSpaceManager);
+
+ foreach(XmlNode paragraph in pars)
+ {
+ List paragraphTexts = new List();
+ foreach (XmlNode node in paragraph.ChildNodes)
+ {
+ if (node.LocalName == "fld" || node.LocalName == "r")
+ {
+ var textNode = node.SelectSingleNode("a:t", NameSpaceManager);
+ var text = textNode.InnerText;
+ paragraphTexts.Add(text);
+ }
+ }
+ strings.Add(paragraphTexts);
+ }
+
+ return strings;
+ }
+
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
diff --git a/src/EPPlusTest/Drawing/Chart/ChartSeriesTest.cs b/src/EPPlusTest/Drawing/Chart/ChartSeriesTest.cs
index f6cea68a8..eb4ae0bd4 100644
--- a/src/EPPlusTest/Drawing/Chart/ChartSeriesTest.cs
+++ b/src/EPPlusTest/Drawing/Chart/ChartSeriesTest.cs
@@ -249,5 +249,169 @@ public void SimpleChartDataLabels()
SaveAndCleanup(p);
}
}
+
+ [TestMethod]
+ //TODO: This test is one instance of a larger problem
+ //Many datalabels have different allowed positions depending on chart type
+ //Going against it will often create corrupt files.
+ //See microsoft offical documentation:
+ //"MS-OE376" page 659 2.1.1475 Part 4 Section 5.7.2.48, dLblPos (Data Label Position) for details.
+ public void TopIsDisallowedOnBarDataLabels()
+ {
+ using (var p = new ExcelPackage())
+ {
+ var ws = p.Workbook.Worksheets.Add("DataLabelSheet");
+
+ ws.Cells["A1"].Value = "Week";
+ ws.Cells["B1"].Value = "Income";
+
+ ws.Cells["A2:A10"].Formula = $"\"Week \"&(ROW()-1)";
+ ws.Cells["B2:B10"].Formula = $"(ROW()-1)*7";
+ ws.Calculate();
+
+ var chart = ws.Drawings.AddBarChart("columnChart", eBarChartType.ColumnClustered);
+ chart.Series.Add(ws.Cells["B2:B10"], ws.Cells["A2:A10"]);
+
+ var SeriesDataLabel = chart.Series[0].DataLabel;
+
+ Assert.Throws(() => SeriesDataLabel.Position = eLabelPosition.Top);
+ }
+ }
+
+ [TestMethod]
+ public void CreateFileWithDataLabelsManualAndGeneral()
+ {
+ using (var p = OpenPackage("dlblMissMatchTest.xlsx", true))
+ {
+ var ws = p.Workbook.Worksheets.Add("DataLabelSheet");
+
+ ws.Cells["A1"].Value = "Week";
+ ws.Cells["B1"].Value = "Income";
+
+ ws.Cells["A2:A10"].Formula = $"\"Week \"&(ROW()-1)";
+ ws.Cells["B2:B10"].Formula = $"(ROW()-1)*7";
+ ws.Cells["C2:C10"].Formula = $"\"Comment \"&(ROW()-1)";
+ ws.Calculate();
+
+ var chart = ws.Drawings.AddBarChart("columnChart", eBarChartType.ColumnClustered);
+
+ var barSerie = chart.Series.Add(ws.Cells["B2:B10"], ws.Cells["A2:A10"]);
+ var sDlbl = barSerie.DataLabel;
+
+ sDlbl.Separator = ",";
+ sDlbl.ShowValue = true;
+ sDlbl.ShowCategory = true;
+ sDlbl.Position = eLabelPosition.OutEnd;
+
+ sDlbl.SelectRange(ws.Cells["C2:C10"]);
+ Assert.AreEqual(ws.Cells["C2:C10"], barSerie.DataLabel.DataLabelRange);
+
+ Assert.AreEqual("C7", chart.Series[0].DataLabel.DataLabels[5].SingleCellAddressFromSeries.Address);
+ Assert.AreEqual("Comment 6", ws.Cells["C7"].Text);
+
+ //Ensure replacement text works
+ var labelFive = chart.Series[0].DataLabel.DataLabels[5];
+ labelFive.SetText("My replacement text");
+
+ Assert.AreEqual("My replacement text", labelFive.GetExistingParagraphStrings()[0][0]);
+
+ SaveAndCleanup(p);
+ }
+
+ //Ensure data is read correctly after write
+ using (var p = OpenPackage("dlblMissMatchTest.xlsx"))
+ {
+ var ws = p.Workbook.Worksheets[0];
+ var chart = ws.Drawings[0].As.Chart.BarChart;
+
+ var barSerie = chart.Series[0];
+ Assert.AreEqual(ws.Cells["C2:C10"], barSerie.DataLabel.DataLabelRange);
+
+ Assert.AreEqual("C7", chart.Series[0].DataLabel.DataLabels[5].SingleCellAddressFromSeries.Address);
+ Assert.AreEqual("Comment 6", ws.Cells["C7"].Text);
+
+ //Ensure replacement text works
+ var labelFive = chart.Series[0].DataLabel.DataLabels[5];
+ Assert.AreEqual("My replacement text", labelFive.GetExistingParagraphStrings()[0][0]);
+ }
+ }
+
+ [TestMethod]
+ public void ReadSimpleFile()
+ {
+ using (var package = OpenTemplatePackage("editedDataLabel.xlsx"))
+ {
+ var ws = package.Workbook.Worksheets[0];
+
+ var myChart = ws.Drawings[0].As.Chart.BarChart;
+
+ var lbl = myChart.Series[0].DataLabel.DataLabels[0];
+
+ var lblTxtBody = myChart.Series[0].DataLabel.DataLabels[0].TextBody;
+
+ SaveAndCleanup(package);
+ }
+ }
+
+ [TestMethod]
+ public void ReadFile()
+ {
+ using (var package = OpenTemplatePackage("S1008_NoComment.xlsx"))
+ {
+ var ws = package.Workbook.Worksheets[0];
+
+ var chart = ws.Drawings[0].As.Chart.LineChart;
+
+ chart.Series[0].DataLabel.Separator = " ";
+
+ //Select comment range
+ chart.Series[0].DataLabel.SelectRange(ws.Cells["E1:E53"]);
+
+ //Set the relevant labels to not show value
+ chart.Series[0].DataLabel.DataLabels[21].ShowValue = false;
+ chart.Series[0].DataLabel.DataLabels[26].ShowValue = false;
+
+ Assert.AreEqual("E22", chart.Series[0].DataLabel.DataLabels[21].SingleCellAddressFromSeries.Address);
+ Assert.AreEqual("First comment", ws.Cells["E22"].Text);
+
+ SaveAndCleanup(package);
+ }
+ }
+
+ [TestMethod]
+ public void TestAddCommentRangeToExistingFile()
+ {
+ using (var package = OpenTemplatePackage("S1008_NoComment.xlsx"))
+ {
+ var ws = package.Workbook.Worksheets[0];
+
+ var commentText = "Added Comment";
+
+ ws.Cells["E30"].Value = commentText;
+
+ var chart = ws.Drawings[0].As.Chart.LineChart;
+ chart.Series[0].DataLabel.Separator = " ";
+
+ //Select comment range
+ chart.Series[0].DataLabel.SelectRange(ws.Cells["E2:E53"]);
+
+ //Note that since we start on E2 the datalabel idx becomes 20 for row 22 etc.
+ var label1 = chart.Series[0].DataLabel.DataLabels[20];
+ var label2 = chart.Series[0].DataLabel.DataLabels[25];
+ var label3 = chart.Series[0].DataLabel.DataLabels[28];
+
+ //Set the relevant labels to not show value as we only want them to show comments
+ label1.ShowValue = false;
+ label2.ShowValue = false;
+ label3.ShowValue = false;
+
+ Assert.AreEqual("E30", chart.Series[0].DataLabel.DataLabels[28].SingleCellAddressFromSeries.Address);
+ Assert.AreEqual(commentText, ws.Cells["E30"].Text);
+
+ //XforSave is set soley on labels that are not truly neccesary
+
+ SaveAndCleanup(package);
+ }
+ }
}
}