diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs index 7a49d70..7b35775 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs @@ -170,6 +170,8 @@ /// The comments for the named range. IXLCell AddToNamed(String rangeName, XLScope scope, String comment); - IXLCell CopyFrom(IXLCell otherCell); + //IXLCell CopyFrom(IXLCell otherCell); + + void CopyTo(IXLCell target); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs index 7e785a1..17892f9 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs @@ -280,6 +280,13 @@ private Boolean SetRange(Object rangeObject) { var asRange = rangeObject as XLRangeBase; + if (asRange == null) + { + var tmp = rangeObject as XLCell; + if (tmp != null) + asRange = tmp.AsRange() as XLRangeBase; + } + if (asRange != null) { Int32 maxRows; @@ -307,8 +314,8 @@ { var sourceCell = (XLCell)asRange.Cell(ro, co); var targetCell = (XLCell)worksheet.Cell(Address.RowNumber + ro - 1, Address.ColumnNumber + co - 1); - targetCell.CopyValues(sourceCell); - targetCell.Style = sourceCell.style; + targetCell.CopyFrom(sourceCell); + //targetCell.Style = sourceCell.style; } } var rangesToMerge = new List(); @@ -1538,5 +1545,10 @@ return retVal; } } + + public void CopyTo(IXLCell target) + { + target.Value = this; + } } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/IXLColumn.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/IXLColumn.cs index 81fabc8..fc595b0 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/IXLColumn.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/IXLColumn.cs @@ -149,5 +149,11 @@ void Expand(); Int32 CellCount(); + + void CopyTo(IXLCell target); + void CopyTo(IXLRangeBase target); + + void SetAutoFilter(); + void SetAutoFilter(Boolean autoFilter); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/IXLWorksheet.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/IXLWorksheet.cs index c2e1743..795c421 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/IXLWorksheet.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/IXLWorksheet.cs @@ -267,5 +267,7 @@ IXLSheetProtection Protect(String password); IXLSheetProtection Unprotect(); IXLSheetProtection Unprotect(String password); + + IXLRangeBase AutoFilterRange { get; set; } } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRange.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRange.cs index e509c5c..26fae12 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRange.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRange.cs @@ -217,6 +217,12 @@ IXLRange RangeUsed(); IXLRange SortBy(String columns); + + void CopyTo(IXLCell target); + void CopyTo(IXLRangeBase target); + + void SetAutoFilter(); + void SetAutoFilter(Boolean autoFilter); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeColumn.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeColumn.cs index c7701ce..acb0046 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeColumn.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeColumn.cs @@ -77,6 +77,12 @@ String ColumnLetter(); Int32 CellCount(); + + void CopyTo(IXLCell target); + void CopyTo(IXLRangeBase target); + + void SetAutoFilter(); + void SetAutoFilter(Boolean autoFilter); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeRow.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeRow.cs index 8bb3055..12d284c 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeRow.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/IXLRangeRow.cs @@ -84,6 +84,12 @@ Int32 RowNumber(); Int32 CellCount(); + + void CopyTo(IXLCell target); + void CopyTo(IXLRangeBase target); + + void SetAutoFilter(); + void SetAutoFilter(Boolean autoFilter); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeBase.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeBase.cs index cd33077..7f060e7 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeBase.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Ranges/XLRangeBase.cs @@ -1017,5 +1017,28 @@ return retVal; } } + + public void CopyTo(IXLRangeBase target) + { + CopyTo(target.FirstCell()); + } + + public void CopyTo(IXLCell target) + { + target.Value = this; + } + + public void SetAutoFilter() + { + SetAutoFilter(true); + } + + public void SetAutoFilter(Boolean autoFilter) + { + if (autoFilter) + Worksheet.AutoFilterRange = this; + else + Worksheet.AutoFilterRange = null; + } } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/IXLRow.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/IXLRow.cs index 7e1b2df..243907a 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/IXLRow.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/IXLRow.cs @@ -149,5 +149,11 @@ void Expand(); Int32 CellCount(); + + void CopyTo(IXLCell target); + void CopyTo(IXLRangeBase target); + + void SetAutoFilter(); + void SetAutoFilter(Boolean autoFilter); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/IXLTable.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/IXLTable.cs index a00f8d6..8c8a767 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/IXLTable.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Tables/IXLTable.cs @@ -121,5 +121,8 @@ /// /// The rows to return. new IXLTableRows Rows(string rows); + + void CopyTo(IXLCell target); + void CopyTo(IXLRangeBase target); } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook.cs index abe6bb5..b50a15a 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook.cs @@ -73,6 +73,7 @@ } private String originalFile; + private Stream originalStream; /// /// Opens an existing workbook from a file. /// @@ -92,6 +93,7 @@ : this() { loadSource = XLLoadSource.Stream; + originalStream = stream; Load(stream); } @@ -131,9 +133,9 @@ public void Save() { if (loadSource == XLLoadSource.New) - throw new Exception("This is a new file, please use one of the SaveAs method."); + throw new Exception("This is a new file, please use one of the SaveAs methods."); else if (loadSource == XLLoadSource.Stream) - throw new Exception("The file was loaded from a stream, please use one of the SaveAs method."); + CreatePackage(originalStream, false); else CreatePackage(originalFile); } @@ -142,21 +144,72 @@ /// public void SaveAs(String file) { - if (originalFile == null) - File.Delete(file); - else if (originalFile.Trim().ToLower() != file.Trim().ToLower()) - File.Copy(originalFile, file, true); + if (loadSource == XLLoadSource.New) + { + if (File.Exists(file)) + File.Delete(file); - CreatePackage(file); + CreatePackage(file); + } + else if (loadSource == XLLoadSource.File) + { + if (originalFile.Trim().ToLower() != file.Trim().ToLower()) + File.Copy(originalFile, file, true); + + CreatePackage(file); + } + else if (loadSource == XLLoadSource.Stream) + { + originalStream.Position = 0; + + using (var fileStream = File.Create(file)) + { + CopyStream(originalStream, fileStream); + //fileStream.Position = 0; + CreatePackage(fileStream, false); + fileStream.Close(); + } + } } /// /// Saves the current workbook to a stream. /// public void SaveAs(Stream stream) { - CreatePackage(stream); + if (loadSource == XLLoadSource.New) + { + CreatePackage(stream, true); + } + else if (loadSource == XLLoadSource.File) + { + using (var fileStream = new FileStream(originalFile, FileMode.Open)) + { + CopyStream(fileStream, stream); + fileStream.Close(); + } + CreatePackage(stream, false); + } + else if (loadSource == XLLoadSource.Stream) + { + originalStream.Position = 0; + if (originalStream != stream) + CopyStream(originalStream, stream); + + CreatePackage(stream, false); + } } + internal void CopyStream(Stream input, Stream output) + { + byte[] buffer = new byte[8 * 1024]; + int len; + while ((len = input.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, len); + } + } + + /// /// Gets or sets the default style for the workbook. /// All new worksheets will use this style. diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs index 0c3e486..9390c89 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs @@ -390,6 +390,8 @@ } #endregion + LoadAutoFilter(worksheetPart, ws); + LoadSheetProtection(worksheetPart, ws); LoadDataValidations(worksheetPart, ws); @@ -481,6 +483,16 @@ return XLCellValues.Text; } + private void LoadAutoFilter(WorksheetPart worksheetPart, XLWorksheet ws) + { + var autoFilterQuery = worksheetPart.Worksheet.Descendants(); + if (autoFilterQuery.Count() > 0) + { + var af = (AutoFilter)autoFilterQuery.First(); + ws.Range(af.Reference.Value).SetAutoFilter(); + } + } + private void LoadSheetProtection(WorksheetPart worksheetPart, XLWorksheet ws) { var sheetProtectionQuery = worksheetPart.Worksheet.Descendants(); diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs index fd89dbd..0a5250e 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs @@ -332,9 +332,14 @@ } } - private void CreatePackage(Stream stream) + private void CreatePackage(Stream stream, Boolean newStream) { - SpreadsheetDocument package = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook); + SpreadsheetDocument package; + if (newStream) + package = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook); + else + package = SpreadsheetDocument.Open(stream, true); + using (package) { CreateParts(package); @@ -2070,6 +2075,27 @@ } #endregion + #region AutoFilter + if (xlWorksheet.AutoFilterRange != null) + { + if (worksheetPart.Worksheet.Elements().Count() == 0) + { + OpenXmlElement previousElement = cm.GetPreviousElementFor(XLWSContentManager.XLWSContents.AutoFilter); + worksheetPart.Worksheet.InsertAfter(new AutoFilter(), previousElement); + } + + var autoFilter = worksheetPart.Worksheet.Elements().First(); + cm.SetElement(XLWSContentManager.XLWSContents.AutoFilter, autoFilter); + + autoFilter.Reference = xlWorksheet.AutoFilterRange.RangeAddress.ToString(); + } + else + { + worksheetPart.Worksheet.RemoveAllChildren(); + cm.SetElement(XLWSContentManager.XLWSContents.AutoFilter, null); + } + #endregion + #region MergeCells MergeCells mergeCells = null; if (xlWorksheet.Internals.MergedRanges.Count() > 0) diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorksheet.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorksheet.cs index 6ff35f2..d687029 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorksheet.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorksheet.cs @@ -602,6 +602,9 @@ } } + if (this.AutoFilterRange != null) + ws.Range(this.AutoFilterRange.RangeAddress).SetAutoFilter(); + return ws; } @@ -699,6 +702,7 @@ { return Protection.Unprotect(password); } - + + public IXLRangeBase AutoFilterRange { get; set; } } } diff --git a/ClosedXML/ClosedXML/ClosedXML_Examples/ClosedXML_Examples.csproj b/ClosedXML/ClosedXML/ClosedXML_Examples/ClosedXML_Examples.csproj index efddf26..e7e95d6 100644 --- a/ClosedXML/ClosedXML/ClosedXML_Examples/ClosedXML_Examples.csproj +++ b/ClosedXML/ClosedXML/ClosedXML_Examples/ClosedXML_Examples.csproj @@ -90,6 +90,7 @@ + diff --git a/ClosedXML/ClosedXML/ClosedXML_Examples/Creating/CreateFiles.cs b/ClosedXML/ClosedXML/ClosedXML_Examples/Creating/CreateFiles.cs index 3065bf7..5c703dc 100644 --- a/ClosedXML/ClosedXML/ClosedXML_Examples/Creating/CreateFiles.cs +++ b/ClosedXML/ClosedXML/ClosedXML_Examples/Creating/CreateFiles.cs @@ -72,6 +72,7 @@ new DataValidation().Create(@"C:\Excel Files\Created\DataValidation.xlsx"); new HideSheets().Create(@"C:\Excel Files\Created\HideSheets.xlsx"); new SheetProtection().Create(@"C:\Excel Files\Created\SheetProtection.xlsx"); + new AutoFilter().Create(@"C:\Excel Files\Created\AutoFilter.xlsx"); } } } diff --git a/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AutoFilter.cs b/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AutoFilter.cs new file mode 100644 index 0000000..4532b08 --- /dev/null +++ b/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AutoFilter.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ClosedXML.Excel; + +using System.Drawing; + +namespace ClosedXML_Examples.Misc +{ + public class AutoFilter + { + #region Variables + + // Public + + // Private + + + #endregion + + #region Properties + + // Public + + // Private + + // Override + + + #endregion + + #region Events + + // Public + + // Private + + // Override + + + #endregion + + #region Methods + + // Public + public void Create(String filePath) + { + var wb = new XLWorkbook(); + var ws = wb.Worksheets.Add("AutoFilter"); + ws.Cell("A1").Value = "Names"; + ws.Cell("A2").Value = "John"; + ws.Cell("A3").Value = "Hank"; + ws.Cell("A4").Value = "Dagny"; + + ws.RangeUsed().SetAutoFilter(); + + // Your can turn off the autofilter in three ways: + // 1) worksheet.AutoFilterRange.SetAutoFilter(false) + // 2) worksheet.AutoFilterRange = null + // 3) Pick any range in the worksheet and call range.SetAutoFilter(false); + + wb.SaveAs(filePath); + } + + // Private + + // Override + + + #endregion + } +} diff --git a/ClosedXML/ClosedXML/ClosedXML_Sandbox/Program.cs b/ClosedXML/ClosedXML/ClosedXML_Sandbox/Program.cs index 32e70df..bceb144 100644 --- a/ClosedXML/ClosedXML/ClosedXML_Sandbox/Program.cs +++ b/ClosedXML/ClosedXML/ClosedXML_Sandbox/Program.cs @@ -14,14 +14,40 @@ { static void Main(string[] args) { - //var fileName = "DifferentKinds"; + //var fileName = "BasicTable"; //var fileName = "Sandbox"; - var fileName = "Issue_6375"; - var wb = new XLWorkbook(String.Format(@"c:\Excel Files\ForTesting\{0}.xlsx", fileName)); + var fileName = "Issue_6429"; + var sourceFile = new XLWorkbook(String.Format(@"c:\Excel Files\ForTesting\{0}.xlsm", fileName)); //var wb = new XLWorkbook(); - //wbSource.Worksheet(1).CopyTo(wb, "Sheet1"); - //String source = @"c:\Excel Files\Created\{0}.xlsx"; + + using (var tempStream = new FileStream(String.Format(@"c:\Excel Files\ForTesting\{0}_Saved.xlsm", fileName), FileMode.Create)) + { + sourceFile.SaveAs(tempStream); + } + sourceFile.SaveAs(@"c:\Excel Files\ForTesting\Issue_6429_FileToFile.xlsm"); + using (var stream = new FileStream(@"c:\Excel Files\ForTesting\Issue_6429_FileToStream.xlsm", FileMode.Create)) + { + sourceFile.SaveAs(stream); + } + + using (var stream = new FileStream( + String.Format(@"c:\Excel Files\ForTesting\{0}.xlsm", fileName), FileMode.Open)) + { + var sourceStream = new XLWorkbook(stream); + sourceStream.SaveAs(@"c:\Excel Files\ForTesting\Issue_6429_StreamToFile.xlsm"); + + using (var stream2 = new FileStream(@"c:\Excel Files\ForTesting\Issue_6429_StreamToStream.xlsm", FileMode.Create)) + { + sourceStream.SaveAs(stream2); + } + } + + //var ws = wb.Worksheet(1); + //var table = ws.RangeUsed(); + //var newColumn = table.Column(1).InsertColumnsAfter(1).Single(); + //table.Column(1).CopyTo(newColumn); + //newColumn.SetAutoFilter(); //CopyWorksheets(String.Format(source, "UsingTables"), wb); //CopyWorksheets(String.Format(source, "NamedRanges"), wb); @@ -35,7 +61,7 @@ //CopyWorksheets(String.Format(source, "DataValidation"), wb); //CopyWorksheets(String.Format(source, "Hyperlinks"), wb); - wb.SaveAs(String.Format(@"c:\Excel Files\ForTesting\{0}_Saved.xlsx", fileName)); + //wb.SaveAs(String.Format(@"c:\Excel Files\ForTesting\{0}_Saved.xlsm", fileName)); } static void CopyWorksheets(String source, XLWorkbook target)