Skip to content

Commit fa015b1

Browse files
swmalswmal
andauthored
Feature/ExcelTable.DataRows (#1849)
* #1821 - started work on a new DataRows api on ExcelTables * Added GetFormula, Insert, Delete methods * Fixed an xml comment * #1821 - fixed some xml comments --------- Co-authored-by: swmal <{ID}+username}@users.noreply.github.com>
1 parent 27ecfcf commit fa015b1

File tree

7 files changed

+776
-0
lines changed

7 files changed

+776
-0
lines changed

src/EPPlus/Table/ExcelTable.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,25 @@ public ExcelTableColumnCollection Columns
649649
return _cols;
650650
}
651651
}
652+
653+
internal ExcelTableRowCollection _rows = null;
654+
/// <summary>
655+
/// Collection of the tables's data rows (header- and total row not included). This property can be used for easier access to the tables data.
656+
/// <seealso cref="ExcelTableRowCollection"/>
657+
/// <seealso cref="ExcelTableRow"/>
658+
/// </summary>
659+
public ExcelTableRowCollection DataRows
660+
{
661+
get
662+
{
663+
if(_rows == null)
664+
{
665+
_rows = new ExcelTableRowCollection(this);
666+
}
667+
return _rows;
668+
}
669+
}
670+
652671
TableStyles _tableStyle = TableStyles.Medium6;
653672
/// <summary>
654673
/// The table style. If this property is custom, the style from the StyleName propery is used.
@@ -1240,6 +1259,7 @@ public ExcelRangeBase DeleteRow(int position, int rows = 1)
12401259
var address = ExcelCellBase.GetAddress(_address._fromRow + position, _address._fromCol, _address._fromRow + position + rows - 1, _address._toCol);
12411260
var range = new ExcelRangeBase(WorkSheet, address);
12421261
range.Delete(eShiftTypeDelete.Up);
1262+
12431263
return range;
12441264
}
12451265
/// <summary>

