diff --git a/ClosedXML/Attributes/XLColumnAttribute.cs b/ClosedXML/Attributes/XLColumnAttribute.cs
index 41b541b..526dcb0 100644
--- a/ClosedXML/Attributes/XLColumnAttribute.cs
+++ b/ClosedXML/Attributes/XLColumnAttribute.cs
@@ -23,7 +23,7 @@
{
var attribute = GetXLColumnAttribute(mi);
if (attribute == null) return null;
- return XLHelper.IsNullOrWhiteSpace(attribute.Header) ? null : attribute.Header;
+ return String.IsNullOrWhiteSpace(attribute.Header) ? null : attribute.Header;
}
internal static Int32 GetOrder(MemberInfo mi)
diff --git a/ClosedXML/ClosedXML.csproj b/ClosedXML/ClosedXML.csproj
index 70c85b8..4d4338c 100644
--- a/ClosedXML/ClosedXML.csproj
+++ b/ClosedXML/ClosedXML.csproj
@@ -76,6 +76,7 @@
+
@@ -89,6 +90,7 @@
+
diff --git a/ClosedXML/Excel/CalcEngine/CalcEngine.cs b/ClosedXML/Excel/CalcEngine/CalcEngine.cs
index def655b..c1a1aa1 100644
--- a/ClosedXML/Excel/CalcEngine/CalcEngine.cs
+++ b/ClosedXML/Excel/CalcEngine/CalcEngine.cs
@@ -77,18 +77,20 @@
// skip leading equals sign
if (_len > 0 && _expr[0] == '=')
- {
_ptr++;
- }
+
+ // skip leading +'s
+ while (_len > _ptr && _expr[_ptr] == '+')
+ _ptr++;
// parse the expression
var expr = ParseExpression();
// check for errors
- if (_token.ID != TKID.END)
- {
- Throw();
- }
+ if (_token.ID == TKID.OPEN)
+ Throw("Unknown function: " + expr.LastParseItem);
+ else if (_token.ID != TKID.END)
+ Throw("Expected end of expression");
// optimize expression
if (_optimize)
@@ -113,10 +115,9 @@
///
public object Evaluate(string expression)
{
- var x = //Parse(expression);
- _cache != null
- ? _cache[expression]
- : Parse(expression);
+ var x = _cache != null
+ ? _cache[expression]
+ : Parse(expression);
return x.Evaluate();
}
@@ -425,11 +426,11 @@
var pCnt = p == null ? 0 : p.Count;
if (fnDef.ParmMin != -1 && pCnt < fnDef.ParmMin)
{
- Throw("Too few parameters.");
+ Throw(string.Format("Too few parameters for function '{0}'. Expected a minimum of {1} and a maximum of {2}.", id, fnDef.ParmMin, fnDef.ParmMax));
}
if (fnDef.ParmMax != -1 && pCnt > fnDef.ParmMax)
{
- Throw("Too many parameters.");
+ Throw(string.Format("Too many parameters for function '{0}'.Expected a minimum of {1} and a maximum of {2}.", id, fnDef.ParmMin, fnDef.ParmMax));
}
x = new FunctionExpression(fnDef, p);
break;
@@ -715,7 +716,7 @@
if (isEnclosed && disallowedSymbols.Contains(c))
break;
- var allowedSymbols = new List() { '_' };
+ var allowedSymbols = new List() { '_', '.' };
if (!isLetter && !isDigit
&& !(isEnclosed || allowedSymbols.Contains(c))
@@ -773,10 +774,10 @@
}
// make sure the list was closed correctly
- if (_token.ID != TKID.CLOSE)
- {
- Throw();
- }
+ if (_token.ID == TKID.OPEN)
+ Throw("Unknown function: " + expr.LastParseItem);
+ else if (_token.ID != TKID.CLOSE)
+ Throw("Syntax error: expected ')'");
// done
return parms;
@@ -818,7 +819,7 @@
private static void Throw(string msg)
{
- throw new Exception(msg);
+ throw new ExpressionParseException(msg);
}
#endregion ** static helpers
diff --git a/ClosedXML/Excel/CalcEngine/Expression.cs b/ClosedXML/Excel/CalcEngine/Expression.cs
index fca1cb5..b9a29ca 100644
--- a/ClosedXML/Excel/CalcEngine/Expression.cs
+++ b/ClosedXML/Excel/CalcEngine/Expression.cs
@@ -3,10 +3,16 @@
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Threading;
namespace ClosedXML.Excel.CalcEngine
{
+ internal abstract class ExpressionBase
+ {
+ public abstract string LastParseItem { get; }
+ }
+
///
/// Base class that represents parsed expressions.
///
@@ -17,13 +23,13 @@
/// object val = expr.Evaluate();
///
///
- internal class Expression : IComparable
+ internal class Expression : ExpressionBase, IComparable
{
//---------------------------------------------------------------------------
#region ** fields
- internal Token _token;
+ internal readonly Token _token;
#endregion ** fields
@@ -222,6 +228,17 @@
}
#endregion ** IComparable
+
+ //---------------------------------------------------------------------------
+
+ #region ** ExpressionBase
+
+ public override string LastParseItem
+ {
+ get { return _token?.Value?.ToString() ?? "Unknown value"; }
+ }
+
+ #endregion ** ExpressionBase
}
///
@@ -259,6 +276,11 @@
? new Expression(this.Evaluate())
: this;
}
+
+ public override string LastParseItem
+ {
+ get { return _expr.LastParseItem; }
+ }
}
///
@@ -342,6 +364,11 @@
? new Expression(this.Evaluate())
: this;
}
+
+ public override string LastParseItem
+ {
+ get { return _rgt.LastParseItem; }
+ }
}
///
@@ -350,14 +377,13 @@
internal class FunctionExpression : Expression
{
// ** fields
- private FunctionDefinition _fn;
+ private readonly FunctionDefinition _fn;
- private List _parms;
+ private readonly List _parms;
// ** ctor
internal FunctionExpression()
- {
- }
+ { }
public FunctionExpression(FunctionDefinition function, List parms)
{
@@ -390,6 +416,11 @@
? new Expression(this.Evaluate())
: this;
}
+
+ public override string LastParseItem
+ {
+ get { return _parms.Last().LastParseItem; }
+ }
}
///
@@ -397,8 +428,8 @@
///
internal class VariableExpression : Expression
{
- private Dictionary _dct;
- private string _name;
+ private readonly Dictionary _dct;
+ private readonly string _name;
public VariableExpression(Dictionary dct, string name)
{
@@ -410,6 +441,11 @@
{
return _dct[_name];
}
+
+ public override string LastParseItem
+ {
+ get { return _name; }
+ }
}
///
@@ -419,7 +455,7 @@
Expression,
IEnumerable
{
- private object _value;
+ private readonly object _value;
// ** ctor
internal XObjectExpression(object value)
@@ -447,6 +483,11 @@
{
return (_value as IEnumerable).GetEnumerator();
}
+
+ public override string LastParseItem
+ {
+ get { return Value.ToString(); }
+ }
}
///
@@ -455,6 +496,11 @@
internal class EmptyValueExpression : Expression
{
internal EmptyValueExpression() { }
+
+ public override string LastParseItem
+ {
+ get { return ""; }
+ }
}
internal class ErrorExpression : Expression
diff --git a/ClosedXML/Excel/CalcEngine/ExpressionParseException.cs b/ClosedXML/Excel/CalcEngine/ExpressionParseException.cs
new file mode 100644
index 0000000..2de2293
--- /dev/null
+++ b/ClosedXML/Excel/CalcEngine/ExpressionParseException.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Text;
+
+namespace ClosedXML.Excel.CalcEngine
+{
+ ///
+ /// The exception that is thrown when the strings to be parsed to an expression is invalid.
+ ///
+ public class ExpressionParseException : Exception
+ {
+ ///
+ /// Initializes a new instance of the ExpressionParseException class with a
+ /// specified error message.
+ ///
+ /// The message that describes the error.
+ public ExpressionParseException(string message)
+ : base(message)
+ {
+ }
+ }
+}
diff --git a/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs b/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs
index 629ac70..801a195 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs
@@ -1,4 +1,4 @@
-using ClosedXML.Excel.CalcEngine.Exceptions;
+using ClosedXML.Excel.CalcEngine.Exceptions;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -16,7 +16,7 @@
//ce.RegisterFunction("COLUMNS", , Columns); // Returns the number of columns in a reference
//ce.RegisterFunction("FORMULATEXT", , Formulatext); // Returns the formula at the given reference as text
//ce.RegisterFunction("GETPIVOTDATA", , Getpivotdata); // Returns data stored in a PivotTable report
- ce.RegisterFunction("HLOOKUP", 4, Hlookup); // Looks in the top row of an array and returns the value of the indicated cell
+ ce.RegisterFunction("HLOOKUP", 3, 4, Hlookup); // Looks in the top row of an array and returns the value of the indicated cell
//ce.RegisterFunction("HYPERLINK", , Hyperlink); // Creates a shortcut or jump that opens a document stored on a network server, an intranet, or the Internet
//ce.RegisterFunction("INDEX", , Index); // Uses an index to choose a value from a reference or array
//ce.RegisterFunction("INDIRECT", , Indirect); // Returns a reference indicated by a text value
@@ -27,7 +27,7 @@
//ce.RegisterFunction("ROWS", , Rows); // Returns the number of rows in a reference
//ce.RegisterFunction("RTD", , Rtd); // Retrieves real-time data from a program that supports COM automation
//ce.RegisterFunction("TRANSPOSE", , Transpose); // Returns the transpose of an array
- ce.RegisterFunction("VLOOKUP", 4, Vlookup); // Looks in the first column of an array and moves across the row to return the value of a cell
+ ce.RegisterFunction("VLOOKUP", 3, 4, Vlookup); // Looks in the first column of an array and moves across the row to return the value of a cell
}
private static object Hlookup(List p)
@@ -35,20 +35,25 @@
var lookup_value = p[0];
var table_array = p[1] as XObjectExpression;
+ if (table_array == null)
+ throw new NoValueAvailableException("table_array has to be a range");
+
var range_reference = table_array.Value as CellRangeReference;
+ if (range_reference == null)
+ throw new NoValueAvailableException("table_array has to be a range");
+
var range = range_reference.Range;
var row_index_num = (int)(p[2]);
- var range_lookup = p.Count < 4 || (bool)(p[3]);
-
- if (table_array == null || range_reference == null)
- throw new ApplicationException("table_array has to be a range");
+ var range_lookup = p.Count < 4
+ || p[3] is EmptyValueExpression
+ || (bool)(p[3]);
if (row_index_num < 1)
- throw new ApplicationException("col_index_num has to be positive");
+ throw new CellReferenceException("Row index has to be positive");
if (row_index_num > range.RowCount())
- throw new ApplicationException("col_index_num must be smaller or equal to the number of rows in the table array");
+ throw new CellReferenceException("Row index has to be positive");
IXLRangeColumn matching_column;
matching_column = range.FindColumn(c => !c.Cell(1).IsEmpty() && new Expression(c.Cell(1).Value).CompareTo(lookup_value) == 0);
@@ -68,7 +73,7 @@
}
if (matching_column == null)
- throw new ApplicationException("No matches found.");
+ throw new NoValueAvailableException("No matches found.");
return matching_column
.Cell(row_index_num)
@@ -80,20 +85,25 @@
var lookup_value = p[0];
var table_array = p[1] as XObjectExpression;
+ if (table_array == null)
+ throw new NoValueAvailableException("table_array has to be a range");
+
var range_reference = table_array.Value as CellRangeReference;
+ if (range_reference == null)
+ throw new NoValueAvailableException("table_array has to be a range");
+
var range = range_reference.Range;
var col_index_num = (int)(p[2]);
- var range_lookup = p.Count < 4 || (bool)(p[3]);
-
- if (table_array == null || range_reference == null)
- throw new NoValueAvailableException("table_array has to be a range");
+ var range_lookup = p.Count < 4
+ || p[3] is EmptyValueExpression
+ || (bool)(p[3]);
if (col_index_num < 1)
- throw new CellReferenceException("col_index_num has to be positive");
+ throw new CellReferenceException("Column index has to be positive");
if (col_index_num > range.ColumnCount())
- throw new CellReferenceException("col_index_num must be smaller or equal to the number of columns in the table array");
+ throw new CellReferenceException("Colum index must be smaller or equal to the number of columns in the table array");
IXLRangeRow matching_row;
try
diff --git a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
index c4e86ca..12e0995 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
@@ -1,8 +1,8 @@
+using ClosedXML.Excel.CalcEngine.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
-using ClosedXML.Excel.CalcEngine.Functions;
namespace ClosedXML.Excel.CalcEngine
{
@@ -29,7 +29,8 @@
ce.RegisterFunction("EXP", 1, Exp);
ce.RegisterFunction("FACT", 1, Fact);
ce.RegisterFunction("FACTDOUBLE", 1, FactDouble);
- ce.RegisterFunction("FLOOR", 1, Floor);
+ ce.RegisterFunction("FLOOR", 1, 2, Floor);
+ ce.RegisterFunction("FLOOR.MATH", 1, 3, FloorMath);
ce.RegisterFunction("GCD", 1, 255, Gcd);
ce.RegisterFunction("INT", 1, Int);
ce.RegisterFunction("LCM", 1, 255, Lcm);
@@ -120,12 +121,44 @@
private static object Floor(List p)
{
- return Math.Floor(p[0]);
+ double number = p[0];
+ double significance = 1;
+ if (p.Count > 1)
+ significance = p[1];
+
+ if (significance < 0)
+ {
+ number = -number;
+ significance = -significance;
+
+ return -Math.Floor(number / significance) * significance;
+ }
+ else if (significance == 1)
+ return Math.Floor(number);
+ else
+ return Math.Floor(number / significance) * significance;
+ }
+
+ private static object FloorMath(List p)
+ {
+ double number = p[0];
+ double significance = 1;
+ if (p.Count > 1) significance = p[1];
+
+ double mode = 0;
+ if (p.Count > 2) mode = p[2];
+
+ if (number >= 0)
+ return Math.Floor(number / Math.Abs(significance)) * Math.Abs(significance);
+ else if (mode >= 0)
+ return Math.Floor(number / Math.Abs(significance)) * Math.Abs(significance);
+ else
+ return -Math.Floor(-number / Math.Abs(significance)) * Math.Abs(significance);
}
private static object Int(List p)
{
- return (int) ((double) p[0]);
+ return (int)((double)p[0]);
}
private static object Ln(List p)
@@ -135,7 +168,7 @@
private static object Log(List p)
{
- var lbase = p.Count > 1 ? (double) p[1] : 10;
+ var lbase = p.Count > 1 ? (double)p[1] : 10;
return Math.Log(p[0], lbase);
}
@@ -161,7 +194,7 @@
private static object RandBetween(List p)
{
- return _rnd.Next((int) (double) p[0], (int) (double) p[1]);
+ return _rnd.Next((int)(double)p[0], (int)(double)p[1]);
}
private static object Sign(List p)
@@ -240,42 +273,42 @@
private static object Trunc(List p)
{
- return (double) (int) ((double) p[0]);
+ return (double)(int)((double)p[0]);
}
public static double DegreesToRadians(double degrees)
{
- return (Math.PI/180.0)*degrees;
+ return (Math.PI / 180.0) * degrees;
}
public static double RadiansToDegrees(double radians)
{
- return (180.0/Math.PI)*radians;
+ return (180.0 / Math.PI) * radians;
}
public static double GradsToRadians(double grads)
{
- return (grads/200.0)*Math.PI;
+ return (grads / 200.0) * Math.PI;
}
public static double RadiansToGrads(double radians)
{
- return (radians/Math.PI)*200.0;
+ return (radians / Math.PI) * 200.0;
}
public static double DegreesToGrads(double degrees)
{
- return (degrees/9.0)*10.0;
+ return (degrees / 9.0) * 10.0;
}
public static double GradsToDegrees(double grads)
{
- return (grads/10.0)*9.0;
+ return (grads / 10.0) * 9.0;
}
public static double ASinh(double x)
{
- return (Math.Log(x + Math.Sqrt(x*x + 1.0)));
+ return (Math.Log(x + Math.Sqrt(x * x + 1.0)));
}
private static object Acosh(List p)
@@ -295,8 +328,8 @@
private static object Combin(List p)
{
- Int32 n = (int) p[0];
- Int32 k = (int) p[1];
+ Int32 n = (int)p[0];
+ Int32 k = (int)p[1];
return XLMath.Combin(n, k);
}
@@ -305,8 +338,6 @@
return p[0] * (180.0 / Math.PI);
}
-
-
private static object Fact(List p)
{
var num = Math.Floor(p[0]);
@@ -348,15 +379,15 @@
private static int Lcm(int a, int b)
{
if (a == 0 || b == 0) return 0;
- return a * ( b / Gcd(a, b));
+ return a * (b / Gcd(a, b));
}
private static object Mod(List p)
{
- Int32 n = (int)Math.Abs(p[0]);
- Int32 d = (int)p[1];
- var ret = n % d;
- return d < 0 ? ret * -1 : ret;
+ double number = p[0];
+ double divisor = p[1];
+
+ return number - Math.Floor(number / divisor) * divisor;
}
private static object MRound(List p)
@@ -479,7 +510,6 @@
temp = Math.Round(temp, 0, MidpointRounding.AwayFromZero);
return temp * Math.Pow(10, digits);
}
-
}
private static object RoundDown(List p)
@@ -512,7 +542,7 @@
var obj = p[3] as XObjectExpression;
if (obj == null)
- return p[3] * Math.Pow(x , n);
+ return p[3] * Math.Pow(x, n);
Double total = 0;
Int32 i = 0;
@@ -540,26 +570,37 @@
{
case 1:
return tally.Average();
+
case 2:
return tally.Count(true);
+
case 3:
return tally.Count(false);
+
case 4:
return tally.Max();
+
case 5:
return tally.Min();
+
case 6:
return tally.Product();
+
case 7:
return tally.Std();
+
case 8:
return tally.StdP();
+
case 9:
return tally.Sum();
+
case 10:
return tally.Var();
+
case 11:
return tally.VarP();
+
default:
throw new ArgumentException("Function not supported.");
}
@@ -591,19 +632,18 @@
}
}
-
return C;
}
private static double[,] GetArray(Expression expression)
{
var oExp1 = expression as XObjectExpression;
- if (oExp1 == null) return new [,]{{(Double)expression}};
+ if (oExp1 == null) return new[,] { { (Double)expression } };
var range = (oExp1.Value as CellRangeReference).Range;
var rowCount = range.RowCount();
var columnCount = range.ColumnCount();
- var arr = new double[rowCount,columnCount];
+ var arr = new double[rowCount, columnCount];
for (int row = 0; row < rowCount; row++)
{
diff --git a/ClosedXML/Excel/CalcEngine/Functions/Text.cs b/ClosedXML/Excel/CalcEngine/Functions/Text.cs
index f05118e..8ff1da3 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/Text.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/Text.cs
@@ -79,7 +79,7 @@
}
var index = text.IndexOf(srch, start, StringComparison.Ordinal);
if (index == -1)
- throw new Exception("String not found.");
+ throw new ArgumentException("String not found.");
else
return index + 1;
}
@@ -195,7 +195,7 @@
var search = WildcardToRegex((string)p[0]);
var text = (string)p[1];
- if ("" == text) throw new Exception("Invalid input string.");
+ if ("" == text) throw new ArgumentException("Invalid input string.");
var start = 0;
if (p.Count > 2)
@@ -206,12 +206,12 @@
Regex r = new Regex(search, RegexOptions.Compiled | RegexOptions.IgnoreCase);
var match = r.Match(text.Substring(start));
if (!match.Success)
- throw new Exception("Search failed.");
+ throw new ArgumentException("Search failed.");
else
return match.Index + start + 1;
//var index = text.IndexOf(search, start, StringComparison.OrdinalIgnoreCase);
//if (index == -1)
- // throw new Exception("String not found.");
+ // throw new ArgumentException("String not found.");
//else
// return index + 1;
}
@@ -236,7 +236,7 @@
int index = (int)p[3];
if (index < 1)
{
- throw new Exception("Invalid index in Substitute.");
+ throw new ArgumentException("Invalid index in Substitute.");
}
int pos = text.IndexOf(oldText);
while (pos > -1 && index > 1)
diff --git a/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs b/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs
index 80d2663..79d6a70 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs
@@ -59,7 +59,7 @@
public void MakeLU() // Function for LU decomposition
{
- if (!IsSquare()) throw new Exception("The matrix is not square!");
+ if (!IsSquare()) throw new InvalidOperationException("The matrix is not square!");
L = IdentityMatrix(rows, cols);
U = Duplicate();
@@ -79,8 +79,8 @@
k0 = i;
}
}
- if (p == 0)
- throw new Exception("The matrix is singular!");
+ if (p == 0)
+ throw new InvalidOperationException("The matrix is singular!");
var pom1 = pi[k];
pi[k] = pi[k0];
@@ -115,8 +115,8 @@
public XLMatrix SolveWith(XLMatrix v) // Function solves Ax = v in confirmity with solution vector "v"
{
- if (rows != cols) throw new Exception("The matrix is not square!");
- if (rows != v.rows) throw new Exception("Wrong number of results in solution vector!");
+ if (rows != cols) throw new InvalidOperationException("The matrix is not square!");
+ if (rows != v.rows) throw new ArgumentException("Wrong number of results in solution vector!");
if (L == null) MakeLU();
var b = new XLMatrix(rows, 1);
@@ -242,9 +242,9 @@
for (var j = 0; j < nums.Length; j++) matrix[i, j] = double.Parse(nums[j]);
}
}
- catch (FormatException)
+ catch (FormatException fe)
{
- throw new Exception("Wrong input format!");
+ throw new FormatException("Wrong input format!", fe);
}
return matrix;
}
@@ -345,7 +345,7 @@
private static XLMatrix StrassenMultiply(XLMatrix A, XLMatrix B) // Smart matrix multiplication
{
- if (A.cols != B.rows) throw new Exception("Wrong dimension of matrix!");
+ if (A.cols != B.rows) throw new ArgumentException("Wrong dimension of matrix!");
XLMatrix R;
@@ -513,7 +513,7 @@
public static XLMatrix StupidMultiply(XLMatrix m1, XLMatrix m2) // Stupid matrix multiplication
{
- if (m1.cols != m2.rows) throw new Exception("Wrong dimensions of matrix!");
+ if (m1.cols != m2.rows) throw new ArgumentException("Wrong dimensions of matrix!");
var result = ZeroMatrix(m1.rows, m2.cols);
for (var i = 0; i < result.rows; i++)
@@ -535,7 +535,7 @@
private static XLMatrix Add(XLMatrix m1, XLMatrix m2)
{
if (m1.rows != m2.rows || m1.cols != m2.cols)
- throw new Exception("Matrices must have the same dimensions!");
+ throw new ArgumentException("Matrices must have the same dimensions!");
var r = new XLMatrix(m1.rows, m1.cols);
for (var i = 0; i < r.rows; i++)
for (var j = 0; j < r.cols; j++)
diff --git a/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs b/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs
index 33011e2..108ea40 100644
--- a/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs
+++ b/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs
@@ -92,13 +92,13 @@
{
if (_evaluating)
{
- throw new Exception("Circular Reference");
+ throw new InvalidOperationException("Circular Reference");
}
try
{
_evaluating = true;
var f = cell.FormulaA1;
- if (XLHelper.IsNullOrWhiteSpace(f))
+ if (String.IsNullOrWhiteSpace(f))
return cell.Value;
else
return new XLCalcEngine(cell.Worksheet).Evaluate(f);
diff --git a/ClosedXML/Excel/Cells/IXLCell.cs b/ClosedXML/Excel/Cells/IXLCell.cs
index d685041..8df2759 100644
--- a/ClosedXML/Excel/Cells/IXLCell.cs
+++ b/ClosedXML/Excel/Cells/IXLCell.cs
@@ -173,6 +173,14 @@
IXLRange InsertData(IEnumerable data);
///
+ /// Inserts the IEnumerable data elements and returns the range it occupies.
+ ///
+ /// The IEnumerable data.
+ /// if set to true the data will be transposed before inserting.
+ ///
+ IXLRange InsertData(IEnumerable data, Boolean tranpose);
+
+ ///
/// Inserts the IEnumerable data elements as a table and returns it.
/// The new table will receive a generic name: Table#
///
@@ -260,7 +268,7 @@
IXLCells InsertCellsBefore(int numberOfColumns);
///
- /// Creates a named range out of this cell.
+ /// Creates a named range out of this cell.
/// If the named range exists, it will add this range to that named range.
/// The default scope for the named range is Workbook.
///
@@ -268,7 +276,7 @@
IXLCell AddToNamed(String rangeName);
///
- /// Creates a named range out of this cell.
+ /// Creates a named range out of this cell.
/// If the named range exists, it will add this range to that named range.
/// Name of the range.
/// The scope for the named range.
@@ -276,7 +284,7 @@
IXLCell AddToNamed(String rangeName, XLScope scope);
///
- /// Creates a named range out of this cell.
+ /// Creates a named range out of this cell.
/// If the named range exists, it will add this range to that named range.
/// Name of the range.
/// The scope for the named range.
@@ -322,6 +330,7 @@
IXLCell SetActive(Boolean value = true);
Boolean HasFormula { get; }
+ Boolean HasArrayFormula { get; }
IXLRangeAddress FormulaReference { get; set; }
}
diff --git a/ClosedXML/Excel/Cells/XLCell.cs b/ClosedXML/Excel/Cells/XLCell.cs
index 3d0e55a..ee602c2 100644
--- a/ClosedXML/Excel/Cells/XLCell.cs
+++ b/ClosedXML/Excel/Cells/XLCell.cs
@@ -1,4 +1,4 @@
-using FastMember;
+using FastMember;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -221,6 +221,9 @@
public IXLCell SetValue(T value)
{
+ if (value == null)
+ return this.Clear(XLClearOptions.Contents);
+
FormulaA1 = String.Empty;
_richText = null;
var style = GetStyleForRead();
@@ -281,7 +284,7 @@
if (TryGetValue(out retVal))
return retVal;
- throw new Exception("Cannot convert cell value to " + typeof(T));
+ throw new FormatException("Cannot convert cell value to " + typeof(T));
}
public string GetString()
@@ -365,7 +368,7 @@
get
{
var fA1 = FormulaA1;
- if (!XLHelper.IsNullOrWhiteSpace(fA1))
+ if (!String.IsNullOrWhiteSpace(fA1))
{
if (fA1[0] == '{')
fA1 = fA1.Substring(1, fA1.Length - 2);
@@ -437,6 +440,8 @@
if (value is XLCells) throw new ArgumentException("Cannot assign IXLCells object to the cell value.");
+ if (SetTableHeader(value)) return;
+
if (SetRangeRows(value)) return;
if (SetRangeColumns(value)) return;
@@ -469,7 +474,7 @@
public IXLTable InsertTable(IEnumerable data, string tableName, bool createTable)
{
- if (data != null && data.GetType() != typeof(String))
+ if (data != null && !(data is String))
{
var ro = Address.RowNumber + 1;
var fRo = Address.RowNumber;
@@ -495,7 +500,7 @@
if (!hasTitles)
{
var fieldName = XLColumnAttribute.GetHeader(itemType);
- if (XLHelper.IsNullOrWhiteSpace(fieldName))
+ if (String.IsNullOrWhiteSpace(fieldName))
fieldName = itemType.Name;
SetValue(fieldName, fRo, co);
@@ -573,7 +578,7 @@
if (!hasTitles)
{
foreach (var fieldName in from DataColumn column in row.Table.Columns
- select XLHelper.IsNullOrWhiteSpace(column.Caption)
+ select String.IsNullOrWhiteSpace(column.Caption)
? column.ColumnName
: column.Caption)
{
@@ -626,7 +631,7 @@
if ((mi as IEnumerable) == null)
{
var fieldName = XLColumnAttribute.GetHeader(mi);
- if (XLHelper.IsNullOrWhiteSpace(fieldName))
+ if (String.IsNullOrWhiteSpace(fieldName))
fieldName = mi.Name;
SetValue(fieldName, fRo, co);
@@ -712,10 +717,18 @@
public IXLRange InsertData(IEnumerable data)
{
- if (data != null && data.GetType() != typeof(String))
+ return InsertData(data, false);
+ }
+
+ public IXLRange InsertData(IEnumerable data, Boolean transpose)
+ {
+ if (data != null && !(data is String))
{
- var ro = Address.RowNumber;
- var maxCo = 0;
+ var rowNumber = Address.RowNumber;
+ var columnNumber = Address.ColumnNumber;
+
+ var maxColumnNumber = 0;
+ var maxRowNumber = 0;
var isDataTable = false;
var isDataReader = false;
@@ -744,20 +757,31 @@
members = memberCache[itemType];
accessor = accessorCache[itemType];
- var co = Address.ColumnNumber;
+ if (transpose)
+ rowNumber = Address.RowNumber;
+ else
+ columnNumber = Address.ColumnNumber;
+
if (itemType.IsPrimitive || itemType == typeof(String) || itemType == typeof(DateTime) || itemType.IsNumber())
{
- SetValue(m, ro, co);
- co++;
+ SetValue(m, rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
else if (itemType.IsArray)
{
- // dynamic arr = m;
foreach (var item in (Array)m)
{
- SetValue(item, ro, co);
- co++;
+ SetValue(item, rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
else if (isDataTable || m is DataRow)
@@ -767,8 +791,12 @@
foreach (var item in (m as DataRow).ItemArray)
{
- SetValue(item, ro, co);
- co++;
+ SetValue(item, rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
else if (isDataReader || m is IDataRecord)
@@ -781,31 +809,45 @@
var fieldCount = record.FieldCount;
for (var i = 0; i < fieldCount; i++)
{
- SetValue(record[i], ro, co);
- co++;
+ SetValue(record[i], rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
else
{
foreach (var mi in members)
{
- SetValue(accessor[m, mi.Name], ro, co);
- co++;
+ SetValue(accessor[m, mi.Name], rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
- if (co > maxCo)
- maxCo = co;
+ if (transpose)
+ columnNumber++;
+ else
+ rowNumber++;
- ro++;
+ if (columnNumber > maxColumnNumber)
+ maxColumnNumber = columnNumber;
+
+ if (rowNumber > maxRowNumber)
+ maxRowNumber = rowNumber;
}
ClearMerged();
return _worksheet.Range(
Address.RowNumber,
Address.ColumnNumber,
- ro - 1,
- maxCo - 1);
+ maxRowNumber - 1,
+ maxColumnNumber - 1);
}
return null;
@@ -967,9 +1009,9 @@
{
get
{
- if (XLHelper.IsNullOrWhiteSpace(_formulaA1))
+ if (String.IsNullOrWhiteSpace(_formulaA1))
{
- if (!XLHelper.IsNullOrWhiteSpace(_formulaR1C1))
+ if (!String.IsNullOrWhiteSpace(_formulaR1C1))
{
_formulaA1 = GetFormulaA1(_formulaR1C1);
return FormulaA1;
@@ -989,7 +1031,7 @@
set
{
- _formulaA1 = XLHelper.IsNullOrWhiteSpace(value) ? null : value;
+ _formulaA1 = String.IsNullOrWhiteSpace(value) ? null : value;
_formulaR1C1 = null;
}
@@ -999,7 +1041,7 @@
{
get
{
- if (XLHelper.IsNullOrWhiteSpace(_formulaR1C1))
+ if (String.IsNullOrWhiteSpace(_formulaR1C1))
_formulaR1C1 = GetFormulaR1C1(FormulaA1);
return _formulaR1C1;
@@ -1007,7 +1049,7 @@
set
{
- _formulaR1C1 = XLHelper.IsNullOrWhiteSpace(value) ? null : value;
+ _formulaR1C1 = String.IsNullOrWhiteSpace(value) ? null : value;
}
}
@@ -1449,6 +1491,23 @@
#endregion IXLStylized Members
+ private bool SetTableHeader(object value)
+ {
+ foreach (var table in Worksheet.Tables.Where(t => t.ShowHeaderRow))
+ {
+ var cells = table.HeadersRow().CellsUsed(c => c.Address.Equals(this.Address));
+ if (cells.Any())
+ {
+ var oldName = cells.First().GetString();
+ var field = table.Field(oldName);
+ field.Name = value.ToString();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private bool SetRangeColumns(object value)
{
var columns = value as XLRangeColumns;
@@ -1531,7 +1590,7 @@
{
var style = GetStyleForRead();
return _dataType == XLCellValues.Number
- && XLHelper.IsNullOrWhiteSpace(style.NumberFormat.Format)
+ && String.IsNullOrWhiteSpace(style.NumberFormat.Format)
&& ((style.NumberFormat.NumberFormatId >= 14
&& style.NumberFormat.NumberFormatId <= 22)
|| (style.NumberFormat.NumberFormatId >= 45
@@ -1542,7 +1601,7 @@
{
var format = String.Empty;
var style = GetStyleForRead();
- if (XLHelper.IsNullOrWhiteSpace(style.NumberFormat.Format))
+ if (String.IsNullOrWhiteSpace(style.NumberFormat.Format))
{
var formatCodes = GetFormatCodes();
if (formatCodes.ContainsKey(style.NumberFormat.NumberFormatId))
@@ -1619,7 +1678,7 @@
private bool SetEnumerable(object collectionObject)
{
// IXLRichText implements IEnumerable, but we don't want to handle this here.
- if ((collectionObject as IXLRichText) != null) return false;
+ if (collectionObject is IXLRichText) return false;
var asEnumerable = collectionObject as IEnumerable;
return InsertData(asEnumerable) != null;
@@ -1638,13 +1697,10 @@
{
if (value == null)
_worksheet.Cell(ro, co).SetValue(String.Empty);
+ else if (value is IConvertible)
+ _worksheet.Cell(ro, co).SetValue((T)Convert.ChangeType(value, typeof(T)));
else
- {
- if (value is IConvertible)
- _worksheet.Cell(ro, co).SetValue((T)Convert.ChangeType(value, typeof(T)));
- else
- _worksheet.Cell(ro, co).SetValue(value);
- }
+ _worksheet.Cell(ro, co).SetValue(value);
}
private void SetValue(object value)
@@ -1782,7 +1838,7 @@
private string GetFormula(string strValue, FormulaConversionType conversionType, int rowsToShift,
int columnsToShift)
{
- if (XLHelper.IsNullOrWhiteSpace(strValue))
+ if (String.IsNullOrWhiteSpace(strValue))
return String.Empty;
var value = ">" + strValue + "<";
@@ -2056,7 +2112,7 @@
internal static String ShiftFormulaRows(String formulaA1, XLWorksheet worksheetInAction, XLRange shiftedRange,
int rowsShifted)
{
- if (XLHelper.IsNullOrWhiteSpace(formulaA1)) return String.Empty;
+ if (String.IsNullOrWhiteSpace(formulaA1)) return String.Empty;
var value = formulaA1; // ">" + formulaA1 + "<";
@@ -2261,7 +2317,7 @@
internal static String ShiftFormulaColumns(String formulaA1, XLWorksheet worksheetInAction, XLRange shiftedRange,
int columnsShifted)
{
- if (XLHelper.IsNullOrWhiteSpace(formulaA1)) return String.Empty;
+ if (String.IsNullOrWhiteSpace(formulaA1)) return String.Empty;
var value = formulaA1; // ">" + formulaA1 + "<";
@@ -2589,7 +2645,9 @@
#endregion XLCell Right
- public Boolean HasFormula { get { return !XLHelper.IsNullOrWhiteSpace(FormulaA1); } }
+ public Boolean HasFormula { get { return !String.IsNullOrWhiteSpace(FormulaA1); } }
+
+ public Boolean HasArrayFormula { get { return FormulaA1.StartsWith("{"); } }
public IXLRangeAddress FormulaReference { get; set; }
}
diff --git a/ClosedXML/Excel/Columns/XLColumn.cs b/ClosedXML/Excel/Columns/XLColumn.cs
index b8036d4..ff70d31 100644
--- a/ClosedXML/Excel/Columns/XLColumn.cs
+++ b/ClosedXML/Excel/Columns/XLColumn.cs
@@ -774,17 +774,27 @@
#endregion
- public new Boolean IsEmpty()
+ public override Boolean IsEmpty()
{
return IsEmpty(false);
}
- public new Boolean IsEmpty(Boolean includeFormats)
+ public override Boolean IsEmpty(Boolean includeFormats)
{
if (includeFormats && !Style.Equals(Worksheet.Style))
return false;
return base.IsEmpty(includeFormats);
}
+
+ public override Boolean IsEntireRow()
+ {
+ return false;
+ }
+
+ public override Boolean IsEntireColumn()
+ {
+ return true;
+ }
}
}
diff --git a/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs b/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs
index f0bd151..ff2d3c0 100644
--- a/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs
+++ b/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs
@@ -7,20 +7,32 @@
namespace ClosedXML.Excel
{
- internal class XLCFDataBarConverter:IXLCFConverter
+ internal class XLCFDataBarConverter : IXLCFConverter
{
public ConditionalFormattingRule Convert(IXLConditionalFormat cf, Int32 priority, XLWorkbook.SaveContext context)
{
var conditionalFormattingRule = new ConditionalFormattingRule { Type = cf.ConditionalFormatType.ToOpenXml(), Priority = priority };
- var dataBar = new DataBar {ShowValue = !cf.ShowBarOnly};
- var conditionalFormatValueObject1 = new ConditionalFormatValueObject { Type = cf.ContentTypes[1].ToOpenXml()};
- if (cf.Values.Count >= 1) conditionalFormatValueObject1.Val = cf.Values[1].Value;
+ var dataBar = new DataBar { ShowValue = !cf.ShowBarOnly };
+ var conditionalFormatValueObject1 = new ConditionalFormatValueObject { Type = cf.ContentTypes[1].ToOpenXml() };
+ if (cf.Values.Any() && cf.Values[1]?.Value != null) conditionalFormatValueObject1.Val = cf.Values[1].Value;
- var conditionalFormatValueObject2 = new ConditionalFormatValueObject { Type = cf.ContentTypes[2].ToOpenXml()};
- if (cf.Values.Count >= 2) conditionalFormatValueObject2.Val = cf.Values[2].Value;
+ var conditionalFormatValueObject2 = new ConditionalFormatValueObject { Type = cf.ContentTypes[2].ToOpenXml() };
+ if (cf.Values.Count >= 2 && cf.Values[2]?.Value != null) conditionalFormatValueObject2.Val = cf.Values[2].Value;
- var color = new Color { Rgb = cf.Colors[1].Color.ToHex() };
+ var color = new Color();
+ switch (cf.Colors[1].ColorType)
+ {
+ case XLColorType.Color:
+ color.Rgb = cf.Colors[1].Color.ToHex();
+ break;
+ case XLColorType.Theme:
+ color.Theme = System.Convert.ToUInt32(cf.Colors[1].ThemeColor);
+ break;
+ case XLColorType.Indexed:
+ color.Indexed = System.Convert.ToUInt32(cf.Colors[1].Indexed);
+ break;
+ }
dataBar.Append(conditionalFormatValueObject1);
dataBar.Append(conditionalFormatValueObject2);
diff --git a/ClosedXML/Excel/DataValidation/XLDataValidation.cs b/ClosedXML/Excel/DataValidation/XLDataValidation.cs
index 321e6d8..17164c0 100644
--- a/ClosedXML/Excel/DataValidation/XLDataValidation.cs
+++ b/ClosedXML/Excel/DataValidation/XLDataValidation.cs
@@ -41,9 +41,9 @@
return
AllowedValues != XLAllowedValues.AnyValue
|| (ShowInputMessage &&
- (!XLHelper.IsNullOrWhiteSpace(InputTitle) || !XLHelper.IsNullOrWhiteSpace(InputMessage)))
+ (!String.IsNullOrWhiteSpace(InputTitle) || !String.IsNullOrWhiteSpace(InputMessage)))
||(ShowErrorMessage &&
- (!XLHelper.IsNullOrWhiteSpace(ErrorTitle) || !XLHelper.IsNullOrWhiteSpace(ErrorMessage)));
+ (!String.IsNullOrWhiteSpace(ErrorTitle) || !String.IsNullOrWhiteSpace(ErrorMessage)));
}
diff --git a/ClosedXML/Excel/Drawings/IXLPicture.cs b/ClosedXML/Excel/Drawings/IXLPicture.cs
index 2c2f750..cf167d2 100644
--- a/ClosedXML/Excel/Drawings/IXLPicture.cs
+++ b/ClosedXML/Excel/Drawings/IXLPicture.cs
@@ -16,6 +16,8 @@
Int32 Height { get; set; }
+ Int32 Id { get; }
+
MemoryStream ImageStream { get; }
Int32 Left { get; set; }
diff --git a/ClosedXML/Excel/Drawings/XLPicture.cs b/ClosedXML/Excel/Drawings/XLPicture.cs
index 86d45ae..9266215 100644
--- a/ClosedXML/Excel/Drawings/XLPicture.cs
+++ b/ClosedXML/Excel/Drawings/XLPicture.cs
@@ -16,6 +16,7 @@
private static IDictionary FormatMap;
private readonly IXLWorksheet _worksheet;
private Int32 height;
+ private Int32 id;
private String name = string.Empty;
private Int32 width;
@@ -32,7 +33,7 @@
}
internal XLPicture(IXLWorksheet worksheet, Stream stream)
- : this(worksheet)
+ : this(worksheet)
{
if (stream == null) throw new ArgumentNullException(nameof(stream));
@@ -67,11 +68,8 @@
using (var bitmap = new Bitmap(ImageStream))
{
- if (FormatMap.ContainsKey(this.Format))
- {
- if (FormatMap[this.Format].Guid != bitmap.RawFormat.Guid)
- throw new ArgumentException("The picture format in the stream and the parameter don't match");
- }
+ if (FormatMap.ContainsKey(this.Format) && FormatMap[this.Format].Guid != bitmap.RawFormat.Guid)
+ throw new ArgumentException("The picture format in the stream and the parameter don't match");
DeduceDimensionsFromBitmap(bitmap);
}
@@ -105,6 +103,13 @@
[XLMarkerPosition.TopLeft] = null,
[XLMarkerPosition.BottomRight] = null
};
+
+ // Calculate default picture ID
+ var allPictures = worksheet.Workbook.Worksheets.SelectMany(ws => ws.Pictures);
+ if (allPictures.Any())
+ this.id = allPictures.Max(p => p.Id) + 1;
+ else
+ this.id = 1;
}
public IXLAddress BottomRightCellAddress
@@ -135,6 +140,16 @@
}
}
+ public Int32 Id
+ {
+ get { return id; }
+ internal set
+ {
+ if ((_worksheet.Pictures.FirstOrDefault(p => p.Id.Equals(value)) ?? this) != this)
+ throw new ArgumentException($"The picture ID '{value}' already exists.");
+ }
+ }
+
public MemoryStream ImageStream { get; private set; }
public Int32 Left
@@ -156,19 +171,10 @@
{
if (name == value) return;
- if (value.IndexOfAny(InvalidNameChars.ToCharArray()) != -1)
- throw new ArgumentException($"Picture names cannot contain any of the following characters: {InvalidNameChars}");
-
- if (XLHelper.IsNullOrWhiteSpace(value))
- throw new ArgumentException("Picture names cannot be empty");
-
- if (value.Length > 31)
- throw new ArgumentException("Picture names cannot be more than 31 characters");
-
if ((_worksheet.Pictures.FirstOrDefault(p => p.Name.Equals(value, StringComparison.OrdinalIgnoreCase)) ?? this) != this)
throw new ArgumentException($"The picture name '{value}' already exists.");
- name = value;
+ SetName(value);
}
}
@@ -323,6 +329,20 @@
return this;
}
+ internal void SetName(string value)
+ {
+ if (value.IndexOfAny(InvalidNameChars.ToCharArray()) != -1)
+ throw new ArgumentException($"Picture names cannot contain any of the following characters: {InvalidNameChars}");
+
+ if (String.IsNullOrWhiteSpace(value))
+ throw new ArgumentException("Picture names cannot be empty");
+
+ if (value.Length > 31)
+ throw new ArgumentException("Picture names cannot be more than 31 characters");
+
+ name = value;
+ }
+
private static ImageFormat FromMimeType(string mimeType)
{
var guid = ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase))?.FormatID;
diff --git a/ClosedXML/Excel/Drawings/XLPictures.cs b/ClosedXML/Excel/Drawings/XLPictures.cs
index 3381309..6a102dd 100644
--- a/ClosedXML/Excel/Drawings/XLPictures.cs
+++ b/ClosedXML/Excel/Drawings/XLPictures.cs
@@ -39,7 +39,7 @@
return picture;
}
- public Drawings.IXLPicture Add(Stream stream, XLPictureFormat format)
+ public IXLPicture Add(Stream stream, XLPictureFormat format)
{
var picture = new XLPicture(_worksheet, stream, format);
_pictures.Add(picture);
@@ -127,13 +127,21 @@
var matches = _pictures.Where(p => p.Name.Equals(pictureName, StringComparison.OrdinalIgnoreCase));
if (matches.Any())
{
- picture = matches.Single();
+ picture = matches.First();
return true;
}
picture = null;
return false;
}
+ internal IXLPicture Add(Stream stream, string name, int Id)
+ {
+ var picture = Add(stream) as XLPicture;
+ picture.SetName(name);
+ picture.Id = Id;
+ return picture;
+ }
+
private String GetNextPictureName()
{
var pictureNumber = this.Count;
diff --git a/ClosedXML/Excel/Misc/XLFormula.cs b/ClosedXML/Excel/Misc/XLFormula.cs
index 34cea84..8027667 100644
--- a/ClosedXML/Excel/Misc/XLFormula.cs
+++ b/ClosedXML/Excel/Misc/XLFormula.cs
@@ -44,7 +44,7 @@
else
{
_value = value.Trim();
- IsFormula = !XLHelper.IsNullOrWhiteSpace(_value) && _value.TrimStart()[0] == '=' ;
+ IsFormula = !String.IsNullOrWhiteSpace(_value) && _value.TrimStart()[0] == '=' ;
if (IsFormula)
_value = _value.Substring(1);
}
diff --git a/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs b/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs
index a7b191f..f3f7304 100644
--- a/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs
+++ b/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs
@@ -69,10 +69,16 @@
if (!match.Success)
{
- if (Worksheet == null || !XLHelper.NamedRangeReferenceRegex.Match(Worksheet.Range(rangeAddress).ToString()).Success)
- throw new ArgumentException("For named ranges in the workbook scope, specify the sheet name in the reference.");
+ var range = Worksheet?.Range(rangeAddress) ?? Workbook.Range(rangeAddress);
+ if (range == null)
+ throw new ArgumentException(string.Format("The range address '{0}' for the named range '{1}' is not a valid range.", rangeAddress, rangeName));
else
- rangeAddress = Worksheet.Range(rangeAddress).ToString();
+ {
+ if (Worksheet == null || !XLHelper.NamedRangeReferenceRegex.Match(range.ToString()).Success)
+ throw new ArgumentException("For named ranges in the workbook scope, specify the sheet name in the reference.");
+ else
+ rangeAddress = Worksheet.Range(rangeAddress).ToString();
+ }
}
}
diff --git a/ClosedXML/Excel/Ranges/IXLRange.cs b/ClosedXML/Excel/Ranges/IXLRange.cs
index fbbe958..992ebf9 100644
--- a/ClosedXML/Excel/Ranges/IXLRange.cs
+++ b/ClosedXML/Excel/Ranges/IXLRange.cs
@@ -1,12 +1,14 @@
using System;
-
namespace ClosedXML.Excel
{
public enum XLShiftDeletedCells { ShiftCellsUp, ShiftCellsLeft }
+
public enum XLTransposeOptions { MoveCells, ReplaceCells }
+
public enum XLSearchContents { Values, Formulas, ValuesAndFormulas }
- public interface IXLRange: IXLRangeBase
+
+ public interface IXLRange : IXLRangeBase
{
///
/// Gets the cell at the specified row and column.
@@ -28,6 +30,7 @@
/// The cell's row.
/// The cell's column.
IXLCell Cell(int row, string column);
+
/// Gets the cell at the specified address.
/// The cell address is relative to the parent range.
/// The cell address in the parent range.
@@ -36,79 +39,100 @@
///
/// Gets the specified column of the range.
///
- /// The range column.
- IXLRangeColumn Column(int column);
+ /// The column number.
+ ///
+ IXLRangeColumn Column(int columnNumber);
+
///
/// Gets the specified column of the range.
///
- /// The range column.
- IXLRangeColumn Column(string column);
+ /// Column letter.
+ IXLRangeColumn Column(string columnLetter);
+
///
/// Gets the first column of the range.
///
IXLRangeColumn FirstColumn(Func predicate = null);
+
///
/// Gets the first column of the range that contains a cell with a value.
///
IXLRangeColumn FirstColumnUsed(Boolean includeFormats, Func predicate = null);
+
IXLRangeColumn FirstColumnUsed(Func predicate = null);
+
///
/// Gets the last column of the range.
///
IXLRangeColumn LastColumn(Func predicate = null);
+
///
/// Gets the last column of the range that contains a cell with a value.
///
IXLRangeColumn LastColumnUsed(Boolean includeFormats, Func predicate = null);
+
IXLRangeColumn LastColumnUsed(Func predicate = null);
+
///
/// Gets a collection of all columns in this range.
///
IXLRangeColumns Columns(Func predicate = null);
+
///
/// Gets a collection of the specified columns in this range.
///
/// The first column to return.
/// The last column to return.
IXLRangeColumns Columns(int firstColumn, int lastColumn);
+
///
/// Gets a collection of the specified columns in this range.
///
/// The first column to return.
/// The last column to return.
IXLRangeColumns Columns(string firstColumn, string lastColumn);
+
///
/// Gets a collection of the specified columns in this range, separated by commas.
/// e.g. Columns("G:H"), Columns("10:11,13:14"), Columns("P:Q,S:T"), Columns("V")
///
/// The columns to return.
IXLRangeColumns Columns(string columns);
+
///
/// Returns the first row that matches the given predicate
///
IXLRangeColumn FindColumn(Func predicate);
+
///
/// Returns the first row that matches the given predicate
///
IXLRangeRow FindRow(Func predicate);
+
///
/// Gets the first row of the range.
///
IXLRangeRow FirstRow(Func predicate = null);
+
///
/// Gets the first row of the range that contains a cell with a value.
///
IXLRangeRow FirstRowUsed(Boolean includeFormats, Func predicate = null);
+
IXLRangeRow FirstRowUsed(Func predicate = null);
+
///
/// Gets the last row of the range.
///
IXLRangeRow LastRow(Func predicate = null);
+
///
/// Gets the last row of the range that contains a cell with a value.
///
IXLRangeRow LastRowUsed(Boolean includeFormats, Func predicate = null);
+
IXLRangeRow LastRowUsed(Func predicate = null);
+
///
/// Gets the specified row of the range.
///
@@ -124,6 +148,7 @@
/// The last row to return.
///
IXLRangeRows Rows(int firstRow, int lastRow);
+
///
/// Gets a collection of the specified rows in this range, separated by commas.
/// e.g. Rows("4:5"), Rows("7:8,10:11"), Rows("13")
@@ -182,27 +207,34 @@
///
/// Number of columns to insert.
IXLRangeColumns InsertColumnsAfter(int numberOfColumns);
+
IXLRangeColumns InsertColumnsAfter(int numberOfColumns, Boolean expandRange);
+
///
/// Inserts X number of columns to the left of this range.
/// This range and all cells to the right of this range will be shifted X number of columns.
///
/// Number of columns to insert.
IXLRangeColumns InsertColumnsBefore(int numberOfColumns);
+
IXLRangeColumns InsertColumnsBefore(int numberOfColumns, Boolean expandRange);
+
///
/// Inserts X number of rows on top of this range.
/// This range and all cells below this range will be shifted X number of rows.
///
/// Number of rows to insert.
IXLRangeRows InsertRowsAbove(int numberOfRows);
+
IXLRangeRows InsertRowsAbove(int numberOfRows, Boolean expandRange);
+
///
/// Inserts X number of rows below this range.
/// All cells below this range will be shifted X number of rows.
///
/// Number of rows to insert.
IXLRangeRows InsertRowsBelow(int numberOfRows);
+
IXLRangeRows InsertRowsBelow(int numberOfRows, Boolean expandRange);
///
@@ -218,13 +250,17 @@
void Transpose(XLTransposeOptions transposeOption);
IXLTable AsTable();
+
IXLTable AsTable(String name);
+
IXLTable CreateTable();
+
IXLTable CreateTable(String name);
IXLRange RangeUsed();
IXLRange CopyTo(IXLCell target);
+
IXLRange CopyTo(IXLRangeBase target);
IXLSortElements SortRows { get; }
@@ -233,9 +269,10 @@
IXLRange Sort();
IXLRange Sort(String columnsToSortBy, XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true);
+
IXLRange Sort(Int32 columnToSortBy, XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true);
+
IXLRange SortLeftToRight(XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true);
-
IXLRange SetDataType(XLCellValues dataType);
@@ -246,9 +283,11 @@
new IXLRange Clear(XLClearOptions clearOptions = XLClearOptions.ContentsAndFormats);
IXLRangeRows RowsUsed(Boolean includeFormats, Func predicate = null);
+
IXLRangeRows RowsUsed(Func predicate = null);
+
IXLRangeColumns ColumnsUsed(Boolean includeFormats, Func predicate = null);
+
IXLRangeColumns ColumnsUsed(Func predicate = null);
}
}
-
diff --git a/ClosedXML/Excel/Ranges/IXLRangeBase.cs b/ClosedXML/Excel/Ranges/IXLRangeBase.cs
index 76902d0..064d975 100644
--- a/ClosedXML/Excel/Ranges/IXLRangeBase.cs
+++ b/ClosedXML/Excel/Ranges/IXLRangeBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
namespace ClosedXML.Excel
{
@@ -8,7 +9,7 @@
Worksheet
}
- public interface IXLRangeBase: IDisposable
+ public interface IXLRangeBase : IDisposable
{
IXLWorksheet Worksheet { get; }
@@ -64,7 +65,6 @@
IXLHyperlinks Hyperlinks { get; }
-
///
/// Returns the collection of cells.
///
@@ -94,6 +94,15 @@
IXLCells CellsUsed(Boolean includeFormats, Func predicate);
///
+ /// Searches the cells' contents for a given piece of text
+ ///
+ /// The search text.
+ /// The compare options.
+ /// if set to true search formulae instead of cell values.
+ ///
+ IXLCells Search(String searchText, CompareOptions compareOptions = CompareOptions.Ordinal, Boolean searchFormulae = false);
+
+ ///
/// Returns the first cell of this range.
///
IXLCell FirstCell();
@@ -236,15 +245,19 @@
IXLRange AsRange();
Boolean IsMerged();
+
Boolean IsEmpty();
+
Boolean IsEmpty(Boolean includeFormats);
+ Boolean IsEntireRow();
+
+ Boolean IsEntireColumn();
IXLPivotTable CreatePivotTable(IXLCell targetCell);
+
IXLPivotTable CreatePivotTable(IXLCell targetCell, String name);
-
-
//IXLChart CreateChart(Int32 firstRow, Int32 firstColumn, Int32 lastRow, Int32 lastColumn);
IXLAutoFilter SetAutoFilter();
diff --git a/ClosedXML/Excel/Ranges/XLRange.cs b/ClosedXML/Excel/Ranges/XLRange.cs
index 94d53e3..1991c89 100644
--- a/ClosedXML/Excel/Ranges/XLRange.cs
+++ b/ClosedXML/Excel/Ranges/XLRange.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
-
namespace ClosedXML.Excel
{
internal class XLRange : XLRangeBase, IXLRange
@@ -23,29 +22,28 @@
SetStyle(xlRangeParameters.DefaultStyle);
}
- #endregion
+ #endregion Constructor
public XLRangeParameters RangeParameters { get; private set; }
#region IXLRange Members
-
IXLRangeRow IXLRange.Row(Int32 row)
{
return Row(row);
}
- IXLRangeColumn IXLRange.Column(Int32 column)
+ IXLRangeColumn IXLRange.Column(Int32 columnNumber)
{
- return Column(column);
+ return Column(columnNumber);
}
- IXLRangeColumn IXLRange.Column(String column)
+ IXLRangeColumn IXLRange.Column(String columnLetter)
{
- return Column(column);
+ return Column(columnLetter);
}
- public IXLRangeColumns Columns(Func predicate = null)
+ public virtual IXLRangeColumns Columns(Func predicate = null)
{
var retVal = new XLRangeColumns();
Int32 columnCount = ColumnCount();
@@ -69,13 +67,13 @@
return retVal;
}
- public IXLRangeColumns Columns(String firstColumn, String lastColumn)
+ public virtual IXLRangeColumns Columns(String firstColumn, String lastColumn)
{
return Columns(XLHelper.GetColumnNumberFromLetter(firstColumn),
XLHelper.GetColumnNumberFromLetter(lastColumn));
}
- public IXLRangeColumns Columns(String columns)
+ public virtual IXLRangeColumns Columns(String columns)
{
var retVal = new XLRangeColumns();
var columnPairs = columns.Split(',');
@@ -274,6 +272,7 @@
{
return CreateTable();
}
+
public XLTable CreateTable()
{
return new XLTable(this, true, true);
@@ -283,6 +282,7 @@
{
return CreateTable(name);
}
+
public XLTable CreateTable(String name)
{
return new XLTable(this, name, true, true);
@@ -333,27 +333,27 @@
return this;
}
-
public new IXLRange Sort()
{
return base.Sort().AsRange();
}
-
+
public new IXLRange Sort(String columnsToSortBy, XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true)
{
return base.Sort(columnsToSortBy, sortOrder, matchCase, ignoreBlanks).AsRange();
}
+
public new IXLRange Sort(Int32 columnToSortBy, XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true)
{
return base.Sort(columnToSortBy, sortOrder, matchCase, ignoreBlanks).AsRange();
}
+
public new IXLRange SortLeftToRight(XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true)
{
return base.SortLeftToRight(sortOrder, matchCase, ignoreBlanks).AsRange();
}
-
- #endregion
+ #endregion IXLRange Members
private void WorksheetRangeShiftedColumns(XLRange range, int columnsShifted)
{
@@ -362,13 +362,14 @@
private void WorksheetRangeShiftedRows(XLRange range, int rowsShifted)
{
- ShiftRows(RangeAddress, range, rowsShifted);
+ ShiftRows(RangeAddress, range, rowsShifted);
}
IXLRangeColumn IXLRange.FirstColumn(Func predicate)
{
return FirstColumn(predicate);
}
+
public XLRangeColumn FirstColumn(Func predicate = null)
{
if (predicate == null)
@@ -390,6 +391,7 @@
{
return LastColumn(predicate);
}
+
public XLRangeColumn LastColumn(Func predicate = null)
{
Int32 columnCount = ColumnCount();
@@ -407,10 +409,11 @@
return null;
}
- IXLRangeColumn IXLRange.FirstColumnUsed(Func predicate )
+ IXLRangeColumn IXLRange.FirstColumnUsed(Func predicate)
{
return FirstColumnUsed(false, predicate);
}
+
public XLRangeColumn FirstColumnUsed(Func predicate = null)
{
return FirstColumnUsed(false, predicate);
@@ -420,6 +423,7 @@
{
return FirstColumnUsed(includeFormats, predicate);
}
+
public XLRangeColumn FirstColumnUsed(Boolean includeFormats, Func predicate = null)
{
if (predicate == null)
@@ -450,6 +454,7 @@
{
return LastColumnUsed(false, predicate);
}
+
public XLRangeColumn LastColumnUsed(Func predicate = null)
{
return LastColumnUsed(false, predicate);
@@ -459,6 +464,7 @@
{
return LastColumnUsed(includeFormats, predicate);
}
+
public XLRangeColumn LastColumnUsed(Boolean includeFormats, Func predicate = null)
{
if (predicate == null)
@@ -489,6 +495,7 @@
{
return FirstRow(predicate);
}
+
public XLRangeRow FirstRow(Func predicate = null)
{
if (predicate == null)
@@ -510,6 +517,7 @@
{
return LastRow(predicate);
}
+
public XLRangeRow LastRow(Func predicate = null)
{
Int32 rowCount = RowCount();
@@ -531,6 +539,7 @@
{
return FirstRowUsed(false, predicate);
}
+
public XLRangeRow FirstRowUsed(Func predicate = null)
{
return FirstRowUsed(false, predicate);
@@ -540,6 +549,7 @@
{
return FirstRowUsed(includeFormats, predicate);
}
+
public XLRangeRow FirstRowUsed(Boolean includeFormats, Func predicate = null)
{
if (predicate == null)
@@ -572,6 +582,7 @@
{
return LastRowUsed(false, predicate);
}
+
public XLRangeRow LastRowUsed(Func predicate = null)
{
return LastRowUsed(false, predicate);
@@ -581,6 +592,7 @@
{
return LastRowUsed(includeFormats, predicate);
}
+
public XLRangeRow LastRowUsed(Boolean includeFormats, Func predicate = null)
{
if (predicate == null)
@@ -607,11 +619,11 @@
return null;
}
-
IXLRangeRows IXLRange.RowsUsed(Boolean includeFormats, Func predicate)
{
return RowsUsed(includeFormats, predicate);
}
+
public XLRangeRows RowsUsed(Boolean includeFormats, Func predicate = null)
{
XLRangeRows rows = new XLRangeRows();
@@ -627,19 +639,23 @@
}
return rows;
}
+
IXLRangeRows IXLRange.RowsUsed(Func predicate)
{
return RowsUsed(predicate);
}
+
public XLRangeRows RowsUsed(Func predicate = null)
{
return RowsUsed(false, predicate);
}
+
IXLRangeColumns IXLRange.ColumnsUsed(Boolean includeFormats, Func predicate)
{
return ColumnsUsed(includeFormats, predicate);
}
- public XLRangeColumns ColumnsUsed(Boolean includeFormats, Func predicate = null)
+
+ public virtual XLRangeColumns ColumnsUsed(Boolean includeFormats, Func predicate = null)
{
XLRangeColumns columns = new XLRangeColumns();
Int32 columnCount = ColumnCount();
@@ -654,11 +670,13 @@
}
return columns;
}
+
IXLRangeColumns IXLRange.ColumnsUsed(Func predicate)
{
return ColumnsUsed(predicate);
}
- public XLRangeColumns ColumnsUsed(Func predicate = null)
+
+ public virtual XLRangeColumns ColumnsUsed(Func predicate = null)
{
return ColumnsUsed(false, predicate);
}
@@ -682,34 +700,30 @@
new XLRangeParameters(new XLRangeAddress(firstCellAddress, lastCellAddress), Worksheet.Style), false);
}
-
-
- public XLRangeColumn Column(Int32 column)
+ public virtual XLRangeColumn Column(Int32 columnNumber)
{
- if (column <= 0 || column > XLHelper.MaxColumnNumber)
+ if (columnNumber <= 0 || columnNumber > XLHelper.MaxColumnNumber)
throw new IndexOutOfRangeException(String.Format("Column number must be between 1 and {0}", XLHelper.MaxColumnNumber));
var firstCellAddress = new XLAddress(Worksheet,
RangeAddress.FirstAddress.RowNumber,
- RangeAddress.FirstAddress.ColumnNumber + column - 1,
+ RangeAddress.FirstAddress.ColumnNumber + columnNumber - 1,
false,
false);
var lastCellAddress = new XLAddress(Worksheet,
RangeAddress.LastAddress.RowNumber,
- RangeAddress.FirstAddress.ColumnNumber + column - 1,
+ RangeAddress.FirstAddress.ColumnNumber + columnNumber - 1,
false,
false);
return new XLRangeColumn(
new XLRangeParameters(new XLRangeAddress(firstCellAddress, lastCellAddress), Worksheet.Style), false);
}
- public XLRangeColumn Column(String column)
+ public virtual XLRangeColumn Column(String columnLetter)
{
- return Column(XLHelper.GetColumnNumberFromLetter(column));
+ return Column(XLHelper.GetColumnNumberFromLetter(columnLetter));
}
-
-
private void TransposeRange(int squareSide)
{
var cellsToInsert = new Dictionary();
@@ -728,7 +742,7 @@
{
var oldCell = rngToTranspose.Cell(ro, co);
var newKey = rngToTranspose.Cell(co, ro).Address;
- // new XLAddress(Worksheet, c.Address.ColumnNumber, c.Address.RowNumber);
+ // new XLAddress(Worksheet, c.Address.ColumnNumber, c.Address.RowNumber);
var newCell = new XLCell(Worksheet, newKey, oldCell.GetStyleId());
newCell.CopyFrom(oldCell, true);
cellsToInsert.Add(new XLSheetPoint(newKey.RowNumber, newKey.ColumnNumber), newCell);
diff --git a/ClosedXML/Excel/Ranges/XLRangeAddress.cs b/ClosedXML/Excel/Ranges/XLRangeAddress.cs
index df631ec..fbe5135 100644
--- a/ClosedXML/Excel/Ranges/XLRangeAddress.cs
+++ b/ClosedXML/Excel/Ranges/XLRangeAddress.cs
@@ -84,7 +84,7 @@
get
{
if (IsInvalid)
- throw new Exception("Range is invalid.");
+ throw new InvalidOperationException("Range is invalid.");
return _firstAddress;
}
@@ -96,7 +96,7 @@
get
{
if (IsInvalid)
- throw new Exception("Range is an invalid state.");
+ throw new InvalidOperationException("Range is an invalid state.");
return _lastAddress;
}
diff --git a/ClosedXML/Excel/Ranges/XLRangeBase.cs b/ClosedXML/Excel/Ranges/XLRangeBase.cs
index 6e34637..0534107 100644
--- a/ClosedXML/Excel/Ranges/XLRangeBase.cs
+++ b/ClosedXML/Excel/Ranges/XLRangeBase.cs
@@ -2,36 +2,39 @@
using ClosedXML.Extensions;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
-
-
namespace ClosedXML.Excel
{
internal abstract class XLRangeBase : IXLRangeBase, IXLStylized
{
public Boolean StyleChanged { get; set; }
+
#region Fields
private IXLStyle _style;
private XLSortElements _sortRows;
private XLSortElements _sortColumns;
- #endregion
+ #endregion Fields
private Int32 _styleCacheId;
+
protected void SetStyle(IXLStyle styleToUse)
{
_styleCacheId = Worksheet.Workbook.GetStyleId(styleToUse);
_style = null;
StyleChanged = false;
}
+
protected void SetStyle(Int32 styleId)
{
_styleCacheId = styleId;
_style = null;
StyleChanged = false;
}
+
public Int32 GetStyleId()
{
if (StyleChanged)
@@ -39,6 +42,7 @@
return _styleCacheId;
}
+
protected IXLStyle GetStyle()
{
return _style ?? (_style = new XLStyle(this, Worksheet.Workbook.GetStyleById(_styleCacheId)));
@@ -46,18 +50,17 @@
#region Constructor
- static Int32 IdCounter = 0;
- readonly Int32 Id;
+ private static Int32 IdCounter = 0;
+ private readonly Int32 Id;
protected XLRangeBase(XLRangeAddress rangeAddress)
{
-
Id = ++IdCounter;
RangeAddress = new XLRangeAddress(rangeAddress);
}
- #endregion
+ #endregion Constructor
private XLCallbackAction _shiftedRowsAction;
@@ -71,6 +74,7 @@
}
private XLCallbackAction _shiftedColumnsAction;
+
protected void SubscribeToShiftedColumns(Action action)
{
if (Worksheet == null || !Worksheet.EventTrackingEnabled) return;
@@ -82,9 +86,8 @@
#region Public properties
- //public XLRangeAddress RangeAddress { get; protected set; }
-
private XLRangeAddress _rangeAddress;
+
public XLRangeAddress RangeAddress
{
get { return _rangeAddress; }
@@ -243,8 +246,6 @@
}
}
-
-
public Object Value
{
set { Cells().ForEach(c => c.Value = value); }
@@ -255,7 +256,7 @@
set { Cells().ForEach(c => c.DataType = value); }
}
- #endregion
+ #endregion IXLRangeBase Members
#region IXLStylized Members
@@ -268,9 +269,9 @@
}
}
- #endregion
+ #endregion IXLStylized Members
- #endregion
+ #endregion Public properties
#region IXLRangeBase Members
@@ -457,17 +458,17 @@
get { return GetStyle(); }
set { Cells().ForEach(c => c.Style = value); }
}
+
IXLRange IXLRangeBase.AsRange()
{
return AsRange();
}
+
public virtual XLRange AsRange()
{
return Worksheet.Range(RangeAddress.FirstAddress, RangeAddress.LastAddress);
}
-
-
public IXLRange AddToNamed(String rangeName)
{
return AddToNamed(rangeName, XLScope.Workbook);
@@ -505,18 +506,30 @@
return Cells().Any(c => c.IsMerged());
}
- public Boolean IsEmpty()
+ public virtual Boolean IsEmpty()
{
return !CellsUsed().Any() || CellsUsed().Any(c => c.IsEmpty());
}
- public Boolean IsEmpty(Boolean includeFormats)
+ public virtual Boolean IsEmpty(Boolean includeFormats)
{
return !CellsUsed(includeFormats).Cast().Any() ||
CellsUsed(includeFormats).Cast().Any(c => c.IsEmpty(includeFormats));
}
- #endregion
+ public virtual Boolean IsEntireRow()
+ {
+ return RangeAddress.FirstAddress.ColumnNumber == 1
+ && RangeAddress.LastAddress.ColumnNumber == XLHelper.MaxColumnNumber;
+ }
+
+ public virtual Boolean IsEntireColumn()
+ {
+ return RangeAddress.FirstAddress.RowNumber == 1
+ && RangeAddress.LastAddress.RowNumber == XLHelper.MaxRowNumber;
+ }
+
+ #endregion IXLRangeBase Members
#region IXLStylized Members
@@ -539,7 +552,28 @@
set { SetStyle(value); }
}
- #endregion
+ #endregion IXLStylized Members
+
+ public IXLCells Search(String searchText, CompareOptions compareOptions = CompareOptions.Ordinal, Boolean searchFormulae = false)
+ {
+ var culture = CultureInfo.CurrentCulture;
+ return this.CellsUsed(false, c =>
+ {
+ try
+ {
+ if (searchFormulae)
+ return c.HasFormula
+ && culture.CompareInfo.IndexOf(c.FormulaA1, searchText, compareOptions) >= 0
+ || culture.CompareInfo.IndexOf(c.Value.ToString(), searchText, compareOptions) >= 0;
+ else
+ return culture.CompareInfo.IndexOf(c.GetFormattedString(), searchText, compareOptions) >= 0;
+ }
+ catch
+ {
+ return false;
+ }
+ });
+ }
public XLCell FirstCell()
{
@@ -642,7 +676,6 @@
}
}
-
if (sp.Row > 0)
return Worksheet.Cell(sp.Row, sp.Column);
@@ -734,7 +767,6 @@
}
}
-
if (sp.Row > 0)
return Worksheet.Cell(sp.Row, sp.Column);
@@ -748,7 +780,6 @@
public XLCell Cell(String cellAddressInRange)
{
-
if (XLHelper.IsValidA1Address(cellAddressInRange))
return Cell(XLAddress.Create(Worksheet, cellAddressInRange));
@@ -810,7 +841,7 @@
Int32 newCellStyleId = styleId;
- // If the default style for this range base is empty, but the worksheet
+ // If the default style for this range base is empty, but the worksheet
// has a default style, use the worksheet's default style
if (styleId == 0 && worksheetStyleId != 0)
newCellStyleId = worksheetStyleId;
@@ -904,7 +935,6 @@
public XLRange Range(IXLRangeAddress rangeAddress)
{
-
var newFirstCellAddress = new XLAddress((XLWorksheet)rangeAddress.FirstAddress.Worksheet,
rangeAddress.FirstAddress.RowNumber + RangeAddress.FirstAddress.RowNumber - 1,
rangeAddress.FirstAddress.ColumnNumber + RangeAddress.FirstAddress.ColumnNumber - 1,
@@ -1072,12 +1102,11 @@
{
foreach (XLWorksheet ws in Worksheet.Workbook.WorksheetsInternal)
{
- foreach (XLCell cell in ws.Internals.CellsCollection.GetCells(c => !XLHelper.IsNullOrWhiteSpace(c.FormulaA1)))
+ foreach (XLCell cell in ws.Internals.CellsCollection.GetCells(c => !String.IsNullOrWhiteSpace(c.FormulaA1)))
using (var asRange = AsRange())
cell.ShiftFormulaColumns(asRange, numberOfColumns);
}
-
var cellsDataValidations = new Dictionary();
var cellsToInsert = new Dictionary();
var cellsToDelete = new List();
@@ -1092,10 +1121,10 @@
{
for (int co = lastColumn; co >= firstColumn; co--)
{
+ int newColumn = co + numberOfColumns;
for (int ro = lastRow; ro >= firstRow; ro--)
{
var oldKey = new XLAddress(Worksheet, ro, co, false, false);
- int newColumn = co + numberOfColumns;
var newKey = new XLAddress(Worksheet, ro, newColumn, false, false);
var oldCell = Worksheet.Internals.CellsCollection.GetCell(ro, co) ??
Worksheet.Cell(oldKey);
@@ -1106,6 +1135,11 @@
cellsToInsert.Add(newKey, newCell);
cellsToDelete.Add(oldKey);
}
+
+ if (this.IsEntireColumn())
+ {
+ Worksheet.Column(newColumn).Width = Worksheet.Column(co).Width;
+ }
}
}
}
@@ -1193,7 +1227,6 @@
: Worksheet.Style;
rangeToReturn.Row(ro).Style = styleToUse;
}
-
}
}
@@ -1284,15 +1317,17 @@
return retVal;
}
- struct DataValidationToCopy
+ private struct DataValidationToCopy
{
public XLAddress SourceAddress;
public XLDataValidation DataValidation;
}
+
public void InsertRowsAboveVoid(Boolean onlyUsedCells, Int32 numberOfRows, Boolean formatFromAbove = true)
{
InsertRowsAboveInternal(onlyUsedCells, numberOfRows, formatFromAbove, nullReturn: true);
}
+
public IXLRangeRows InsertRowsAbove(Boolean onlyUsedCells, Int32 numberOfRows, Boolean formatFromAbove = true)
{
return InsertRowsAboveInternal(onlyUsedCells, numberOfRows, formatFromAbove, nullReturn: false);
@@ -1303,7 +1338,7 @@
using (var asRange = AsRange())
foreach (XLWorksheet ws in Worksheet.Workbook.WorksheetsInternal)
{
- foreach (XLCell cell in ws.Internals.CellsCollection.GetCells(c => !XLHelper.IsNullOrWhiteSpace(c.FormulaA1)))
+ foreach (XLCell cell in ws.Internals.CellsCollection.GetCells(c => !String.IsNullOrWhiteSpace(c.FormulaA1)))
cell.ShiftFormulaRows(asRange, numberOfRows);
}
@@ -1323,10 +1358,11 @@
{
for (int ro = lastRow; ro >= firstRow; ro--)
{
+ int newRow = ro + numberOfRows;
+
for (int co = lastColumn; co >= firstColumn; co--)
{
var oldKey = new XLAddress(Worksheet, ro, co, false, false);
- int newRow = ro + numberOfRows;
var newKey = new XLAddress(Worksheet, newRow, co, false, false);
var oldCell = Worksheet.Internals.CellsCollection.GetCell(ro, co);
if (oldCell != null)
@@ -1338,6 +1374,10 @@
cellsToDelete.Add(oldKey);
}
}
+ if (this.IsEntireRow())
+ {
+ Worksheet.Row(newRow).Height = Worksheet.Row(ro).Height;
+ }
}
}
}
@@ -1363,7 +1403,6 @@
newCell.FormulaA1 = c.FormulaA1;
cellsToInsert.Add(newKey, newCell);
cellsToDelete.Add(c.Address);
-
}
}
@@ -1381,7 +1420,6 @@
cellsToDelete.ForEach(c => Worksheet.Internals.CellsCollection.Remove(c.RowNumber, c.ColumnNumber));
cellsToInsert.ForEach(c => Worksheet.Internals.CellsCollection.Add(c.Key.RowNumber, c.Key.ColumnNumber, c.Value));
-
Int32 firstRowReturn = RangeAddress.FirstAddress.RowNumber;
Int32 lastRowReturn = RangeAddress.FirstAddress.RowNumber + numberOfRows - 1;
Int32 firstColumnReturn = RangeAddress.FirstAddress.ColumnNumber;
@@ -1472,12 +1510,11 @@
RangeAddress.LastAddress.RowNumber,
RangeAddress.LastAddress.ColumnNumber);
-
foreach (
XLCell cell in
Worksheet.Workbook.Worksheets.Cast().SelectMany(
xlWorksheet => (xlWorksheet).Internals.CellsCollection.GetCells(
- c => !XLHelper.IsNullOrWhiteSpace(c.FormulaA1))))
+ c => !String.IsNullOrWhiteSpace(c.FormulaA1))))
{
if (shiftDeleteCells == XLShiftDeletedCells.ShiftCellsUp)
cell.ShiftFormulaRows((XLRange)shiftedRangeFormula, numberOfRows * -1);
@@ -1501,7 +1538,6 @@
Worksheet.Internals.CellsCollection.MaxRowUsed,
RangeAddress.LastAddress.ColumnNumber);
-
int columnModifier = shiftDeleteCells == XLShiftDeletedCells.ShiftCellsLeft ? ColumnCount() : 0;
int rowModifier = shiftDeleteCells == XLShiftDeletedCells.ShiftCellsUp ? RowCount() : 0;
var cellsQuery = shiftDeleteCells == XLShiftDeletedCells.ShiftCellsLeft ? shiftLeftQuery : shiftUpQuery;
@@ -1523,7 +1559,6 @@
cellsToInsert.Add(newKey, newCell);
}
-
cellsToDelete.ForEach(c => Worksheet.Internals.CellsCollection.Remove(c.RowNumber, c.ColumnNumber));
cellsToInsert.ForEach(
c => Worksheet.Internals.CellsCollection.Add(c.Key.RowNumber, c.Key.ColumnNumber, c.Value));
@@ -1698,17 +1733,16 @@
// return chart;
//}
-
IXLPivotTable IXLRangeBase.CreatePivotTable(IXLCell targetCell)
{
return CreatePivotTable(targetCell);
}
+
IXLPivotTable IXLRangeBase.CreatePivotTable(IXLCell targetCell, String name)
{
return CreatePivotTable(targetCell, name);
}
-
public XLPivotTable CreatePivotTable(IXLCell targetCell)
{
return CreatePivotTable(targetCell, Guid.NewGuid().ToString());
@@ -1760,7 +1794,7 @@
public IXLRangeBase Sort(String columnsToSortBy, XLSortOrder sortOrder = XLSortOrder.Ascending, Boolean matchCase = false, Boolean ignoreBlanks = true)
{
SortColumns.Clear();
- if (XLHelper.IsNullOrWhiteSpace(columnsToSortBy))
+ if (String.IsNullOrWhiteSpace(columnsToSortBy))
{
columnsToSortBy = String.Empty;
Int32 maxColumn = ColumnCount();
@@ -1821,7 +1855,6 @@
return this;
}
-
#region Sort Rows
private void SortRangeRows()
@@ -1886,7 +1919,7 @@
SortingRangeRows(pivot + 1, end);
}
- #endregion
+ #endregion Sort Rows
#region Sort Columns
@@ -1951,9 +1984,9 @@
SortingRangeColumns(pivot + 1, end);
}
- #endregion
+ #endregion Sort Columns
- #endregion
+ #endregion Sort
public XLRangeColumn ColumnQuick(Int32 column)
{
@@ -2017,7 +2050,6 @@
}
}
-
internal IXLConditionalFormat AddConditionalFormat(IXLConditionalFormat source)
{
using (var asRange = AsRange())
diff --git a/ClosedXML/Excel/Ranges/XLRangeColumn.cs b/ClosedXML/Excel/Ranges/XLRangeColumn.cs
index 7449d3c..34710ea 100644
--- a/ClosedXML/Excel/Ranges/XLRangeColumn.cs
+++ b/ClosedXML/Excel/Ranges/XLRangeColumn.cs
@@ -1,9 +1,8 @@
+using System;
+using System.Linq;
+
namespace ClosedXML.Excel
{
- using System;
- using System.Linq;
-
-
internal class XLRangeColumn : XLRangeBase, IXLRangeColumn
{
#region Constructor
@@ -13,18 +12,24 @@
{
if (quickLoad) return;
- SubscribeToShiftedRows((range, rowsShifted) => this.WorksheetRangeShiftedRows(range, rowsShifted));
- SubscribeToShiftedColumns((range, columnsShifted) => this.WorksheetRangeShiftedColumns(range, columnsShifted));
+ SubscribeToShiftedRows((range, rowsShifted) => this.WorksheetRangeShiftedRows(range, rowsShifted));
+ SubscribeToShiftedColumns((range, columnsShifted) => this.WorksheetRangeShiftedColumns(range, columnsShifted));
SetStyle(rangeParameters.DefaultStyle);
}
- #endregion
+ public XLRangeColumn(XLRangeParameters rangeParameters, bool quickLoad, IXLTable table)
+ : this(rangeParameters, quickLoad)
+ {
+ this.Table = table;
+ }
+
+ #endregion Constructor
#region IXLRangeColumn Members
- IXLCell IXLRangeColumn.Cell(int row)
+ IXLCell IXLRangeColumn.Cell(int rowNumber)
{
- return Cell(row);
+ return Cell(rowNumber);
}
public new IXLCells Cells(string cellsInColumn)
@@ -43,6 +48,22 @@
public void Delete()
{
+ Delete(true);
+ }
+
+ internal void Delete(Boolean deleteTableField)
+ {
+ if (deleteTableField && IsTableColumn())
+ {
+ var table = Table as XLTable;
+ var firstCellValue = Cell(1).Value.ToString();
+ if (!table.FieldNames.ContainsKey(firstCellValue))
+ throw new ArgumentException(string.Format("Field {0} not found.", firstCellValue));
+
+ var field = table.Fields.Cast().Single(f => f.Name == firstCellValue);
+ field.Delete(false);
+ }
+
Delete(XLShiftDeletedCells.ShiftCellsLeft);
}
@@ -77,7 +98,6 @@
return this;
}
-
public new IXLRangeColumn CopyTo(IXLCell target)
{
base.CopyTo(target);
@@ -166,7 +186,7 @@
return Worksheet.Column(RangeAddress.FirstAddress.ColumnNumber);
}
- #endregion
+ #endregion IXLRangeColumn Members
public XLCell Cell(int row)
{
@@ -289,7 +309,7 @@
return ColumnShift(step * -1);
}
- #endregion
+ #endregion XLRangeColumn Left
#region XLRangeColumn Right
@@ -313,29 +333,40 @@
return ColumnShift(step);
}
- #endregion
-
+ #endregion XLRangeColumn Right
public IXLTable AsTable()
{
+ if (IsTableColumn())
+ throw new InvalidOperationException("This column is already part of a table.");
+
using (var asRange = AsRange())
- return asRange.AsTable();
+ return asRange.AsTable();
}
public IXLTable AsTable(string name)
{
+ if (IsTableColumn())
+ throw new InvalidOperationException("This column is already part of a table.");
+
using (var asRange = AsRange())
return asRange.AsTable(name);
}
public IXLTable CreateTable()
{
+ if (IsTableColumn())
+ throw new InvalidOperationException("This column is already part of a table.");
+
using (var asRange = AsRange())
return asRange.CreateTable();
}
public IXLTable CreateTable(string name)
{
+ if (IsTableColumn())
+ throw new InvalidOperationException("This column is already part of a table.");
+
using (var asRange = AsRange())
return asRange.CreateTable(name);
}
@@ -351,5 +382,11 @@
return Column(FirstCellUsed(includeFormats), LastCellUsed(includeFormats));
}
+ internal IXLTable Table { get; set; }
+
+ public Boolean IsTableColumn()
+ {
+ return Table != null;
+ }
}
}
diff --git a/ClosedXML/Excel/Rows/IXLRow.cs b/ClosedXML/Excel/Rows/IXLRow.cs
index 3bec732..70816fb 100644
--- a/ClosedXML/Excel/Rows/IXLRow.cs
+++ b/ClosedXML/Excel/Rows/IXLRow.cs
@@ -15,6 +15,11 @@
Double Height { get; set; }
///
+ /// Clears the height for the row and defaults it to the spreadsheet row height.
+ ///
+ void ClearHeight();
+
+ ///
/// Deletes this row and shifts the rows below this one accordingly.
///
void Delete();
diff --git a/ClosedXML/Excel/Rows/XLRow.cs b/ClosedXML/Excel/Rows/XLRow.cs
index 944cb17..a847178 100644
--- a/ClosedXML/Excel/Rows/XLRow.cs
+++ b/ClosedXML/Excel/Rows/XLRow.cs
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Drawing;
-
+using System.Linq;
namespace ClosedXML.Excel
{
@@ -15,7 +14,7 @@
private Boolean _isHidden;
private Int32 _outlineLevel;
- #endregion
+ #endregion Private fields
#region Constructor
@@ -44,7 +43,7 @@
_height = row._height;
IsReference = row.IsReference;
if (IsReference)
- SubscribeToShiftedRows((range, rowShifted) => this.WorksheetRangeShiftedRows(range, rowShifted));
+ SubscribeToShiftedRows((range, rowShifted) => this.WorksheetRangeShiftedRows(range, rowShifted));
_collapsed = row._collapsed;
_isHidden = row._isHidden;
@@ -53,7 +52,7 @@
SetStyle(row.GetStyleId());
}
- #endregion
+ #endregion Constructor
public Boolean IsReference { get; private set; }
@@ -108,6 +107,7 @@
#region IXLRow Members
private Boolean _loading;
+
public Boolean Loading
{
get { return IsReference ? Worksheet.Internals.RowsCollection[RowNumber()].Loading : _loading; }
@@ -121,6 +121,7 @@
}
public Boolean HeightChanged { get; private set; }
+
public Double Height
{
get { return IsReference ? Worksheet.Internals.RowsCollection[RowNumber()].Height : _height; }
@@ -136,6 +137,12 @@
}
}
+ public void ClearHeight()
+ {
+ Height = Worksheet.RowHeight;
+ HeightChanged = false;
+ }
+
public void Delete()
{
int rowNumber = RowNumber();
@@ -291,7 +298,7 @@
foreach (IXLRichString rt in c.RichText)
{
String formattedString = rt.Text;
- var arr = formattedString.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
+ var arr = formattedString.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
Int32 arrCount = arr.Count();
for (Int32 i = 0; i < arrCount; i++)
{
@@ -305,7 +312,7 @@
else
{
String formattedString = c.GetFormattedString();
- var arr = formattedString.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
+ var arr = formattedString.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
Int32 arrCount = arr.Count();
for (Int32 i = 0; i < arrCount; i++)
{
@@ -338,7 +345,7 @@
}
}
else
- thisHeight = c.Style.Font.GetHeight( fontCache);
+ thisHeight = c.Style.Font.GetHeight(fontCache);
if (thisHeight >= maxHeight)
{
@@ -520,15 +527,15 @@
IXLRangeRow IXLRow.CopyTo(IXLCell target)
{
using (var asRange = AsRange())
- using (var copy = asRange.CopyTo(target))
- return copy.Row(1);
+ using (var copy = asRange.CopyTo(target))
+ return copy.Row(1);
}
IXLRangeRow IXLRow.CopyTo(IXLRangeBase target)
{
using (var asRange = AsRange())
- using (var copy = asRange.CopyTo(target))
- return copy.Row(1);
+ using (var copy = asRange.CopyTo(target))
+ return copy.Row(1);
}
public IXLRow CopyTo(IXLRow row)
@@ -581,7 +588,7 @@
return Row(FirstCellUsed(includeFormats), LastCellUsed(includeFormats));
}
- #endregion
+ #endregion IXLRow Members
public override XLRange AsRange()
{
@@ -676,7 +683,7 @@
return RowShift(step * -1);
}
- #endregion
+ #endregion XLRow Above
#region XLRow Below
@@ -700,14 +707,14 @@
return RowShift(step);
}
- #endregion
+ #endregion XLRow Below
- public new Boolean IsEmpty()
+ public override Boolean IsEmpty()
{
return IsEmpty(false);
}
- public new Boolean IsEmpty(Boolean includeFormats)
+ public override Boolean IsEmpty(Boolean includeFormats)
{
if (includeFormats && !Style.Equals(Worksheet.Style))
return false;
@@ -715,6 +722,14 @@
return base.IsEmpty(includeFormats);
}
+ public override Boolean IsEntireRow()
+ {
+ return true;
+ }
+ public override Boolean IsEntireColumn()
+ {
+ return false;
+ }
}
}
diff --git a/ClosedXML/Excel/SaveOptions.cs b/ClosedXML/Excel/SaveOptions.cs
new file mode 100644
index 0000000..7dcd9a1
--- /dev/null
+++ b/ClosedXML/Excel/SaveOptions.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ClosedXML.Excel
+{
+ public sealed class SaveOptions
+ {
+ public SaveOptions()
+ {
+#if DEBUG
+ this.ValidatePackage = true;
+#else
+ this.ValidatePackage = false;
+#endif
+
+ this.EvaluateFormulasBeforeSaving = false;
+ this.GenerateCalculationChain = true;
+ }
+ public Boolean ValidatePackage;
+ public Boolean EvaluateFormulasBeforeSaving;
+ public Boolean GenerateCalculationChain;
+ }
+}
diff --git a/ClosedXML/Excel/Style/Colors/XLColor_Public.cs b/ClosedXML/Excel/Style/Colors/XLColor_Public.cs
index 6feefe3..4d0d9d3 100644
--- a/ClosedXML/Excel/Style/Colors/XLColor_Public.cs
+++ b/ClosedXML/Excel/Style/Colors/XLColor_Public.cs
@@ -55,7 +55,7 @@
get
{
if (_colorType == XLColorType.Theme)
- throw new Exception("Cannot convert theme color to Color.");
+ throw new InvalidOperationException("Cannot convert theme color to Color.");
if (_colorType == XLColorType.Indexed)
if (_indexed == TOOLTIPCOLORINDEX)
@@ -72,12 +72,12 @@
get
{
if (ColorType == XLColorType.Theme)
- throw new Exception("Cannot convert theme color to indexed color.");
+ throw new InvalidOperationException("Cannot convert theme color to indexed color.");
if (ColorType == XLColorType.Indexed)
return _indexed;
- throw new Exception("Cannot convert Color to indexed color.");
+ throw new InvalidOperationException("Cannot convert Color to indexed color.");
}
}
@@ -89,9 +89,9 @@
return _themeColor;
if (ColorType == XLColorType.Indexed)
- throw new Exception("Cannot convert indexed color to theme color.");
+ throw new InvalidOperationException("Cannot convert indexed color to theme color.");
- throw new Exception("Cannot convert Color to theme color.");
+ throw new InvalidOperationException("Cannot convert Color to theme color.");
}
}
@@ -103,7 +103,7 @@
return _themeTint;
if (ColorType == XLColorType.Indexed)
- throw new Exception("Cannot extract theme tint from an indexed color.");
+ throw new InvalidOperationException("Cannot extract theme tint from an indexed color.");
return _color.A/255.0;
}
diff --git a/ClosedXML/Excel/Tables/IXLTableField.cs b/ClosedXML/Excel/Tables/IXLTableField.cs
index 5bc695c..91ba4e8 100644
--- a/ClosedXML/Excel/Tables/IXLTableField.cs
+++ b/ClosedXML/Excel/Tables/IXLTableField.cs
@@ -18,11 +18,14 @@
public interface IXLTableField
{
+ IXLRangeColumn Column { get; }
Int32 Index { get; }
String Name { get; set; }
- String TotalsRowLabel { get; set; }
String TotalsRowFormulaA1 { get; set; }
String TotalsRowFormulaR1C1 { get; set; }
XLTotalsRowFunction TotalsRowFunction { get; set; }
+ String TotalsRowLabel { get; set; }
+
+ void Delete();
}
}
diff --git a/ClosedXML/Excel/Tables/XLTable.cs b/ClosedXML/Excel/Tables/XLTable.cs
index 51bfac7..6048e33 100644
--- a/ClosedXML/Excel/Tables/XLTable.cs
+++ b/ClosedXML/Excel/Tables/XLTable.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -13,12 +13,12 @@
internal bool _showTotalsRow;
internal HashSet _uniqueNames;
- #endregion
+ #endregion Private fields
#region Constructor
public XLTable(XLRange range, Boolean addToTables, Boolean setAutofilter = true)
- : base(new XLRangeParameters(range.RangeAddress, range.Style ))
+ : base(new XLRangeParameters(range.RangeAddress, range.Style))
{
InitializeValues(setAutofilter);
@@ -45,10 +45,11 @@
AddToTables(range, addToTables);
}
- #endregion
+ #endregion Constructor
private IXLRangeAddress _lastRangeAddress;
private Dictionary _fieldNames = null;
+
public Dictionary FieldNames
{
get
@@ -65,7 +66,7 @@
foreach (var cell in headersRow.Cells())
{
var name = cell.GetString();
- if (XLHelper.IsNullOrWhiteSpace(name))
+ if (String.IsNullOrWhiteSpace(name))
{
name = "Column" + (cellPos + 1);
cell.SetValue(name);
@@ -73,13 +74,11 @@
if (_fieldNames.ContainsKey(name))
throw new ArgumentException("The header row contains more than one field name '" + name + "'.");
- _fieldNames.Add(name, new XLTableField(this, name) {Index = cellPos++ });
+ _fieldNames.Add(name, new XLTableField(this, name) { Index = cellPos++ });
}
}
else
{
- if (_fieldNames == null) _fieldNames = new Dictionary();
-
Int32 colCount = ColumnCount();
for (Int32 i = 1; i <= colCount; i++)
{
@@ -87,7 +86,7 @@
{
var name = "Column" + i;
- _fieldNames.Add(name, new XLTableField(this, name) {Index = i - 1 });
+ _fieldNames.Add(name, new XLTableField(this, name) { Index = i - 1 });
}
}
}
@@ -100,12 +99,21 @@
_fieldNames = new Dictionary();
Int32 cellPos = 0;
- foreach(var name in fieldNames)
+ foreach (var name in fieldNames)
{
_fieldNames.Add(name, new XLTableField(this, name) { Index = cellPos++ });
}
}
+ internal void RenameField(String oldName, String newName)
+ {
+ if (!_fieldNames.ContainsKey(oldName))
+ throw new ArgumentException("The field does not exist in this table", "oldName");
+
+ var field = _fieldNames[oldName];
+ _fieldNames.Remove(oldName);
+ _fieldNames.Add(newName, field);
+ }
internal String RelId { get; set; }
@@ -121,7 +129,7 @@
if (_showHeaderRow)
{
range = _showTotalsRow
- ? Range(2, 1,RowCount() - 1,ColumnCount())
+ ? Range(2, 1, RowCount() - 1, ColumnCount())
: Range(2, 1, RowCount(), ColumnCount());
}
else
@@ -136,6 +144,7 @@
}
private XLAutoFilter _autoFilter;
+
public XLAutoFilter AutoFilter
{
get
@@ -164,10 +173,13 @@
public Boolean ShowColumnStripes { get; set; }
private Boolean _showAutoFilter;
- public Boolean ShowAutoFilter {
+
+ public Boolean ShowAutoFilter
+ {
get { return _showHeaderRow && _showAutoFilter; }
set { _showAutoFilter = value; }
- }
+ }
+
public XLTableTheme Theme { get; set; }
public String Name
@@ -364,9 +376,7 @@
base.Dispose();
}
- #endregion
-
-
+ #endregion IXLTable Members
private void InitializeValues(Boolean setAutofilter)
{
@@ -395,7 +405,7 @@
Int32 co = 1;
foreach (IXLCell c in range.Row(1).Cells())
{
- if (XLHelper.IsNullOrWhiteSpace(((XLCell)c).InnerText))
+ if (String.IsNullOrWhiteSpace(((XLCell)c).InnerText))
c.Value = GetUniqueName("Column" + co.ToInvariantString());
_uniqueNames.Add(c.GetString());
co++;
@@ -403,7 +413,6 @@
Worksheet.Tables.Add(this);
}
-
private String GetUniqueName(String originalName)
{
String name = originalName;
@@ -424,6 +433,10 @@
public Int32 GetFieldIndex(String name)
{
+ // There is a discrepancy in the way headers with line breaks are stored.
+ // The entry in the table definition will contain \r\n
+ // but the shared string value of the actual cell will contain only \n
+ name = name.Replace("\r\n", "\n");
if (FieldNames.ContainsKey(name))
return FieldNames[name].Index;
@@ -431,6 +444,7 @@
}
internal Boolean _showHeaderRow;
+
public Boolean ShowHeaderRow
{
get { return _showHeaderRow; }
@@ -445,7 +459,7 @@
Int32 co = 1;
foreach (IXLCell c in headersRow.Cells())
{
- if (XLHelper.IsNullOrWhiteSpace(((XLCell)c).InnerText))
+ if (String.IsNullOrWhiteSpace(((XLCell)c).InnerText))
c.Value = GetUniqueName("Column" + co.ToInvariantString());
_uniqueNames.Add(c.GetString());
co++;
@@ -461,59 +475,59 @@
}
else
{
- using(var asRange = Worksheet.Range(
- RangeAddress.FirstAddress.RowNumber - 1 ,
+ using (var asRange = Worksheet.Range(
+ RangeAddress.FirstAddress.RowNumber - 1,
RangeAddress.FirstAddress.ColumnNumber,
RangeAddress.LastAddress.RowNumber,
RangeAddress.LastAddress.ColumnNumber
))
- using (var firstRow = asRange.FirstRow())
- {
- IXLRangeRow rangeRow;
- if (firstRow.IsEmpty(true))
- {
- rangeRow = firstRow;
- RangeAddress.FirstAddress = new XLAddress(Worksheet,
- RangeAddress.FirstAddress.RowNumber - 1,
- RangeAddress.FirstAddress.ColumnNumber,
- RangeAddress.FirstAddress.FixedRow,
- RangeAddress.FirstAddress.FixedColumn);
- }
- else
- {
- var fAddress = RangeAddress.FirstAddress;
- var lAddress = RangeAddress.LastAddress;
+ using (var firstRow = asRange.FirstRow())
+ {
+ IXLRangeRow rangeRow;
+ if (firstRow.IsEmpty(true))
+ {
+ rangeRow = firstRow;
+ RangeAddress.FirstAddress = new XLAddress(Worksheet,
+ RangeAddress.FirstAddress.RowNumber - 1,
+ RangeAddress.FirstAddress.ColumnNumber,
+ RangeAddress.FirstAddress.FixedRow,
+ RangeAddress.FirstAddress.FixedColumn);
+ }
+ else
+ {
+ var fAddress = RangeAddress.FirstAddress;
+ var lAddress = RangeAddress.LastAddress;
- rangeRow = firstRow.InsertRowsBelow(1, false).First();
+ rangeRow = firstRow.InsertRowsBelow(1, false).First();
+ RangeAddress.FirstAddress = new XLAddress(Worksheet, fAddress.RowNumber,
+ fAddress.ColumnNumber,
+ fAddress.FixedRow,
+ fAddress.FixedColumn);
- RangeAddress.FirstAddress = new XLAddress(Worksheet, fAddress.RowNumber,
- fAddress.ColumnNumber,
- fAddress.FixedRow,
- fAddress.FixedColumn);
+ RangeAddress.LastAddress = new XLAddress(Worksheet, lAddress.RowNumber + 1,
+ lAddress.ColumnNumber,
+ lAddress.FixedRow,
+ lAddress.FixedColumn);
+ }
- RangeAddress.LastAddress = new XLAddress(Worksheet, lAddress.RowNumber + 1,
- lAddress.ColumnNumber,
- lAddress.FixedRow,
- lAddress.FixedColumn);
- }
-
- Int32 co = 1;
- foreach (var name in FieldNames.Values.Select(f => f.Name))
- {
- rangeRow.Cell(co).SetValue(name);
- co++;
- }
-
- }
+ Int32 co = 1;
+ foreach (var name in FieldNames.Values.Select(f => f.Name))
+ {
+ rangeRow.Cell(co).SetValue(name);
+ co++;
+ }
+ }
}
_showHeaderRow = value;
}
}
+
public IXLTable SetShowHeaderRow()
{
return SetShowHeaderRow(true);
}
+
public IXLTable SetShowHeaderRow(Boolean value)
{
ShowHeaderRow = value;
@@ -528,5 +542,60 @@
RangeAddress.LastAddress.FixedColumn);
}
+ public override XLRangeColumn Column(int columnNumber)
+ {
+ var column = base.Column(columnNumber);
+ column.Table = this;
+ return column;
+ }
+
+ public override XLRangeColumn Column(string columnName)
+ {
+ var column = base.Column(columnName);
+ column.Table = this;
+ return column;
+ }
+
+ public override IXLRangeColumns Columns(int firstColumn, int lastColumn)
+ {
+ var columns = base.Columns(firstColumn, lastColumn);
+ columns.Cast().ForEach(column => column.Table = this);
+ return columns;
+ }
+
+ public override IXLRangeColumns Columns(Func predicate = null)
+ {
+ var columns = base.Columns(predicate);
+ columns.Cast().ForEach(column => column.Table = this);
+ return columns;
+ }
+
+ public override IXLRangeColumns Columns(string columns)
+ {
+ var cols = base.Columns(columns);
+ cols.Cast().ForEach(column => column.Table = this);
+ return cols;
+ }
+
+ public override IXLRangeColumns Columns(string firstColumn, string lastColumn)
+ {
+ var columns = base.Columns(firstColumn, lastColumn);
+ columns.Cast().ForEach(column => column.Table = this);
+ return columns;
+ }
+
+ public override XLRangeColumns ColumnsUsed(bool includeFormats, Func predicate = null)
+ {
+ var columns = base.ColumnsUsed(includeFormats, predicate);
+ columns.Cast().ForEach(column => column.Table = this);
+ return columns;
+ }
+
+ public override XLRangeColumns ColumnsUsed(Func predicate = null)
+ {
+ var columns = base.ColumnsUsed(predicate);
+ columns.Cast().ForEach(column => column.Table = this);
+ return columns;
+ }
}
}
diff --git a/ClosedXML/Excel/Tables/XLTableField.cs b/ClosedXML/Excel/Tables/XLTableField.cs
index 744700f..528d7d2 100644
--- a/ClosedXML/Excel/Tables/XLTableField.cs
+++ b/ClosedXML/Excel/Tables/XLTableField.cs
@@ -1,19 +1,30 @@
-using System;
+using System;
+using System.Diagnostics;
+using System.Linq;
namespace ClosedXML.Excel
{
- internal class XLTableField: IXLTableField
+ [DebuggerDisplay("{Name}")]
+ internal class XLTableField : IXLTableField
{
- private XLTable table;
+ internal XLTotalsRowFunction totalsRowFunction;
+ internal String totalsRowLabel;
+ private readonly XLTable table;
+
+ private String name;
+
public XLTableField(XLTable table, String name)
{
this.table = table;
this.name = name;
}
- public Int32 Index { get; internal set; }
+ public IXLRangeColumn Column
+ {
+ get { return table.Column(this.Index); }
+ }
- private String name;
+ public Int32 Index { get; internal set; }
public String Name
{
@@ -26,22 +37,11 @@
if (table.ShowHeaderRow)
table.HeadersRow().Cell(Index + 1).SetValue(value);
+ table.RenameField(name, value);
name = value;
}
}
- internal String totalsRowLabel;
- public String TotalsRowLabel
- {
- get { return totalsRowLabel; }
- set
- {
- totalsRowFunction = XLTotalsRowFunction.None;
- table.TotalsRow().Cell(Index + 1).SetValue(value);
- totalsRowLabel = value;
- }
- }
-
public String TotalsRowFormulaA1
{
get { return table.TotalsRow().Cell(Index + 1).FormulaA1; }
@@ -51,6 +51,7 @@
table.TotalsRow().Cell(Index + 1).FormulaA1 = value;
}
}
+
public String TotalsRowFormulaR1C1
{
get { return table.TotalsRow().Cell(Index + 1).FormulaR1C1; }
@@ -61,7 +62,6 @@
}
}
- internal XLTotalsRowFunction totalsRowFunction;
public XLTotalsRowFunction TotalsRowFunction
{
get { return totalsRowFunction; }
@@ -94,5 +94,31 @@
totalsRowFunction = value;
}
}
+
+ public String TotalsRowLabel
+ {
+ get { return totalsRowLabel; }
+ set
+ {
+ totalsRowFunction = XLTotalsRowFunction.None;
+ table.TotalsRow().Cell(Index + 1).SetValue(value);
+ totalsRowLabel = value;
+ }
+ }
+
+ public void Delete()
+ {
+ Delete(true);
+ }
+
+ internal void Delete(Boolean deleteUnderlyingRangeColumn)
+ {
+ var fields = table.Fields.Cast();
+ fields.Where(f => f.Index > this.Index).ForEach(f => f.Index--);
+ table.FieldNames.Remove(this.Name);
+
+ if (deleteUnderlyingRangeColumn)
+ (this.Column as XLRangeColumn).Delete(false);
+ }
}
}
diff --git a/ClosedXML/Excel/XLWorkbook.cs b/ClosedXML/Excel/XLWorkbook.cs
index 9e86a67..bdcc86c 100644
--- a/ClosedXML/Excel/XLWorkbook.cs
+++ b/ClosedXML/Excel/XLWorkbook.cs
@@ -4,13 +4,14 @@
using System;
using System.Collections.Generic;
using System.Data;
+using System.Globalization;
using System.IO;
using System.Linq;
namespace ClosedXML.Excel
{
-
public enum XLEventTracking { Enabled, Disabled }
+
public enum XLCalculateMode
{
Auto,
@@ -58,14 +59,11 @@
Italic = false,
Underline = XLFontUnderlineValues.None,
Strikethrough = false,
- VerticalAlignment =
- XLFontVerticalTextAlignmentValues.
- Baseline,
+ VerticalAlignment = XLFontVerticalTextAlignmentValues.Baseline,
FontSize = 11,
FontColor = XLColor.FromArgb(0, 0, 0),
FontName = "Calibri",
- FontFamilyNumbering =
- XLFontFamilyNumberingValues.Swiss
+ FontFamilyNumbering = XLFontFamilyNumberingValues.Swiss
},
Fill = new XLFill(null)
{
@@ -75,10 +73,8 @@
},
Border = new XLBorder(null, null)
{
- BottomBorder =
- XLBorderStyleValues.None,
- DiagonalBorder =
- XLBorderStyleValues.None,
+ BottomBorder = XLBorderStyleValues.None,
+ DiagonalBorder = XLBorderStyleValues.None,
DiagonalDown = false,
DiagonalUp = false,
LeftBorder = XLBorderStyleValues.None,
@@ -90,24 +86,17 @@
RightBorderColor = XLColor.Black,
TopBorderColor = XLColor.Black
},
- NumberFormat =
- new XLNumberFormat(null, null) {NumberFormatId = 0},
+ NumberFormat = new XLNumberFormat(null, null) { NumberFormatId = 0 },
Alignment = new XLAlignment(null)
{
Indent = 0,
- Horizontal =
- XLAlignmentHorizontalValues.
- General,
+ Horizontal = XLAlignmentHorizontalValues.General,
JustifyLastLine = false,
- ReadingOrder =
- XLAlignmentReadingOrderValues.
- ContextDependent,
+ ReadingOrder = XLAlignmentReadingOrderValues.ContextDependent,
RelativeIndent = 0,
ShrinkToFit = false,
TextRotation = 0,
- Vertical =
- XLAlignmentVerticalValues.
- Bottom,
+ Vertical = XLAlignmentVerticalValues.Bottom,
WrapText = false
},
Protection = new XLProtection(null)
@@ -166,7 +155,12 @@
///
public static XLCellSetValueBehavior CellSetValueBehavior { get; set; }
- #endregion
+ public static XLWorkbook OpenFromTemplate(String path)
+ {
+ return new XLWorkbook(path, true);
+ }
+
+ #endregion Static
internal readonly List UnsupportedSheets =
new List();
@@ -203,7 +197,7 @@
Stream
};
- #endregion
+ #endregion Nested Type: XLLoadSource
internal XLWorksheets WorksheetsInternal { get; private set; }
@@ -265,7 +259,6 @@
///
public XLCalculateMode CalculateMode { get; set; }
-
public Boolean CalculationOnSave { get; set; }
public Boolean ForceFullCalculation { get; set; }
public Boolean FullCalculationOnLoad { get; set; }
@@ -352,24 +345,34 @@
{
case XLThemeColor.Text1:
return Theme.Text1;
+
case XLThemeColor.Background1:
return Theme.Background1;
+
case XLThemeColor.Text2:
return Theme.Text2;
+
case XLThemeColor.Background2:
return Theme.Background2;
+
case XLThemeColor.Accent1:
return Theme.Accent1;
+
case XLThemeColor.Accent2:
return Theme.Accent2;
+
case XLThemeColor.Accent3:
return Theme.Accent3;
+
case XLThemeColor.Accent4:
return Theme.Accent4;
+
case XLThemeColor.Accent5:
return Theme.Accent5;
+
case XLThemeColor.Accent6:
return Theme.Accent6;
+
default:
throw new ArgumentException("Invalid theme color");
}
@@ -422,7 +425,6 @@
return null;
}
-
///
/// Saves the current workbook.
///
@@ -440,16 +442,26 @@
///
public void Save(Boolean validate, Boolean evaluateFormulae = false)
{
+ Save(new SaveOptions
+ {
+ ValidatePackage = validate,
+ EvaluateFormulasBeforeSaving = evaluateFormulae,
+ GenerateCalculationChain = true
+ });
+ }
+
+ public void Save(SaveOptions options)
+ {
checkForWorksheetsPresent();
if (_loadSource == XLLoadSource.New)
- throw new Exception("This is a new file, please use one of the SaveAs methods.");
+ throw new InvalidOperationException("This is a new file. Please use one of the 'SaveAs' methods.");
if (_loadSource == XLLoadSource.Stream)
{
- CreatePackage(_originalStream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(_originalStream, false, _spreadsheetDocumentType, options);
}
else
- CreatePackage(_originalFile, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(_originalFile, _spreadsheetDocumentType, options);
}
///
@@ -469,6 +481,16 @@
///
public void SaveAs(String file, Boolean validate, Boolean evaluateFormulae = false)
{
+ SaveAs(file, new SaveOptions
+ {
+ ValidatePackage = validate,
+ EvaluateFormulasBeforeSaving = evaluateFormulae,
+ GenerateCalculationChain = true
+ });
+ }
+
+ public void SaveAs(String file, SaveOptions options)
+ {
checkForWorksheetsPresent();
PathHelper.CreateDirectory(Path.GetDirectoryName(file));
if (_loadSource == XLLoadSource.New)
@@ -476,14 +498,14 @@
if (File.Exists(file))
File.Delete(file);
- CreatePackage(file, GetSpreadsheetDocumentType(file), validate, evaluateFormulae);
+ CreatePackage(file, GetSpreadsheetDocumentType(file), options);
}
else if (_loadSource == XLLoadSource.File)
{
if (String.Compare(_originalFile.Trim(), file.Trim(), true) != 0)
File.Copy(_originalFile, file, true);
- CreatePackage(file, GetSpreadsheetDocumentType(file), validate, evaluateFormulae);
+ CreatePackage(file, GetSpreadsheetDocumentType(file), options);
}
else if (_loadSource == XLLoadSource.Stream)
{
@@ -492,8 +514,7 @@
using (var fileStream = File.Create(file))
{
CopyStream(_originalStream, fileStream);
- //fileStream.Position = 0;
- CreatePackage(fileStream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(fileStream, false, _spreadsheetDocumentType, options);
fileStream.Close();
}
}
@@ -502,7 +523,8 @@
private static SpreadsheetDocumentType GetSpreadsheetDocumentType(string filePath)
{
var extension = Path.GetExtension(filePath);
- if (extension == null) throw new Exception("Empty extension is not supported.");
+
+ if (extension == null) throw new ArgumentException("Empty extension is not supported.");
extension = extension.Substring(1).ToLowerInvariant();
switch (extension)
@@ -510,19 +532,20 @@
case "xlsm":
case "xltm":
return SpreadsheetDocumentType.MacroEnabledWorkbook;
+
case "xlsx":
case "xltx":
return SpreadsheetDocumentType.Workbook;
+
default:
throw new ArgumentException(String.Format("Extension '{0}' is not supported. Supported extensions are '.xlsx', '.xslm', '.xltx' and '.xltm'.", extension));
-
}
}
private void checkForWorksheetsPresent()
{
if (Worksheets.Count() == 0)
- throw new Exception("Workbooks need at least one worksheet.");
+ throw new InvalidOperationException("Workbooks need at least one worksheet.");
}
///
@@ -542,6 +565,16 @@
///
public void SaveAs(Stream stream, Boolean validate, Boolean evaluateFormulae = false)
{
+ SaveAs(stream, new SaveOptions
+ {
+ ValidatePackage = validate,
+ EvaluateFormulasBeforeSaving = evaluateFormulae,
+ GenerateCalculationChain = true
+ });
+ }
+
+ public void SaveAs(Stream stream, SaveOptions options)
+ {
checkForWorksheetsPresent();
if (_loadSource == XLLoadSource.New)
{
@@ -552,13 +585,13 @@
if (stream.CanRead && stream.CanSeek && stream.CanWrite)
{
// all is fine the package can be created in a direct way
- CreatePackage(stream, true, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(stream, true, _spreadsheetDocumentType, options);
}
else
{
// the harder way
MemoryStream ms = new MemoryStream();
- CreatePackage(ms, true, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(ms, true, _spreadsheetDocumentType, options);
// not really nessesary, because I changed CopyStream too.
// but for better understanding and if somebody in the future
// provide an changed version of CopyStream
@@ -573,7 +606,7 @@
CopyStream(fileStream, stream);
fileStream.Close();
}
- CreatePackage(stream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(stream, false, _spreadsheetDocumentType, options);
}
else if (_loadSource == XLLoadSource.Stream)
{
@@ -581,7 +614,7 @@
if (_originalStream != stream)
CopyStream(_originalStream, stream);
- CreatePackage(stream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ CreatePackage(stream, false, _spreadsheetDocumentType, options);
}
}
@@ -596,7 +629,6 @@
output.Write(buffer, 0, len);
// dm 20130422, and flushing the output after write
output.Flush();
-
}
public IXLWorksheet Worksheet(String name)
@@ -650,24 +682,44 @@
return columns;
}
+ ///
+ /// Searches the cells' contents for a given piece of text
+ ///
+ /// The search text.
+ /// The compare options.
+ /// if set to true search formulae instead of cell values.
+ ///
+ public IEnumerable Search(String searchText, CompareOptions compareOptions = CompareOptions.Ordinal, Boolean searchFormulae = false)
+ {
+ foreach (var ws in WorksheetsInternal)
+ {
+ foreach (var cell in ws.Search(searchText, compareOptions, searchFormulae))
+ yield return cell;
+ }
+ }
+
#region Fields
private readonly XLLoadSource _loadSource = XLLoadSource.New;
private readonly String _originalFile;
private readonly Stream _originalStream;
-#endregion
+ #endregion Fields
#region Constructor
-
///
/// Creates a new Excel workbook.
///
public XLWorkbook()
:this(XLEventTracking.Enabled)
{
+ }
+ internal XLWorkbook(String file, Boolean asTemplate)
+ : this(XLEventTracking.Enabled)
+ {
+ LoadSheetsFromTemplate(file);
}
public XLWorkbook(XLEventTracking eventTracking)
@@ -706,7 +758,6 @@
public XLWorkbook(String file)
: this(file, XLEventTracking.Enabled)
{
-
}
public XLWorkbook(String file, XLEventTracking eventTracking)
@@ -718,15 +769,12 @@
Load(file);
}
-
-
///
/// Opens an existing workbook from a stream.
///
/// The stream to open.
public XLWorkbook(Stream stream):this(stream, XLEventTracking.Enabled)
{
-
}
public XLWorkbook(Stream stream, XLEventTracking eventTracking)
@@ -737,7 +785,7 @@
Load(stream);
}
-#endregion
+ #endregion Constructor
#region Nested type: UnsupportedSheet
@@ -748,7 +796,7 @@
public Int32 Position;
}
-#endregion
+ #endregion Nested type: UnsupportedSheet
public IXLCell Cell(String namedCell)
{
@@ -790,13 +838,13 @@
internal XLIdManager ShapeIdManager { get; private set; }
-
public void Dispose()
{
Worksheets.ForEach(w => w.Dispose());
}
public Boolean Use1904DateSystem { get; set; }
+
public XLWorkbook SetUse1904DateSystem()
{
return SetUse1904DateSystem(true);
@@ -817,10 +865,12 @@
{
return Worksheets.Add(sheetName, position);
}
+
public IXLWorksheet AddWorksheet(DataTable dataTable)
{
return Worksheets.Add(dataTable);
}
+
public void AddWorksheet(DataSet dataSet)
{
Worksheets.Add(dataSet);
@@ -837,10 +887,12 @@
}
private XLCalcEngine _calcEngine;
+
private XLCalcEngine CalcEngine
{
get { return _calcEngine ?? (_calcEngine = new XLCalcEngine(this)); }
}
+
public Object Evaluate(String expression)
{
return CalcEngine.Evaluate(expression);
@@ -853,6 +905,7 @@
{
get { return _calcEngineExpr ?? (_calcEngineExpr = new XLCalcEngine()); }
}
+
public static Object EvaluateExpr(String expression)
{
return CalcEngineExpr.Evaluate(expression);
@@ -861,12 +914,16 @@
public String Author { get; set; }
public Boolean LockStructure { get; set; }
+
public XLWorkbook SetLockStructure(Boolean value) { LockStructure = value; return this; }
+
public Boolean LockWindows { get; set; }
+
public XLWorkbook SetLockWindows(Boolean value) { LockWindows = value; return this; }
+
internal HexBinaryValue LockPassword { get; set; }
public Boolean IsPasswordProtected { get { return LockPassword != null; } }
-
+
public void Protect(Boolean lockStructure, Boolean lockWindows, String workbookPassword)
{
if (IsPasswordProtected && workbookPassword == null)
@@ -886,7 +943,6 @@
LockPassword = null;
}
-
if (!IsPasswordProtected && hashPassword != null && (lockStructure || lockWindows))
{
//Protect workbook using password.
@@ -896,7 +952,7 @@
LockStructure = lockStructure;
LockWindows = lockWindows;
}
-
+
public void Protect()
{
Protect(true);
@@ -927,4 +983,4 @@
Protect(false, false, workbookPassword);
}
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML/Excel/XLWorkbook_ImageHandling.cs b/ClosedXML/Excel/XLWorkbook_ImageHandling.cs
index 37e85da..9dbaf3e 100644
--- a/ClosedXML/Excel/XLWorkbook_ImageHandling.cs
+++ b/ClosedXML/Excel/XLWorkbook_ImageHandling.cs
@@ -43,7 +43,13 @@
if (!IsAllowedAnchor(anchor))
return null;
- return anchor
+ var picture = anchor
+ .Descendants()
+ .FirstOrDefault();
+
+ if (picture == null) return null;
+
+ return picture
.Descendants()
.FirstOrDefault();
}
diff --git a/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/Excel/XLWorkbook_Load.cs
index a23ab4e..be0d818 100644
--- a/ClosedXML/Excel/XLWorkbook_Load.cs
+++ b/ClosedXML/Excel/XLWorkbook_Load.cs
@@ -55,11 +55,17 @@
LoadSpreadsheetDocument(dSpreadsheet);
}
+ private void LoadSheetsFromTemplate(String fileName)
+ {
+ using (var dSpreadsheet = SpreadsheetDocument.CreateFromTemplate(fileName))
+ LoadSpreadsheetDocument(dSpreadsheet);
+ }
+
private void LoadSpreadsheetDocument(SpreadsheetDocument dSpreadsheet)
{
ShapeIdManager = new XLIdManager();
SetProperties(dSpreadsheet);
- //var sharedStrings = dSpreadsheet.WorkbookPart.SharedStringTablePart.SharedStringTable.Elements();
+
SharedStringItem[] sharedStrings = null;
if (dSpreadsheet.WorkbookPart.GetPartsOfType().Count() > 0)
{
@@ -265,11 +271,15 @@
#region LoadTables
- foreach (TableDefinitionPart tablePart in wsPart.TableDefinitionParts)
+ foreach (var tablePart in wsPart.TableDefinitionParts)
{
var dTable = tablePart.Table;
- string reference = dTable.Reference.Value;
- XLTable xlTable = ws.Range(reference).CreateTable(dTable.Name, false) as XLTable;
+ String reference = dTable.Reference.Value;
+ String tableName = dTable?.Name ?? dTable.DisplayName ?? string.Empty;
+ if (String.IsNullOrWhiteSpace(tableName))
+ throw new InvalidDataException("The table name is missing.");
+
+ XLTable xlTable = ws.Range(reference).CreateTable(tableName, false) as XLTable;
if (dTable.HeaderRowCount != null && dTable.HeaderRowCount == 0)
{
xlTable._showHeaderRow = false;
@@ -500,6 +510,14 @@
if (pivotTableDefinition.ShowError != null && pivotTableDefinition.ErrorCaption != null)
pt.ErrorValueReplacement = pivotTableDefinition.ErrorCaption.Value;
+ // Subtotal configuration
+ if (pivotTableDefinition.PivotFields.Cast().All(pf => pf.SubtotalTop != null && pf.SubtotalTop.HasValue && pf.SubtotalTop.Value))
+ pt.SetSubtotals(XLPivotSubtotals.AtTop);
+ else if (pivotTableDefinition.PivotFields.Cast().All(pf => pf.SubtotalTop != null && pf.SubtotalTop.HasValue && !pf.SubtotalTop.Value))
+ pt.SetSubtotals(XLPivotSubtotals.AtBottom);
+ else
+ pt.SetSubtotals(XLPivotSubtotals.DoNotShow);
+
// Row labels
if (pivotTableDefinition.RowFields != null)
{
@@ -640,7 +658,7 @@
{
var vsdp = GetPropertiesFromAnchor(anchor);
- var picture = ws.AddPicture(stream, vsdp.Name) as XLPicture;
+ var picture = (ws as XLWorksheet).AddPicture(stream, vsdp.Name, Convert.ToInt32(vsdp.Id.Value)) as XLPicture;
picture.RelId = imgId;
Xdr.ShapeProperties spPr = anchor.Descendants().First();
@@ -725,7 +743,7 @@
if (shape != null) break;
}
- if (xdoc == null) throw new Exception("Could not load comments file");
+ if (xdoc == null) throw new ArgumentException("Could not load comments file");
return xdoc;
}
@@ -1062,7 +1080,7 @@
else
{
if (!Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges.Any(nr => nr.Name == name))
- Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges.Add(name, text, comment).Visible = visible;
+ (Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges as XLNamedRanges).Add(name, text, comment, true).Visible = visible;
}
}
}
@@ -1073,7 +1091,6 @@
private IEnumerable validateDefinedNames(IEnumerable definedNames)
{
- var fixedNames = new List();
var sb = new StringBuilder();
foreach (string testName in definedNames)
{
@@ -1175,7 +1192,11 @@
formula = cell.CellFormula.Text;
if (cell.CellFormula.Reference != null)
+ {
+ // Parent cell of shared formulas
+ // Child cells will use this shared index to set its R1C1 style formula
xlCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress;
+ }
xlCell.FormulaA1 = formula;
sharedFormulasR1C1.Add(cell.CellFormula.SharedIndex.Value, xlCell.FormulaR1C1);
@@ -1187,7 +1208,7 @@
{
if (cell.CellFormula.SharedIndex != null)
xlCell.FormulaR1C1 = sharedFormulasR1C1[cell.CellFormula.SharedIndex.Value];
- else
+ else if (!String.IsNullOrWhiteSpace(cell.CellFormula.Text))
{
String formula;
if (cell.CellFormula.FormulaType != null && cell.CellFormula.FormulaType == CellFormulaValues.Array)
@@ -1199,7 +1220,16 @@
}
if (cell.CellFormula.Reference != null)
- xlCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress;
+ {
+ foreach (var childCell in ws.Range(cell.CellFormula.Reference.Value).Cells(c => c.FormulaReference == null || !c.HasFormula))
+ {
+ if (childCell.FormulaReference == null)
+ childCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress;
+
+ if (!childCell.HasFormula)
+ childCell.FormulaA1 = xlCell.FormulaA1;
+ }
+ }
if (cell.CellValue != null)
xlCell.ValueCached = cell.CellValue.Text;
@@ -1223,7 +1253,7 @@
}
else if (cell.DataType == CellValues.SharedString)
{
- if (cell.CellValue != null && !XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
+ if (cell.CellValue != null && !String.IsNullOrWhiteSpace(cell.CellValue.Text))
{
var sharedString = sharedStrings[Int32.Parse(cell.CellValue.Text, XLHelper.NumberStyle, XLHelper.ParseCulture)];
ParseCellValue(sharedString, xlCell);
@@ -1235,7 +1265,7 @@
}
else if (cell.DataType == CellValues.Date)
{
- if (cell.CellValue != null && !XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
+ if (cell.CellValue != null && !String.IsNullOrWhiteSpace(cell.CellValue.Text))
xlCell._cellValue = Double.Parse(cell.CellValue.Text, XLHelper.NumberStyle, XLHelper.ParseCulture).ToInvariantString();
xlCell._dataType = XLCellValues.DateTime;
}
@@ -1247,7 +1277,7 @@
}
else if (cell.DataType == CellValues.Number)
{
- if (cell.CellValue != null && !XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
+ if (cell.CellValue != null && !String.IsNullOrWhiteSpace(cell.CellValue.Text))
xlCell._cellValue = Double.Parse(cell.CellValue.Text, XLHelper.NumberStyle, XLHelper.ParseCulture).ToInvariantString();
if (s == null)
@@ -1265,7 +1295,7 @@
else
{
var numberFormatId = ((CellFormat)(s.CellFormats).ElementAt(styleIndex)).NumberFormatId;
- if (!XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
+ if (!String.IsNullOrWhiteSpace(cell.CellValue.Text))
xlCell._cellValue = Double.Parse(cell.CellValue.Text, CultureInfo.InvariantCulture).ToInvariantString();
if (s.NumberingFormats != null &&
@@ -1557,7 +1587,7 @@
return XLCellValues.Text;
else
{
- if (!XLHelper.IsNullOrWhiteSpace(numberFormat.Format))
+ if (!String.IsNullOrWhiteSpace(numberFormat.Format))
{
var dataType = GetDataTypeFromFormat(numberFormat.Format);
return dataType.HasValue ? dataType.Value : XLCellValues.Number;
@@ -1772,7 +1802,7 @@
foreach (DataValidation dvs in dataValidations.Elements())
{
String txt = dvs.SequenceOfReferences.InnerText;
- if (XLHelper.IsNullOrWhiteSpace(txt)) continue;
+ if (String.IsNullOrWhiteSpace(txt)) continue;
foreach (var dvt in txt.Split(' ').Select(rangeAddress => ws.Range(rangeAddress).DataValidation))
{
if (dvs.AllowBlank != null) dvt.IgnoreBlanks = dvs.AllowBlank;
@@ -1820,7 +1850,7 @@
if (conditionalFormat.ConditionalFormatType == XLConditionalFormatType.CellIs && fr.Operator != null)
conditionalFormat.Operator = fr.Operator.Value.ToClosedXml();
- if (fr.Text != null && !XLHelper.IsNullOrWhiteSpace(fr.Text))
+ if (fr.Text != null && !String.IsNullOrWhiteSpace(fr.Text))
conditionalFormat.Values.Add(GetFormula(fr.Text.Value));
if (conditionalFormat.ConditionalFormatType == XLConditionalFormatType.Top10)
@@ -2399,4 +2429,4 @@
return false;
}
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs
index fcba6c8..57edc21 100644
--- a/ClosedXML/Excel/XLWorkbook_Save.cs
+++ b/ClosedXML/Excel/XLWorkbook_Save.cs
@@ -87,7 +87,7 @@
}
}
- private bool Validate(SpreadsheetDocument package)
+ private Boolean Validate(SpreadsheetDocument package)
{
var backupCulture = Thread.CurrentThread.CurrentCulture;
@@ -111,7 +111,7 @@
return true;
}
- private void CreatePackage(String filePath, SpreadsheetDocumentType spreadsheetDocumentType, bool validate, bool evaluateFormulae)
+ private void CreatePackage(String filePath, SpreadsheetDocumentType spreadsheetDocumentType, SaveOptions options)
{
PathHelper.CreateDirectory(Path.GetDirectoryName(filePath));
var package = File.Exists(filePath)
@@ -120,12 +120,12 @@
using (package)
{
- CreateParts(package, evaluateFormulae);
- if (validate) Validate(package);
+ CreateParts(package, options);
+ if (options.ValidatePackage) Validate(package);
}
}
- private void CreatePackage(Stream stream, bool newStream, SpreadsheetDocumentType spreadsheetDocumentType, bool validate, bool evaluateFormulae)
+ private void CreatePackage(Stream stream, bool newStream, SpreadsheetDocumentType spreadsheetDocumentType, SaveOptions options)
{
var package = newStream
? SpreadsheetDocument.Create(stream, spreadsheetDocumentType)
@@ -133,8 +133,8 @@
using (package)
{
- CreateParts(package, evaluateFormulae);
- if (validate) Validate(package);
+ CreateParts(package, options);
+ if (options.ValidatePackage) Validate(package);
}
}
@@ -142,9 +142,10 @@
private void DeleteSheetAndDependencies(WorkbookPart wbPart, string sheetId)
{
//Get the SheetToDelete from workbook.xml
- Sheet worksheet = wbPart.Workbook.Descendants().Where(s => s.Id == sheetId).FirstOrDefault();
+ Sheet worksheet = wbPart.Workbook.Descendants().FirstOrDefault(s => s.Id == sheetId);
if (worksheet == null)
- { }
+ return;
+
string sheetName = worksheet.Name;
// Get the pivot Table Parts
@@ -154,8 +155,8 @@
{
PivotCacheDefinition pvtCacheDef = Item.PivotCacheDefinition;
//Check if this CacheSource is linked to SheetToDelete
- var pvtCahce = pvtCacheDef.Descendants().Where(s => s.WorksheetSource.Sheet == sheetName);
- if (pvtCahce.Count() > 0)
+ var pvtCache = pvtCacheDef.Descendants().Where(s => s.WorksheetSource.Sheet == sheetName);
+ if (pvtCache.Any())
{
pvtTableCacheDefinationPart.Add(Item, Item.ToString());
}
@@ -178,7 +179,7 @@
{
List defNamesToDelete = new List();
- foreach (DefinedName Item in definedNames)
+ foreach (var Item in definedNames.OfType())
{
// This condition checks to delete only those names which are part of Sheet in question
if (Item.Text.Contains(worksheet.Name + "!"))
@@ -201,24 +202,20 @@
var calChainEntries = calChainPart.CalculationChain.Descendants().Where(c => c.SheetId == sheetId);
List calcsToDelete = new List();
foreach (CalculationCell Item in calChainEntries)
- {
calcsToDelete.Add(Item);
- }
+
foreach (CalculationCell Item in calcsToDelete)
- {
Item.Remove();
- }
- if (calChainPart.CalculationChain.Count() == 0)
- {
+
+ if (!calChainPart.CalculationChain.Any())
wbPart.DeletePart(calChainPart);
- }
}
}
// Adds child parts and generates content of the specified part.
- private void CreateParts(SpreadsheetDocument document, bool evaluateFormulae)
+ private void CreateParts(SpreadsheetDocument document, SaveOptions options)
{
var context = new SaveContext();
@@ -241,12 +238,12 @@
// Ensure all RelId's have been added to the context
context.RelIdGenerator.AddValues(workbookPart.Parts.Select(p => p.RelationshipId), RelType.Workbook);
- context.RelIdGenerator.AddValues(WorksheetsInternal.Cast().Where(ws => !XLHelper.IsNullOrWhiteSpace(ws.RelId)).Select(ws => ws.RelId), RelType.Workbook);
- context.RelIdGenerator.AddValues(WorksheetsInternal.Cast().Where(ws => !XLHelper.IsNullOrWhiteSpace(ws.LegacyDrawingId)).Select(ws => ws.LegacyDrawingId), RelType.Workbook);
+ context.RelIdGenerator.AddValues(WorksheetsInternal.Cast().Where(ws => !String.IsNullOrWhiteSpace(ws.RelId)).Select(ws => ws.RelId), RelType.Workbook);
+ context.RelIdGenerator.AddValues(WorksheetsInternal.Cast().Where(ws => !String.IsNullOrWhiteSpace(ws.LegacyDrawingId)).Select(ws => ws.LegacyDrawingId), RelType.Workbook);
context.RelIdGenerator.AddValues(WorksheetsInternal
.Cast()
.SelectMany(ws => ws.Tables.Cast())
- .Where(t => !XLHelper.IsNullOrWhiteSpace(t.RelId))
+ .Where(t => !String.IsNullOrWhiteSpace(t.RelId))
.Select(t => t.RelId), RelType.Workbook);
var extendedFilePropertiesPart = document.ExtendedFilePropertiesPart ??
@@ -303,7 +300,7 @@
var vmlDrawingPart = worksheetPart.VmlDrawingParts.FirstOrDefault();
if (vmlDrawingPart == null)
{
- if (XLHelper.IsNullOrWhiteSpace(worksheet.LegacyDrawingId))
+ if (String.IsNullOrWhiteSpace(worksheet.LegacyDrawingId))
{
worksheet.LegacyDrawingId = context.RelIdGenerator.GetNext(RelType.Workbook);
worksheet.LegacyDrawingIsNew = true;
@@ -314,7 +311,7 @@
GenerateVmlDrawingPartContent(vmlDrawingPart, worksheet, context);
}
- GenerateWorksheetPartContent(worksheetPart, worksheet, evaluateFormulae, context);
+ GenerateWorksheetPartContent(worksheetPart, worksheet, options.EvaluateFormulasBeforeSaving, context);
if (worksheet.PivotTables.Any())
{
@@ -333,7 +330,10 @@
if (workbookPart.Workbook.PivotCaches != null && !workbookPart.Workbook.PivotCaches.Any())
workbookPart.Workbook.RemoveChild(workbookPart.Workbook.PivotCaches);
- GenerateCalculationChainPartContent(workbookPart, context);
+ if (options.GenerateCalculationChain)
+ GenerateCalculationChainPartContent(workbookPart, context);
+ else
+ DeleteCalculationChainPartContent(workbookPart, context);
if (workbookPart.ThemePart == null)
{
@@ -350,6 +350,9 @@
GenerateCustomFilePropertiesPartContent(customFilePropertiesPart);
}
SetPackageProperties(document);
+
+ // Clear list of deleted worksheets to prevent errors on multiple saves
+ worksheets.Deleted.Clear();
}
private void DeleteComments(WorksheetPart worksheetPart, XLWorksheet worksheet, SaveContext context)
@@ -473,7 +476,7 @@
if (Properties.Manager != null)
{
- if (!XLHelper.IsNullOrWhiteSpace(Properties.Manager))
+ if (!String.IsNullOrWhiteSpace(Properties.Manager))
{
if (properties.Manager == null)
properties.Manager = new Manager();
@@ -486,7 +489,7 @@
if (Properties.Company == null) return;
- if (!XLHelper.IsNullOrWhiteSpace(Properties.Company))
+ if (!String.IsNullOrWhiteSpace(Properties.Company))
{
if (properties.Company == null)
properties.Company = new Company();
@@ -590,7 +593,7 @@
workbook.WorkbookProtection = null;
}
- #endregion
+ #endregion WorkbookProtection
if (workbook.BookViews == null)
workbook.BookViews = new BookViews();
@@ -616,7 +619,7 @@
foreach (var xlSheet in WorksheetsInternal.Cast().OrderBy(w => w.Position))
{
string rId;
- if (xlSheet.SheetId == 0 && XLHelper.IsNullOrWhiteSpace(xlSheet.RelId))
+ if (xlSheet.SheetId == 0 && String.IsNullOrWhiteSpace(xlSheet.RelId))
{
rId = context.RelIdGenerator.GetNext(RelType.Workbook);
@@ -628,7 +631,7 @@
}
else
{
- if (XLHelper.IsNullOrWhiteSpace(xlSheet.RelId))
+ if (String.IsNullOrWhiteSpace(xlSheet.RelId))
{
rId = String.Format("rId{0}", xlSheet.SheetId);
context.RelIdGenerator.AddValues(new List { rId }, RelType.Workbook);
@@ -773,7 +776,7 @@
if (!nr.Visible)
definedName.Hidden = BooleanValue.FromBoolean(true);
- if (!XLHelper.IsNullOrWhiteSpace(nr.Comment))
+ if (!String.IsNullOrWhiteSpace(nr.Comment))
definedName.Comment = nr.Comment;
definedNames.AppendChild(definedName);
}
@@ -827,7 +830,7 @@
if (!nr.Visible)
definedName.Hidden = BooleanValue.FromBoolean(true);
- if (!XLHelper.IsNullOrWhiteSpace(nr.Comment))
+ if (!String.IsNullOrWhiteSpace(nr.Comment))
definedName.Comment = nr.Comment;
definedNames.AppendChild(definedName);
}
@@ -873,7 +876,7 @@
w.Internals.CellsCollection.GetCells(
c => ((c.DataType == XLCellValues.Text && c.ShareString) || c.HasRichText)
&& (c as XLCell).InnerText.Length > 0
- && XLHelper.IsNullOrWhiteSpace(c.FormulaA1)
+ && String.IsNullOrWhiteSpace(c.FormulaA1)
)))
{
c.DataType = XLCellValues.Text;
@@ -1002,11 +1005,16 @@
return run;
}
+ private void DeleteCalculationChainPartContent(WorkbookPart workbookPart, SaveContext context)
+ {
+ if (workbookPart.CalculationChainPart != null)
+ workbookPart.DeletePart(workbookPart.CalculationChainPart);
+ }
+
private void GenerateCalculationChainPartContent(WorkbookPart workbookPart, SaveContext context)
{
- var thisRelId = context.RelIdGenerator.GetNext(RelType.Workbook);
if (workbookPart.CalculationChainPart == null)
- workbookPart.AddNewPart(thisRelId);
+ workbookPart.AddNewPart(context.RelIdGenerator.GetNext(RelType.Workbook));
if (workbookPart.CalculationChainPart.CalculationChain == null)
workbookPart.CalculationChainPart.CalculationChain = new CalculationChain();
@@ -1019,29 +1027,37 @@
var cellsWithoutFormulas = new HashSet();
foreach (var c in worksheet.Internals.CellsCollection.GetCells())
{
- if (XLHelper.IsNullOrWhiteSpace(c.FormulaA1))
+ if (String.IsNullOrWhiteSpace(c.FormulaA1))
cellsWithoutFormulas.Add(c.Address.ToStringRelative());
else
{
- if (c.FormulaA1.StartsWith("{"))
+ if (c.HasArrayFormula)
{
- var cc = new CalculationCell
- {
- CellReference = c.Address.ToString(),
- SheetId = worksheet.SheetId
- };
-
- if (c.FormulaReference == null)
- c.FormulaReference = c.AsRange().RangeAddress;
if (c.FormulaReference.FirstAddress.Equals(c.Address))
{
+ var cc = new CalculationCell
+ {
+ CellReference = c.Address.ToString(),
+ SheetId = worksheet.SheetId
+ };
+
+ if (c.FormulaReference == null)
+ c.FormulaReference = c.AsRange().RangeAddress;
+
cc.Array = true;
calculationChain.AppendChild(cc);
- calculationChain.AppendChild(new CalculationCell { CellReference = c.Address.ToString(), InChildChain = true });
- }
- else
- {
- calculationChain.AppendChild(cc);
+
+ foreach (var childCell in worksheet.Range(c.FormulaReference.ToString()).Cells())
+ {
+ calculationChain.AppendChild(
+ new CalculationCell
+ {
+ CellReference = childCell.Address.ToString(),
+ SheetId = worksheet.SheetId,
+ InChildChain = true
+ }
+ );
+ }
}
}
else
@@ -1055,17 +1071,34 @@
}
}
- //var cCellsToRemove = new List();
- var m = from cc in calculationChain.Elements()
- where !(cc.SheetId != null || cc.InChildChain != null)
- && calculationChain.Elements()
- .Where(c1 => c1.SheetId != null)
- .Select(c1 => c1.CellReference.Value)
- .Contains(cc.CellReference.Value)
- || cellsWithoutFormulas.Contains(cc.CellReference.Value)
- select cc;
- //m.ToList().ForEach(cc => cCellsToRemove.Add(cc));
- m.ToList().ForEach(cc => calculationChain.RemoveChild(cc));
+ // This part shouldn't be necessary anymore, but I'm keeping it in the DEBUG configuration until I'm 100% sure.
+
+#if DEBUG
+ var sheetCellReferences = calculationChain.Elements()
+ .Where(cc1 => cc1.SheetId != null)
+ .Select(cc1 => cc1.CellReference.Value)
+ .ToList();
+
+ // Remove orphaned calc chain cells
+ var cellsToRemove = calculationChain.Elements()
+ .Where(cc =>
+ {
+ return cc.SheetId == worksheet.SheetId
+ && cellsWithoutFormulas.Contains(cc.CellReference.Value)
+ || cc.SheetId == null
+ && cc.InChildChain == null
+ && sheetCellReferences.Contains(cc.CellReference.Value);
+ })
+ .ToArray();
+
+ // This shouldn't happen, because the calc chain should be correctly generated
+ System.Diagnostics.Debug.Assert(!cellsToRemove.Any());
+
+ foreach (var cc in cellsToRemove)
+ {
+ calculationChain.RemoveChild(cc);
+ }
+#endif
}
if (!calculationChain.Any())
@@ -1810,7 +1843,7 @@
tableColumn1.TotalsRowFormula = new TotalsRowFormula(xlField.TotalsRowFormulaA1);
}
- if (!XLHelper.IsNullOrWhiteSpace(xlField.TotalsRowLabel))
+ if (!String.IsNullOrWhiteSpace(xlField.TotalsRowLabel))
tableColumn1.TotalsRowLabel = xlField.TotalsRowLabel;
}
tableColumns1.AppendChild(tableColumn1);
@@ -1872,7 +1905,7 @@
var workbookCacheRelId = pt.WorkbookCacheRelId;
PivotCache pivotCache;
PivotTableCacheDefinitionPart pivotTableCacheDefinitionPart;
- if (!XLHelper.IsNullOrWhiteSpace(pt.WorkbookCacheRelId))
+ if (!String.IsNullOrWhiteSpace(pt.WorkbookCacheRelId))
{
pivotCache = pivotCaches.Cast().Single(pc => pc.Id.Value == pt.WorkbookCacheRelId);
pivotTableCacheDefinitionPart = workbookPart.GetPartById(pt.WorkbookCacheRelId) as PivotTableCacheDefinitionPart;
@@ -1886,18 +1919,18 @@
GeneratePivotTableCacheDefinitionPartContent(pivotTableCacheDefinitionPart, pt);
- if (XLHelper.IsNullOrWhiteSpace(pt.WorkbookCacheRelId))
+ if (String.IsNullOrWhiteSpace(pt.WorkbookCacheRelId))
pivotCaches.AppendChild(pivotCache);
PivotTablePart pivotTablePart;
- if (XLHelper.IsNullOrWhiteSpace(pt.RelId))
+ if (String.IsNullOrWhiteSpace(pt.RelId))
pivotTablePart = worksheetPart.AddNewPart(context.RelIdGenerator.GetNext(RelType.Workbook));
else
pivotTablePart = worksheetPart.GetPartById(pt.RelId) as PivotTablePart;
GeneratePivotTablePartContent(pivotTablePart, pt, pivotCache.CacheId, context);
- if (XLHelper.IsNullOrWhiteSpace(pt.RelId))
+ if (String.IsNullOrWhiteSpace(pt.RelId))
pivotTablePart.AddPart(pivotTableCacheDefinitionPart, context.RelIdGenerator.GetNext(RelType.Workbook));
}
}
@@ -2112,6 +2145,21 @@
IXLPivotField labelField = null;
var pf = new PivotField { ShowAll = false, Name = xlpf.CustomName };
+ switch (pt.Subtotals)
+ {
+ case XLPivotSubtotals.DoNotShow:
+ pf.DefaultSubtotal = false;
+ break;
+ case XLPivotSubtotals.AtBottom:
+ pf.DefaultSubtotal = true;
+ pf.SubtotalTop = false;
+ break;
+ case XLPivotSubtotals.AtTop:
+ pf.DefaultSubtotal = true;
+ pf.SubtotalTop = true;
+ break;
+ }
+
if (pt.RowLabels.Any(p => p.SourceName == xlpf.SourceName))
{
labelField = pt.RowLabels.Single(p => p.SourceName == xlpf.SourceName);
@@ -2135,7 +2183,7 @@
var fieldItems = new Items();
- if (xlpf.SharedStrings.Count > 0)
+ if (xlpf.SharedStrings.Any())
{
for (uint i = 0; i < xlpf.SharedStrings.Count; i++)
{
@@ -2146,7 +2194,7 @@
}
}
- if (xlpf.Subtotals.Count > 0)
+ if (xlpf.Subtotals.Any())
{
foreach (var subtotal in xlpf.Subtotals)
{
@@ -2211,13 +2259,17 @@
fieldItems.AppendChild(itemSubtotal);
}
}
- else
+ // If the field itself doesn't have subtotals, but the pivot table is set to show pivot tables, add the default item
+ else if (pt.Subtotals != XLPivotSubtotals.DoNotShow)
{
fieldItems.AppendChild(new Item { ItemType = ItemValues.Default });
}
- fieldItems.Count = Convert.ToUInt32(fieldItems.Count());
- pf.AppendChild(fieldItems);
+ if (fieldItems.Any())
+ {
+ fieldItems.Count = Convert.ToUInt32(fieldItems.Count());
+ pf.AppendChild(fieldItems);
+ }
pivotFields.AppendChild(pf);
}
@@ -2494,7 +2546,7 @@
StrokeWeight = String.Format(CultureInfo.InvariantCulture, "{0}pt", c.Comment.Style.ColorsAndLines.LineWeight),
InsetMode = c.Comment.Style.Margins.Automatic ? InsetMarginValues.Auto : InsetMarginValues.Custom
};
- if (!XLHelper.IsNullOrWhiteSpace(c.Comment.Style.Web.AlternateText))
+ if (!String.IsNullOrWhiteSpace(c.Comment.Style.Web.AlternateText))
shape.Alternate = c.Comment.Style.Web.AlternateText;
return shape;
@@ -3048,7 +3100,7 @@
{
var differentialFormat = new DifferentialFormat();
differentialFormat.Append(GetNewFont(new FontInfo { Font = cf.Style.Font as XLFont }, false));
- if (!XLHelper.IsNullOrWhiteSpace(cf.Style.NumberFormat.Format))
+ if (!String.IsNullOrWhiteSpace(cf.Style.NumberFormat.Format))
{
var numberFormat = new NumberingFormat
{
@@ -3692,7 +3744,7 @@
{
var newXLNumberFormat = new XLNumberFormat();
- if (nf.FormatCode != null && !XLHelper.IsNullOrWhiteSpace(nf.FormatCode.Value))
+ if (nf.FormatCode != null && !String.IsNullOrWhiteSpace(nf.FormatCode.Value))
newXLNumberFormat.Format = nf.FormatCode.Value;
else if (nf.NumberFormatId != null)
newXLNumberFormat.NumberFormatId = (Int32)nf.NumberFormatId.Value;
@@ -4236,16 +4288,17 @@
}
cell.StyleIndex = styleId;
- var formula = xlCell.FormulaA1;
if (xlCell.HasFormula)
{
- if (formula.StartsWith("{"))
+ var formula = xlCell.FormulaA1;
+ if (xlCell.HasArrayFormula)
{
formula = formula.Substring(1, formula.Length - 2);
var f = new CellFormula { FormulaType = CellFormulaValues.Array };
if (xlCell.FormulaReference == null)
xlCell.FormulaReference = xlCell.AsRange().RangeAddress;
+
if (xlCell.FormulaReference.FirstAddress.Equals(xlCell.Address))
{
f.Text = formula;
@@ -4270,7 +4323,6 @@
if (!xlCell.HasFormula || evaluateFormulae)
SetCellValue(xlCell, cell);
-
}
}
xlWorksheet.Internals.CellsCollection.deleted.Remove(distinctRow);
@@ -4301,7 +4353,7 @@
var protection = xlWorksheet.Protection;
sheetProtection.Sheet = protection.Protected;
- if (!XLHelper.IsNullOrWhiteSpace(protection.PasswordHash))
+ if (!String.IsNullOrWhiteSpace(protection.PasswordHash))
sheetProtection.Password = protection.PasswordHash;
sheetProtection.FormatCells = GetBooleanValue(!protection.FormatCells, true);
sheetProtection.FormatColumns = GetBooleanValue(!protection.FormatColumns, true);
@@ -4502,7 +4554,7 @@
Display = hl.Cell.GetFormattedString()
};
}
- if (!XLHelper.IsNullOrWhiteSpace(hl.Tooltip))
+ if (!String.IsNullOrWhiteSpace(hl.Tooltip))
hyperlink.Tooltip = hl.Tooltip;
hyperlinks.AppendChild(hyperlink);
}
@@ -4759,7 +4811,7 @@
{
worksheetPart.Worksheet.RemoveAllChildren();
{
- if (!XLHelper.IsNullOrWhiteSpace(xlWorksheet.LegacyDrawingId))
+ if (!String.IsNullOrWhiteSpace(xlWorksheet.LegacyDrawingId))
{
var previousElement = cm.GetPreviousElementFor(XLWSContentManager.XLWSContents.LegacyDrawing);
worksheetPart.Worksheet.InsertAfter(new LegacyDrawing { Id = xlWorksheet.LegacyDrawingId },
@@ -4839,7 +4891,7 @@
}
else if (dataType == XLCellValues.DateTime || dataType == XLCellValues.Number)
{
- if (!XLHelper.IsNullOrWhiteSpace(xlCell.InnerText))
+ if (!String.IsNullOrWhiteSpace(xlCell.InnerText))
{
var cellValue = new CellValue();
cellValue.Text = Double.Parse(xlCell.InnerText, XLHelper.NumberStyle, XLHelper.ParseCulture).ToInvariantString();
diff --git a/ClosedXML/Excel/XLWorksheet.cs b/ClosedXML/Excel/XLWorksheet.cs
index c28ef98..c40ad1b 100644
--- a/ClosedXML/Excel/XLWorksheet.cs
+++ b/ClosedXML/Excel/XLWorksheet.cs
@@ -176,7 +176,7 @@
throw new ArgumentException("Worksheet names cannot contain any of the following characters: " +
InvalidNameChars);
- if (XLHelper.IsNullOrWhiteSpace(value))
+ if (String.IsNullOrWhiteSpace(value))
throw new ArgumentException("Worksheet names cannot be empty");
if (value.Length > 31)
@@ -606,11 +606,18 @@
}
}
- foreach (IXLNamedRange r in NamedRanges)
+ foreach (var nr in NamedRanges)
{
var ranges = new XLRanges();
- r.Ranges.ForEach(ranges.Add);
- targetSheet.NamedRanges.Add(r.Name, ranges);
+ foreach (var r in nr.Ranges)
+ {
+ if (this == r.Worksheet)
+ // Named ranges on the source worksheet have to point to the new destination sheet
+ ranges.Add(targetSheet.Range(r.RangeAddress.FirstAddress.RowNumber, r.RangeAddress.FirstAddress.ColumnNumber, r.RangeAddress.LastAddress.RowNumber, r.RangeAddress.LastAddress.ColumnNumber));
+ else
+ ranges.Add(r);
+ }
+ targetSheet.NamedRanges.Add(nr.Name, ranges);
}
foreach (XLTable t in Tables.Cast())
@@ -651,7 +658,7 @@
private String ReplaceRelativeSheet(string newSheetName, String value)
{
- if (XLHelper.IsNullOrWhiteSpace(value)) return value;
+ if (String.IsNullOrWhiteSpace(value)) return value;
var newValue = new StringBuilder();
var addresses = value.Split(',');
@@ -1523,6 +1530,11 @@
public String Author { get; set; }
+ public override string ToString()
+ {
+ return this.Name;
+ }
+
public IXLPictures Pictures { get; private set; }
public IXLPicture Picture(string pictureName)
@@ -1540,7 +1552,12 @@
return Pictures.Add(stream, name);
}
- public Drawings.IXLPicture AddPicture(Stream stream, XLPictureFormat format)
+ internal IXLPicture AddPicture(Stream stream, string name, int Id)
+ {
+ return (Pictures as XLPictures).Add(stream, name, Id);
+ }
+
+ public IXLPicture AddPicture(Stream stream, XLPictureFormat format)
{
return Pictures.Add(stream, format);
}
@@ -1569,5 +1586,14 @@
{
return Pictures.Add(imageFile, name);
}
+ public override Boolean IsEntireRow()
+ {
+ return true;
+ }
+
+ public override Boolean IsEntireColumn()
+ {
+ return true;
+ }
}
}
diff --git a/ClosedXML/Excel/XLWorksheets.cs b/ClosedXML/Excel/XLWorksheets.cs
index 4d14cb7..9061e1d 100644
--- a/ClosedXML/Excel/XLWorksheets.cs
+++ b/ClosedXML/Excel/XLWorksheets.cs
@@ -77,18 +77,18 @@
if (wss.Any())
return wss.First().Value;
- throw new Exception("There isn't a worksheet named '" + sheetName + "'.");
+ throw new ArgumentException("There isn't a worksheet named '" + sheetName + "'.");
}
public IXLWorksheet Worksheet(Int32 position)
{
int wsCount = _worksheets.Values.Count(w => w.Position == position);
if (wsCount == 0)
- throw new Exception("There isn't a worksheet associated with that position.");
+ throw new ArgumentException("There isn't a worksheet associated with that position.");
if (wsCount > 1)
{
- throw new Exception(
+ throw new ArgumentException(
"Can't retrieve a worksheet because there are multiple worksheets associated with that position.");
}
@@ -130,14 +130,14 @@
{
int wsCount = _worksheets.Values.Count(w => w.Position == position);
if (wsCount == 0)
- throw new Exception("There isn't a worksheet associated with that index.");
+ throw new ArgumentException("There isn't a worksheet associated with that index.");
if (wsCount > 1)
- throw new Exception(
+ throw new ArgumentException(
"Can't delete the worksheet because there are multiple worksheets associated with that index.");
var ws = _worksheets.Values.Single(w => w.Position == position);
- if (!XLHelper.IsNullOrWhiteSpace(ws.RelId) && !Deleted.Contains(ws.RelId))
+ if (!String.IsNullOrWhiteSpace(ws.RelId) && !Deleted.Contains(ws.RelId))
Deleted.Add(ws.RelId);
_worksheets.RemoveAll(w => w.Position == position);
@@ -178,9 +178,10 @@
public void Rename(String oldSheetName, String newSheetName)
{
- if (XLHelper.IsNullOrWhiteSpace(oldSheetName) || !_worksheets.ContainsKey(oldSheetName)) return;
+ if (String.IsNullOrWhiteSpace(oldSheetName) || !_worksheets.ContainsKey(oldSheetName)) return;
- if (_worksheets.Any(ws1 => ws1.Key.Equals(newSheetName, StringComparison.OrdinalIgnoreCase)))
+ if (!oldSheetName.Equals(newSheetName, StringComparison.OrdinalIgnoreCase)
+ && _worksheets.Any(ws1 => ws1.Key.Equals(newSheetName, StringComparison.OrdinalIgnoreCase)))
throw new ArgumentException(String.Format("A worksheet with the same name ({0}) has already been added.", newSheetName), nameof(newSheetName));
var ws = _worksheets[oldSheetName];
diff --git a/ClosedXML/Extensions.cs b/ClosedXML/Extensions.cs
index 7655168..699d251 100644
--- a/ClosedXML/Extensions.cs
+++ b/ClosedXML/Extensions.cs
@@ -221,7 +221,7 @@
public static Double GetWidth(this IXLFontBase fontBase, String text, Dictionary fontCache)
{
- if (XLHelper.IsNullOrWhiteSpace(text))
+ if (String.IsNullOrWhiteSpace(text))
return 0;
var font = GetCachedFont(fontBase, fontCache);
diff --git a/ClosedXML/Properties/AssemblyVersionInfo.cs b/ClosedXML/Properties/AssemblyVersionInfo.cs
index d9a81ab..57466c5 100644
--- a/ClosedXML/Properties/AssemblyVersionInfo.cs
+++ b/ClosedXML/Properties/AssemblyVersionInfo.cs
@@ -7,6 +7,6 @@
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.88.0.0")]
-[assembly: AssemblyFileVersion("0.88.0.0")]
-[assembly: AssemblyInformationalVersion("0.88.0-beta")]
+[assembly: AssemblyVersion("0.89.0.0")]
+[assembly: AssemblyFileVersion("0.89.0.0")]
+[assembly: AssemblyInformationalVersion("0.89.0-beta1")]
diff --git a/ClosedXML/XLHelper.cs b/ClosedXML/XLHelper.cs
index 585b8ca..dd08d44 100644
--- a/ClosedXML/XLHelper.cs
+++ b/ClosedXML/XLHelper.cs
@@ -117,7 +117,7 @@
public static bool IsValidColumn(string column)
{
var length = column.Length;
- if (IsNullOrWhiteSpace(column) || length > 3)
+ if (String.IsNullOrWhiteSpace(column) || length > 3)
return false;
var theColumn = column.ToUpper();
@@ -153,7 +153,7 @@
public static bool IsValidA1Address(string address)
{
- if (IsNullOrWhiteSpace(address))
+ if (String.IsNullOrWhiteSpace(address))
return false;
address = address.Replace("$", "");
@@ -226,26 +226,6 @@
return rows;
}
- public static bool IsNullOrWhiteSpace(string value)
- {
-#if NET4
- return String.IsNullOrWhiteSpace(value);
-#else
- if (value != null)
- {
- var length = value.Length;
- for (int i = 0; i < length; i++)
- {
- if (!char.IsWhiteSpace(value[i]))
- {
- return false;
- }
- }
- }
- return true;
-#endif
- }
-
private static readonly Regex A1RegexRelative = new Regex(
@"(?<=\W)(?\$?[a-zA-Z]{1,3}\$?\d{1,7})(?=\W)" // A1
+ @"|(?<=\W)(?\$?\d{1,7}:\$?\d{1,7})(?=\W)" // 1:1
diff --git a/ClosedXML_Examples/Misc/Formulas.cs b/ClosedXML_Examples/Misc/Formulas.cs
index 729cb9e..8066a81 100644
--- a/ClosedXML_Examples/Misc/Formulas.cs
+++ b/ClosedXML_Examples/Misc/Formulas.cs
@@ -54,6 +54,7 @@
// Just put the formula between curly braces
ws.Cell("A6").Value = "Array Formula: ";
ws.Cell("B6").FormulaA1 = "{A2+A3}";
+ ws.Range("C6:D6").FormulaA1 = "{TRANSPOSE(A2:A3)}";
ws.Range(1, 1, 1, 7).Style.Fill.BackgroundColor = XLColor.Cyan;
ws.Range(1, 1, 1, 7).Style.Font.Bold = true;
diff --git a/ClosedXML_Examples/Misc/InsertingData.cs b/ClosedXML_Examples/Misc/InsertingData.cs
index d0ade19..d1035d5 100644
--- a/ClosedXML_Examples/Misc/InsertingData.cs
+++ b/ClosedXML_Examples/Misc/InsertingData.cs
@@ -13,59 +13,65 @@
// Public
public void Create(String filePath)
{
- var wb = new XLWorkbook();
- var ws = wb.Worksheets.Add("Inserting Data");
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.Worksheets.Add("Inserting Data");
- // From a list of strings
- var listOfStrings = new List();
- listOfStrings.Add("House");
- listOfStrings.Add("001");
- ws.Cell(1, 1).Value = "From Strings";
- ws.Cell(1, 1).AsRange().AddToNamed("Titles");
- ws.Cell(2, 1).InsertData(listOfStrings);
+ // From a list of strings
+ var listOfStrings = new List();
+ listOfStrings.Add("House");
+ listOfStrings.Add("001");
+ ws.Cell(1, 1).Value = "From Strings";
+ ws.Cell(1, 1).AsRange().AddToNamed("Titles");
+ ws.Cell(2, 1).InsertData(listOfStrings);
- // From a list of arrays
- var listOfArr = new List();
- listOfArr.Add(new Int32[] { 1, 2, 3 });
- listOfArr.Add(new Int32[] { 1 });
- listOfArr.Add(new Int32[] { 1, 2, 3, 4, 5, 6 });
- ws.Cell(1, 3).Value = "From Arrays";
- ws.Range(1, 3, 1, 8).Merge().AddToNamed("Titles");
- ws.Cell(2, 3).InsertData(listOfArr);
+ // From a list of arrays
+ var listOfArr = new List();
+ listOfArr.Add(new Int32[] { 1, 2, 3 });
+ listOfArr.Add(new Int32[] { 1 });
+ listOfArr.Add(new Int32[] { 1, 2, 3, 4, 5, 6 });
+ ws.Cell(1, 3).Value = "From Arrays";
+ ws.Range(1, 3, 1, 8).Merge().AddToNamed("Titles");
+ ws.Cell(2, 3).InsertData(listOfArr);
- // From a DataTable
- var dataTable = GetTable();
- ws.Cell(6, 1).Value = "From DataTable";
- ws.Range(6, 1, 6, 4).Merge().AddToNamed("Titles");
- ws.Cell(7, 1).InsertData(dataTable.AsEnumerable());
+ // From a DataTable
+ var dataTable = GetTable();
+ ws.Cell(6, 1).Value = "From DataTable";
+ ws.Range(6, 1, 6, 4).Merge().AddToNamed("Titles");
+ ws.Cell(7, 1).InsertData(dataTable.AsEnumerable());
- // From a query
- var list = new List();
- list.Add(new Person() { Name = "John", Age = 30, House = "On Elm St." });
- list.Add(new Person() { Name = "Mary", Age = 15, House = "On Main St." });
- list.Add(new Person() { Name = "Luis", Age = 21, House = "On 23rd St." });
- list.Add(new Person() { Name = "Henry", Age = 45, House = "On 5th Ave." });
+ // From a query
+ var list = new List();
+ list.Add(new Person() { Name = "John", Age = 30, House = "On Elm St." });
+ list.Add(new Person() { Name = "Mary", Age = 15, House = "On Main St." });
+ list.Add(new Person() { Name = "Luis", Age = 21, House = "On 23rd St." });
+ list.Add(new Person() { Name = "Henry", Age = 45, House = "On 5th Ave." });
- var people = from p in list
- where p.Age >= 21
- select new { p.Name, p.House, p.Age };
+ var people = from p in list
+ where p.Age >= 21
+ select new { p.Name, p.House, p.Age };
- ws.Cell(6, 6).Value = "From Query";
- ws.Range(6, 6, 6, 8).Merge().AddToNamed("Titles");
- ws.Cell(7, 6).InsertData(people.AsEnumerable());
+ ws.Cell(6, 6).Value = "From Query";
+ ws.Range(6, 6, 6, 8).Merge().AddToNamed("Titles");
+ ws.Cell(7, 6).InsertData(people.AsEnumerable());
- // Prepare the style for the titles
- var titlesStyle = wb.Style;
- titlesStyle.Font.Bold = true;
- titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
- titlesStyle.Fill.BackgroundColor = XLColor.Cyan;
-
- // Format all titles in one shot
- wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
+ ws.Cell("F13").Value = "Transposed";
+ ws.Range(13, 6, 13, 8).Merge().AddToNamed("Titles");
+ ws.Cell("F14").InsertData(people.AsEnumerable(), true);
- ws.Columns().AdjustToContents();
+ // Prepare the style for the titles
+ var titlesStyle = wb.Style;
+ titlesStyle.Font.Bold = true;
+ titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
+ titlesStyle.Fill.BackgroundColor = XLColor.Cyan;
- wb.SaveAs(filePath);
+ // Format all titles in one shot
+ wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
+
+ ws.Columns().AdjustToContents();
+
+ wb.SaveAs(filePath);
+ }
}
class Person
diff --git a/ClosedXML_Examples/PivotTables/PivotTables.cs b/ClosedXML_Examples/PivotTables/PivotTables.cs
index 9eb24ea..fa479da 100644
--- a/ClosedXML_Examples/PivotTables/PivotTables.cs
+++ b/ClosedXML_Examples/PivotTables/PivotTables.cs
@@ -60,6 +60,8 @@
IXLWorksheet ptSheet;
IXLPivotTable pt;
+ #region Pivots
+
for (int i = 1; i <= 3; i++)
{
// Add a new sheet for our pivot table
@@ -95,7 +97,10 @@
ptSheet.Columns().AdjustToContents();
}
- // Different kind of pivot
+ #endregion Pivots
+
+ #region Different kind of pivot
+
ptSheet = wb.Worksheets.Add("pvtNoColumnLabels");
pt = ptSheet.PivotTables.AddNew("pvtNoColumnLabels", ptSheet.Cell(1, 1), dataRange);
@@ -105,8 +110,10 @@
pt.Values.Add("NumberOfOrders").SetSummaryFormula(XLPivotSummary.Sum);
pt.Values.Add("Quality").SetSummaryFormula(XLPivotSummary.Sum);
+ #endregion Different kind of pivot
- // Pivot table with collapsed fields
+ #region Pivot table with collapsed fields
+
ptSheet = wb.Worksheets.Add("pvtCollapsedFields");
pt = ptSheet.PivotTables.AddNew("pvtCollapsedFields", ptSheet.Cell(1, 1), dataRange);
@@ -116,8 +123,10 @@
pt.Values.Add("NumberOfOrders").SetSummaryFormula(XLPivotSummary.Sum);
pt.Values.Add("Quality").SetSummaryFormula(XLPivotSummary.Sum);
+ #endregion Pivot table with collapsed fields
- // Pivot table with a field both as a value and as a row/column/filter label
+ #region Pivot table with a field both as a value and as a row/column/filter label
+
ptSheet = wb.Worksheets.Add("pvtFieldAsValueAndLabel");
pt = ptSheet.PivotTables.AddNew("pvtFieldAsValueAndLabel", ptSheet.Cell(1, 1), dataRange);
@@ -126,6 +135,37 @@
pt.Values.Add("Name").SetSummaryFormula(XLPivotSummary.Count);//.NumberFormat.Format = "#0.00";
+ #endregion Pivot table with a field both as a value and as a row/column/filter label
+
+ #region Pivot table with subtotals disabled
+
+ ptSheet = wb.Worksheets.Add("pvtHideSubTotals");
+
+ // Create the pivot table, using the data from the "PastrySalesData" table
+ pt = ptSheet.PivotTables.AddNew("pvtHidesubTotals", ptSheet.Cell(1, 1), dataRange);
+
+ // The rows in our pivot table will be the names of the pastries
+ pt.RowLabels.Add(XLConstants.PivotTableValuesSentinalLabel);
+
+ // The columns will be the months
+ pt.ColumnLabels.Add("Month");
+ pt.ColumnLabels.Add("Name");
+
+ // The values in our table will come from the "NumberOfOrders" field
+ // The default calculation setting is a total of each row/column
+ pt.Values.Add("NumberOfOrders", "NumberOfOrdersPercentageOfBearclaw")
+ .ShowAsPercentageFrom("Name").And("Bearclaw")
+ .NumberFormat.Format = "0%";
+
+ pt.Values.Add("Quality", "Sum of Quality")
+ .NumberFormat.SetFormat("#,##0.00");
+
+ pt.Subtotals = XLPivotSubtotals.DoNotShow;
+
+ ptSheet.Columns().AdjustToContents();
+
+ #endregion Pivot table with subtotals disabled
+
wb.SaveAs(filePath);
}
}
diff --git a/ClosedXML_Tests/ClosedXML_Tests.csproj b/ClosedXML_Tests/ClosedXML_Tests.csproj
index 2533a4c..e4182dd 100644
--- a/ClosedXML_Tests/ClosedXML_Tests.csproj
+++ b/ClosedXML_Tests/ClosedXML_Tests.csproj
@@ -81,10 +81,12 @@
+
+
@@ -92,6 +94,7 @@
+
@@ -286,6 +289,9 @@
+
+
+
diff --git a/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs b/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
index 3fca48e..3ad7f8e 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
@@ -620,7 +620,7 @@
Assert.AreEqual(0, cell.Value);
cell = wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=SUM(D1,D2)");
Assert.AreEqual(0, cell.Value);
- Assert.That(() => wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=AVERAGE(D1,D2)").Value, Throws.Exception);
+ Assert.That(() => wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=AVERAGE(D1,D2)").Value, Throws.TypeOf());
}
[Test]
diff --git a/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs b/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs
index 44b9156..a18e509 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs
@@ -1,4 +1,4 @@
-using ClosedXML.Excel;
+using ClosedXML.Excel;
using ClosedXML.Excel.CalcEngine.Exceptions;
using NUnit.Framework;
using System;
@@ -107,6 +107,12 @@
value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(179.64, value);
+ value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8)");
+ Assert.AreEqual(179.64, value);
+
+ value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8,)");
+ Assert.AreEqual(179.64, value);
+
value = workbook.Evaluate("=VLOOKUP(14.5,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(174.65, value);
diff --git a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs
new file mode 100644
index 0000000..5012bb5
--- /dev/null
+++ b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs
@@ -0,0 +1,123 @@
+using ClosedXML.Excel;
+using NUnit.Framework;
+using System;
+
+namespace ClosedXML_Tests.Excel.CalcEngine
+{
+ [TestFixture]
+ public class MathTrigTests
+ {
+ private readonly double tolerance = 1e-10;
+
+ [Test]
+ public void Floor()
+ {
+ Object actual;
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.2)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.7)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(-1.7)");
+ Assert.AreEqual(-2, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.2, 1)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.7, 1)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(-1.7, 1)");
+ Assert.AreEqual(-2, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(0.4, 2)");
+ Assert.AreEqual(0, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(2.7, 2)");
+ Assert.AreEqual(2, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(7.8, 2)");
+ Assert.AreEqual(6, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(-5.5, -2)");
+ Assert.AreEqual(-4, actual);
+ }
+
+ [Test]
+ // Functions have to support a period first before we can implement this
+ public void FloorMath()
+ {
+ double actual;
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(24.3, 5)");
+ Assert.AreEqual(20, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(6.7)");
+ Assert.AreEqual(6, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-8.1, 2)");
+ Assert.AreEqual(-10, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, 2.1, 0)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, -2.1, 0)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, 2.1, -1)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, -2.1, -1)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, 2.1, 0)");
+ Assert.AreEqual(-6.3, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, -2.1, 0)");
+ Assert.AreEqual(-6.3, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, 2.1, -1)");
+ Assert.AreEqual(-4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, -2.1, -1)");
+ Assert.AreEqual(-4.2, actual, tolerance);
+ }
+
+ [Test]
+ public void Mod()
+ {
+ double actual;
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(1.5, 1)");
+ Assert.AreEqual(0.5, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(3, 2)");
+ Assert.AreEqual(1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(-3, 2)");
+ Assert.AreEqual(1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(3, -2)");
+ Assert.AreEqual(-1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(-3, -2)");
+ Assert.AreEqual(-1, actual, tolerance);
+
+ //////
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(-4.3, -0.5)");
+ Assert.AreEqual(-0.3, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(6.9, -0.2)");
+ Assert.AreEqual(-0.1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(0.7, 0.6)");
+ Assert.AreEqual(0.1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(6.2, 1.1)");
+ Assert.AreEqual(0.7, actual, tolerance);
+ }
+ }
+}
diff --git a/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs b/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs
index c59e34d..2550868 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs
@@ -22,7 +22,7 @@
value = ws.Evaluate("AVERAGE(G3:G45)").CastTo();
Assert.AreEqual(49.3255814, value, tolerance);
- Assert.That(() => ws.Evaluate("AVERAGE(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate("AVERAGE(D3:D45)"), Throws.TypeOf());
}
[Test]
@@ -146,7 +146,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=STDEV(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=STDEV(D3:D45)"), Throws.TypeOf());
value = ws.Evaluate(@"=STDEV(H3:H45)").CastTo();
Assert.AreEqual(47.34511769, value, tolerance);
@@ -163,7 +163,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=STDEVP(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=STDEVP(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=STDEVP(H3:H45)").CastTo();
Assert.AreEqual(46.79135458, value, tolerance);
@@ -180,7 +180,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=VAR(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=VAR(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=VAR(H3:H45)").CastTo();
Assert.AreEqual(2241.560169, value, tolerance);
@@ -197,7 +197,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=VARP(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=VARP(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=VARP(H3:H45)").CastTo();
Assert.AreEqual(2189.430863, value, tolerance);
diff --git a/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs b/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs
index 3a89de2..59d0a59 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs
@@ -1,4 +1,6 @@
using ClosedXML.Excel;
+using ClosedXML.Excel.CalcEngine;
+using ClosedXML.Excel.CalcEngine.Exceptions;
using NUnit.Framework;
using System;
using System.Globalization;
@@ -19,13 +21,13 @@
[Test]
public void Char_Empty_Input_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Char("""")"), Throws.Exception);
+ Assert.Throws(() => XLWorkbook.EvaluateExpr(@"Char("""")"));
}
[Test]
public void Char_Input_Too_Large()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Char(9797)"), Throws.Exception);
+ Assert.Throws< CellValueException>(() => XLWorkbook.EvaluateExpr(@"Char(9797)"));
}
[Test]
@@ -56,7 +58,7 @@
public void Code_Empty_Input_String()
{
// Todo: more specific exception - ValueException?
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Code("""")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Code("""")"), Throws.TypeOf());
}
[Test]
@@ -82,7 +84,7 @@
[Test]
public void Dollar_Empty_Input_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Dollar("", 3)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Dollar("", 3)"), Throws.TypeOf());
}
[Test]
@@ -121,26 +123,26 @@
[Test]
public void Find_Start_Position_Too_Large()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", ""abcdef"", 10)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", ""abcdef"", 10)"), Throws.TypeOf());
}
[Test]
public void Find_String_In_Another_Empty_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", """")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", """")"), Throws.TypeOf());
}
[Test]
public void Find_String_Not_Found()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""123"", ""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""123"", ""asdf"")"), Throws.TypeOf());
}
[Test]
public void Find_Case_Sensitive_String_Not_Found()
{
// Find is case-sensitive
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""excel"", ""Microsoft Excel 2010"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""excel"", ""Microsoft Excel 2010"")"), Throws.TypeOf());
}
[Test]
@@ -159,7 +161,7 @@
[Test]
public void Fixed_Input_Is_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Fixed(""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Fixed(""asdf"")"), Throws.TypeOf());
}
[Test]
@@ -297,7 +299,7 @@
[Test]
public void Rept_Start_Is_Negative()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Rept(""Francois"", -1)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Rept(""Francois"", -1)"), Throws.TypeOf());
}
[Test]
@@ -344,7 +346,7 @@
[Test]
public void Search_No_Parameters_With_Values()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search("""", """")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search("""", """")"), Throws.TypeOf());
}
[Test]
@@ -357,31 +359,31 @@
[Test]
public void Search_Start_Position_Too_Large()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", ""abcdef"", 10)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", ""abcdef"", 10)"), Throws.TypeOf());
}
[Test]
public void Search_Empty_Input_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", """")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", """")"), Throws.TypeOf());
}
[Test]
public void Search_String_Not_Found()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""123"", ""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""123"", ""asdf"")"), Throws.TypeOf());
}
[Test]
public void Search_Wildcard_String_Not_Found()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""soft?2010"", ""Microsoft Excel 2010"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""soft?2010"", ""Microsoft Excel 2010"")"), Throws.TypeOf());
}
[Test]
public void Search_Start_Position_Too_Large2()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""text"", ""This is some text"", 15)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""text"", ""This is some text"", 15)"), Throws.TypeOf());
}
// http://www.excel-easy.com/examples/find-vs-search.html
@@ -517,7 +519,7 @@
[Test]
public void Value_Input_String_Is_Not_A_Number()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Value(""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Value(""asdf"")"), Throws.TypeOf());
}
[Test]
diff --git a/ClosedXML_Tests/Excel/Cells/XLCellTests.cs b/ClosedXML_Tests/Excel/Cells/XLCellTests.cs
index 31e66f9..2fb6166 100644
--- a/ClosedXML_Tests/Excel/Cells/XLCellTests.cs
+++ b/ClosedXML_Tests/Excel/Cells/XLCellTests.cs
@@ -83,6 +83,22 @@
}
[Test]
+ public void InsertData2()
+ {
+ IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
+ IXLRange range = ws.Cell(2, 2).InsertData(new[] { "a", "b", "c" }, false);
+ Assert.AreEqual("Sheet1!B2:B4", range.ToString());
+ }
+
+ [Test]
+ public void InsertData3()
+ {
+ IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
+ IXLRange range = ws.Cell(2, 2).InsertData(new[] { "a", "b", "c" }, true);
+ Assert.AreEqual("Sheet1!B2:D2", range.ToString());
+ }
+
+ [Test]
public void IsEmpty1()
{
IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
@@ -388,5 +404,27 @@
Assert.AreEqual("\u0018", wb.Worksheets.First().FirstCell().Value);
}
}
+
+ [Test]
+ public void CanClearCellValueBySettingNullValue()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.AddWorksheet("Sheet1");
+ var cell = ws.FirstCell();
+
+ cell.Value = "Test";
+ Assert.AreEqual("Test", cell.Value);
+ Assert.AreEqual(XLCellValues.Text, cell.DataType);
+
+ string s = null;
+ cell.SetValue(s);
+ Assert.AreEqual(string.Empty, cell.Value);
+
+ cell.Value = "Test";
+ cell.Value = null;
+ Assert.AreEqual(string.Empty, cell.Value);
+ }
+ }
}
}
diff --git a/ClosedXML_Tests/Excel/ImageHandling/PictureTests.cs b/ClosedXML_Tests/Excel/ImageHandling/PictureTests.cs
index b0ba0d6..a06902e 100644
--- a/ClosedXML_Tests/Excel/ImageHandling/PictureTests.cs
+++ b/ClosedXML_Tests/Excel/ImageHandling/PictureTests.cs
@@ -145,6 +145,35 @@
}
[Test]
+ public void TestDefaultIds()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.AddWorksheet("Sheet1");
+
+ using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClosedXML_Tests.Resource.Images.ImageHandling.png"))
+ {
+ ws.AddPicture(stream, XLPictureFormat.Png);
+ stream.Position = 0;
+
+ ws.AddPicture(stream, XLPictureFormat.Png);
+ stream.Position = 0;
+
+ ws.AddPicture(stream, XLPictureFormat.Png).Name = "Picture 4";
+ stream.Position = 0;
+
+ ws.AddPicture(stream, XLPictureFormat.Png);
+ stream.Position = 0;
+ }
+
+ Assert.AreEqual(1, ws.Pictures.Skip(0).First().Id);
+ Assert.AreEqual(2, ws.Pictures.Skip(1).First().Id);
+ Assert.AreEqual(3, ws.Pictures.Skip(2).First().Id);
+ Assert.AreEqual(4, ws.Pictures.Skip(3).First().Id);
+ }
+ }
+
+ [Test]
public void XLMarkerTests()
{
IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
diff --git a/ClosedXML_Tests/Excel/Loading/LoadingTests.cs b/ClosedXML_Tests/Excel/Loading/LoadingTests.cs
index 218ae90..5b1fc42 100644
--- a/ClosedXML_Tests/Excel/Loading/LoadingTests.cs
+++ b/ClosedXML_Tests/Excel/Loading/LoadingTests.cs
@@ -1,6 +1,8 @@
using ClosedXML.Excel;
using ClosedXML.Excel.Drawings;
+using ClosedXML_Tests.Utils;
using NUnit.Framework;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -27,7 +29,10 @@
@"Misc\InvalidPrintTitles.xlsx",
@"Misc\ExcelProducedWorkbookWithImages.xlsx",
@"Misc\EmptyCellValue.xlsx",
- @"Misc\AllShapes.xlsx"
+ @"Misc\AllShapes.xlsx",
+ @"Misc\TableHeadersWithLineBreaks.xlsx",
+ @"Misc\TableWithNameNull.xlsx",
+ @"Misc\DuplicateImageNames.xlsx"
};
foreach (var file in files)
@@ -178,5 +183,26 @@
wb.SaveAs(ms, true);
}
}
+
+ [Test]
+ public void CanLoadFromTemplate()
+ {
+ using (var tf1 = new TemporaryFile())
+ using (var tf2 = new TemporaryFile())
+ {
+ using (var stream = TestHelper.GetStreamFromResource(TestHelper.GetResourcePath(@"Misc\AllShapes.xlsx")))
+ using (var wb = new XLWorkbook(stream))
+ {
+ // Save as temporary file
+ wb.SaveAs(tf1.Path);
+ }
+
+ var workbook = XLWorkbook.OpenFromTemplate(tf1.Path);
+ Assert.True(workbook.Worksheets.Any());
+ Assert.Throws(() => workbook.Save());
+
+ workbook.SaveAs(tf2.Path);
+ }
+ }
}
}
diff --git a/ClosedXML_Tests/Excel/Misc/FormulaTests.cs b/ClosedXML_Tests/Excel/Misc/FormulaTests.cs
index 0ba9217..3ff4c55 100644
--- a/ClosedXML_Tests/Excel/Misc/FormulaTests.cs
+++ b/ClosedXML_Tests/Excel/Misc/FormulaTests.cs
@@ -159,6 +159,23 @@
}
[Test]
+ public void FormulaThatStartsWithEqualsAndPlus()
+ {
+ object actual;
+ actual = XLWorkbook.EvaluateExpr("=MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+
+ actual = XLWorkbook.EvaluateExpr("=+MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+
+ actual = XLWorkbook.EvaluateExpr("=+++++MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+
+ actual = XLWorkbook.EvaluateExpr("+MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+ }
+
+ [Test]
public void FormulasWithErrors()
{
Assert.Throws(() => XLWorkbook.EvaluateExpr("YEAR(#REF!)"));
diff --git a/ClosedXML_Tests/Excel/Misc/SearchTests.cs b/ClosedXML_Tests/Excel/Misc/SearchTests.cs
new file mode 100644
index 0000000..21e299d
--- /dev/null
+++ b/ClosedXML_Tests/Excel/Misc/SearchTests.cs
@@ -0,0 +1,78 @@
+using ClosedXML.Excel;
+using NUnit.Framework;
+using System.Globalization;
+using System.Linq;
+
+namespace ClosedXML_Tests.Excel.Misc
+{
+ [TestFixture]
+ public class SearchTests
+ {
+ [Test]
+ public void TestSearch()
+ {
+ using (var stream = TestHelper.GetStreamFromResource(TestHelper.GetResourcePath(@"Examples\Misc\CellValues.xlsx")))
+ using (var wb = new XLWorkbook(stream))
+ {
+ var ws = wb.Worksheets.First();
+
+ IXLCells foundCells;
+
+ foundCells = ws.Search("Initial Value");
+ Assert.AreEqual(1, foundCells.Count());
+ Assert.AreEqual("B2", foundCells.Single().Address.ToString());
+ Assert.AreEqual("Initial Value", foundCells.Single().GetString());
+
+ foundCells = ws.Search("Using");
+ Assert.AreEqual(2, foundCells.Count());
+ Assert.AreEqual("D2", foundCells.First().Address.ToString());
+ Assert.AreEqual("Using Get...()", foundCells.First().GetString());
+ Assert.AreEqual(2, foundCells.Count());
+ Assert.AreEqual("E2", foundCells.Last().Address.ToString());
+ Assert.AreEqual("Using GetValue()", foundCells.Last().GetString());
+
+ foundCells = ws.Search("1234");
+ Assert.AreEqual(4, foundCells.Count());
+ Assert.AreEqual("C5,D5,E5,F5", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("Sep");
+ Assert.AreEqual(2, foundCells.Count());
+ Assert.AreEqual("B3,G3", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("1234", CompareOptions.Ordinal, true);
+ Assert.AreEqual(5, foundCells.Count());
+ Assert.AreEqual("B5,C5,D5,E5,F5", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("test case", CompareOptions.Ordinal);
+ Assert.AreEqual(0, foundCells.Count());
+
+ foundCells = ws.Search("test case", CompareOptions.OrdinalIgnoreCase);
+ Assert.AreEqual(6, foundCells.Count());
+ }
+ }
+
+ [Test]
+ public void TestSearch2()
+ {
+ using (var stream = TestHelper.GetStreamFromResource(TestHelper.GetResourcePath(@"Examples\Misc\Formulas.xlsx")))
+ using (var wb = new XLWorkbook(stream))
+ {
+ var ws = wb.Worksheets.First();
+
+ IXLCells foundCells;
+
+ foundCells = ws.Search("3", CompareOptions.Ordinal);
+ Assert.AreEqual(10, foundCells.Count());
+ Assert.AreEqual("C2", foundCells.First().Address.ToString());
+
+ foundCells = ws.Search("A2", CompareOptions.Ordinal, true);
+ Assert.AreEqual(6, foundCells.Count());
+ Assert.AreEqual("C2,D2,B6,C6,D6,A11", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("RC", CompareOptions.Ordinal, true);
+ Assert.AreEqual(3, foundCells.Count());
+ Assert.AreEqual("E2,E3,E4", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+ }
+ }
+ }
+}
diff --git a/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs b/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs
index 907bc96..afe5c7b 100644
--- a/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs
+++ b/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs
@@ -140,5 +140,38 @@
Assert.Throws(() => wb.NamedRanges.Add("MyRange", "A1:C1"));
}
}
+
+ [Test]
+ public void NamedRangesWhenCopyingWorksheets()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws1 = wb.AddWorksheet("Sheet1");
+ ws1.FirstCell().Value = Enumerable.Range(1, 10);
+ wb.NamedRanges.Add("wbNamedRange", ws1.Range("A1:A10"));
+ ws1.NamedRanges.Add("wsNamedRange", ws1.Range("A3"));
+
+ var ws2 = wb.AddWorksheet("Sheet2");
+ ws2.FirstCell().Value = Enumerable.Range(101, 10);
+ ws1.NamedRanges.Add("wsNamedRangeAcrossSheets", ws2.Range("A4"));
+
+ ws1.Cell("C1").FormulaA1 = "=wbNamedRange";
+ ws1.Cell("C2").FormulaA1 = "=wsNamedRange";
+ ws1.Cell("C3").FormulaA1 = "=wsNamedRangeAcrossSheets";
+
+ Assert.AreEqual(1, ws1.Cell("C1").Value);
+ Assert.AreEqual(3, ws1.Cell("C2").Value);
+ Assert.AreEqual(104, ws1.Cell("C3").Value);
+
+ var wsCopy = ws1.CopyTo("Copy");
+ Assert.AreEqual(1, wsCopy.Cell("C1").Value);
+ Assert.AreEqual(3, wsCopy.Cell("C2").Value);
+ Assert.AreEqual(104, wsCopy.Cell("C3").Value);
+
+ Assert.AreEqual("Sheet1!A1:A10", wb.NamedRange("wbNamedRange").Ranges.First().RangeAddress.ToStringRelative(true));
+ Assert.AreEqual("Copy!A3:A3", wsCopy.NamedRange("wsNamedRange").Ranges.First().RangeAddress.ToStringRelative(true));
+ Assert.AreEqual("Sheet2!A4:A4", wsCopy.NamedRange("wsNamedRangeAcrossSheets").Ranges.First().RangeAddress.ToStringRelative(true));
+ }
+ }
}
}
diff --git a/ClosedXML_Tests/Excel/Rows/RowTests.cs b/ClosedXML_Tests/Excel/Rows/RowTests.cs
index 17cddeb..bb74d4f 100644
--- a/ClosedXML_Tests/Excel/Rows/RowTests.cs
+++ b/ClosedXML_Tests/Excel/Rows/RowTests.cs
@@ -185,6 +185,36 @@
}
[Test]
+ public void InsertingRowsAbove4()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.Worksheets.Add("Sheet1");
+
+ ws.Row(2).Height = 15;
+ ws.Row(3).Height = 20;
+ ws.Row(4).Height = 25;
+ ws.Row(5).Height = 35;
+
+ ws.Row(2).FirstCell().SetValue("Row height: 15");
+ ws.Row(3).FirstCell().SetValue("Row height: 20");
+ ws.Row(4).FirstCell().SetValue("Row height: 25");
+ ws.Row(5).FirstCell().SetValue("Row height: 35");
+
+ ws.Range("3:3").InsertRowsAbove(1);
+
+ Assert.AreEqual(15, ws.Row(2).Height);
+ Assert.AreEqual(20, ws.Row(4).Height);
+ Assert.AreEqual(25, ws.Row(5).Height);
+ Assert.AreEqual(35, ws.Row(6).Height);
+
+ Assert.AreEqual(20, ws.Row(3).Height);
+ ws.Row(3).ClearHeight();
+ Assert.AreEqual(ws.RowHeight, ws.Row(3).Height);
+ }
+ }
+
+ [Test]
public void NoRowsUsed()
{
var wb = new XLWorkbook();
@@ -224,4 +254,4 @@
ws.Rows(1, 2).Ungroup(true);
}
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML_Tests/Excel/Saving/SavingTests.cs b/ClosedXML_Tests/Excel/Saving/SavingTests.cs
index ca2fd98..60a1d7a 100644
--- a/ClosedXML_Tests/Excel/Saving/SavingTests.cs
+++ b/ClosedXML_Tests/Excel/Saving/SavingTests.cs
@@ -34,6 +34,35 @@
}
[Test]
+ public void CanSaveFileMultipleTimesAfterDeletingWorksheet()
+ {
+ // https://github.com/ClosedXML/ClosedXML/issues/435
+
+
+ using (var ms = new MemoryStream())
+ {
+ using (XLWorkbook book1 = new XLWorkbook())
+ {
+ book1.AddWorksheet("sheet1");
+ book1.AddWorksheet("sheet2");
+
+ book1.SaveAs(ms);
+ }
+ ms.Position = 0;
+
+ using (XLWorkbook book2 = new XLWorkbook(ms))
+ {
+ var ws = book2.Worksheet(1);
+ Assert.AreEqual("sheet1", ws.Name);
+ ws.Delete();
+ book2.Save();
+ book2.Save();
+ }
+ }
+ }
+
+
+ [Test]
public void CanSaveAndValidateFileInAnotherCulture()
{
string[] cultures = new string[] { "it", "de-AT" };
diff --git a/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs b/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs
index 3c94664..326340b 100644
--- a/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs
+++ b/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs
@@ -14,7 +14,6 @@
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
- ws.Column(1).Style.NumberFormat.Format = "yy-MM-dd";
var table = new DataTable();
table.Columns.Add("Date", typeof(DateTime));
@@ -24,9 +23,13 @@
table.Rows.Add(new DateTime(2017, 1, 1).AddMonths(i));
}
+ ws.Column(1).Style.NumberFormat.Format = "yy-MM-dd";
ws.Cell("A1").InsertData(table.AsEnumerable());
-
Assert.AreEqual("yy-MM-dd", ws.Cell("A5").Style.DateFormat.Format);
+
+ ws.Row(1).Style.NumberFormat.Format = "yy-MM-dd";
+ ws.Cell("A1").InsertData(table.AsEnumerable(), true);
+ Assert.AreEqual("yy-MM-dd", ws.Cell("E1").Style.DateFormat.Format);
}
}
}
diff --git a/ClosedXML_Tests/Excel/Tables/TablesTests.cs b/ClosedXML_Tests/Excel/Tables/TablesTests.cs
index ddc7b84..1a35952 100644
--- a/ClosedXML_Tests/Excel/Tables/TablesTests.cs
+++ b/ClosedXML_Tests/Excel/Tables/TablesTests.cs
@@ -1,4 +1,4 @@
-using ClosedXML.Attributes;
+using ClosedXML.Attributes;
using ClosedXML.Excel;
using NUnit.Framework;
using System;
@@ -42,100 +42,112 @@
dt.Columns.Add("col1", typeof(string));
dt.Columns.Add("col2", typeof(double));
- var wb = new XLWorkbook();
- wb.AddWorksheet(dt);
+ using (var wb = new XLWorkbook())
+ {
+ wb.AddWorksheet(dt);
- using (var ms = new MemoryStream())
- wb.SaveAs(ms, true);
+ using (var ms = new MemoryStream())
+ wb.SaveAs(ms, true);
+ }
}
[Test]
public void CanSaveTableCreatedFromSingleRow()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Title");
- ws.Range("A1").CreateTable();
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Title");
+ ws.Range("A1").CreateTable();
- using (var ms = new MemoryStream())
- wb.SaveAs(ms, true);
+ using (var ms = new MemoryStream())
+ wb.SaveAs(ms, true);
+ }
}
[Test]
public void CreatingATableFromHeadersPushCellsBelow()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Title")
- .CellBelow().SetValue("X");
- ws.Range("A1").CreateTable();
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Title")
+ .CellBelow().SetValue("X");
+ ws.Range("A1").CreateTable();
- Assert.AreEqual(ws.Cell("A2").GetString(), String.Empty);
- Assert.AreEqual(ws.Cell("A3").GetString(), "X");
+ Assert.AreEqual(ws.Cell("A2").GetString(), String.Empty);
+ Assert.AreEqual(ws.Cell("A3").GetString(), "X");
+ }
}
[Test]
public void Inserting_Column_Sets_Header()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Categories")
- .CellBelow().SetValue("A")
- .CellBelow().SetValue("B")
- .CellBelow().SetValue("C");
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Categories")
+ .CellBelow().SetValue("A")
+ .CellBelow().SetValue("B")
+ .CellBelow().SetValue("C");
- IXLTable table = ws.RangeUsed().CreateTable();
- table.InsertColumnsAfter(1);
- Assert.AreEqual("Column2", table.HeadersRow().LastCell().GetString());
+ IXLTable table = ws.RangeUsed().CreateTable();
+ table.InsertColumnsAfter(1);
+ Assert.AreEqual("Column2", table.HeadersRow().LastCell().GetString());
+ }
}
[Test]
public void SavingLoadingTableWithNewLineInHeader()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- string columnName = "Line1" + Environment.NewLine + "Line2";
- ws.FirstCell().SetValue(columnName)
- .CellBelow().SetValue("A");
- ws.RangeUsed().CreateTable();
- using (var ms = new MemoryStream())
+ using (var wb = new XLWorkbook())
{
- wb.SaveAs(ms, true);
- var wb2 = new XLWorkbook(ms);
- IXLWorksheet ws2 = wb2.Worksheet(1);
- IXLTable table2 = ws2.Table(0);
- string fieldName = table2.Field(0).Name;
- Assert.AreEqual("Line1\nLine2", fieldName);
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ string columnName = "Line1" + Environment.NewLine + "Line2";
+ ws.FirstCell().SetValue(columnName)
+ .CellBelow().SetValue("A");
+ ws.RangeUsed().CreateTable();
+ using (var ms = new MemoryStream())
+ {
+ wb.SaveAs(ms, true);
+ var wb2 = new XLWorkbook(ms);
+ IXLWorksheet ws2 = wb2.Worksheet(1);
+ IXLTable table2 = ws2.Table(0);
+ string fieldName = table2.Field(0).Name;
+ Assert.AreEqual("Line1\nLine2", fieldName);
+ }
}
}
[Test]
public void SavingLoadingTableWithNewLineInHeader2()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.Worksheets.Add("Test");
-
- var dt = new DataTable();
- string columnName = "Line1" + Environment.NewLine + "Line2";
- dt.Columns.Add(columnName);
-
- DataRow dr = dt.NewRow();
- dr[columnName] = "some text";
- dt.Rows.Add(dr);
- ws.Cell(1, 1).InsertTable(dt.AsEnumerable());
-
- IXLTable table1 = ws.Table(0);
- string fieldName1 = table1.Field(0).Name;
- Assert.AreEqual(columnName, fieldName1);
-
- using (var ms = new MemoryStream())
+ using (var wb = new XLWorkbook())
{
- wb.SaveAs(ms, true);
- var wb2 = new XLWorkbook(ms);
- IXLWorksheet ws2 = wb2.Worksheet(1);
- IXLTable table2 = ws2.Table(0);
- string fieldName2 = table2.Field(0).Name;
- Assert.AreEqual("Line1\nLine2", fieldName2);
+ IXLWorksheet ws = wb.Worksheets.Add("Test");
+
+ var dt = new DataTable();
+ string columnName = "Line1" + Environment.NewLine + "Line2";
+ dt.Columns.Add(columnName);
+
+ DataRow dr = dt.NewRow();
+ dr[columnName] = "some text";
+ dt.Rows.Add(dr);
+ ws.Cell(1, 1).InsertTable(dt.AsEnumerable());
+
+ IXLTable table1 = ws.Table(0);
+ string fieldName1 = table1.Field(0).Name;
+ Assert.AreEqual(columnName, fieldName1);
+
+ using (var ms = new MemoryStream())
+ {
+ wb.SaveAs(ms, true);
+ var wb2 = new XLWorkbook(ms);
+ IXLWorksheet ws2 = wb2.Worksheet(1);
+ IXLTable table2 = ws2.Table(0);
+ string fieldName2 = table2.Field(0).Name;
+ Assert.AreEqual("Line1\nLine2", fieldName2);
+ }
}
}
@@ -146,10 +158,12 @@
dt.Columns.Add("col1", typeof(string));
dt.Columns.Add("col2", typeof(double));
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().InsertTable(dt);
- Assert.AreEqual(2, ws.Tables.First().ColumnCount());
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().InsertTable(dt);
+ Assert.AreEqual(2, ws.Tables.First().ColumnCount());
+ }
}
[Test]
@@ -157,10 +171,12 @@
{
var l = new List();
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().InsertTable(l);
- Assert.AreEqual(1, ws.Tables.First().ColumnCount());
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().InsertTable(l);
+ Assert.AreEqual(1, ws.Tables.First().ColumnCount());
+ }
}
[Test]
@@ -168,10 +184,12 @@
{
var l = new List();
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().InsertTable(l);
- Assert.AreEqual(2, ws.Tables.First().ColumnCount());
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().InsertTable(l);
+ Assert.AreEqual(2, ws.Tables.First().ColumnCount());
+ }
}
[Test]
@@ -183,184 +201,255 @@
new TestObjectWithAttributes() { Column1 = "c", Column2 = "d", MyField = 5, UnOrderedColumn = 777 }
};
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().InsertTable(l);
- Assert.AreEqual(4, ws.Tables.First().ColumnCount());
- Assert.AreEqual("FirstColumn", ws.FirstCell().Value);
- Assert.AreEqual("SecondColumn", ws.FirstCell().CellRight().Value);
- Assert.AreEqual("SomeFieldNotProperty", ws.FirstCell().CellRight().CellRight().Value);
- Assert.AreEqual("UnOrderedColumn", ws.FirstCell().CellRight().CellRight().CellRight().Value);
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().InsertTable(l);
+ Assert.AreEqual(4, ws.Tables.First().ColumnCount());
+ Assert.AreEqual("FirstColumn", ws.FirstCell().Value);
+ Assert.AreEqual("SecondColumn", ws.FirstCell().CellRight().Value);
+ Assert.AreEqual("SomeFieldNotProperty", ws.FirstCell().CellRight().CellRight().Value);
+ Assert.AreEqual("UnOrderedColumn", ws.FirstCell().CellRight().CellRight().CellRight().Value);
+ }
}
[Test]
public void TableInsertAboveFromData()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Value");
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Value");
- IXLTable table = ws.Range("A1:A2").CreateTable();
- table.SetShowTotalsRow()
- .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
+ IXLTable table = ws.Range("A1:A2").CreateTable();
+ table.SetShowTotalsRow()
+ .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
- IXLTableRow row = table.DataRange.FirstRow();
- row.Field("Value").Value = 3;
- row = table.DataRange.InsertRowsAbove(1).First();
- row.Field("Value").Value = 2;
- row = table.DataRange.InsertRowsAbove(1).First();
- row.Field("Value").Value = 1;
+ IXLTableRow row = table.DataRange.FirstRow();
+ row.Field("Value").Value = 3;
+ row = table.DataRange.InsertRowsAbove(1).First();
+ row.Field("Value").Value = 2;
+ row = table.DataRange.InsertRowsAbove(1).First();
+ row.Field("Value").Value = 1;
- Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
- Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
- Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
+ Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
+ Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ }
}
[Test]
public void TableInsertAboveFromRows()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Value");
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Value");
- IXLTable table = ws.Range("A1:A2").CreateTable();
- table.SetShowTotalsRow()
- .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
+ IXLTable table = ws.Range("A1:A2").CreateTable();
+ table.SetShowTotalsRow()
+ .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
- IXLTableRow row = table.DataRange.FirstRow();
- row.Field("Value").Value = 3;
- row = row.InsertRowsAbove(1).First();
- row.Field("Value").Value = 2;
- row = row.InsertRowsAbove(1).First();
- row.Field("Value").Value = 1;
+ IXLTableRow row = table.DataRange.FirstRow();
+ row.Field("Value").Value = 3;
+ row = row.InsertRowsAbove(1).First();
+ row.Field("Value").Value = 2;
+ row = row.InsertRowsAbove(1).First();
+ row.Field("Value").Value = 1;
- Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
- Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
- Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
+ Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
+ Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ }
}
[Test]
public void TableInsertBelowFromData()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Value");
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Value");
- IXLTable table = ws.Range("A1:A2").CreateTable();
- table.SetShowTotalsRow()
- .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
+ IXLTable table = ws.Range("A1:A2").CreateTable();
+ table.SetShowTotalsRow()
+ .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
- IXLTableRow row = table.DataRange.FirstRow();
- row.Field("Value").Value = 1;
- row = table.DataRange.InsertRowsBelow(1).First();
- row.Field("Value").Value = 2;
- row = table.DataRange.InsertRowsBelow(1).First();
- row.Field("Value").Value = 3;
+ IXLTableRow row = table.DataRange.FirstRow();
+ row.Field("Value").Value = 1;
+ row = table.DataRange.InsertRowsBelow(1).First();
+ row.Field("Value").Value = 2;
+ row = table.DataRange.InsertRowsBelow(1).First();
+ row.Field("Value").Value = 3;
- Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
- Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
- Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
+ Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
+ Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ }
}
[Test]
public void TableInsertBelowFromRows()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Value");
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Value");
- IXLTable table = ws.Range("A1:A2").CreateTable();
- table.SetShowTotalsRow()
- .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
+ IXLTable table = ws.Range("A1:A2").CreateTable();
+ table.SetShowTotalsRow()
+ .Field(0).TotalsRowFunction = XLTotalsRowFunction.Sum;
- IXLTableRow row = table.DataRange.FirstRow();
- row.Field("Value").Value = 1;
- row = row.InsertRowsBelow(1).First();
- row.Field("Value").Value = 2;
- row = row.InsertRowsBelow(1).First();
- row.Field("Value").Value = 3;
+ IXLTableRow row = table.DataRange.FirstRow();
+ row.Field("Value").Value = 1;
+ row = row.InsertRowsBelow(1).First();
+ row.Field("Value").Value = 2;
+ row = row.InsertRowsBelow(1).First();
+ row.Field("Value").Value = 3;
- Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
- Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
- Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ Assert.AreEqual(1, ws.Cell(2, 1).GetDouble());
+ Assert.AreEqual(2, ws.Cell(3, 1).GetDouble());
+ Assert.AreEqual(3, ws.Cell(4, 1).GetDouble());
+ }
}
[Test]
public void TableShowHeader()
{
- var wb = new XLWorkbook();
- IXLWorksheet ws = wb.AddWorksheet("Sheet1");
- ws.FirstCell().SetValue("Categories")
- .CellBelow().SetValue("A")
- .CellBelow().SetValue("B")
- .CellBelow().SetValue("C");
+ using (var wb = new XLWorkbook())
+ {
+ IXLWorksheet ws = wb.AddWorksheet("Sheet1");
+ ws.FirstCell().SetValue("Categories")
+ .CellBelow().SetValue("A")
+ .CellBelow().SetValue("B")
+ .CellBelow().SetValue("C");
- IXLTable table = ws.RangeUsed().CreateTable();
+ IXLTable table = ws.RangeUsed().CreateTable();
- Assert.AreEqual("Categories", table.Fields.First().Name);
+ Assert.AreEqual("Categories", table.Fields.First().Name);
- table.SetShowHeaderRow(false);
+ table.SetShowHeaderRow(false);
- Assert.AreEqual("Categories", table.Fields.First().Name);
+ Assert.AreEqual("Categories", table.Fields.First().Name);
- Assert.IsTrue(ws.Cell(1, 1).IsEmpty(true));
- Assert.AreEqual(null, table.HeadersRow());
- Assert.AreEqual("A", table.DataRange.FirstRow().Field("Categories").GetString());
- Assert.AreEqual("C", table.DataRange.LastRow().Field("Categories").GetString());
- Assert.AreEqual("A", table.DataRange.FirstCell().GetString());
- Assert.AreEqual("C", table.DataRange.LastCell().GetString());
+ Assert.IsTrue(ws.Cell(1, 1).IsEmpty(true));
+ Assert.AreEqual(null, table.HeadersRow());
+ Assert.AreEqual("A", table.DataRange.FirstRow().Field("Categories").GetString());
+ Assert.AreEqual("C", table.DataRange.LastRow().Field("Categories").GetString());
+ Assert.AreEqual("A", table.DataRange.FirstCell().GetString());
+ Assert.AreEqual("C", table.DataRange.LastCell().GetString());
- table.SetShowHeaderRow();
- IXLRangeRow headerRow = table.HeadersRow();
- Assert.AreNotEqual(null, headerRow);
- Assert.AreEqual("Categories", headerRow.Cell(1).GetString());
+ table.SetShowHeaderRow();
+ IXLRangeRow headerRow = table.HeadersRow();
+ Assert.AreNotEqual(null, headerRow);
+ Assert.AreEqual("Categories", headerRow.Cell(1).GetString());
- table.SetShowHeaderRow(false);
+ table.SetShowHeaderRow(false);
- ws.FirstCell().SetValue("x");
+ ws.FirstCell().SetValue("x");
- table.SetShowHeaderRow();
+ table.SetShowHeaderRow();
- Assert.AreEqual("x", ws.FirstCell().GetString());
- Assert.AreEqual("Categories", ws.Cell("A2").GetString());
- Assert.AreNotEqual(null, headerRow);
- Assert.AreEqual("A", table.DataRange.FirstRow().Field("Categories").GetString());
- Assert.AreEqual("C", table.DataRange.LastRow().Field("Categories").GetString());
- Assert.AreEqual("A", table.DataRange.FirstCell().GetString());
- Assert.AreEqual("C", table.DataRange.LastCell().GetString());
+ Assert.AreEqual("x", ws.FirstCell().GetString());
+ Assert.AreEqual("Categories", ws.Cell("A2").GetString());
+ Assert.AreNotEqual(null, headerRow);
+ Assert.AreEqual("A", table.DataRange.FirstRow().Field("Categories").GetString());
+ Assert.AreEqual("C", table.DataRange.LastRow().Field("Categories").GetString());
+ Assert.AreEqual("A", table.DataRange.FirstCell().GetString());
+ Assert.AreEqual("C", table.DataRange.LastCell().GetString());
+ }
}
[Test]
public void ChangeFieldName()
{
- XLWorkbook wb = new XLWorkbook();
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.AddWorksheet("Sheet");
+ ws.Cell("A1").SetValue("FName")
+ .CellBelow().SetValue("John");
- var ws = wb.AddWorksheet("Sheet");
- ws.Cell("A1").SetValue("FName")
- .CellBelow().SetValue("John");
+ ws.Cell("B1").SetValue("LName")
+ .CellBelow().SetValue("Doe");
- ws.Cell("B1").SetValue("LName")
- .CellBelow().SetValue("Doe");
+ var tbl = ws.RangeUsed().CreateTable();
+ var nameBefore = tbl.Field(tbl.Fields.Last().Index).Name;
+ tbl.Field(tbl.Fields.Last().Index).Name = "LastName";
+ var nameAfter = tbl.Field(tbl.Fields.Last().Index).Name;
- var tbl = ws.RangeUsed().CreateTable();
- var nameBefore = tbl.Field(tbl.Fields.Last().Index).Name;
- tbl.Field(tbl.Fields.Last().Index).Name = "LastName";
- var nameAfter = tbl.Field(tbl.Fields.Last().Index).Name;
+ var cellValue = ws.Cell("B1").GetString();
- var cellValue = ws.Cell("B1").GetString();
+ Assert.AreEqual("LName", nameBefore);
+ Assert.AreEqual("LastName", nameAfter);
+ Assert.AreEqual("LastName", cellValue);
- Assert.AreEqual("LName", nameBefore);
- Assert.AreEqual("LastName", nameAfter);
- Assert.AreEqual("LastName", cellValue);
+ tbl.ShowHeaderRow = false;
+ tbl.Field(tbl.Fields.Last().Index).Name = "LastNameChanged";
+ nameAfter = tbl.Field(tbl.Fields.Last().Index).Name;
+ Assert.AreEqual("LastNameChanged", nameAfter);
- tbl.ShowHeaderRow = false;
- tbl.Field(tbl.Fields.Last().Index).Name = "LastNameChanged";
- nameAfter = tbl.Field(tbl.Fields.Last().Index).Name;
- Assert.AreEqual("LastNameChanged", nameAfter);
+ tbl.SetShowHeaderRow(true);
+ nameAfter = tbl.Cell("B1").Value.ToString();
+ Assert.AreEqual("LastNameChanged", nameAfter);
- tbl.SetShowHeaderRow(true);
- nameAfter = tbl.Cell("B1").Value.ToString();
- Assert.AreEqual("LastNameChanged", nameAfter);
+ var field = tbl.Field("LastNameChanged");
+ Assert.AreEqual("LastNameChanged", field.Name);
+
+ tbl.Cell(1, 1).Value = "FirstName";
+ Assert.AreEqual("FirstName", tbl.Field(0).Name);
+ }
+ }
+
+ [Test]
+ public void CanDeleteTableColumn()
+ {
+ var l = new List()
+ {
+ new TestObjectWithAttributes() { Column1 = "a", Column2 = "b", MyField = 4, UnOrderedColumn = 999 },
+ new TestObjectWithAttributes() { Column1 = "c", Column2 = "d", MyField = 5, UnOrderedColumn = 777 }
+ };
+
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.AddWorksheet("Sheet1");
+ var table = ws.FirstCell().InsertTable(l);
+
+ table.Column("C").Delete();
+
+ Assert.AreEqual(3, table.Fields.Count());
+
+ Assert.AreEqual("FirstColumn", table.Fields.First().Name);
+ Assert.AreEqual(0, table.Fields.First().Index);
+
+ Assert.AreEqual("UnOrderedColumn", table.Fields.Last().Name);
+ Assert.AreEqual(2, table.Fields.Last().Index);
+ }
+ }
+
+ [Test]
+ public void CanDeleteTableField()
+ {
+ var l = new List()
+ {
+ new TestObjectWithAttributes() { Column1 = "a", Column2 = "b", MyField = 4, UnOrderedColumn = 999 },
+ new TestObjectWithAttributes() { Column1 = "c", Column2 = "d", MyField = 5, UnOrderedColumn = 777 }
+ };
+
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.AddWorksheet("Sheet1");
+ var table = ws.FirstCell().InsertTable(l);
+
+ table.Field("SomeFieldNotProperty").Delete();
+
+ Assert.AreEqual(3, table.Fields.Count());
+
+ Assert.AreEqual("FirstColumn", table.Fields.First().Name);
+ Assert.AreEqual(0, table.Fields.First().Index);
+
+ Assert.AreEqual("UnOrderedColumn", table.Fields.Last().Name);
+ Assert.AreEqual(2, table.Fields.Last().Index);
+ }
}
}
}
diff --git a/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs b/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs
index f679187..0918e5a 100644
--- a/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs
+++ b/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs
@@ -140,5 +140,25 @@
Assert.AreEqual(6, value);
}
}
+
+ [Test]
+ public void CanRenameWorksheet()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws1 = wb.AddWorksheet("Sheet1");
+ var ws2 = wb.AddWorksheet("Sheet2");
+
+ ws1.Name = "New sheet name";
+ Assert.AreEqual("New sheet name", ws1.Name);
+
+ ws2.Name = "sheet2";
+ Assert.AreEqual("sheet2", ws2.Name);
+
+ Assert.Throws(() => ws1.Name = "SHEET2");
+
+
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML_Tests/OleDb/OleDbTests.cs b/ClosedXML_Tests/OleDb/OleDbTests.cs
index e502614..2aa897c 100644
--- a/ClosedXML_Tests/OleDb/OleDbTests.cs
+++ b/ClosedXML_Tests/OleDb/OleDbTests.cs
@@ -1,4 +1,5 @@
using ClosedXML.Excel;
+using ClosedXML_Tests.Utils;
using NUnit.Framework;
using System;
using System.Collections.Generic;
@@ -16,7 +17,7 @@
[Test]
public void TestOleDbValues()
{
- using (var tf = new TestFile(CreateTestFile()))
+ using (var tf = new TemporaryFile(CreateTestFile()))
{
Console.Write("Using temporary file\t{0}", tf.Path);
var connectionString = string.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1';", tf.Path);
@@ -115,32 +116,5 @@
return path;
}
}
-
- internal class TestFile : IDisposable
- {
- internal TestFile(string path)
- : this(path, false)
- { }
-
- internal TestFile(string path, bool preserve)
- {
- this.Path = path;
- this.Preserve = preserve;
- }
-
- public string Path { get; private set; }
- public bool Preserve { get; private set; }
-
- public void Dispose()
- {
- if (!Preserve)
- File.Delete(Path);
- }
-
- public override string ToString()
- {
- return this.Path;
- }
- }
}
}
diff --git a/ClosedXML_Tests/Resource/Examples/Misc/CopyingWorksheets.xlsx b/ClosedXML_Tests/Resource/Examples/Misc/CopyingWorksheets.xlsx
index 6d14038..28c4b9b 100644
--- a/ClosedXML_Tests/Resource/Examples/Misc/CopyingWorksheets.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/Misc/CopyingWorksheets.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Examples/Misc/Formulas.xlsx b/ClosedXML_Tests/Resource/Examples/Misc/Formulas.xlsx
index dea7693..c49d20a 100644
--- a/ClosedXML_Tests/Resource/Examples/Misc/Formulas.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/Misc/Formulas.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Examples/Misc/FormulasWithEvaluation.xlsx b/ClosedXML_Tests/Resource/Examples/Misc/FormulasWithEvaluation.xlsx
index 7a93ddb..f1dde09 100644
--- a/ClosedXML_Tests/Resource/Examples/Misc/FormulasWithEvaluation.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/Misc/FormulasWithEvaluation.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx b/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx
index 9e9d20f..c8ae77a 100644
--- a/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx b/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx
index 6e3156d..7c0b68e 100644
--- a/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Examples/Ranges/NamedRanges.xlsx b/ClosedXML_Tests/Resource/Examples/Ranges/NamedRanges.xlsx
index 8d4e6a2..2b450d6 100644
--- a/ClosedXML_Tests/Resource/Examples/Ranges/NamedRanges.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/Ranges/NamedRanges.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Misc/DuplicateImageNames.xlsx b/ClosedXML_Tests/Resource/Misc/DuplicateImageNames.xlsx
new file mode 100644
index 0000000..29df50b
--- /dev/null
+++ b/ClosedXML_Tests/Resource/Misc/DuplicateImageNames.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Misc/TableHeadersWithLineBreaks.xlsx b/ClosedXML_Tests/Resource/Misc/TableHeadersWithLineBreaks.xlsx
new file mode 100644
index 0000000..8e7dbdc
--- /dev/null
+++ b/ClosedXML_Tests/Resource/Misc/TableHeadersWithLineBreaks.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Misc/TableWithNameNull.xlsx b/ClosedXML_Tests/Resource/Misc/TableWithNameNull.xlsx
new file mode 100644
index 0000000..0a5a8de
--- /dev/null
+++ b/ClosedXML_Tests/Resource/Misc/TableWithNameNull.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Utils/TemporaryFile.cs b/ClosedXML_Tests/Utils/TemporaryFile.cs
new file mode 100644
index 0000000..6d95b1f
--- /dev/null
+++ b/ClosedXML_Tests/Utils/TemporaryFile.cs
@@ -0,0 +1,37 @@
+using System;
+using System.IO;
+
+namespace ClosedXML_Tests.Utils
+{
+ internal class TemporaryFile : IDisposable
+ {
+ internal TemporaryFile()
+ : this(System.IO.Path.ChangeExtension(System.IO.Path.GetTempFileName(), "xlsx"))
+ { }
+
+ internal TemporaryFile(string path)
+ : this(path, false)
+ { }
+
+ internal TemporaryFile(String path, bool preserve)
+ {
+ this.Path = path;
+ this.Preserve = preserve;
+ }
+
+
+ public string Path { get; private set; }
+ public bool Preserve { get; private set; }
+
+ public void Dispose()
+ {
+ if (!Preserve)
+ File.Delete(Path);
+ }
+
+ public override string ToString()
+ {
+ return this.Path;
+ }
+ }
+}
diff --git a/ClosedXML_Tests/packages.config b/ClosedXML_Tests/packages.config
index c32aa84..5e0ab7c 100644
--- a/ClosedXML_Tests/packages.config
+++ b/ClosedXML_Tests/packages.config
@@ -1,5 +1,5 @@
-
-
-
-
+
+
+
+
\ No newline at end of file