diff --git a/.gitignore b/.gitignore
index 4bcc6612..4bc5bde0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,4 +52,12 @@ _ReSharper*/
~$*
#NuGet
-packages/
\ No newline at end of file
+packages/
+.idea/.idea.EPPlus/.idea/contentModel.xml
+.idea/.idea.EPPlus/.idea/encodings.xml
+.idea/.idea.EPPlus/.idea/indexLayout.xml
+.idea/.idea.EPPlus/.idea/misc.xml
+.idea/.idea.EPPlus/.idea/modules.xml
+.idea/.idea.EPPlus/.idea/vcs.xml
+.idea/.idea.EPPlus/.idea/workspace.xml
+.idea/.idea.EPPlus/riderModule.iml
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
index d10f0af7..9dd780d8 100644
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
+++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
@@ -113,7 +113,15 @@ private XmlNode AddDrawing(ExcelRangeBase cell)
{
ix = ~ix;
var prevDraw = _drawings[ix] as ExcelVmlDrawingBase;
- prevDraw.TopNode.ParentNode.InsertBefore(node, prevDraw.TopNode);
+ var parentNode = prevDraw.TopNode.ParentNode;
+ if (parentNode!=null)
+ {
+ parentNode.InsertBefore(node, prevDraw.TopNode);
+ }
+ else
+ {
+ VmlDrawingXml.DocumentElement.AppendChild(node);
+ }
}
else
{
diff --git a/EPPlus/EPPlus.csproj b/EPPlus/EPPlus.csproj
index 1f411ce0..00b7eafb 100644
--- a/EPPlus/EPPlus.csproj
+++ b/EPPlus/EPPlus.csproj
@@ -25,7 +25,7 @@
3.5
- v3.5
+ v4.0
publish\
true
Disk
diff --git a/EPPlus/ExcelCommentCollection.cs b/EPPlus/ExcelCommentCollection.cs
index 9835142f..3b68d9d7 100644
--- a/EPPlus/ExcelCommentCollection.cs
+++ b/EPPlus/ExcelCommentCollection.cs
@@ -218,10 +218,15 @@ public void Remove(ExcelComment comment)
}
if (comment==c)
{
- comment.TopNode.ParentNode.RemoveChild(comment.TopNode); //Remove VML
- comment._commentHelper.TopNode.ParentNode.RemoveChild(comment._commentHelper.TopNode); //Remove Comment
+ //
+ comment.TopNode.ParentNode?.RemoveChild(comment.TopNode); //Remove VML
+ comment._commentHelper.TopNode.ParentNode?.RemoveChild(comment._commentHelper.TopNode); //Remove Comment
+
+ if (Worksheet.VmlDrawingsComments._drawings.ContainsKey(id))
+ {
+ Worksheet.VmlDrawingsComments._drawings.Delete(id);
+ }
- Worksheet.VmlDrawingsComments._drawings.Delete(id);
_list.RemoveAt(i);
Worksheet._commentsStore.Delete(comment.Range._fromRow, comment.Range._fromCol, 1, 1, false); //Issue 15549, Comments should not be shifted
var ci = new CellsStoreEnumerator(Worksheet._commentsStore);
diff --git a/EPPlus/ExcelRangeBase.cs b/EPPlus/ExcelRangeBase.cs
index 0519de60..50921ec2 100644
--- a/EPPlus/ExcelRangeBase.cs
+++ b/EPPlus/ExcelRangeBase.cs
@@ -253,11 +253,11 @@ private static void Set_StyleName(ExcelRangeBase range, object value, int row, i
private static void Set_Value(ExcelRangeBase range, object value, int row, int col)
{
var sfi = range._worksheet._formulas.GetValue(row, col);
- if (sfi is int)
+ if (sfi is int && !range.IsSingleCell)
{
range.SplitFormulas(range._worksheet.Cells[row, col]);
}
- if (sfi != null) range._worksheet._formulas.SetValue(row, col, string.Empty);
+ // if (sfi != null) range._worksheet._formulas.SetValue(row, col, string.Empty);
range._worksheet.SetValueInner(row, col, value);
}
private static void Set_Formula(ExcelRangeBase range, object value, int row, int col)
@@ -1270,7 +1270,11 @@ public bool Merge
set
{
IsRangeValid("merging");
- _worksheet.MergedCells.Clear(this);
+ if (!_worksheet.DisableMergeValidation)
+ {
+ _worksheet.MergedCells.Clear(this);
+ }
+
if (value)
{
_worksheet.MergedCells.Add(new ExcelAddressBase(FirstAddress), true);
@@ -1608,7 +1612,7 @@ private void SplitFormula(ExcelAddressBase address, int ix)
//The formula is inside the currenct range, remove it
if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside)
{
- _worksheet._sharedFormulas.Remove(ix);
+ // _worksheet._sharedFormulas.Remove(ix);
return;
//fRange.SetSharedFormulaID(int.MinValue);
}
@@ -2609,29 +2613,35 @@ public void Copy(ExcelRangeBase Destination, ExcelRangeCopyOptionFlags? excelRan
}
var copiedMergedCells = new Dictionary();
//Merged cells
- var csem = new CellsStoreEnumerator(_worksheet.MergedCells._cells, _fromRow, _fromCol, _toRow, _toCol);
- while (csem.Next())
+
+ for (var row = _fromRow; row <= _toRow; row++)
{
- if (!copiedMergedCells.ContainsKey(csem.Value))
+ for (var col = _fromCol; col <= _toCol; col++)
{
- var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[csem.Value]);
- var collideResult = Collide(adr);
- if (collideResult == eAddressCollition.Inside || collideResult == eAddressCollition.Equal)
- {
- copiedMergedCells.Add(csem.Value, new ExcelAddress(
- Destination._fromRow + (adr.Start.Row - _fromRow),
- Destination._fromCol + (adr.Start.Column - _fromCol),
- Destination._fromRow + (adr.End.Row - _fromRow),
- Destination._fromCol + (adr.End.Column - _fromCol)));
- }
- else
+ var key = _worksheet.GetMergeCellId(row, col) - 1;
+ if (key >= 0 && !copiedMergedCells.ContainsKey(key))
{
- //Partial merge of the address ignore.
- copiedMergedCells.Add(csem.Value, null);
+ var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[key]);
+ var collideResult = Collide(adr);
+ if (collideResult == eAddressCollition.Inside || collideResult == eAddressCollition.Equal)
+ {
+ copiedMergedCells.Add(
+ key,
+ new ExcelAddress(
+ Destination._fromRow + (adr.Start.Row - _fromRow),
+ Destination._fromCol + (adr.Start.Column - _fromCol),
+ Destination._fromRow + (adr.End.Row - _fromRow),
+ Destination._fromCol + (adr.End.Column - _fromCol)));
+ }
+ else
+ {
+ //Partial merge of the address ignore.
+ copiedMergedCells.Add(key, null);
+ }
}
}
}
-
+
Destination._worksheet.MergedCells.Clear(new ExcelAddressBase(Destination._fromRow, Destination._fromCol, Destination._fromRow + toRow - 1, Destination._fromCol + toCol - 1));
Destination._worksheet._values.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
diff --git a/EPPlus/ExcelStyles.cs b/EPPlus/ExcelStyles.cs
index 79708310..cfdc8a20 100644
--- a/EPPlus/ExcelStyles.cs
+++ b/EPPlus/ExcelStyles.cs
@@ -953,6 +953,7 @@ internal int CloneStyle(ExcelStyles style, int styleID, bool isNamedStyle, bool
xfs = style.CellXfs[styleID];
}
ExcelXfs newXfs = xfs.Copy(this);
+ newXfs.XfId = 0;
//Numberformat
if (xfs.NumberFormatId > 0)
{
@@ -1026,7 +1027,7 @@ internal int CloneStyle(ExcelStyles style, int styleID, bool isNamedStyle, bool
}
//Named style reference
- if (xfs.XfId > 0)
+ if (isNamedStyle && xfs.XfId > 0)
{
var id = style.CellStyleXfs[xfs.XfId].Id;
var newId = CellStyleXfs.FindIndexByID(id);
diff --git a/EPPlus/ExcelWorkbook.cs b/EPPlus/ExcelWorkbook.cs
index 0887bd35..f7880b24 100644
--- a/EPPlus/ExcelWorkbook.cs
+++ b/EPPlus/ExcelWorkbook.cs
@@ -175,6 +175,11 @@ internal void GetDefinedNames()
{
string fullAddress = elem.InnerText;
+ if(fullAddress.EndsWith("!#REF!"))
+ {
+ continue;
+ }
+
int localSheetID;
ExcelWorksheet nameWorksheet;
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs
index ac1ff800..2a6e7e3d 100644
--- a/EPPlus/ExcelWorksheet.cs
+++ b/EPPlus/ExcelWorksheet.cs
@@ -185,13 +185,69 @@ public Formulas Clone()
///
public class MergeCellsCollection : IEnumerable
{
- internal MergeCellsCollection()
+ private struct AddressDimensions
{
+ internal int StartRow;
+ internal int StartCol;
+
+ internal int EndRow;
+
+ internal int EndCol;
+
+ internal AddressDimensions(int startRow, int startCol, int endRow, int endCol)
+ {
+ StartRow = startRow;
+ StartCol = startCol;
+ EndRow = endRow;
+ EndCol = endCol;
+ }
+ }
+
+ private readonly ExcelWorksheet _ws;
+ internal MergeCellsCollection(ExcelWorksheet ws)
+ {
+ _ws = ws;
}
internal CellStore _cells = new CellStore();
List _list = new List();
internal List List { get { return _list; } }
+
+ private IDictionary _mergedAreasDimsCache = new Dictionary();
+
+ ///
+ /// Get MergeCell Index No
+ ///
+ ///
+ ///
+ ///
+ public int GetId(int row, int column)
+ {
+ for (int i = 0; i < _list.Count; i++)
+ {
+ var mergedAddress = _list[i];
+ if(!string.IsNullOrEmpty( mergedAddress))
+ {
+ if (!_mergedAreasDimsCache.ContainsKey(mergedAddress))
+ {
+ ExcelCellBase.GetRowColFromAddress(mergedAddress, out var startRow, out var startColumn, out int toRow, out int toColumn);
+ _mergedAreasDimsCache.Add(mergedAddress, new AddressDimensions(startRow, startColumn, toRow, toColumn));
+ }
+
+ var mergedDims = _mergedAreasDimsCache[mergedAddress];
+
+ if (mergedDims.StartRow <= row && row <= mergedDims.EndRow)
+ {
+ if (mergedDims.StartCol <= column && column <= mergedDims.EndCol)
+ {
+ return i + 1;
+ }
+ }
+ }
+ }
+ return 0;
+ }
+
public string this[int row, int column]
{
get
@@ -226,6 +282,15 @@ internal void Add(ExcelAddressBase address, bool doValidate)
lock (this)
{
ix = _list.Count;
+ var addressDimension = new AddressDimensions(address.Start.Row, address.Start.Column, address.End.Row, address.End.Column);
+ if (!_mergedAreasDimsCache.ContainsKey(address.Address))
+ {
+ _mergedAreasDimsCache.Add(address.Address, addressDimension);
+ }
+ else
+ {
+ _mergedAreasDimsCache[address.Address] = addressDimension;
+ }
_list.Add(address.Address);
SetIndex(address, ix);
}
@@ -324,29 +389,33 @@ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
#endregion
internal void Clear(ExcelAddressBase Destination)
{
- var cse = new CellsStoreEnumerator(_cells, Destination._fromRow, Destination._fromCol, Destination._toRow, Destination._toCol);
var used = new HashSet();
- while (cse.Next())
+ _cells.Clear(Destination._fromRow, Destination._fromCol, Destination._toRow - Destination._fromRow + 1, Destination._toCol - Destination._fromCol + 1);
+ for (var row = Destination._fromRow; row <= Destination._toRow; row++)
{
- var v = cse.Value;
- if (!used.Contains(v) && _list[v] != null)
+ for (var col = Destination._fromCol; col <= Destination._toCol; col++)
{
- var adr = new ExcelAddressBase(_list[v]);
- if (!(Destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Inside || Destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Equal))
+ var mergedRangeId = GetId(row, col);
+
+ if (mergedRangeId == 0 || used.Contains(mergedRangeId))
{
- throw (new InvalidOperationException(string.Format("Can't delete/overwrite merged cells. A range is partly merged with the another merged range. {0}", adr._address)));
+ continue;
}
- used.Add(v);
- }
- }
- _cells.Clear(Destination._fromRow, Destination._fromCol, Destination._toRow - Destination._fromRow + 1, Destination._toCol - Destination._fromCol + 1);
- foreach (var i in used)
- {
- _list[i] = null;
+ used.Add(mergedRangeId);
+ // из метода GetId возвращается индекс в списке _list + 1, т.к. результат 0 означает, что значение в списке не найдено
+ // поэтому, чтобы восстановить исходный индекс, передаем mergedRangeId-1
+ var mergedRangeAddress = new ExcelAddressBase(_list[mergedRangeId-1]);
+ if (Destination.Collide(mergedRangeAddress) == ExcelAddressBase.eAddressCollition.Partly)
+ {
+ throw (new InvalidOperationException(string.Format("Can't delete/overwrite merged cells. A range is partly merged with the another merged range. {0}", mergedRangeAddress._address)));
+ }
+ _list[mergedRangeId-1] = null;
+ }
}
}
}
+ public bool DisableMergeValidation { get; set; }
//internal CellStore