|
| 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