diff --git a/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj b/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj
index 3e55efc..7f22e1d 100644
--- a/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj
+++ b/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj
@@ -138,6 +138,7 @@
+
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs
index 09c6e3f..e7a6c06 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs
@@ -2062,19 +2062,19 @@
if (row1String[0] == '$')
{
row1 = "$" +
- (Int32.Parse(row1String.Substring(1)) + rowsShifted).ToStringLookup();
+ (Int32.Parse(row1String.Substring(1)) + rowsShifted).ToInvariantString();
}
else
- row1 = (Int32.Parse(row1String) + rowsShifted).ToStringLookup();
+ row1 = (Int32.Parse(row1String) + rowsShifted).ToInvariantString();
string row2;
if (row2String[0] == '$')
{
row2 = "$" +
- (Int32.Parse(row2String.Substring(1)) + rowsShifted).ToStringLookup();
+ (Int32.Parse(row2String.Substring(1)) + rowsShifted).ToInvariantString();
}
else
- row2 = (Int32.Parse(row2String) + rowsShifted).ToStringLookup();
+ row2 = (Int32.Parse(row2String) + rowsShifted).ToInvariantString();
sb.Append(useSheetName
? String.Format("'{0}'!{1}:{2}", sheetName, row1, row2)
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Coordinates/XLAddress.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Coordinates/XLAddress.cs
index 8d0f040..d9b9a8e 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/Coordinates/XLAddress.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Coordinates/XLAddress.cs
@@ -207,7 +207,7 @@
{
retVal += "$";
}
- retVal += _rowNumber.ToStringLookup();
+ retVal += _rowNumber.ToInvariantString();
return retVal;
}
@@ -215,23 +215,23 @@
{
if (referenceStyle == XLReferenceStyle.A1)
{
- return ColumnLetter + _rowNumber.ToStringLookup();
+ return ColumnLetter + _rowNumber.ToInvariantString();
}
if (referenceStyle == XLReferenceStyle.R1C1)
{
- return String.Format("R{0}C{1}", _rowNumber.ToStringLookup(), ColumnNumber);
+ return String.Format("R{0}C{1}", _rowNumber.ToInvariantString(), ColumnNumber);
}
if (HasWorksheet && Worksheet.Workbook.ReferenceStyle == XLReferenceStyle.R1C1)
{
- return String.Format("R{0}C{1}", _rowNumber.ToStringLookup(), ColumnNumber);
+ return String.Format("R{0}C{1}", _rowNumber.ToInvariantString(), ColumnNumber);
}
- return ColumnLetter + _rowNumber.ToStringLookup();
+ return ColumnLetter + _rowNumber.ToInvariantString();
}
#endregion
#region Methods
public string GetTrimmedAddress()
{
- return _trimmedAddress ?? (_trimmedAddress = ColumnLetter + _rowNumber.ToStringLookup());
+ return _trimmedAddress ?? (_trimmedAddress = ColumnLetter + _rowNumber.ToInvariantString());
}
@@ -362,13 +362,13 @@
{
String address;
if (referenceStyle == XLReferenceStyle.A1)
- address = String.Format("${0}${1}", ColumnLetter, _rowNumber.ToStringLookup());
+ address = String.Format("${0}${1}", ColumnLetter, _rowNumber.ToInvariantString());
else if (referenceStyle == XLReferenceStyle.R1C1)
- address = String.Format("R{0}C{1}", _rowNumber.ToStringLookup(), ColumnNumber);
+ address = String.Format("R{0}C{1}", _rowNumber.ToInvariantString(), ColumnNumber);
else if (HasWorksheet && Worksheet.Workbook.ReferenceStyle == XLReferenceStyle.R1C1)
- address = String.Format("R{0}C{1}", _rowNumber.ToStringLookup(), ColumnNumber);
+ address = String.Format("R{0}C{1}", _rowNumber.ToInvariantString(), ColumnNumber);
else
- address = String.Format("${0}${1}", ColumnLetter, _rowNumber.ToStringLookup());
+ address = String.Format("${0}${1}", ColumnLetter, _rowNumber.ToInvariantString());
if (includeSheet)
return String.Format("'{0}'!{1}",
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeAddress.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeAddress.cs
index 1a02e91..d5b0e94 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeAddress.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeAddress.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using System.Globalization;
using System.Linq;
namespace ClosedXML.Excel
@@ -64,7 +65,7 @@
else
{
FirstAddress = XLAddress.Create(worksheet, firstPart + "1");
- LastAddress = XLAddress.Create(worksheet, secondPart + XLHelper.MaxRowNumber.ToStringLookup());
+ LastAddress = XLAddress.Create(worksheet, secondPart + XLHelper.MaxRowNumber.ToString(CultureInfo.InvariantCulture));
}
}
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Style/Colors/XLColor_Static.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Style/Colors/XLColor_Static.cs
index dfaaaa7..d66e191 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/Style/Colors/XLColor_Static.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Style/Colors/XLColor_Static.cs
@@ -7,14 +7,19 @@
{
public partial class XLColor
{
- private static Dictionary byColor = new Dictionary();
+ private static readonly Dictionary ByColor = new Dictionary();
+ private static readonly Object ByColorLock = new Object();
+
public static XLColor FromColor(Color color)
{
XLColor ret;
- if (!byColor.TryGetValue(color, out ret))
+ lock (ByColorLock)
{
- ret = new XLColor(color);
- byColor.Add(color, ret);
+ if (!ByColor.TryGetValue(color, out ret))
+ {
+ ret = new XLColor(color);
+ ByColor.Add(color, ret);
+ }
}
return ret;
}
@@ -44,50 +49,65 @@
return FromColor(ColorTranslator.FromHtml(htmlColor));
}
- private static Dictionary byIndex = new Dictionary();
+ private static readonly Dictionary ByIndex = new Dictionary();
+ private static readonly Object ByIndexLock = new Object();
+
public static XLColor FromIndex(Int32 index)
{
XLColor ret;
- if (!byIndex.TryGetValue(index, out ret))
+ lock (ByIndexLock)
{
- ret = new XLColor(index);
- byIndex.Add(index, ret);
+ if (!ByIndex.TryGetValue(index, out ret))
+ {
+ ret = new XLColor(index);
+ ByIndex.Add(index, ret);
+ }
}
return ret;
}
- private static Dictionary byTheme = new Dictionary();
+ private static readonly Dictionary ByTheme = new Dictionary();
+ private static readonly Object ByThemeLock = new Object();
+
public static XLColor FromTheme(XLThemeColor themeColor)
{
XLColor ret;
- if (!byTheme.TryGetValue(themeColor, out ret))
+ lock (ByThemeLock)
{
- ret = new XLColor(themeColor);
- byTheme.Add(themeColor, ret);
+ if (!ByTheme.TryGetValue(themeColor, out ret))
+ {
+ ret = new XLColor(themeColor);
+ ByTheme.Add(themeColor, ret);
+ }
}
return ret;
}
- private static Dictionary> byThemeTint = new Dictionary>();
+ private static readonly Dictionary> ByThemeTint = new Dictionary>();
+ private static readonly Object ByThemeTintLock = new Object();
+
public static XLColor FromTheme(XLThemeColor themeColor, Double themeTint)
{
XLColor ret;
- Dictionary themeTints;
- if (byThemeTint.TryGetValue(themeColor, out themeTints))
+ lock (ByThemeTintLock)
{
- if (!themeTints.TryGetValue(themeTint, out ret))
+ Dictionary themeTints;
+ if (ByThemeTint.TryGetValue(themeColor, out themeTints))
{
+ if (!themeTints.TryGetValue(themeTint, out ret))
+ {
+ ret = new XLColor(themeColor, themeTint);
+ themeTints.Add(themeTint, ret);
+ }
+ }
+ else
+ {
+ themeTints = new Dictionary();
ret = new XLColor(themeColor, themeTint);
themeTints.Add(themeTint, ret);
- }
- }
- else
- {
- themeTints = new Dictionary();
- ret = new XLColor(themeColor, themeTint);
- themeTints.Add(themeTint, ret);
- byThemeTint.Add(themeColor, themeTints);
+ ByThemeTint.Add(themeColor, themeTints);
+ }
}
return ret;
}
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs
index 112221e..a090dfc 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs
@@ -396,7 +396,7 @@
foreach (IXLCell c in range.Row(1).Cells())
{
if (XLHelper.IsNullOrWhiteSpace(((XLCell)c).InnerText))
- c.Value = GetUniqueName("Column" + co.ToStringLookup());
+ c.Value = GetUniqueName("Column" + co.ToInvariantString());
_uniqueNames.Add(c.GetString());
co++;
}
@@ -410,11 +410,11 @@
if (_uniqueNames.Contains(name))
{
Int32 i = 1;
- name = originalName + i.ToStringLookup();
+ name = originalName + i.ToInvariantString();
while (_uniqueNames.Contains(name))
{
i++;
- name = originalName + i.ToStringLookup();
+ name = originalName + i.ToInvariantString();
}
}
@@ -446,7 +446,7 @@
foreach (IXLCell c in headersRow.Cells())
{
if (XLHelper.IsNullOrWhiteSpace(((XLCell)c).InnerText))
- c.Value = GetUniqueName("Column" + co.ToStringLookup());
+ c.Value = GetUniqueName("Column" + co.ToInvariantString());
_uniqueNames.Add(c.GetString());
co++;
}
diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs
index 21072b9..70ef083 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs
@@ -1580,11 +1580,11 @@
if (context.TableNames.Contains(name))
{
var i = 1;
- name = tableName + i.ToStringLookup();
+ name = tableName + i.ToInvariantString();
while (context.TableNames.Contains(name))
{
i++;
- name = tableName + i.ToStringLookup();
+ name = tableName + i.ToInvariantString();
}
}
@@ -3282,7 +3282,7 @@
maxColumn = xlWorksheet.Internals.CellsCollection.MaxColumnUsed;
var maxRow = xlWorksheet.Internals.CellsCollection.MaxRowUsed;
sheetDimensionReference = "A1:" + XLHelper.GetColumnLetterFromNumber(maxColumn) +
- maxRow.ToStringLookup();
+ maxRow.ToInvariantString();
}
if (xlWorksheet.Internals.ColumnsCollection.Count > 0)
@@ -3637,7 +3637,7 @@
}
if (maxColumn > 0)
- row.Spans = new ListValue {InnerText = "1:" + maxColumn.ToStringLookup()};
+ row.Spans = new ListValue {InnerText = "1:" + maxColumn.ToInvariantString()};
row.Height = null;
row.CustomHeight = null;
@@ -3679,7 +3679,7 @@
{
foreach (var delCo in kpDel.Value.ToList())
{
- var key = XLHelper.GetColumnLetterFromNumber(delCo) + kpDel.Key.ToStringLookup();
+ var key = XLHelper.GetColumnLetterFromNumber(delCo) + kpDel.Key.ToInvariantString();
if (!cellsByReference.ContainsKey(key)) continue;
row.RemoveChild(cellsByReference[key]);
kpDel.Value.Remove(delCo);
diff --git a/ClosedXML/ClosedXML/ClosedXML/Extensions.cs b/ClosedXML/ClosedXML/ClosedXML/Extensions.cs
index cac055e..dbc2e57 100644
--- a/ClosedXML/ClosedXML/ClosedXML/Extensions.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/Extensions.cs
@@ -9,6 +9,7 @@
using System.Xml.Linq;
using System.IO;
using System.Xml;
+using ClosedXML.Utils;
[assembly: CLSCompliantAttribute(true)]
namespace ClosedXML.Excel
@@ -162,18 +163,12 @@
public static class IntegerExtensions
{
- private static readonly NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat;
- private static readonly Dictionary intToString = new Dictionary();
- public static String ToStringLookup(this Int32 value)
+
+ public static String ToInvariantString(this Int32 value)
{
- if (!intToString.ContainsKey(value))
- {
- intToString.Add(value, value.ToString(nfi));
- }
- return intToString[value];
+ return value.ToString(CultureInfo.InvariantCulture);
}
-
}
public static class FontBaseExtensions
@@ -190,7 +185,6 @@
return font;
}
- private static Graphics graphics = Graphics.FromImage(new Bitmap(1, 1));
public static Double GetWidth(this IXLFontBase fontBase, String text, Dictionary fontCache)
{
if (XLHelper.IsNullOrWhiteSpace(text))
@@ -198,7 +192,7 @@
var font = GetCachedFont(fontBase, fontCache);
- var textSize = graphics.MeasureString(text, font, Int32.MaxValue, StringFormat.GenericTypographic);
+ var textSize = GraphicsUtils.MeasureString(text, font);
double width = (((textSize.Width / (double)7) * 256) - (128 / 7)) / 256;
width = (double)decimal.Round((decimal)width + 0.2M, 2);
@@ -219,7 +213,7 @@
public static Double GetHeight(this IXLFontBase fontBase, Dictionary fontCache)
{
var font = GetCachedFont(fontBase, fontCache);
- var textSize = graphics.MeasureString("X", font, Int32.MaxValue, StringFormat.GenericTypographic);
+ var textSize = GraphicsUtils.MeasureString("X", font);
return (double)textSize.Height * 0.85;
}
diff --git a/ClosedXML/ClosedXML/ClosedXML/Utils/GraphicsUtils.cs b/ClosedXML/ClosedXML/ClosedXML/Utils/GraphicsUtils.cs
new file mode 100644
index 0000000..954c22c
--- /dev/null
+++ b/ClosedXML/ClosedXML/ClosedXML/Utils/GraphicsUtils.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Drawing;
+
+namespace ClosedXML.Utils
+{
+ internal static class GraphicsUtils
+ {
+ public static SizeF MeasureString(string s, Font font)
+ {
+ SizeF result;
+ using (var image = new Bitmap(1, 1))
+ {
+ using (var g = Graphics.FromImage(image))
+ {
+ result = g.MeasureString(s, font, Int32.MaxValue, StringFormat.GenericTypographic);
+ }
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/ClosedXML/ClosedXML/ClosedXML/XLHelper.cs b/ClosedXML/ClosedXML/ClosedXML/XLHelper.cs
index 6bb853c..8f5f073 100644
--- a/ClosedXML/ClosedXML/ClosedXML/XLHelper.cs
+++ b/ClosedXML/ClosedXML/ClosedXML/XLHelper.cs
@@ -54,85 +54,52 @@
RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture
);
- private static Dictionary columnNumbers = new Dictionary();
///
- /// Gets the column number of a given column letter.
+ /// Gets the column number of a given column letter.
///
/// The column letter to translate into a column number.
public static int GetColumnNumberFromLetter(string columnLetter)
{
+ if (string.IsNullOrEmpty(columnLetter)) throw new ArgumentNullException("columnLetter");
+
int retVal;
columnLetter = columnLetter.ToUpper();
- if (columnNumbers.TryGetValue(columnLetter, out retVal))
- return retVal;
+ //Extra check because we allow users to pass row col positions in as strings
if (columnLetter[0] <= '9')
{
retVal = Int32.Parse(columnLetter, NumberFormatForParse);
- columnNumbers.Add(columnLetter, retVal);
return retVal;
}
-
- var length = columnLetter.Length;
- if (length == 1)
+
+ int sum = 0;
+
+ for (int i = 0; i < columnLetter.Length; i++)
{
- retVal = Convert.ToByte(columnLetter[0]) - 64;
- columnNumbers.Add(columnLetter, retVal);
- return retVal;
+ sum *= 26;
+ sum += (columnLetter[i] - 'A' + 1);
}
- if (length == 2)
- {
- retVal =
- ((Convert.ToByte(columnLetter[0]) - 64)*26) +
- (Convert.ToByte(columnLetter[1]) - 64);
- columnNumbers.Add(columnLetter, retVal);
- return retVal;
- }
- if (length == 3)
- {
- retVal = ((Convert.ToByte(columnLetter[0]) - 64)*TwoT26) +
- ((Convert.ToByte(columnLetter[1]) - 64)*26) +
- (Convert.ToByte(columnLetter[2]) - 64);
- columnNumbers.Add(columnLetter, retVal);
- return retVal;
- }
- throw new ApplicationException("Column Length must be between 1 and 3.");
+
+ return sum;
}
- private static Dictionary columnLetters = new Dictionary();
///
/// Gets the column letter of a given column number.
///
- /// The column number to translate into a column letter.
+ /// The column number to translate into a column letter.
public static string GetColumnLetterFromNumber(int columnNumber)
{
- String retVal;
- if (columnLetters.TryGetValue(columnNumber, out retVal))
- return retVal;
+ var dividend = columnNumber;
+ var columnName = String.Empty;
- #region Check
-
- if (columnNumber <= 0)
- throw new ArgumentOutOfRangeException("column", "Must be more than 0");
-
- #endregion
-
- var value = new StringBuilder(6);
- int column = columnNumber;
- while (column > 0)
+ while (dividend > 0)
{
- var residue = column%26;
- column /= 26;
- if (residue == 0)
- {
- residue = 26;
- column--;
- }
- value.Insert(0, (char) (64 + residue));
+ var modulo = (dividend - 1) % 26;
+ columnName = Convert.ToChar(65 + modulo) + columnName;
+ dividend = (dividend - modulo) / 26;
}
- retVal = value.ToString();
- columnLetters.Add(columnNumber, retVal);
- return retVal;
+
+ return columnName;
}
public static bool IsValidColumn(string column)
diff --git a/ClosedXML/ClosedXML/ClosedXML_Net3.5/ClosedXML_Net3.5.csproj b/ClosedXML/ClosedXML/ClosedXML_Net3.5/ClosedXML_Net3.5.csproj
index b73f954..b41afcb 100644
--- a/ClosedXML/ClosedXML/ClosedXML_Net3.5/ClosedXML_Net3.5.csproj
+++ b/ClosedXML/ClosedXML/ClosedXML_Net3.5/ClosedXML_Net3.5.csproj
@@ -876,6 +876,9 @@
PathHelper.cs
+
+ Utils\GraphicsUtils.cs
+
XLHelper.cs