src/EPPlus/Table/ExcelTableRow.cs

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
2+
using System;
3+
using System.Collections;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
8+
namespace OfficeOpenXml.Table
9+
{
10+
/// <summary>
11+
/// Represents a row in an <see cref="ExcelTable"/>
12+
/// </summary>
13+
public class ExcelTableRow
14+
{
15+
/// <summary>
16+
/// Constructor
17+
/// </summary>
18+
/// <param name="table">The <see cref="ExcelTable"/> that the row belongs to</param>
19+
/// <param name="rowIx">0 based index of the table row</param>
20+
internal ExcelTableRow(ExcelTable table, int rowIx)
21+
{
22+
_table = table;
23+
_rowIx = rowIx;
24+
_table.DataRows.RowsDeleted += DataRows_RowsDeleted;
25+
SetRowRange();
26+
}
27+
28+
private void SetRowRange()
29+
{
30+
var startCol = _table.DataRange._fromCol;
31+
var endCol = _table.DataRange._toCol;
32+
var startRow = _table.DataRange._fromRow;
33+
_rowRange = _table.WorkSheet.Cells[startRow + _rowIx, startCol, startRow + _rowIx, endCol];
34+
}
35+
36+
private void DataRows_RowsDeleted(object sender, RowsDeletedEventArgs e)
37+
{
38+
if(e.Position <= _rowIx && _rowIx <= e.Position + e.NumberOfDeletedRows - 1)
39+
{
40+
_isDeleted = true;
41+
_table.DataRows.RowsDeleted -= DataRows_RowsDeleted;
42+
}
43+
else if(_rowIx > e.Position + e.NumberOfDeletedRows - 1)
44+
{
45+
_rowIx -= e.NumberOfDeletedRows;
46+
SetRowRange();
47+
}
48+
}
49+
50+
private readonly ExcelTable _table;
51+
private int _rowIx;
52+
private ExcelRangeBase _rowRange;
53+
private bool _isDeleted;
54+
55+
private void CheckDeleted()
56+
{
57+
if(_isDeleted)
58+
{
59+
throw new InvalidOperationException("Cannot call methods/properties on deleted table row");
60+
}
61+
}
62+
63+
/// <summary>
64+
/// Number of columns
65+
/// </summary>
66+
public int ColumnCount => _table.Columns.Count;
67+
68+
/// <summary>
69+
/// Returns true if the entire row is hidden
70+
/// </summary>
71+
public bool IsHidden
72+
{
73+
get
74+
{
75+
return _table.WorkSheet.Row(_rowRange.Start.Row).Hidden;
76+
}
77+
}
78+
79+
/// <summary>
80+
/// Indicates if this row has been deleted.
81+
/// </summary>
82+
public bool IsDeleted => _isDeleted;
83+
84+
internal int RowIx => _rowIx;
85+
86+
87+
/// <summary>
88+
/// Returns true if every cell in the row has null values
89+
/// </summary>
90+
public bool IsEmpty
91+
{
92+
get
93+
{
94+
return !_rowRange.Any(x => x.Value != null);
95+
}
96+
}
97+
98+
/// <summary>
99+
/// An <see cref="ExcelRangeBase"/> representing the row from first to last cell
100+
/// </summary>
101+
public ExcelRangeBase RowRange
102+
{
103+
get { return _rowRange; }
104+
}
105+
106+
/// <summary>
107+
/// Returns formula by column name.
108+
/// </summary>
109+
/// <param name="columnName"></param>
110+
/// <returns></returns>
111+
public string GetFormula(string columnName)
112+
{
113+
CheckDeleted();
114+
var ix = _table.Columns.GetIndexOfColName(columnName);
115+
var startRow = _table.DataRange._fromRow;
116+
return _table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + ix].Formula;
117+
}
118+
119+
/// <summary>
120+
/// Returns formula by 0-based column index
121+
/// </summary>
122+
/// <param name="offsetIndex"></param>
123+
/// <returns></returns>
124+
public string GetFormula(int offsetIndex)
125+
{
126+
CheckDeleted();
127+
var startRow = _table.DataRange._fromRow;
128+
return _table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + offsetIndex].Formula;
129+
}
130+
131+
/// <summary>
132+
/// Returns cell value by column name
133+
/// </summary>
134+
/// <typeparam name="T">Cell value type</typeparam>
135+
/// <param name="columnName"></param>
136+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
137+
/// <returns></returns>
138+
public T GetValue<T>(string columnName)
139+
{
140+
CheckDeleted();
141+
var ix = _table.Columns.GetIndexOfColName(columnName);
142+
var startRow = _table.DataRange._fromRow;
143+
return _table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + ix].GetValue<T>();
144+
}
145+
146+
/// <summary>
147+
/// Returns cell value by column name
148+
/// </summary>
149+
/// <param name="columnName"></param>
150+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
151+
/// <returns></returns>
152+
public object GetValue(string columnName)
153+
{
154+
CheckDeleted();
155+
var ix = _table.Columns.GetIndexOfColName(columnName);
156+
var startRow = _table.DataRange._fromRow;
157+
return _table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + ix].GetValue<object>();
158+
}
159+
160+
/// <summary>
161+
/// Returns cell value by column index
162+
/// </summary>
163+
/// <typeparam name="T">Cell value type</typeparam>
164+
/// <param name="offsetIndex">0-based column index</param>
165+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
166+
/// <returns></returns>
167+
public T GetValue<T>(int offsetIndex)
168+
{
169+
CheckDeleted();
170+
var startRow = _table.DataRange._fromRow;
171+
return _table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + offsetIndex].GetValue<T>();
172+
}
173+
174+
/// <summary>
175+
/// Returns cell value by column index
176+
/// </summary>
177+
/// <param name="offsetIndex">0-based column index</param>
178+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
179+
/// <returns></returns>
180+
public object GetValue(int offsetIndex)
181+
{
182+
CheckDeleted();
183+
var startRow = _table.DataRange._fromRow;
184+
return _table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + offsetIndex].GetValue<object>();
185+
}
186+
187+
/// <summary>
188+
/// Set a cell value by column name
189+
/// </summary>
190+
/// <param name="columnName">The table column name</param>
191+
/// <param name="value">The table cell value</param>
192+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
193+
/// <returns></returns>
194+
public ExcelTableRow SetValue(string columnName, object value)
195+
{
196+
CheckDeleted();
197+
var ix = _table.Columns.GetIndexOfColName(columnName);
198+
var startRow = _table.DataRange._fromRow;
199+
_table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + ix].Value = value;
200+
return this;
201+
}
202+
203+
/// <summary>
204+
/// Set a cell value by column index
205+
/// </summary>
206+
/// <param name="offsetIndex">0-based column index</param>
207+
/// <param name="value">The table cell value</param>
208+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
209+
/// <returns></returns>
210+
public ExcelTableRow SetValue(int offsetIndex, object value)
211+
{
212+
CheckDeleted();
213+
var startRow = _table.DataRange._fromRow;
214+
_table.WorkSheet.Cells[startRow + _rowIx, _table.Range._fromCol + offsetIndex].Value = value;
215+
return this;
216+
}
217+
218+
/// <summary>
219+
/// Set all the cell values of the table row by providing an array of <see cref="object"/>
220+
/// </summary>
221+
/// <param name="values"></param>
222+
/// <exception cref="ArgumentNullException">Will be thrown if <paramref name="values"/> is null</exception>
223+
/// <exception cref="ArgumentException">Will be thrown if <paramref name="values"/> is an empty array</exception>
224+
/// <exception cref="ArgumentOutOfRangeException">Will be thrown if number of items in <paramref name="values"/> exceeds number of columns in the table.</exception>
225+
/// <exception cref="InvalidOperationException">If the row has previously been deleted.</exception>
226+
public void SetValues(params object[] values)
227+
{
228+
CheckDeleted();
229+
if (values == null) throw new ArgumentNullException(nameof(values));
230+
if(values.Length == 0) throw new ArgumentException("values cannot be an empty array", nameof(values));
231+
var vals = values;
232+
if (values[0].GetType().IsArray)
233+
{
234+
vals = ((IEnumerable)values[0]).Cast<object>().ToArray();
235+
}
236+
var row = _rowRange._fromRow;
237+
var startCol = _rowRange._fromCol;
238+
var endCol = _rowRange._toCol;
239+
if (vals.Length > endCol - startCol + 1) throw new ArgumentOutOfRangeException(nameof(values), "Number of values exceeds number of columns in the table");
240+
for(var col = startCol; col <= endCol; col++)
241+
{
242+
if (col - startCol > vals.Length) break;
243+
_rowRange.Worksheet.Cells[row, col].Value = vals[col - startCol];
244+
}
245+
}
246+
247+
/// <summary>
248+
/// Removes this row from the table
249+
/// </summary>
250+
public void Delete()
251+
{
252+
if(!_isDeleted)
253+
{
254+
_table.DataRows.DeleteRows(_rowIx, 1);
255+
}
256+
}
257+
258+
/// <summary>
259+
/// Clear all cell values in the row's range.
260+
/// </summary>
261+
/// <returns></returns>
262+
public ExcelTableRow Clear()
263+
{
264+
CheckDeleted();
265+
_rowRange.Clear();
266+
return this;
267+
}
268+
}
269+
}

0 commit comments

Comments
 (0)