diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs index 3a0dc7f..f6f5c79 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/XLTable.cs @@ -9,8 +9,6 @@ { #region Private fields - public readonly Dictionary FieldNames = new Dictionary(); - private readonly Dictionary _fields = new Dictionary(); private string _name; internal bool _showTotalsRow; internal HashSet _uniqueNames; @@ -49,6 +47,66 @@ #endregion + private IXLRangeAddress _lastRangeAddress; + private Dictionary _fieldNames = null; + public Dictionary FieldNames + { + get + { + if (_fieldNames != null && _lastRangeAddress != null && _lastRangeAddress.Equals(RangeAddress)) return _fieldNames; + + _fieldNames = new Dictionary(); + _lastRangeAddress = RangeAddress; + + if (ShowHeaderRow) + { + var headersRow = HeadersRow(); + Int32 cellPos = 0; + foreach (var cell in headersRow.Cells()) + { + var name = cell.GetString(); + if (StringExtensions.IsNullOrWhiteSpace(name)) + { + name = "Column" + (cellPos + 1); + cell.SetValue(name); + } + if (_fieldNames.ContainsKey(name)) + throw new ArgumentException("The header row contains more than one field name '" + name + "'."); + + _fieldNames.Add(name, new XLTableField(this) {Index = cellPos++, Name = name}); + } + } + else + { + if (_fieldNames == null) _fieldNames = new Dictionary(); + + Int32 colCount = ColumnCount(); + for (Int32 i = 1; i <= colCount; i++) + { + if (!_fieldNames.Values.Any(f => f.Index == i - 1)) + { + var name = "Column" + i; + + _fieldNames.Add(name, new XLTableField(this) {Index = i - 1, Name = name}); + } + } + } + return _fieldNames; + } + } + + internal void AddFields(IEnumerable fieldNames) + { + _fieldNames = new Dictionary(); + + Int32 cellPos = 0; + foreach(var name in fieldNames) + { + _fieldNames.Add(name, new XLTableField(this) { Index = cellPos++, Name = name }); + } + } + + public String RelId { get; set; } public IXLTableRange DataRange @@ -152,7 +210,10 @@ public IXLRangeRow HeadersRow() { - return ShowHeaderRow ? FirstRow() : null; + if (!ShowHeaderRow) return null; + + var m = FieldNames; + return FirstRow(); } public IXLRangeRow TotalsRow() @@ -167,17 +228,7 @@ public IXLTableField Field(Int32 fieldIndex) { - if (!_fields.ContainsKey(fieldIndex)) - { - if (fieldIndex >= HeadersRow().CellCount()) - throw new ArgumentOutOfRangeException(); - - var newField = new XLTableField(this) - {Index = fieldIndex, Name = HeadersRow().Cell(fieldIndex + 1).GetString()}; - _fields.Add(fieldIndex, newField); - } - - return _fields[fieldIndex]; + return FieldNames.Values.First(f => f.Index == fieldIndex); } public IEnumerable Fields @@ -373,22 +424,6 @@ if (FieldNames.ContainsKey(name)) return FieldNames[name].Index; - var headersRow = HeadersRow(); - Int32 cellCount = headersRow.CellCount(); - for (Int32 cellPos = 1; cellPos <= cellCount; cellPos++) - { - if (!headersRow.Cell(cellPos).GetString().Equals(name)) continue; - - if (FieldNames.ContainsKey(name)) - { - throw new ArgumentException("The header row contains more than one field name '" + name + - "'."); - } - FieldNames.Add(name, Field(cellPos - 1)); - } - if (FieldNames.ContainsKey(name)) - return FieldNames[name].Index; - throw new ArgumentOutOfRangeException("The header row doesn't contain field name '" + name + "'."); } @@ -412,7 +447,7 @@ _uniqueNames.Add(c.GetString()); co++; } - _uniqueNames.ForEach(n=>AddField(n)); + headersRow.Clear(); RangeAddress.FirstAddress = new XLAddress(Worksheet, RangeAddress.FirstAddress.RowNumber + 1, RangeAddress.FirstAddress.ColumnNumber, @@ -482,18 +517,6 @@ return this; } - public XLTable AddField(String name) - { - var field = new XLTableField(this) {Index = _fields.Count, Name = name}; - if (!_fields.ContainsKey(_fields.Count)) - _fields.Add(_fields.Count, field); - - if (!FieldNames.ContainsKey(name)) - FieldNames.Add(name, field); - - return this; - } - public void ExpandTableRows(Int32 rows) { RangeAddress.LastAddress = new XLAddress(Worksheet, RangeAddress.LastAddress.RowNumber + rows, diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs index 0a1b36e..cc52e57 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs @@ -232,8 +232,8 @@ if (dTable.HeaderRowCount != null && dTable.HeaderRowCount == 0) { xlTable._showHeaderRow = false; - foreach (var tableColumn in dTable.TableColumns.Cast()) - xlTable.AddField(tableColumn.Name); + //foreach (var tableColumn in dTable.TableColumns.Cast()) + xlTable.AddFields(dTable.TableColumns.Cast().Select(t=>t.Name.Value)); } else { diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs index 58dfcaa..a17545f 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs @@ -657,6 +657,10 @@ private void GenerateSharedStringTablePartContent(SharedStringTablePart sharedStringTablePart, SaveContext context) { + // Call all table headers to make sure their names are filled + Int32 x = 0; + Worksheets.ForEach(w => w.Tables.ForEach(t => x = (t as XLTable).FieldNames.Count)); + sharedStringTablePart.SharedStringTable = new SharedStringTable {Count = 0, UniqueCount = 0}; Int32 stringId = 0; @@ -1585,14 +1589,9 @@ table.TotalsRowShown = false; var tableColumns1 = new TableColumns {Count = (UInt32)xlTable.ColumnCount()}; - IEnumerable names; - if (xlTable.ShowHeaderRow) - names = xlTable.HeadersRow().Cells().Select(c => c.GetString()); - else - names = xlTable.FieldNames.Keys; UInt32 columnId = 0; - foreach (var fieldName in names) + foreach (var fieldName in xlTable.FieldNames.Keys) { columnId++; var xlField = xlTable.Field(fieldName); diff --git a/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/Tables/TablesTests.cs b/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/Tables/TablesTests.cs index e164b98..f7e2df0 100644 --- a/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/Tables/TablesTests.cs +++ b/ClosedXML/ClosedXML/ClosedXML_Tests/Excel/Tables/TablesTests.cs @@ -11,6 +11,20 @@ [TestClass] public class TablesTests { + [TestMethod] + public void Inserting_Column_Sets_Header() + { + var wb = new XLWorkbook(); + var ws = wb.AddWorksheet("Sheet1"); + ws.FirstCell().SetValue("Categories") + .CellBelow().SetValue("A") + .CellBelow().SetValue("B") + .CellBelow().SetValue("C"); + + var table = ws.RangeUsed().CreateTable(); + table.InsertColumnsAfter(1); + Assert.AreEqual("Column2", table.HeadersRow().LastCell().GetString()); + } [TestMethod] public void TableShowHeader()