|  | /******************************************************************************* | 
|  | * You may amend and distribute as you like, but don't remove this header! | 
|  | * | 
|  | * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. | 
|  | * See http://www.codeplex.com/EPPlus for details. | 
|  | * | 
|  | * Copyright (C) 2011  Jan Källman | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  |  | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
|  | * See the GNU Lesser General Public License for more details. | 
|  | * | 
|  | * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php | 
|  | * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html | 
|  | * | 
|  | * All code and executables are provided "as is" with no warranty either express or implied. | 
|  | * The author accepts no liability for any damage or loss of business that this product may cause. | 
|  | * | 
|  | * Code change notes: | 
|  | * | 
|  | * Author							Change						Date | 
|  | * ****************************************************************************** | 
|  | * Jan Källman		    Initial Release		        2010-01-28 | 
|  | * Jan Källman		    License changed GPL-->LGPL  2011-12-27 | 
|  | * Eyal Seagull		    Conditional Formatting      2012-04-03 | 
|  | *******************************************************************************/ | 
|  |  | 
|  | using System; | 
|  | using System.Collections; | 
|  | using System.Collections.Generic; | 
|  | using System.ComponentModel; | 
|  | using System.Data; | 
|  | using System.Globalization; | 
|  | using System.IO; | 
|  | using System.Linq; | 
|  | using System.Reflection; | 
|  | using System.Security; | 
|  | using System.Text; | 
|  | using System.Text.RegularExpressions; | 
|  | using System.Threading; | 
|  | using System.Xml; | 
|  | using OfficeOpenXml.ConditionalFormatting; | 
|  | using OfficeOpenXml.DataValidation; | 
|  | using OfficeOpenXml.FormulaParsing.LexicalAnalysis; | 
|  | using OfficeOpenXml.Style; | 
|  | using OfficeOpenXml.Style.XmlAccess; | 
|  | using OfficeOpenXml.Table; | 
|  |  | 
|  | namespace OfficeOpenXml; | 
|  |  | 
|  | /// <summary> | 
|  | /// A range of cells | 
|  | /// </summary> | 
|  | public class ExcelRangeBase | 
|  | : ExcelAddress, | 
|  | IExcelCell, | 
|  | IDisposable, | 
|  | IEnumerable<ExcelRangeBase>, | 
|  | IEnumerator<ExcelRangeBase> { | 
|  | /// <summary> | 
|  | /// Reference to the worksheet | 
|  | /// </summary> | 
|  | protected ExcelWorksheet _worksheet; | 
|  | internal ExcelWorkbook _workbook; | 
|  |  | 
|  | private delegate void ChangePropHandler(SetValueHandler method, object value); | 
|  |  | 
|  | private delegate void SetValueHandler(object value, int row, int col); | 
|  |  | 
|  | private ChangePropHandler _changePropMethod; | 
|  | private int _styleID; | 
|  |  | 
|  | private class CopiedCell { | 
|  | internal int Row { get; set; } | 
|  |  | 
|  | internal int Column { get; set; } | 
|  |  | 
|  | internal object Value { get; set; } | 
|  |  | 
|  | internal string Type { get; set; } | 
|  |  | 
|  | internal object Formula { get; set; } | 
|  |  | 
|  | internal int? StyleID { get; set; } | 
|  |  | 
|  | internal Uri HyperLink { get; set; } | 
|  |  | 
|  | internal ExcelComment Comment { get; set; } | 
|  |  | 
|  | internal Byte Flag { get; set; } | 
|  | } | 
|  |  | 
|  | //private class CopiedFlag | 
|  | //{ | 
|  | //    internal int Row { get; set; } | 
|  | //    internal int Column { get; set; } | 
|  | //    internal Byte Flag { get; set; } | 
|  | //} | 
|  |  | 
|  |  | 
|  | internal ExcelRangeBase(ExcelWorksheet worksheet) { | 
|  | _worksheet = worksheet; | 
|  | _ws = _worksheet.Name; | 
|  | _workbook = _worksheet.Workbook; | 
|  | AddressChange += ExcelRangeBase_AddressChange; | 
|  | SetDelegate(); | 
|  | } | 
|  |  | 
|  | private void ExcelRangeBase_AddressChange(object sender, EventArgs e) { | 
|  | if (Table != null) { | 
|  | SetRcFromTable(_workbook, null); | 
|  | } | 
|  | SetDelegate(); | 
|  | } | 
|  |  | 
|  | internal ExcelRangeBase(ExcelWorksheet worksheet, string address) | 
|  | : base(worksheet == null ? "" : worksheet.Name, address) { | 
|  | _worksheet = worksheet; | 
|  | _workbook = worksheet.Workbook; | 
|  | SetRcFromTable(_workbook, null); | 
|  | if (string.IsNullOrEmpty(_ws)) { | 
|  | _ws = _worksheet == null ? "" : _worksheet.Name; | 
|  | } | 
|  | AddressChange += ExcelRangeBase_AddressChange; | 
|  | SetDelegate(); | 
|  | } | 
|  |  | 
|  | internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) | 
|  | : base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) { | 
|  | SetRcFromTable(wb, null); | 
|  | _worksheet = xlWorksheet; | 
|  | _workbook = wb; | 
|  | if (string.IsNullOrEmpty(_ws)) { | 
|  | _ws = (xlWorksheet == null ? null : xlWorksheet.Name); | 
|  | } | 
|  | AddressChange += ExcelRangeBase_AddressChange; | 
|  | SetDelegate(); | 
|  | } | 
|  |  | 
|  | ~ExcelRangeBase() { | 
|  | //this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange); | 
|  | } | 
|  |  | 
|  | private void SetDelegate() { | 
|  | if (_fromRow == -1) { | 
|  | _changePropMethod = SetUnknown; | 
|  | } | 
|  | //Single cell | 
|  | else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null) { | 
|  | _changePropMethod = SetSingle; | 
|  | } | 
|  | //Range (ex A1:A2) | 
|  | else if (Addresses == null) { | 
|  | _changePropMethod = SetRange; | 
|  | } | 
|  | //Multi Range (ex A1:A2,C1:C2) | 
|  | else { | 
|  | _changePropMethod = SetMultiRange; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// We dont know the address yet. Set the delegate first time a property is set. | 
|  | /// </summary> | 
|  | /// <param name="valueMethod"></param> | 
|  | /// <param name="value"></param> | 
|  | private void SetUnknown(SetValueHandler valueMethod, object value) { | 
|  | //Address is not set use, selected range | 
|  | if (_fromRow == -1) { | 
|  | SetToSelectedRange(); | 
|  | } | 
|  | SetDelegate(); | 
|  | _changePropMethod(valueMethod, value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set a single cell | 
|  | /// </summary> | 
|  | /// <param name="valueMethod"></param> | 
|  | /// <param name="value"></param> | 
|  | private void SetSingle(SetValueHandler valueMethod, object value) { | 
|  | valueMethod(value, _fromRow, _fromCol); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set a range | 
|  | /// </summary> | 
|  | /// <param name="valueMethod"></param> | 
|  | /// <param name="value"></param> | 
|  | private void SetRange(SetValueHandler valueMethod, object value) { | 
|  | SetValueAddress(this, valueMethod, value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set a multirange (A1:A2,C1:C2) | 
|  | /// </summary> | 
|  | /// <param name="valueMethod"></param> | 
|  | /// <param name="value"></param> | 
|  | private void SetMultiRange(SetValueHandler valueMethod, object value) { | 
|  | SetValueAddress(this, valueMethod, value); | 
|  | foreach (var address in Addresses) { | 
|  | SetValueAddress(address, valueMethod, value); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set the property for an address | 
|  | /// </summary> | 
|  | /// <param name="address"></param> | 
|  | /// <param name="valueMethod"></param> | 
|  | /// <param name="value"></param> | 
|  | private void SetValueAddress(ExcelAddress address, SetValueHandler valueMethod, object value) { | 
|  | IsRangeValid(""); | 
|  | if (_fromRow == 1 | 
|  | && _fromCol == 1 | 
|  | && _toRow == ExcelPackage.MaxRows | 
|  | && _toCol | 
|  | == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging | 
|  | { | 
|  | throw (new ArgumentException( | 
|  | "Can't reference all cells. Please use the indexer to set the range")); | 
|  | } | 
|  | for (int col = address.Start.Column; col <= address.End.Column; col++) { | 
|  | for (int row = address.Start.Row; row <= address.End.Row; row++) { | 
|  | valueMethod(value, row, col); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private void Set_StyleID(object value, int row, int col) { | 
|  | _worksheet._styles.SetValue(row, col, (int)value); | 
|  | } | 
|  |  | 
|  | private void Set_StyleName(object value, int row, int col) { | 
|  | //_worksheet.Cell(row, col).SetNewStyleName(value.ToString(), _styleID); | 
|  | _worksheet._styles.SetValue(row, col, _styleID); | 
|  | } | 
|  |  | 
|  | private void Set_Value(object value, int row, int col) { | 
|  | //ExcelCell c = _worksheet.Cell(row, col); | 
|  | var sfi = _worksheet._formulas.GetValue(row, col); | 
|  | if (sfi is int) { | 
|  | SplitFormulas(_worksheet.Cells[row, col]); | 
|  | } | 
|  | if (sfi != null) { | 
|  | _worksheet._formulas.SetValue(row, col, string.Empty); | 
|  | } | 
|  | _worksheet._values.SetValue(row, col, value); | 
|  | } | 
|  |  | 
|  | private void Set_Formula(object value, int row, int col) { | 
|  | //ExcelCell c = _worksheet.Cell(row, col); | 
|  | var f = _worksheet._formulas.GetValue(row, col); | 
|  | if (f is int && (int)f >= 0) { | 
|  | SplitFormulas(_worksheet.Cells[row, col]); | 
|  | } | 
|  |  | 
|  | string formula = (value == null ? string.Empty : value.ToString()); | 
|  | if (formula == string.Empty) { | 
|  | _worksheet._formulas.SetValue(row, col, string.Empty); | 
|  | } else { | 
|  | if (formula[0] == '=') { | 
|  | value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign. | 
|  | } | 
|  | _worksheet._formulas.SetValue(row, col, formula); | 
|  | _worksheet._values.SetValue(row, col, null); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Handles shared formulas | 
|  | /// </summary> | 
|  | /// <param name="value">The  formula</param> | 
|  | /// <param name="address">The address of the formula</param> | 
|  | /// <param name="isArray">If the forumla is an array formula.</param> | 
|  | private void Set_SharedFormula(string value, ExcelAddress address, bool isArray) { | 
|  | if (_fromRow == 1 | 
|  | && _fromCol == 1 | 
|  | && _toRow == ExcelPackage.MaxRows | 
|  | && _toCol | 
|  | == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging | 
|  | { | 
|  | throw (new InvalidOperationException("Can't set a formula for the entire worksheet")); | 
|  | } | 
|  | if (address.Start.Row == address.End.Row | 
|  | && address.Start.Column == address.End.Column | 
|  | && !isArray) //is it really a shared formula? Arrayformulas can be one cell only | 
|  | { | 
|  | //Nope, single cell. Set the formula | 
|  | Set_Formula(value, address.Start.Row, address.Start.Column); | 
|  | return; | 
|  | } | 
|  | //RemoveFormuls(address); | 
|  | CheckAndSplitSharedFormula(address); | 
|  | ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); | 
|  | f.Formula = value; | 
|  | f.Index = _worksheet.GetMaxShareFunctionIndex(isArray); | 
|  | f.Address = address.FirstAddress; | 
|  | f.StartCol = address.Start.Column; | 
|  | f.StartRow = address.Start.Row; | 
|  | f.IsArray = isArray; | 
|  |  | 
|  | _worksheet._sharedFormulas.Add(f.Index, f); | 
|  | //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index; | 
|  | //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value; | 
|  |  | 
|  | for (int col = address.Start.Column; col <= address.End.Column; col++) { | 
|  | for (int row = address.Start.Row; row <= address.End.Row; row++) { | 
|  | //_worksheet.Cell(row, col).SharedFormulaID = f.Index; | 
|  | _worksheet._formulas.SetValue(row, col, f.Index); | 
|  | _worksheet._values.SetValue(row, col, null); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private void Set_HyperLink(object value, int row, int col) { | 
|  | //_worksheet.Cell(row, col).Hyperlink = value as Uri; | 
|  | if (value is Uri) { | 
|  | _worksheet._hyperLinks.SetValue(row, col, (Uri)value); | 
|  |  | 
|  | if (value is ExcelHyperLink) { | 
|  | _worksheet._values.SetValue(row, col, ((ExcelHyperLink)value).Display); | 
|  | } else { | 
|  | _worksheet._values.SetValue(row, col, ((Uri)value).OriginalString); | 
|  | } | 
|  | } else { | 
|  | _worksheet._hyperLinks.SetValue(row, col, null); | 
|  | _worksheet._values.SetValue(row, col, null); | 
|  | } | 
|  | } | 
|  |  | 
|  | private void Set_IsArrayFormula(object value, int row, int col) { | 
|  | _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.ArrayFormula); | 
|  | } | 
|  |  | 
|  | private void Set_IsRichText(object value, int row, int col) { | 
|  | //_worksheet.Cell(row, col).IsRichText = (bool)value; | 
|  | _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText); | 
|  | } | 
|  |  | 
|  | private void Exists_Comment(object value, int row, int col) { | 
|  | ulong cellId = GetCellId(_worksheet.SheetID, row, col); | 
|  | if (_worksheet.Comments._comments.ContainsKey(cellId)) { | 
|  | throw (new InvalidOperationException( | 
|  | string.Format( | 
|  | "Cell {0} already contain a comment.", | 
|  | new ExcelCellAddress(row, col).Address))); | 
|  | } | 
|  | } | 
|  |  | 
|  | private void Set_Comment(object value, int row, int col) { | 
|  | string[] v = (string[])value; | 
|  | Worksheet.Comments.Add(new(_worksheet, GetAddress(_fromRow, _fromCol)), v[0], v[1]); | 
|  | //   _worksheet.Cell(row, col).Comment = comment; | 
|  | } | 
|  |  | 
|  | private void SetToSelectedRange() { | 
|  | if (_worksheet.View.SelectedRange == "") { | 
|  | Address = "A1"; | 
|  | } else { | 
|  | Address = _worksheet.View.SelectedRange; | 
|  | } | 
|  | } | 
|  |  | 
|  | private void IsRangeValid(string type) { | 
|  | if (_fromRow <= 0) { | 
|  | if (_address == "") { | 
|  | SetToSelectedRange(); | 
|  | } else { | 
|  | if (type == "") { | 
|  | throw (new InvalidOperationException( | 
|  | string.Format("Range is not valid for this operation: {0}", _address))); | 
|  | } | 
|  | throw (new InvalidOperationException( | 
|  | string.Format("Range is not valid for {0} : {1}", type, _address))); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The styleobject for the range. | 
|  | /// </summary> | 
|  | public ExcelStyle Style { | 
|  | get { | 
|  | IsRangeValid("styling"); | 
|  | int s = 0; | 
|  | if (!_worksheet._styles.Exists( | 
|  | _fromRow, | 
|  | _fromCol, | 
|  | ref s)) //Cell exists | 
|  | { | 
|  | if (!_worksheet._styles.Exists( | 
|  | _fromRow, | 
|  | 0, | 
|  | ref s)) //No, check Row style | 
|  | { | 
|  | var c = Worksheet.GetColumn(_fromCol); | 
|  | if (c == null) { | 
|  | s = 0; | 
|  | } else { | 
|  | s = c.StyleID; | 
|  | } | 
|  | } | 
|  | } | 
|  | return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The named style | 
|  | /// </summary> | 
|  | public string StyleName { | 
|  | get { | 
|  | IsRangeValid("styling"); | 
|  | int xfId; | 
|  | if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) { | 
|  | xfId = GetColumnStyle(_fromCol); | 
|  | } else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) { | 
|  | xfId = 0; | 
|  | if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) { | 
|  | xfId = GetColumnStyle(_fromCol); | 
|  | } | 
|  | } else { | 
|  | xfId = 0; | 
|  | if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId)) { | 
|  | if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) { | 
|  | xfId = GetColumnStyle(_fromCol); | 
|  | } | 
|  | } | 
|  | } | 
|  | int nsId; | 
|  | if (xfId <= 0) { | 
|  | nsId = Style.Styles.CellXfs[0].XfId; | 
|  | } else { | 
|  | nsId = Style.Styles.CellXfs[xfId].XfId; | 
|  | } | 
|  | foreach (var ns in Style.Styles.NamedStyles) { | 
|  | if (ns.StyleXfId == nsId) { | 
|  | return ns.Name; | 
|  | } | 
|  | } | 
|  |  | 
|  | return ""; | 
|  | } | 
|  | set { | 
|  | _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); | 
|  | int col = _fromCol; | 
|  | if (_fromRow == 1 | 
|  | && _toRow | 
|  | == ExcelPackage.MaxRows) //Full column | 
|  | { | 
|  | ExcelColumn column; | 
|  | //Get the startcolumn | 
|  | //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column); | 
|  | var c = _worksheet.GetValue(0, _fromCol); | 
|  | if (c == null) { | 
|  | column = _worksheet.Column(_fromCol); | 
|  | //if (_worksheet._values.PrevCell(ref row, ref col)) | 
|  | //{ | 
|  | //    var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col); | 
|  | //    column = prevCol.Clone(_worksheet, column); | 
|  | //    prevCol.ColumnMax = column - 1; | 
|  | //} | 
|  | } else { | 
|  | column = (ExcelColumn)c; | 
|  | } | 
|  |  | 
|  | column.StyleName = value; | 
|  | column.StyleID = _styleID; | 
|  |  | 
|  | //var index = _worksheet._columns.IndexOf(colID); | 
|  | var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol); | 
|  | if (cols.Next()) { | 
|  | col = _fromCol; | 
|  | while (column.ColumnMin <= _toCol) { | 
|  | if (column.ColumnMax > _toCol) { | 
|  | var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax); | 
|  | column.ColumnMax = _toCol; | 
|  | } | 
|  |  | 
|  | column._styleName = value; | 
|  | column.StyleID = _styleID; | 
|  |  | 
|  | if (cols.Value == null) { | 
|  | break; | 
|  | } | 
|  | var nextCol = (ExcelColumn)cols.Value; | 
|  | if (column.ColumnMax < nextCol.ColumnMax - 1) { | 
|  | column.ColumnMax = nextCol.ColumnMax - 1; | 
|  | } | 
|  | column = nextCol; | 
|  | cols.Next(); | 
|  | } | 
|  | } | 
|  | if (column.ColumnMax < _toCol) { | 
|  | column.ColumnMax = _toCol; | 
|  | } | 
|  | //if (column.ColumnMin == column) | 
|  | //{ | 
|  | //    column.ColumnMax = _toCol; | 
|  | //} | 
|  | //else if (column._columnMax < _toCol) | 
|  | //{ | 
|  | //    var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn; | 
|  | //    newCol._columnMax = _toCol; | 
|  |  | 
|  | //    newCol._styleID = _styleID; | 
|  | //    newCol._styleName = value; | 
|  | //} | 
|  | if (_fromCol == 1 | 
|  | && _toCol | 
|  | == ExcelPackage.MaxColumns) //FullRow | 
|  | { | 
|  | var rows = new CellsStoreEnumerator<object>( | 
|  | _worksheet._values, | 
|  | 1, | 
|  | 0, | 
|  | ExcelPackage.MaxRows, | 
|  | 0); | 
|  | rows.Next(); | 
|  | while (rows.Value != null) { | 
|  | _worksheet._styles.SetValue(rows.Row, 0, _styleID); | 
|  | if (!rows.Next()) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | } else if (_fromCol == 1 | 
|  | && _toCol | 
|  | == ExcelPackage.MaxColumns) //FullRow | 
|  | { | 
|  | for (int r = _fromRow; r <= _toRow; r++) { | 
|  | _worksheet.Row(r)._styleName = value; | 
|  | _worksheet.Row(r).StyleID = _styleID; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows) | 
|  | || (_fromCol == 1 | 
|  | && _toCol | 
|  | == ExcelPackage.MaxColumns))) //Cell specific | 
|  | { | 
|  | for (int c = _fromCol; c <= _toCol; c++) { | 
|  | for (int r = _fromRow; r <= _toRow; r++) { | 
|  | _worksheet._styles.SetValue(r, c, _styleID); | 
|  | } | 
|  | } | 
|  | } else //Only set name on created cells. (uncreated cells is set on full row or full column). | 
|  | { | 
|  | var cells = new CellsStoreEnumerator<object>( | 
|  | _worksheet._values, | 
|  | _fromRow, | 
|  | _fromCol, | 
|  | _toRow, | 
|  | _toCol); | 
|  | while (cells.Next()) { | 
|  | _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID); | 
|  | } | 
|  | } | 
|  | //_changePropMethod(Set_StyleName, value); | 
|  | } | 
|  | } | 
|  |  | 
|  | private int GetColumnStyle(int col) { | 
|  | object c = null; | 
|  | if (_worksheet._values.Exists(0, col, ref c)) { | 
|  | return (c as ExcelColumn).StyleID; | 
|  | } | 
|  | int row = 0; | 
|  | if (_worksheet._values.PrevCell(ref row, ref col)) { | 
|  | var column = _worksheet._values.GetValue(row, col) as ExcelColumn; | 
|  | if (column.ColumnMax >= col) { | 
|  | return _worksheet._styles.GetValue(row, col); | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The style ID. | 
|  | /// It is not recomended to use this one. Use Named styles as an alternative. | 
|  | /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook. | 
|  | /// </summary> | 
|  | public int StyleID { | 
|  | get { | 
|  | int s = 0; | 
|  | if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref s)) { | 
|  | if (!_worksheet._styles.Exists(_fromRow, 0, ref s)) { | 
|  | s = _worksheet._styles.GetValue(0, _fromCol); | 
|  | } | 
|  | } | 
|  | return s; | 
|  | } | 
|  | set => _changePropMethod(Set_StyleID, value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set the range to a specific value | 
|  | /// </summary> | 
|  | public object Value { | 
|  | get { | 
|  | if (IsName) { | 
|  | if (_worksheet == null) { | 
|  | return _workbook._names[_address].NameValue; | 
|  | } | 
|  | return _worksheet.Names[_address].NameValue; | 
|  | } | 
|  | if (_fromRow == _toRow && _fromCol == _toCol) { | 
|  | return _worksheet.GetValue(_fromRow, _fromCol); | 
|  | } | 
|  | return GetValueArray(); | 
|  | } | 
|  | set { | 
|  | if (IsName) { | 
|  | if (_worksheet == null) { | 
|  | _workbook._names[_address].NameValue = value; | 
|  | } else { | 
|  | _worksheet.Names[_address].NameValue = value; | 
|  | } | 
|  | } else { | 
|  | _changePropMethod(Set_Value, value); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private bool IsInfinityValue(object value) { | 
|  | double? valueAsDouble = value as double?; | 
|  |  | 
|  | if (valueAsDouble.HasValue | 
|  | && (double.IsNegativeInfinity(valueAsDouble.Value) | 
|  | || double.IsPositiveInfinity(valueAsDouble.Value))) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | private object GetValueArray() { | 
|  | ExcelAddressBase addr; | 
|  | if (_fromRow == 1 | 
|  | && _fromCol == 1 | 
|  | && _toRow == ExcelPackage.MaxRows | 
|  | && _toCol == ExcelPackage.MaxColumns) { | 
|  | addr = _worksheet.Dimension; | 
|  | if (addr == null) { | 
|  | return null; | 
|  | } | 
|  | } else { | 
|  | addr = this; | 
|  | } | 
|  | object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1]; | 
|  |  | 
|  | for (int col = addr._fromCol; col <= addr._toCol; col++) { | 
|  | for (int row = addr._fromRow; row <= addr._toRow; row++) { | 
|  | if (_worksheet._values.Exists(row, col)) { | 
|  | if (_worksheet._flags.GetFlagValue(row, col, CellFlags.RichText)) { | 
|  | v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text; | 
|  | } else { | 
|  | v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return v; | 
|  | } | 
|  |  | 
|  | private ExcelAddressBase GetAddressDim(ExcelRangeBase addr) { | 
|  | int fromRow, | 
|  | fromCol, | 
|  | toRow, | 
|  | toCol; | 
|  | var d = _worksheet.Dimension; | 
|  | fromRow = addr._fromRow < d._fromRow ? d._fromRow : addr._fromRow; | 
|  | fromCol = addr._fromCol < d._fromCol ? d._fromCol : addr._fromCol; | 
|  |  | 
|  | toRow = addr._toRow > d._toRow ? d._toRow : addr._toRow; | 
|  | toCol = addr._toCol > d._toCol ? d._toCol : addr._toCol; | 
|  |  | 
|  | if (addr._fromCol == fromRow && addr._toRow == toRow && addr._toCol == _toCol) { | 
|  | return addr; | 
|  | } | 
|  | if (_fromRow > _toRow || _fromCol > _toCol) { | 
|  | return null; | 
|  | } | 
|  | return new(fromRow, fromCol, toRow, toCol); | 
|  | } | 
|  |  | 
|  | private object GetSingleValue() { | 
|  | if (IsRichText) { | 
|  | return RichText.Text; | 
|  | } | 
|  | return _worksheet._values.GetValue(_fromRow, _fromCol); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Returns the formatted value. | 
|  | /// </summary> | 
|  | public string Text => GetFormattedText(false); | 
|  |  | 
|  | private void SetMinWidth(double minimumWidth, int fromCol, int toCol) { | 
|  | var iterator = new CellsStoreEnumerator<object>(_worksheet._values, 0, fromCol, 0, toCol); | 
|  | var prevCol = fromCol; | 
|  | foreach (ExcelColumn col in iterator) { | 
|  | col.Width = minimumWidth; | 
|  | if (_worksheet.DefaultColWidth > minimumWidth && col.ColumnMin > prevCol) { | 
|  | var newCol = _worksheet.Column(prevCol); | 
|  | newCol.ColumnMax = col.ColumnMin - 1; | 
|  | newCol.Width = minimumWidth; | 
|  | } | 
|  | prevCol = col.ColumnMax + 1; | 
|  | } | 
|  | if (_worksheet.DefaultColWidth > minimumWidth && prevCol < toCol) { | 
|  | var newCol = _worksheet.Column(prevCol); | 
|  | newCol.ColumnMax = toCol; | 
|  | newCol.Width = minimumWidth; | 
|  | } | 
|  | } | 
|  |  | 
|  | internal string TextForWidth => GetFormattedText(true); | 
|  |  | 
|  | private string GetFormattedText(bool forWidthCalc) { | 
|  | object v = Value; | 
|  | if (v == null) { | 
|  | return ""; | 
|  | } | 
|  | var styles = Worksheet.Workbook.Styles; | 
|  | var nfId = styles.CellXfs[StyleID].NumberFormatId; | 
|  | ExcelNumberFormatXml.ExcelFormatTranslator nf = null; | 
|  | for (int i = 0; i < styles.NumberFormats.Count; i++) { | 
|  | if (nfId == styles.NumberFormats[i].NumFmtId) { | 
|  | nf = styles.NumberFormats[i].FormatTranslator; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | string format, | 
|  | textFormat; | 
|  | if (forWidthCalc) { | 
|  | format = nf.NetFormatForWidth; | 
|  | textFormat = nf.NetTextFormatForWidth; | 
|  | } else { | 
|  | format = nf.NetFormat; | 
|  | textFormat = nf.NetTextFormat; | 
|  | } | 
|  |  | 
|  | return FormatValue(v, nf, format, textFormat); | 
|  | } | 
|  |  | 
|  | internal static string FormatValue( | 
|  | object v, | 
|  | ExcelNumberFormatXml.ExcelFormatTranslator nf, | 
|  | string format, | 
|  | string textFormat) { | 
|  | if (v is decimal || v.GetType().IsPrimitive) { | 
|  | double d; | 
|  | try { | 
|  | d = Convert.ToDouble(v); | 
|  | } catch { | 
|  | return ""; | 
|  | } | 
|  |  | 
|  | if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number) { | 
|  | if (string.IsNullOrEmpty(nf.FractionFormat)) { | 
|  | return d.ToString(format, nf.Culture); | 
|  | } | 
|  | return nf.FormatFraction(d); | 
|  | } | 
|  | if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { | 
|  | var date = DateTime.FromOADate(d); | 
|  | return date.ToString(format, nf.Culture); | 
|  | } | 
|  | } else if (v is DateTime) { | 
|  | if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { | 
|  | return ((DateTime)v).ToString(format, nf.Culture); | 
|  | } | 
|  | double d = ((DateTime)v).ToOADate(); | 
|  | if (string.IsNullOrEmpty(nf.FractionFormat)) { | 
|  | return d.ToString(format, nf.Culture); | 
|  | } | 
|  | return nf.FormatFraction(d); | 
|  | } else if (v is TimeSpan) { | 
|  | if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { | 
|  | return new DateTime(((TimeSpan)v).Ticks).ToString(format, nf.Culture); | 
|  | } | 
|  | double d = (new DateTime(((TimeSpan)v).Ticks)).ToOADate(); | 
|  | if (string.IsNullOrEmpty(nf.FractionFormat)) { | 
|  | return d.ToString(format, nf.Culture); | 
|  | } | 
|  | return nf.FormatFraction(d); | 
|  | } else { | 
|  | if (textFormat == "") { | 
|  | return v.ToString(); | 
|  | } | 
|  | return string.Format(textFormat, v); | 
|  | } | 
|  | return v.ToString(); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Gets or sets a formula for a range. | 
|  | /// </summary> | 
|  | public string Formula { | 
|  | get { | 
|  | if (IsName) { | 
|  | if (_worksheet == null) { | 
|  | return _workbook._names[_address].NameFormula; | 
|  | } | 
|  | return _worksheet.Names[_address].NameFormula; | 
|  | } | 
|  | return _worksheet.GetFormula(_fromRow, _fromCol); | 
|  | } | 
|  | set { | 
|  | if (IsName) { | 
|  | if (_worksheet == null) { | 
|  | _workbook._names[_address].NameFormula = value; | 
|  | } else { | 
|  | _worksheet.Names[_address].NameFormula = value; | 
|  | } | 
|  | } else { | 
|  | if (value == null || value.Trim() == "") { | 
|  | //Set the cells to null | 
|  | Value = null; | 
|  | } else if (_fromRow == _toRow && _fromCol == _toCol) { | 
|  | Set_Formula(value, _fromRow, _fromCol); | 
|  | } else { | 
|  | Set_SharedFormula(value, this, false); | 
|  | if (Addresses != null) { | 
|  | foreach (var address in Addresses) { | 
|  | Set_SharedFormula(value, address, false); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Gets or Set a formula in R1C1 format. | 
|  | /// </summary> | 
|  | public string FormulaR1C1 { | 
|  | get { | 
|  | IsRangeValid("FormulaR1C1"); | 
|  | return _worksheet.GetFormulaR1C1(_fromRow, _fromCol); | 
|  | } | 
|  | set { | 
|  | IsRangeValid("FormulaR1C1"); | 
|  | if (value.Length > 0 && value[0] == '=') { | 
|  | value = value.Substring(1, value.Length - 1); // remove any starting equalsign. | 
|  | } | 
|  |  | 
|  | if (value == null || value.Trim() == "") { | 
|  | //Set the cells to null | 
|  | _worksheet.Cells[TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null; | 
|  | } else if (Addresses == null) { | 
|  | Set_SharedFormula(TranslateFromR1C1(value, _fromRow, _fromCol), this, false); | 
|  | } else { | 
|  | Set_SharedFormula( | 
|  | TranslateFromR1C1(value, _fromRow, _fromCol), | 
|  | new(WorkSheet, FirstAddress), | 
|  | false); | 
|  | foreach (var address in Addresses) { | 
|  | Set_SharedFormula( | 
|  | TranslateFromR1C1(value, address.Start.Row, address.Start.Column), | 
|  | address, | 
|  | false); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Gets or Set a formula in R1C1 format. | 
|  | /// | 
|  | public string FormulaR1C1_V1 { | 
|  | get { | 
|  | IsRangeValid("FormulaR1C1"); | 
|  | return _worksheet.GetFormulaR1C1_V1(_fromRow, _fromCol); | 
|  | } | 
|  | } | 
|  |  | 
|  | public string ArrayFormulaAddress { | 
|  | get { | 
|  | IsRangeValid("FormulaR1C1"); | 
|  | return _worksheet.GetArrayFormulaAddress(_fromRow, _fromCol); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set the hyperlink property for a range of cells | 
|  | /// </summary> | 
|  | public Uri Hyperlink { | 
|  | get { | 
|  | IsRangeValid("formulaR1C1"); | 
|  | return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol); | 
|  | } | 
|  | set => _changePropMethod(Set_HyperLink, value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the cells in the range are merged. | 
|  | /// </summary> | 
|  | public bool Merge { | 
|  | get { | 
|  | IsRangeValid("merging"); | 
|  | for (int col = _fromCol; col <= _toCol; col++) { | 
|  | for (int row = _fromRow; row <= _toRow; row++) { | 
|  | if (_worksheet.MergedCells[row, col] == null) { | 
|  | return false; | 
|  | } | 
|  | //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged)) | 
|  | //{ | 
|  | //    return false; | 
|  | //} | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  | set { | 
|  | IsRangeValid("merging"); | 
|  | //SetMerge(value, FirstAddress); | 
|  | if (value) { | 
|  | _worksheet.MergedCells.Add(new(FirstAddress), true); | 
|  | if (Addresses != null) { | 
|  | foreach (var address in Addresses) { | 
|  | _worksheet.MergedCells.Add(address, true); | 
|  | //SetMerge(value, address._address); | 
|  | } | 
|  | } | 
|  | } else { | 
|  | _worksheet.MergedCells.Clear(this); | 
|  | if (Addresses != null) { | 
|  | foreach (var address in Addresses) { | 
|  | _worksheet.MergedCells.Clear(address); | 
|  | ; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | //private void SetMerge(bool value, string address) | 
|  | //{ | 
|  | //    if (!value) | 
|  | //    { | 
|  | //        if (_worksheet.MergedCells.List.Contains(address)) | 
|  | //        { | 
|  | //            SetCellMerge(false, address); | 
|  | //            _worksheet.MergedCells.List.Remove(address); | 
|  | //        } | 
|  | //        else if (!CheckMergeDiff(false, address)) | 
|  | //        { | 
|  | //            throw (new Exception("Range is not fully merged.Specify the exact range")); | 
|  | //        } | 
|  | //    } | 
|  | //    else | 
|  | //    { | 
|  | //        if (CheckMergeDiff(false, address)) | 
|  | //        { | 
|  | //            SetCellMerge(true, address); | 
|  | //            _worksheet.MergedCells.List.Add(address); | 
|  | //        } | 
|  | //        else | 
|  | //        { | 
|  | //            if (!_worksheet.MergedCells.List.Contains(address)) | 
|  | //            { | 
|  | //                throw (new Exception("Cells are already merged")); | 
|  | //            } | 
|  | //        } | 
|  | //    } | 
|  | //} | 
|  | /// <summary> | 
|  | /// Set an autofilter for the range | 
|  | /// </summary> | 
|  | public bool AutoFilter { | 
|  | get { | 
|  | IsRangeValid("autofilter"); | 
|  | ExcelAddressBase address = _worksheet.AutoFilterAddress; | 
|  | if (address == null) { | 
|  | return false; | 
|  | } | 
|  | if (_fromRow >= address.Start.Row | 
|  | && _toRow <= address.End.Row | 
|  | && _fromCol >= address.Start.Column | 
|  | && _toCol <= address.End.Column) { | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  | set { | 
|  | IsRangeValid("autofilter"); | 
|  | _worksheet.AutoFilterAddress = this; | 
|  | if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase")) { | 
|  | _worksheet.Names.Remove("_xlnm._FilterDatabase"); | 
|  | } | 
|  | var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this); | 
|  | result.IsNameHidden = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// If the value is in richtext format. | 
|  | /// </summary> | 
|  | public bool IsRichText { | 
|  | get { | 
|  | IsRangeValid("richtext"); | 
|  | return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.RichText); | 
|  | } | 
|  | set => _changePropMethod(Set_IsRichText, value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Is the range a part of an Arrayformula | 
|  | /// </summary> | 
|  | public bool IsArrayFormula { | 
|  | get { | 
|  | IsRangeValid("arrayformulas"); | 
|  | return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula); | 
|  | } | 
|  | set => _changePropMethod(Set_IsArrayFormula, value); | 
|  | } | 
|  |  | 
|  | private ExcelRichTextCollection _rtc; | 
|  |  | 
|  | /// <summary> | 
|  | /// Cell value is richtext formatted. | 
|  | /// Richtext-property only apply to the left-top cell of the range. | 
|  | /// </summary> | 
|  | public ExcelRichTextCollection RichText { | 
|  | get { | 
|  | IsRangeValid("richtext"); | 
|  | if (_rtc == null) { | 
|  | _rtc = GetRichText(_fromRow, _fromCol); | 
|  | } | 
|  | return _rtc; | 
|  | } | 
|  | } | 
|  |  | 
|  | private ExcelRichTextCollection GetRichText(int row, int col) { | 
|  | XmlDocument xml = new XmlDocument(); | 
|  | var v = _worksheet._values.GetValue(row, col); | 
|  | var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText); | 
|  | if (v != null) { | 
|  | if (isRt) { | 
|  | XmlHelper.LoadXmlSafe( | 
|  | xml, | 
|  | "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >" | 
|  | + v | 
|  | + "</d:si>", | 
|  | Encoding.UTF8); | 
|  | } else { | 
|  | xml.LoadXml( | 
|  | "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>" | 
|  | + SecurityElement.Escape(v.ToString()) | 
|  | + "</d:t></d:r></d:si>"); | 
|  | } | 
|  | } else { | 
|  | xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />"); | 
|  | } | 
|  | var rtc = new ExcelRichTextCollection( | 
|  | _worksheet.NameSpaceManager, | 
|  | xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager), | 
|  | this); | 
|  | return rtc; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// returns the comment object of the first cell in the range | 
|  | /// </summary> | 
|  | public ExcelComment Comment { | 
|  | get { | 
|  | IsRangeValid("comments"); | 
|  | ulong cellId = GetCellId(_worksheet.SheetID, _fromRow, _fromCol); | 
|  | if (_worksheet.Comments._comments.ContainsKey(cellId)) { | 
|  | return _worksheet._comments._comments[cellId] as ExcelComment; | 
|  | } | 
|  | return null; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// WorkSheet object | 
|  | /// </summary> | 
|  | public ExcelWorksheet Worksheet => _worksheet; | 
|  |  | 
|  | /// <summary> | 
|  | /// Address including sheetname | 
|  | /// </summary> | 
|  | public string FullAddress { | 
|  | get { | 
|  | string fullAddress = GetFullAddress(_worksheet.Name, _address); | 
|  | if (Addresses != null) { | 
|  | foreach (var a in Addresses) { | 
|  | fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address); | 
|  | ; | 
|  | } | 
|  | } | 
|  | return fullAddress; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Address including sheetname | 
|  | /// </summary> | 
|  | public string FullAddressAbsolute { | 
|  | get { | 
|  | string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws; | 
|  | string fullAddress = GetFullAddress( | 
|  | wbwsRef, | 
|  | GetAddress(_fromRow, _fromCol, _toRow, _toCol, true)); | 
|  | if (Addresses != null) { | 
|  | foreach (var a in Addresses) { | 
|  | fullAddress += | 
|  | "," | 
|  | + GetFullAddress( | 
|  | wbwsRef, | 
|  | GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true)); | 
|  | ; | 
|  | } | 
|  | } | 
|  | return fullAddress; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Address including sheetname | 
|  | /// </summary> | 
|  | internal string FullAddressAbsoluteNoFullRowCol { | 
|  | get { | 
|  | string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws; | 
|  | string fullAddress = GetFullAddress( | 
|  | wbwsRef, | 
|  | GetAddress(_fromRow, _fromCol, _toRow, _toCol, true), | 
|  | false); | 
|  | if (Addresses != null) { | 
|  | foreach (var a in Addresses) { | 
|  | fullAddress += | 
|  | "," | 
|  | + GetFullAddress( | 
|  | wbwsRef, | 
|  | GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true), | 
|  | false); | 
|  | ; | 
|  | } | 
|  | } | 
|  | return fullAddress; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Set the value without altering the richtext property | 
|  | /// </summary> | 
|  | /// <param name="value">the value</param> | 
|  | internal void SetValueRichText(object value) { | 
|  | if (_fromRow == 1 | 
|  | && _fromCol == 1 | 
|  | && _toRow == ExcelPackage.MaxRows | 
|  | && _toCol | 
|  | == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging | 
|  | { | 
|  | //_worksheet.Cell(1, 1).SetValueRichText(value); | 
|  | SetValue(value, 1, 1); | 
|  | } else { | 
|  | //for (int col = _fromCol; col <= _toCol; col++) | 
|  | //{ | 
|  | //    for (int row = _fromRow; row <= _toRow; row++) | 
|  | //    { | 
|  | //_worksheet.Cell(row, col).SetValueRichText(value); | 
|  | SetValue(value, _fromRow, _fromCol); | 
|  | //} | 
|  | //} | 
|  | } | 
|  | } | 
|  |  | 
|  | private void SetValue(object value, int row, int col) { | 
|  | _worksheet.SetValue(row, col, value); | 
|  | // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, ""); | 
|  | _worksheet._formulas.SetValue(row, col, ""); | 
|  | } | 
|  |  | 
|  | internal void SetSharedFormulaId(int id) { | 
|  | for (int col = _fromCol; col <= _toCol; col++) { | 
|  | for (int row = _fromRow; row <= _toRow; row++) { | 
|  | _worksheet._formulas.SetValue(row, col, id); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private void CheckAndSplitSharedFormula(ExcelAddressBase address) { | 
|  | for (int col = address._fromCol; col <= address._toCol; col++) { | 
|  | for (int row = address._fromRow; row <= address._toRow; row++) { | 
|  | var f = _worksheet._formulas.GetValue(row, col); | 
|  | if (f is int && (int)f >= 0) { | 
|  | SplitFormulas(address); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private void SplitFormulas(ExcelAddressBase address) { | 
|  | List<int> formulas = new List<int>(); | 
|  | for (int col = address._fromCol; col <= address._toCol; col++) { | 
|  | for (int row = address._fromRow; row <= address._toRow; row++) { | 
|  | var f = _worksheet._formulas.GetValue(row, col); | 
|  | if (f is int) { | 
|  | int id = (int)f; | 
|  | if (id >= 0 && !formulas.Contains(id)) { | 
|  | if (_worksheet._sharedFormulas[id].IsArray | 
|  | && Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address]) | 
|  | == eAddressCollition.Partly) // If the formula is an array formula and its on the inside the overwriting range throw an exception | 
|  | { | 
|  | throw (new InvalidOperationException("Can not overwrite a part of an array-formula")); | 
|  | } | 
|  | formulas.Add(id); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | foreach (int ix in formulas) { | 
|  | SplitFormula(address, ix); | 
|  | } | 
|  |  | 
|  | ////Clear any formula references inside the refered range | 
|  | //_worksheet._formulas.Clear(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1); | 
|  | } | 
|  |  | 
|  | private void SplitFormula(ExcelAddressBase address, int ix) { | 
|  | var f = _worksheet._sharedFormulas[ix]; | 
|  | var fRange = _worksheet.Cells[f.Address]; | 
|  | var collide = address.Collide(fRange); | 
|  |  | 
|  | //The formula is inside the currenct range, remove it | 
|  | if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside) { | 
|  | _worksheet._sharedFormulas.Remove(ix); | 
|  | return; | 
|  | //fRange.SetSharedFormulaID(int.MinValue); | 
|  | } | 
|  | var firstCellCollide = address.Collide( | 
|  | new(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol)); | 
|  | if (collide == eAddressCollition.Partly | 
|  | && (firstCellCollide == eAddressCollition.Inside | 
|  | || firstCellCollide | 
|  | == eAddressCollition.Equal)) //Do we need to split? Only if the functions first row is inside the new range. | 
|  | { | 
|  | //The formula partly collides with the current range | 
|  | bool fIsSet = false; | 
|  | string formulaR1C1 = fRange.FormulaR1C1; | 
|  | //Top Range | 
|  | if (fRange._fromRow < _fromRow) { | 
|  | f.Address = GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol); | 
|  | fIsSet = true; | 
|  | } | 
|  | //Left Range | 
|  | if (fRange._fromCol < address._fromCol) { | 
|  | if (fIsSet) { | 
|  | f = new(SourceCodeTokenizer.Default); | 
|  | f.Index = _worksheet.GetMaxShareFunctionIndex(false); | 
|  | f.StartCol = fRange._fromCol; | 
|  | f.IsArray = false; | 
|  | _worksheet._sharedFormulas.Add(f.Index, f); | 
|  | } else { | 
|  | fIsSet = true; | 
|  | } | 
|  | if (fRange._fromRow < address._fromRow) { | 
|  | f.StartRow = address._fromRow; | 
|  | } else { | 
|  | f.StartRow = fRange._fromRow; | 
|  | } | 
|  | if (fRange._toRow < address._toRow) { | 
|  | f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, address._fromCol - 1); | 
|  | } else { | 
|  | f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, address._fromCol - 1); | 
|  | } | 
|  | f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); | 
|  | _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); | 
|  | } | 
|  | //Right Range | 
|  | if (fRange._toCol > address._toCol) { | 
|  | if (fIsSet) { | 
|  | f = new(SourceCodeTokenizer.Default); | 
|  | f.Index = _worksheet.GetMaxShareFunctionIndex(false); | 
|  | f.IsArray = false; | 
|  | _worksheet._sharedFormulas.Add(f.Index, f); | 
|  | } else { | 
|  | fIsSet = true; | 
|  | } | 
|  | f.StartCol = address._toCol + 1; | 
|  | if (address._fromRow < fRange._fromRow) { | 
|  | f.StartRow = fRange._fromRow; | 
|  | } else { | 
|  | f.StartRow = address._fromRow; | 
|  | } | 
|  |  | 
|  | if (fRange._toRow < address._toRow) { | 
|  | f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol); | 
|  | } else { | 
|  | f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, fRange._toCol); | 
|  | } | 
|  | f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); | 
|  | _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); | 
|  | } | 
|  | //Bottom Range | 
|  | if (fRange._toRow > address._toRow) { | 
|  | if (fIsSet) { | 
|  | f = new(SourceCodeTokenizer.Default); | 
|  | f.Index = _worksheet.GetMaxShareFunctionIndex(false); | 
|  | f.IsArray = false; | 
|  | _worksheet._sharedFormulas.Add(f.Index, f); | 
|  | } | 
|  |  | 
|  | f.StartCol = fRange._fromCol; | 
|  | f.StartRow = _toRow + 1; | 
|  |  | 
|  | f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); | 
|  |  | 
|  | f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol); | 
|  | _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private object ConvertData(ExcelTextFormat format, string v, int col, bool isText) { | 
|  | if (isText && (format.DataTypes == null || format.DataTypes.Length < col)) { | 
|  | return v; | 
|  | } | 
|  |  | 
|  | double d; | 
|  | DateTime dt; | 
|  | if (format.DataTypes == null | 
|  | || format.DataTypes.Length <= col | 
|  | || format.DataTypes[col] == eDataTypes.Unknown) { | 
|  | string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; | 
|  | if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) { | 
|  | if (v2 == v) { | 
|  | return d; | 
|  | } | 
|  | return d / 100; | 
|  | } | 
|  | if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) { | 
|  | return dt; | 
|  | } | 
|  | return v; | 
|  | } | 
|  | switch (format.DataTypes[col]) { | 
|  | case eDataTypes.Number: | 
|  | if (double.TryParse(v, NumberStyles.Any, format.Culture, out d)) { | 
|  | return d; | 
|  | } | 
|  | return v; | 
|  | case eDataTypes.DateTime: | 
|  | if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) { | 
|  | return dt; | 
|  | } | 
|  | return v; | 
|  | case eDataTypes.Percent: | 
|  | string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; | 
|  | if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) { | 
|  | return d / 100; | 
|  | } | 
|  | return v; | 
|  |  | 
|  | default: | 
|  | return v; | 
|  | } | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Conditional Formatting for this range. | 
|  | /// </summary> | 
|  | public IRangeConditionalFormatting ConditionalFormatting => | 
|  | new RangeConditionalFormatting(_worksheet, new(Address)); | 
|  |  | 
|  | /// <summary> | 
|  | /// Data validation for this range. | 
|  | /// </summary> | 
|  | public IRangeDataValidation DataValidation => new RangeDataValidation(_worksheet, Address); | 
|  |  | 
|  | /// <summary> | 
|  | /// Load the data from the datareader starting from the top left cell of the range | 
|  | /// </summary> | 
|  | /// <param name="reader">The datareader to loadfrom</param> | 
|  | /// <param name="printHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param> | 
|  | /// <param name="tableName">The name of the table</param> | 
|  | /// <param name="tableStyle">The table style to apply to the data</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromDataReader( | 
|  | IDataReader reader, | 
|  | bool printHeaders, | 
|  | string tableName, | 
|  | TableStyles tableStyle = TableStyles.None) { | 
|  | var r = LoadFromDataReader(reader, printHeaders); | 
|  |  | 
|  | int rows = r.Rows - 1; | 
|  | if (rows >= 0 && r.Columns > 0) { | 
|  | var tbl = _worksheet.Tables.Add( | 
|  | new(_fromRow, _fromCol, _fromRow + (rows <= 0 ? 1 : rows), _fromCol + r.Columns - 1), | 
|  | tableName); | 
|  | tbl.ShowHeader = printHeaders; | 
|  | tbl.TableStyle = tableStyle; | 
|  | } | 
|  | return r; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load the data from the datareader starting from the top left cell of the range | 
|  | /// </summary> | 
|  | /// <param name="reader">The datareader to load from</param> | 
|  | /// <param name="printHeaders">Print the caption property (if set) or the columnname property if not, on first row</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromDataReader(IDataReader reader, bool printHeaders) { | 
|  | if (reader == null) { | 
|  | throw (new ArgumentNullException("reader", "Reader can't be null")); | 
|  | } | 
|  | int fieldCount = reader.FieldCount; | 
|  |  | 
|  | int col = _fromCol, | 
|  | row = _fromRow; | 
|  | if (printHeaders) { | 
|  | for (int i = 0; i < fieldCount; i++) { | 
|  | // If no caption is set, the ColumnName property is called implicitly. | 
|  | _worksheet._values.SetValue(row, col++, reader.GetName(i)); | 
|  | } | 
|  | row++; | 
|  | col = _fromCol; | 
|  | } | 
|  | while (reader.Read()) { | 
|  | for (int i = 0; i < fieldCount; i++) { | 
|  | _worksheet._values.SetValue(row, col++, reader.GetValue(i)); | 
|  | } | 
|  | row++; | 
|  | col = _fromCol; | 
|  | } | 
|  | return _worksheet.Cells[_fromRow, _fromCol, row - 1, _fromCol + fieldCount - 1]; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load the data from the datatable starting from the top left cell of the range | 
|  | /// </summary> | 
|  | /// <param name="table">The datatable to load</param> | 
|  | /// <param name="printHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param> | 
|  | /// <param name="tableStyle">The table style to apply to the data</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromDataTable( | 
|  | DataTable table, | 
|  | bool printHeaders, | 
|  | TableStyles tableStyle) { | 
|  | var r = LoadFromDataTable(table, printHeaders); | 
|  |  | 
|  | int rows = (table.Rows.Count == 0 ? 1 : table.Rows.Count) + (printHeaders ? 1 : 0); | 
|  | if (rows >= 0 && table.Columns.Count > 0) { | 
|  | var tbl = _worksheet.Tables.Add( | 
|  | new(_fromRow, _fromCol, _fromRow + rows - 1, _fromCol + table.Columns.Count - 1), | 
|  | table.TableName); | 
|  | tbl.ShowHeader = printHeaders; | 
|  | tbl.TableStyle = tableStyle; | 
|  | } | 
|  | return r; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load the data from the datatable starting from the top left cell of the range | 
|  | /// </summary> | 
|  | /// <param name="table">The datatable to load</param> | 
|  | /// <param name="printHeaders">Print the caption property (if set) or the columnname property if not, on first row</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromDataTable(DataTable table, bool printHeaders) { | 
|  | if (table == null) { | 
|  | throw (new ArgumentNullException("Table can't be null")); | 
|  | } | 
|  |  | 
|  | int col = _fromCol, | 
|  | row = _fromRow; | 
|  | if (printHeaders) { | 
|  | foreach (DataColumn dc in table.Columns) { | 
|  | // If no caption is set, the ColumnName property is called implicitly. | 
|  | _worksheet._values.SetValue(row, col++, dc.Caption); | 
|  | } | 
|  | row++; | 
|  | col = _fromCol; | 
|  | } else if (table.Rows.Count == 0) { | 
|  | return null; | 
|  | } | 
|  | foreach (DataRow dr in table.Rows) { | 
|  | foreach (object value in dr.ItemArray) { | 
|  | if (value != null && value != DBNull.Value && !string.IsNullOrEmpty(value.ToString())) { | 
|  | _worksheet._values.SetValue(row, col++, value); | 
|  | } else { | 
|  | col++; | 
|  | } | 
|  | } | 
|  | row++; | 
|  | col = _fromCol; | 
|  | } | 
|  | return _worksheet.Cells[_fromRow, | 
|  | _fromCol, | 
|  | (row == _fromRow ? _fromRow : row - 1), | 
|  | _fromCol + table.Columns.Count - 1]; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads data from the collection of arrays of objects into the range, starting from | 
|  | /// the top-left cell. | 
|  | /// </summary> | 
|  | /// <param name="data">The data.</param> | 
|  | public ExcelRangeBase LoadFromArrays(IEnumerable<object[]> data) { | 
|  | //thanx to Abdullin for the code contribution | 
|  | if (data == null) { | 
|  | throw new ArgumentNullException("data"); | 
|  | } | 
|  |  | 
|  | int column = _fromCol, | 
|  | row = _fromRow; | 
|  |  | 
|  | foreach (var rowData in data) { | 
|  | column = _fromCol; | 
|  | foreach (var cellData in rowData) { | 
|  | _worksheet._values.SetValue(row, column, cellData); | 
|  | column += 1; | 
|  | } | 
|  | row += 1; | 
|  | } | 
|  | return _worksheet.Cells[_fromRow, _fromCol, row - 1, column - 1]; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load a collection into a the worksheet starting from the top left row of the range. | 
|  | /// </summary> | 
|  | /// <typeparam name="T">The datatype in the collection</typeparam> | 
|  | /// <param name="collection">The collection to load</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> collection) { | 
|  | return LoadFromCollection( | 
|  | collection, | 
|  | false, | 
|  | TableStyles.None, | 
|  | BindingFlags.Public | BindingFlags.Instance, | 
|  | null); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load a collection of T into the worksheet starting from the top left row of the range. | 
|  | /// Default option will load all public instance properties of T | 
|  | /// </summary> | 
|  | /// <typeparam name="T">The datatype in the collection</typeparam> | 
|  | /// <param name="collection">The collection to load</param> | 
|  | /// <param name="printHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> collection, bool printHeaders) { | 
|  | return LoadFromCollection( | 
|  | collection, | 
|  | printHeaders, | 
|  | TableStyles.None, | 
|  | BindingFlags.Public | BindingFlags.Instance, | 
|  | null); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load a collection of T into the worksheet starting from the top left row of the range. | 
|  | /// Default option will load all public instance properties of T | 
|  | /// </summary> | 
|  | /// <typeparam name="T">The datatype in the collection</typeparam> | 
|  | /// <param name="collection">The collection to load</param> | 
|  | /// <param name="printHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> | 
|  | /// <param name="tableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromCollection<T>( | 
|  | IEnumerable<T> collection, | 
|  | bool printHeaders, | 
|  | TableStyles tableStyle) { | 
|  | return LoadFromCollection( | 
|  | collection, | 
|  | printHeaders, | 
|  | tableStyle, | 
|  | BindingFlags.Public | BindingFlags.Instance, | 
|  | null); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Load a collection into the worksheet starting from the top left row of the range. | 
|  | /// </summary> | 
|  | /// <typeparam name="T">The datatype in the collection</typeparam> | 
|  | /// <param name="collection">The collection to load</param> | 
|  | /// <param name="printHeaders">Print the property names on the first row. Any underscore in the property name will be converted to a space. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> | 
|  | /// <param name="tableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param> | 
|  | /// <param name="memberFlags">Property flags to use</param> | 
|  | /// <param name="members">The properties to output. Must be of type T</param> | 
|  | /// <returns>The filled range</returns> | 
|  | public ExcelRangeBase LoadFromCollection<T>( | 
|  | IEnumerable<T> collection, | 
|  | bool printHeaders, | 
|  | TableStyles tableStyle, | 
|  | BindingFlags memberFlags, | 
|  | MemberInfo[] members) { | 
|  | var type = typeof(T); | 
|  | if (members == null) { | 
|  | members = type.GetProperties(memberFlags); | 
|  | } else { | 
|  | foreach (var t in members) { | 
|  | if (t.DeclaringType != null | 
|  | && t.DeclaringType != type | 
|  | && !t.DeclaringType.IsSubclassOf(type)) { | 
|  | throw new InvalidCastException( | 
|  | "Supplied properties in parameter Properties must be of the same type as T (or an assignable type from T"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int col = _fromCol, | 
|  | row = _fromRow; | 
|  | if (members.Length > 0 && printHeaders) { | 
|  | foreach (var t in members) { | 
|  | var descriptionAttribute = | 
|  | t.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() | 
|  | as DescriptionAttribute; | 
|  | var header = string.Empty; | 
|  | if (descriptionAttribute != null) { | 
|  | header = descriptionAttribute.Description; | 
|  | } else { | 
|  | var displayNameAttribute = | 
|  | t.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault() | 
|  | as DisplayNameAttribute; | 
|  | if (displayNameAttribute != null) { | 
|  | header = displayNameAttribute.DisplayName; | 
|  | } else { | 
|  | header = t.Name.Replace('_', ' '); | 
|  | } | 
|  | } | 
|  | _worksheet._values.SetValue(row, col++, header); | 
|  | } | 
|  | row++; | 
|  | } | 
|  |  | 
|  | if (!collection.Any() && (members.Length == 0 || printHeaders == false)) { | 
|  | return null; | 
|  | } | 
|  |  | 
|  | if (members.Length == 0) { | 
|  | foreach (var item in collection) { | 
|  | _worksheet.Cells[row++, col].Value = item; | 
|  | } | 
|  | } else { | 
|  | foreach (var item in collection) { | 
|  | col = _fromCol; | 
|  | if (item is string || item is decimal || item is DateTime || item.GetType().IsPrimitive) { | 
|  | _worksheet.Cells[row, col++].Value = item; | 
|  | } else { | 
|  | foreach (var t in members) { | 
|  | if (t is PropertyInfo) { | 
|  | _worksheet.Cells[row, col++].Value = ((PropertyInfo)t).GetValue(item, null); | 
|  | } else if (t is FieldInfo) { | 
|  | _worksheet.Cells[row, col++].Value = ((FieldInfo)t).GetValue(item); | 
|  | } else if (t is MethodInfo) { | 
|  | _worksheet.Cells[row, col++].Value = ((MethodInfo)t).Invoke(item, null); | 
|  | } | 
|  | } | 
|  | } | 
|  | row++; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (_fromRow == row - 1 && printHeaders) { | 
|  | row++; | 
|  | } | 
|  |  | 
|  | var r = _worksheet.Cells[_fromRow, _fromCol, row - 1, members.Length == 0 ? col : col - 1]; | 
|  |  | 
|  | if (tableStyle != TableStyles.None) { | 
|  | var tbl = _worksheet.Tables.Add(r, ""); | 
|  | tbl.ShowHeader = printHeaders; | 
|  | tbl.TableStyle = tableStyle; | 
|  | } | 
|  | return r; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads a CSV text into a range starting from the top left cell. | 
|  | /// Default settings is Comma separation | 
|  | /// </summary> | 
|  | /// <param name="text">The Text</param> | 
|  | /// <returns>The range containing the data</returns> | 
|  | public ExcelRangeBase LoadFromText(string text) { | 
|  | return LoadFromText(text, new()); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads a CSV text into a range starting from the top left cell. | 
|  | /// </summary> | 
|  | /// <param name="text">The Text</param> | 
|  | /// <param name="format">Information how to load the text</param> | 
|  | /// <returns>The range containing the data</returns> | 
|  | public ExcelRangeBase LoadFromText(string text, ExcelTextFormat format) { | 
|  | if (string.IsNullOrEmpty(text)) { | 
|  | var r = _worksheet.Cells[_fromRow, _fromCol]; | 
|  | r.Value = ""; | 
|  | return r; | 
|  | } | 
|  |  | 
|  | if (format == null) { | 
|  | format = new(); | 
|  | } | 
|  |  | 
|  | string splitRegex = String.Format( | 
|  | "{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*[^{1}]*$)", | 
|  | format.EOL, | 
|  | format.TextQualifier); | 
|  | string[] lines = Regex.Split(text, splitRegex); | 
|  | int row = _fromRow; | 
|  | int col = _fromCol; | 
|  | int maxCol = col; | 
|  | int lineNo = 1; | 
|  | foreach (string line in lines) { | 
|  | if (lineNo > format.SkipLinesBeginning && lineNo <= lines.Length - format.SkipLinesEnd) { | 
|  | col = _fromCol; | 
|  | string v = ""; | 
|  | bool isText = false, | 
|  | isQualifier = false; | 
|  | int qCount = 0; | 
|  | int lineQCount = 0; | 
|  | foreach (char c in line) { | 
|  | if (format.TextQualifier != 0 && c == format.TextQualifier) { | 
|  | if (!isText && v != "") { | 
|  | throw (new(string.Format("Invalid Text Qualifier in line : {0}", line))); | 
|  | } | 
|  | isQualifier = !isQualifier; | 
|  | qCount += 1; | 
|  | lineQCount++; | 
|  | isText = true; | 
|  | } else { | 
|  | if (qCount > 1 && !string.IsNullOrEmpty(v)) { | 
|  | v += new string(format.TextQualifier, qCount / 2); | 
|  | } else if (qCount > 2 && string.IsNullOrEmpty(v)) { | 
|  | v += new string(format.TextQualifier, (qCount - 1) / 2); | 
|  | } | 
|  |  | 
|  | if (isQualifier) { | 
|  | v += c; | 
|  | } else { | 
|  | if (c == format.Delimiter) { | 
|  | _worksheet.SetValue(row, col, ConvertData(format, v, col - _fromCol, isText)); | 
|  | v = ""; | 
|  | isText = false; | 
|  | col++; | 
|  | } else { | 
|  | if (qCount % 2 == 1) { | 
|  | throw (new(string.Format("Text delimiter is not closed in line : {0}", line))); | 
|  | } | 
|  | v += c; | 
|  | } | 
|  | } | 
|  | qCount = 0; | 
|  | } | 
|  | } | 
|  | if (qCount > 1) { | 
|  | v += new string(format.TextQualifier, qCount / 2); | 
|  | } | 
|  | if (lineQCount % 2 == 1) { | 
|  | throw (new(string.Format("Text delimiter is not closed in line : {0}", line))); | 
|  | } | 
|  |  | 
|  | _worksheet._values.SetValue(row, col, ConvertData(format, v, col - _fromCol, isText)); | 
|  | if (col > maxCol) { | 
|  | maxCol = col; | 
|  | } | 
|  | row++; | 
|  | } | 
|  | lineNo++; | 
|  | } | 
|  | return _worksheet.Cells[_fromRow, _fromCol, row - 1, maxCol]; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads a CSV text into a range starting from the top left cell. | 
|  | /// </summary> | 
|  | /// <param name="text">The Text</param> | 
|  | /// <param name="format">Information how to load the text</param> | 
|  | /// <param name="tableStyle">Create a table with this style</param> | 
|  | /// <param name="firstRowIsHeader">Use the first row as header</param> | 
|  | /// <returns></returns> | 
|  | public ExcelRangeBase LoadFromText( | 
|  | string text, | 
|  | ExcelTextFormat format, | 
|  | TableStyles tableStyle, | 
|  | bool firstRowIsHeader) { | 
|  | var r = LoadFromText(text, format); | 
|  |  | 
|  | var tbl = _worksheet.Tables.Add(r, ""); | 
|  | tbl.ShowHeader = firstRowIsHeader; | 
|  | tbl.TableStyle = tableStyle; | 
|  |  | 
|  | return r; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads a CSV file into a range starting from the top left cell. | 
|  | /// </summary> | 
|  | /// <param name="textFile">The Textfile</param> | 
|  | /// <returns></returns> | 
|  | public ExcelRangeBase LoadFromText(FileInfo textFile) { | 
|  | return LoadFromText(File.ReadAllText(textFile.FullName, Encoding.ASCII)); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads a CSV file into a range starting from the top left cell. | 
|  | /// </summary> | 
|  | /// <param name="textFile">The Textfile</param> | 
|  | /// <param name="format">Information how to load the text</param> | 
|  | /// <returns></returns> | 
|  | public ExcelRangeBase LoadFromText(FileInfo textFile, ExcelTextFormat format) { | 
|  | return LoadFromText(File.ReadAllText(textFile.FullName, format.Encoding), format); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Loads a CSV file into a range starting from the top left cell. | 
|  | /// </summary> | 
|  | /// <param name="textFile">The Textfile</param> | 
|  | /// <param name="format">Information how to load the text</param> | 
|  | /// <param name="tableStyle">Create a table with this style</param> | 
|  | /// <param name="firstRowIsHeader">Use the first row as header</param> | 
|  | /// <returns></returns> | 
|  | public ExcelRangeBase LoadFromText( | 
|  | FileInfo textFile, | 
|  | ExcelTextFormat format, | 
|  | TableStyles tableStyle, | 
|  | bool firstRowIsHeader) { | 
|  | return LoadFromText( | 
|  | File.ReadAllText(textFile.FullName, format.Encoding), | 
|  | format, | 
|  | tableStyle, | 
|  | firstRowIsHeader); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Get the strongly typed value of the cell. | 
|  | /// </summary> | 
|  | /// <typeparam name="T">The type</typeparam> | 
|  | /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns> | 
|  | public T GetValue<T>() { | 
|  | return _worksheet.GetTypedValue<T>(Value); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Get a range with an offset from the top left cell. | 
|  | /// The new range has the same dimensions as the current range | 
|  | /// </summary> | 
|  | /// <param name="rowOffset">Row Offset</param> | 
|  | /// <param name="columnOffset">Column Offset</param> | 
|  | /// <returns></returns> | 
|  | public ExcelRangeBase Offset(int rowOffset, int columnOffset) { | 
|  | if (_fromRow + rowOffset < 1 | 
|  | || _fromCol + columnOffset < 1 | 
|  | || _fromRow + rowOffset > ExcelPackage.MaxRows | 
|  | || _fromCol + columnOffset > ExcelPackage.MaxColumns) { | 
|  | throw (new ArgumentOutOfRangeException("Offset value out of range")); | 
|  | } | 
|  | string address = GetAddress( | 
|  | _fromRow + rowOffset, | 
|  | _fromCol + columnOffset, | 
|  | _toRow + rowOffset, | 
|  | _toCol + columnOffset); | 
|  | return new(_worksheet, address); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Get a range with an offset from the top left cell. | 
|  | /// </summary> | 
|  | /// <param name="rowOffset">Row Offset</param> | 
|  | /// <param name="columnOffset">Column Offset</param> | 
|  | /// <param name="numberOfRows">Number of rows. Minimum 1</param> | 
|  | /// <param name="numberOfColumns">Number of colums. Minimum 1</param> | 
|  | /// <returns></returns> | 
|  | public ExcelRangeBase Offset( | 
|  | int rowOffset, | 
|  | int columnOffset, | 
|  | int numberOfRows, | 
|  | int numberOfColumns) { | 
|  | if (numberOfRows < 1 || numberOfColumns < 1) { | 
|  | throw (new("Number of rows/columns must be greater than 0")); | 
|  | } | 
|  | numberOfRows--; | 
|  | numberOfColumns--; | 
|  | if (_fromRow + rowOffset < 1 | 
|  | || _fromCol + columnOffset < 1 | 
|  | || _fromRow + rowOffset > ExcelPackage.MaxRows | 
|  | || _fromCol + columnOffset > ExcelPackage.MaxColumns | 
|  | || _fromRow + rowOffset + numberOfRows < 1 | 
|  | || _fromCol + columnOffset + numberOfColumns < 1 | 
|  | || _fromRow + rowOffset + numberOfRows > ExcelPackage.MaxRows | 
|  | || _fromCol + columnOffset + numberOfColumns > ExcelPackage.MaxColumns) { | 
|  | throw (new ArgumentOutOfRangeException("Offset value out of range")); | 
|  | } | 
|  | string address = GetAddress( | 
|  | _fromRow + rowOffset, | 
|  | _fromCol + columnOffset, | 
|  | _fromRow + rowOffset + numberOfRows, | 
|  | _fromCol + columnOffset + numberOfColumns); | 
|  | return new(_worksheet, address); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Adds a new comment for the range. | 
|  | /// If this range contains more than one cell, the top left comment is returned by the method. | 
|  | /// </summary> | 
|  | /// <param name="text"></param> | 
|  | /// <param name="author"></param> | 
|  | /// <returns>A reference comment of the top left cell</returns> | 
|  | public ExcelComment AddComment(string text, string author) { | 
|  | if (string.IsNullOrEmpty(author)) { | 
|  | author = Thread.CurrentPrincipal.Identity.Name; | 
|  | } | 
|  | //Check if any comments exists in the range and throw an exception | 
|  | _changePropMethod(Exists_Comment, null); | 
|  | //Create the comments | 
|  | _changePropMethod(Set_Comment, new[] { text, author }); | 
|  |  | 
|  | return _worksheet.Comments[new ExcelCellAddress(_fromRow, _fromCol)]; | 
|  | } | 
|  |  | 
|  | ///// <summary> | 
|  | ///// Copies the range of cells to an other range | 
|  | ///// </summary> | 
|  | ///// <param name="Destination">The start cell where the range will be copied.</param> | 
|  | public void Copy(ExcelRangeBase destination) { | 
|  | bool sameWorkbook = destination._worksheet.Workbook == _worksheet.Workbook; | 
|  | ExcelStyles sourceStyles = _worksheet.Workbook.Styles, | 
|  | styles = destination._worksheet.Workbook.Styles; | 
|  | Dictionary<int, int> styleCashe = new Dictionary<int, int>(); | 
|  |  | 
|  | //Clear all existing cells; | 
|  | int toRow = _toRow - _fromRow + 1, | 
|  | toCol = _toCol - _fromCol + 1; | 
|  |  | 
|  | string s = ""; | 
|  | int i = 0; | 
|  | object o = null; | 
|  | byte flag = 0; | 
|  | Uri hl = null; | 
|  | ExcelComment comment = null; | 
|  |  | 
|  | var cse = new CellsStoreEnumerator<object>( | 
|  | _worksheet._values, | 
|  | _fromRow, | 
|  | _fromCol, | 
|  | _toRow, | 
|  | _toCol); | 
|  | var copiedValue = new List<CopiedCell>(); | 
|  | while (cse.Next()) { | 
|  | var row = cse.Row; | 
|  | var col = cse.Column; //Issue 15070 | 
|  | var cell = new CopiedCell { | 
|  | Row = destination._fromRow + (row - _fromRow), | 
|  | Column = destination._fromCol + (col - _fromCol), | 
|  | Value = cse.Value, | 
|  | }; | 
|  |  | 
|  | //Destination._worksheet._values.SetValue(row, col, cse.Value); | 
|  |  | 
|  | if (_worksheet._types.Exists(row, col, ref s)) { | 
|  | //Destination._worksheet._types.SetValue(row, col,s); | 
|  | cell.Type = s; | 
|  | } | 
|  |  | 
|  | if (_worksheet._formulas.Exists(row, col, ref o)) { | 
|  | if (o is int) { | 
|  | // Destination._worksheet._formulas.SetValue(row, col, _worksheet.GetFormula(cse.Row, cse.Column));    //Shared formulas, set the formula per cell to simplify | 
|  | cell.Formula = _worksheet.GetFormula(cse.Row, cse.Column); | 
|  | } else { | 
|  | //Destination._worksheet._formulas.SetValue(row, col, o); | 
|  | cell.Formula = o; | 
|  | } | 
|  | } | 
|  | if (_worksheet._styles.Exists(row, col, ref i)) { | 
|  | if (sameWorkbook) { | 
|  | //Destination._worksheet._styles.SetValue(row, col, i); | 
|  | cell.StyleID = i; | 
|  | } else { | 
|  | if (styleCashe.ContainsKey(i)) { | 
|  | i = styleCashe[i]; | 
|  | } else { | 
|  | var oldStyleId = i; | 
|  | i = styles.CloneStyle(sourceStyles, i); | 
|  | styleCashe.Add(oldStyleId, i); | 
|  | } | 
|  | //Destination._worksheet._styles.SetValue(row, col, i); | 
|  | cell.StyleID = i; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (_worksheet._hyperLinks.Exists(row, col, ref hl)) { | 
|  | //Destination._worksheet._hyperLinks.SetValue(row, col, hl); | 
|  | cell.HyperLink = hl; | 
|  | } | 
|  |  | 
|  | if (_worksheet._commentsStore.Exists(row, col, ref comment)) { | 
|  | cell.Comment = comment; | 
|  | } | 
|  |  | 
|  | if (_worksheet._flags.Exists(row, col, ref flag)) { | 
|  | cell.Flag = flag; | 
|  | } | 
|  | copiedValue.Add(cell); | 
|  | } | 
|  |  | 
|  | //Copy styles with no cell value | 
|  | var cses = new CellsStoreEnumerator<int>( | 
|  | _worksheet._styles, | 
|  | _fromRow, | 
|  | _fromCol, | 
|  | _toRow, | 
|  | _toCol); | 
|  | while (cses.Next()) { | 
|  | if (!_worksheet._values.Exists(cses.Row, cses.Column)) { | 
|  | var row = destination._fromRow + (cses.Row - _fromRow); | 
|  | var col = destination._fromCol + (cses.Column - _fromCol); | 
|  | var cell = new CopiedCell { | 
|  | Row = row, | 
|  | Column = col, | 
|  | Value = null, | 
|  | }; | 
|  |  | 
|  | i = cses.Value; | 
|  | if (sameWorkbook) { | 
|  | cell.StyleID = i; | 
|  | } else { | 
|  | if (styleCashe.ContainsKey(i)) { | 
|  | i = styleCashe[i]; | 
|  | } else { | 
|  | var oldStyleId = i; | 
|  | i = styles.CloneStyle(sourceStyles, i); | 
|  | styleCashe.Add(oldStyleId, i); | 
|  | } | 
|  | //Destination._worksheet._styles.SetValue(row, col, i); | 
|  | cell.StyleID = i; | 
|  | } | 
|  | copiedValue.Add(cell); | 
|  | } | 
|  | } | 
|  | var copiedMergedCells = new Dictionary<int, ExcelAddress>(); | 
|  | //Merged cells | 
|  | var csem = new CellsStoreEnumerator<int>( | 
|  | _worksheet.MergedCells._cells, | 
|  | _fromRow, | 
|  | _fromCol, | 
|  | _toRow, | 
|  | _toCol); | 
|  | while (csem.Next()) { | 
|  | if (!copiedMergedCells.ContainsKey(csem.Value)) { | 
|  | var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[csem.Value]); | 
|  | if (Collide(adr) == eAddressCollition.Inside) { | 
|  | copiedMergedCells.Add( | 
|  | csem.Value, | 
|  | new( | 
|  | destination._fromRow + (adr.Start.Row - _fromRow), | 
|  | destination._fromCol + (adr.Start.Column - _fromCol), | 
|  | destination._fromRow + (adr.End.Row - _fromRow), | 
|  | destination._fromCol + (adr.End.Column - _fromCol))); | 
|  | } else { | 
|  | //Partial merge of the address ignore. | 
|  | copiedMergedCells.Add(csem.Value, null); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | destination._worksheet.MergedCells.Clear( | 
|  | new( | 
|  | destination._fromRow, | 
|  | destination._fromCol, | 
|  | destination._fromRow + toRow - 1, | 
|  | destination._fromCol + toCol - 1)); | 
|  |  | 
|  | destination._worksheet._values.Clear(destination._fromRow, destination._fromCol, toRow, toCol); | 
|  | destination._worksheet._formulas.Clear( | 
|  | destination._fromRow, | 
|  | destination._fromCol, | 
|  | toRow, | 
|  | toCol); | 
|  | destination._worksheet._styles.Clear(destination._fromRow, destination._fromCol, toRow, toCol); | 
|  | destination._worksheet._types.Clear(destination._fromRow, destination._fromCol, toRow, toCol); | 
|  | destination._worksheet._hyperLinks.Clear( | 
|  | destination._fromRow, | 
|  | destination._fromCol, | 
|  | toRow, | 
|  | toCol); | 
|  | destination._worksheet._flags.Clear(destination._fromRow, destination._fromCol, toRow, toCol); | 
|  | destination._worksheet._commentsStore.Clear( | 
|  | destination._fromRow, | 
|  | destination._fromCol, | 
|  | toRow, | 
|  | toCol); | 
|  |  | 
|  | foreach (var cell in copiedValue) { | 
|  | destination._worksheet._values.SetValue(cell.Row, cell.Column, cell.Value); | 
|  |  | 
|  | if (cell.Type != null) { | 
|  | destination._worksheet._types.SetValue(cell.Row, cell.Column, cell.Type); | 
|  | } | 
|  |  | 
|  | if (cell.StyleID != null) { | 
|  | destination._worksheet._styles.SetValue(cell.Row, cell.Column, cell.StyleID.Value); | 
|  | } | 
|  |  | 
|  | if (cell.Formula != null) { | 
|  | cell.Formula = UpdateFormulaReferences( | 
|  | cell.Formula.ToString(), | 
|  | destination._fromRow - _fromRow, | 
|  | destination._fromCol - _fromCol, | 
|  | 0, | 
|  | 0, | 
|  | true); | 
|  | destination._worksheet._formulas.SetValue(cell.Row, cell.Column, cell.Formula); | 
|  | } | 
|  | if (cell.HyperLink != null) { | 
|  | destination._worksheet._hyperLinks.SetValue(cell.Row, cell.Column, cell.HyperLink); | 
|  | } | 
|  |  | 
|  | if (cell.Comment != null) { | 
|  | //Destination._worksheet._commentsStore.SetValue(cell.Row, cell.Column, cell.Comment); | 
|  | } | 
|  | if (cell.Flag != 0) { | 
|  | destination._worksheet._flags.SetValue(cell.Row, cell.Column, cell.Flag); | 
|  | } | 
|  | } | 
|  |  | 
|  | //Add merged cells | 
|  | foreach (var m in copiedMergedCells.Values) { | 
|  | if (m != null) { | 
|  | destination._worksheet.MergedCells.Add(m, true); | 
|  | } | 
|  | } | 
|  |  | 
|  | //Clone the cell | 
|  | //var copiedCell = (_worksheet._cells[GetCellID(_worksheet.SheetID, cell._fromRow, cell.column)] as ExcelCell); | 
|  |  | 
|  | //var newCell = copiedCell.Clone(Destination._worksheet, | 
|  | //        Destination._fromRow + (copiedCell.Row - _fromRow), | 
|  | //        Destination.column + (copiedCell.Column - column)); | 
|  |  | 
|  | //        newCell.MergeId = _worksheet.GetMergeCellId(copiedCell.Row, copiedCell.Column); | 
|  |  | 
|  | //        if (!string.IsNullOrEmpty(newCell.Formula)) | 
|  | //        { | 
|  | //            newCell.Formula = ExcelCell.UpdateFormulaReferences(newCell.Formula, newCell.Row - copiedCell.Row, (newCell.Column - copiedCell.Column), 1, 1); | 
|  | //        } | 
|  |  | 
|  | //        //If its not the same workbook we must copy the styles to the new workbook. | 
|  | //        if (!sameWorkbook) | 
|  | //        { | 
|  | //            if (styleCashe.ContainsKey(cell.StyleID)) | 
|  | //            { | 
|  | //                newCell.StyleID = styleCashe[cell.StyleID]; | 
|  | //            } | 
|  | //            else | 
|  | //            { | 
|  | //                newCell.StyleID = styles.CloneStyle(sourceStyles, cell.StyleID); | 
|  | //                styleCashe.Add(cell.StyleID, newCell.StyleID); | 
|  | //            } | 
|  | //        } | 
|  | //        newCells.Add(newCell); | 
|  | //        if (newCell.Merge) mergedCells.Add(newCell.CellID, newCell); | 
|  | //    } | 
|  |  | 
|  | //    //Now clear the destination. | 
|  | //    Destination.Offset(0, 0, (_toRow - _fromRow) + 1, (_toCol - column) + 1).Clear(); | 
|  |  | 
|  | //    //And last add the new cells to the worksheet | 
|  | //    foreach (var cell in newCells) | 
|  | //    { | 
|  | //        Destination.Worksheet._cells.Add(cell); | 
|  | //    } | 
|  | //    //Add merged cells | 
|  | //    if (mergedCells.Count > 0) | 
|  | //    { | 
|  | //        List<ExcelAddressBase> mergedAddresses = new List<ExcelAddressBase>(); | 
|  | //        foreach (var cell in mergedCells.Values) | 
|  | //        { | 
|  | //            if (!IsAdded(cell, mergedAddresses)) | 
|  | //            { | 
|  | //                int startRow = cell.Row, startCol = cell.Column, endRow = cell.Row, endCol = cell.Column + 1; | 
|  | //                while (mergedCells.ContainsKey(ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol))) | 
|  | //                { | 
|  | //                    ExcelCell next = mergedCells[ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)]; | 
|  | //                    if (cell.MergeId != next.MergeId) | 
|  | //                    { | 
|  | //                        break; | 
|  | //                    } | 
|  | //                    endCol++; | 
|  | //                } | 
|  |  | 
|  | //                while (IsMerged(mergedCells, Destination.Worksheet, endRow, startCol, endCol - 1, cell)) | 
|  | //                { | 
|  | //                    endRow++; | 
|  | //                } | 
|  |  | 
|  | //                mergedAddresses.Add(new ExcelAddressBase(startRow, startCol, endRow - 1, endCol - 1)); | 
|  | //            } | 
|  | //        } | 
|  | //        Destination.Worksheet.MergedCells.List.AddRange((from r in mergedAddresses select r.Address)); | 
|  | //    } | 
|  | //} | 
|  |  | 
|  | //private bool IsAdded(ExcelCell cell, List<ExcelAddressBase> mergedAddresses) | 
|  | //{ | 
|  | //    foreach (var address in mergedAddresses) | 
|  | //    { | 
|  | //        if (address.Collide(new ExcelAddressBase(cell.CellAddress)) == eAddressCollition.Inside) | 
|  | //        { | 
|  | //            return true; | 
|  | //        } | 
|  | //    } | 
|  | //    return false; | 
|  | //} | 
|  |  | 
|  | //private bool IsMerged(Dictionary<ulong, ExcelCell> mergedCells, ExcelWorksheet worksheet, int row, int startCol, int endCol, ExcelCell cell) | 
|  | //{ | 
|  | //    for (int col = startCol; col <= endCol; col++) | 
|  | //    { | 
|  | //        if (!mergedCells.ContainsKey(ExcelCell.GetCellID(worksheet.SheetID, row, col))) | 
|  | //        { | 
|  | //            return false; | 
|  | //        } | 
|  | //        else | 
|  | //        { | 
|  | //            ExcelCell next = mergedCells[ExcelCell.GetCellID(worksheet.SheetID, row, col)]; | 
|  | //            if (cell.MergeId != next.MergeId) | 
|  | //            { | 
|  | //                return false; | 
|  | //            } | 
|  | //        } | 
|  | //    } | 
|  | //    return true; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Clear all cells | 
|  | /// </summary> | 
|  | public void Clear() { | 
|  | Delete(this, false); | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// Creates an array-formula. | 
|  | /// </summary> | 
|  | /// <param name="arrayFormula">The formula</param> | 
|  | public void CreateArrayFormula(string arrayFormula) { | 
|  | if (Addresses != null) { | 
|  | throw (new("An Arrayformula can not have more than one address")); | 
|  | } | 
|  | Set_SharedFormula(arrayFormula, this, true); | 
|  | } | 
|  |  | 
|  | //private void Clear(ExcelAddressBase Range) | 
|  | //{ | 
|  | //    Clear(Range, true); | 
|  | //} | 
|  | internal void Delete(ExcelAddressBase range, bool shift) { | 
|  | //DeleteCheckMergedCells(Range); | 
|  | _worksheet.MergedCells.Clear(range); | 
|  | //First find the start cell | 
|  | int fromRow, | 
|  | fromCol; | 
|  | var d = Worksheet.Dimension; | 
|  | if (d != null | 
|  | && range._fromRow <= d._fromRow | 
|  | && range._toRow | 
|  | >= d._toRow) //EntireRow? | 
|  | { | 
|  | fromRow = 0; | 
|  | } else { | 
|  | fromRow = range._fromRow; | 
|  | } | 
|  | if (d != null | 
|  | && range._fromCol <= d._fromCol | 
|  | && range._toCol | 
|  | >= d._toCol) //EntireRow? | 
|  | { | 
|  | fromCol = 0; | 
|  | } else { | 
|  | fromCol = range._fromCol; | 
|  | } | 
|  |  | 
|  | var rows = range._toRow - fromRow + 1; | 
|  | var cols = range._toCol - fromCol + 1; | 
|  |  | 
|  | _worksheet._values.Delete(fromRow, fromCol, rows, cols, shift); | 
|  | _worksheet._types.Delete(fromRow, fromCol, rows, cols, shift); | 
|  | _worksheet._styles.Delete(fromRow, fromCol, rows, cols, shift); | 
|  | _worksheet._formulas.Delete(fromRow, fromCol, rows, cols, shift); | 
|  | _worksheet._hyperLinks.Delete(fromRow, fromCol, rows, cols, shift); | 
|  | _worksheet._flags.Delete(fromRow, fromCol, rows, cols, shift); | 
|  | _worksheet._commentsStore.Delete(fromRow, fromCol, rows, cols, shift); | 
|  |  | 
|  | //if(shift) | 
|  | //{ | 
|  | //    _worksheet.AdjustFormulasRow(fromRow, rows); | 
|  | //} | 
|  |  | 
|  | //Clear multi addresses as well | 
|  | if (Addresses != null) { | 
|  | foreach (var sub in Addresses) { | 
|  | Delete(sub, shift); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | private void DeleteCheckMergedCells(ExcelAddressBase range) { | 
|  | var removeItems = new List<string>(); | 
|  | foreach (var addr in Worksheet.MergedCells) { | 
|  | var addrCol = range.Collide(new ExcelAddress(range.WorkSheet, addr)); | 
|  | if (addrCol != eAddressCollition.No) { | 
|  | if (addrCol == eAddressCollition.Inside) { | 
|  | removeItems.Add(addr); | 
|  | } else { | 
|  | throw (new InvalidOperationException( | 
|  | "Can't remove/overwrite a part of cells that are merged")); | 
|  | } | 
|  | } | 
|  | } | 
|  | foreach (var item in removeItems) { | 
|  | Worksheet.MergedCells.Remove(item); | 
|  | } | 
|  | } | 
|  |  | 
|  | public void Dispose() {} | 
|  |  | 
|  | //int _index; | 
|  | //ulong _toCellId; | 
|  | //int _enumAddressIx; | 
|  | private CellsStoreEnumerator<object> cellEnum; | 
|  |  | 
|  | public IEnumerator<ExcelRangeBase> GetEnumerator() { | 
|  | Reset(); | 
|  | return this; | 
|  | } | 
|  |  | 
|  | IEnumerator IEnumerable.GetEnumerator() { | 
|  | Reset(); | 
|  | return this; | 
|  | } | 
|  |  | 
|  | /// <summary> | 
|  | /// The current range when enumerating | 
|  | /// </summary> | 
|  | public ExcelRangeBase Current => new(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column)); | 
|  |  | 
|  | /// <summary> | 
|  | /// The current range when enumerating | 
|  | /// </summary> | 
|  | object IEnumerator.Current => | 
|  | new ExcelRangeBase(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column)); | 
|  |  | 
|  | private int _enumAddressIx = -1; | 
|  |  | 
|  | public bool MoveNext() { | 
|  | if (cellEnum.Next()) { | 
|  | return true; | 
|  | } | 
|  | if (_addresses != null) { | 
|  | _enumAddressIx++; | 
|  | if (_enumAddressIx < _addresses.Count) { | 
|  | cellEnum = new( | 
|  | _worksheet._values, | 
|  | _addresses[_enumAddressIx]._fromRow, | 
|  | _addresses[_enumAddressIx]._fromCol, | 
|  | _addresses[_enumAddressIx]._toRow, | 
|  | _addresses[_enumAddressIx]._toCol); | 
|  | return MoveNext(); | 
|  | } | 
|  | return false; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | public void Reset() { | 
|  | _enumAddressIx = -1; | 
|  | cellEnum = new(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol); | 
|  | } | 
|  |  | 
|  | //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol) | 
|  | //{ | 
|  | //    if (_index >= _worksheet._cells.Count) return; | 
|  | //    ExcelCell cell = _worksheet._cells[_index] as ExcelCell; | 
|  | //    while (cell.Column > toCol || cell.Column < fromCol) | 
|  | //    { | 
|  | //        if (cell.Column < fromCol) | 
|  | //        { | 
|  | //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol)); | 
|  | //        } | 
|  | //        else | 
|  | //        { | 
|  | //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol)); | 
|  | //        } | 
|  |  | 
|  | //        if (_index < 0) | 
|  | //        { | 
|  | //            _index = ~_index; | 
|  | //        } | 
|  | //        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId) | 
|  | //        { | 
|  | //            break; | 
|  | //        } | 
|  | //        cell = _worksheet._cells[_index] as ExcelCell; | 
|  | //    } | 
|  | //} | 
|  |  | 
|  | //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol) | 
|  | //{ | 
|  | //    _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol)); | 
|  | //    _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol); | 
|  | //    if (_index < 0) | 
|  | //    { | 
|  | //        _index = ~_index; | 
|  | //    } | 
|  | //    _index--; | 
|  | //} | 
|  | } |