0

Update: it turns out it was the SaveToStream() method which saves all sheets instead of the the one, that was the confusing part which lead me to believe the sheet being returned wasn't right

Given the documentation on the CopyAfter() method, the return value is the newly copied sheet

So I wrote the first line of code, now commented out (see below).

The problem is, when I use the sheetWithValues variable from the return of the method, the code below it, does not work (ie The formulas are not replaced with values)

When I comment out the use of the returned value from CopyAfter() and substitute it with workbook.Worksheets[0] as done in the code below, it does work (ie the formulas in the sheet are replaced with values)

Given that experiment, it doesn't seem possible that the return value of CopyAfter() is actually returning the newly created sheet, it's returning something else.

So why does the return value of CopyAfter() not return what is obviously expected here? I really want to use the return value, because the alternative code below seems brittle and is unlikely to continue working if sheets are re-arranged.

The goal of the code BTW is simply to copy the entire sheet, with values, before exporting... shortly after this code, I take the copied sheet and stream it to PDF.

//var sheetWithValues = workbook.ActiveWorksheet.CopyAfter(workbook.ActiveWorksheet);
workbook.ActiveWorksheet.CopyAfter(workbook.ActiveWorksheet);
var sheetWithValues = workbook.Worksheets[0];  // no idea why this works and the return value does not
sheetWithValues.UsedRange.Value = sheetWithValues.UsedRange.Value
PandaWood
  • 8,086
  • 9
  • 49
  • 54
  • The CopyAfter method absolutely, without a doubt, will return the newly-copied sheet. This behavior is well-tested (I work for SpreadsheetGear and can confirm this), is used by thousands of developers, and nothing like this has ever been reported before. So, the problem must lie elsewhere. I see you use "ActiveWorksheet" which can change depending on what sheet is selected, whereas Worksheets[0] is more absolute in referring to a sheet via tab index position. Are you sure you are operating on correct sheets? A more complete test case would need to be provided to figure out what's going on. – Tim Andersen Apr 27 '22 at 13:40
  • Fair enough, and I'll still need to provide some more details in a test case, but this code, involving no other libraries but SG, is streaming all sheets in the document. It's a reference to a sheet returned by CopyBefore, yet it streams out the entire workbook (2 sheets) - how can that possibly be happening `var valuesOnly = (IWorksheet)workbook.ActiveWorksheet.CopyBefore(workbook.ActiveWorksheet); valuesOnly.Unprotect("pass"); valuesOnly.UsedRange.Value = valuesOnly.UsedRange.Value; using (var ms = new MemoryStream()) { valuesOnly.SaveToStream(ms, FileFormat.OpenXMLWorkbook); } ` – PandaWood May 04 '22 at 00:51
  • @TimAndersen So I guess this issue might be that `SaveToStream()` on a worksheet, still saves the entire workbook. Either by design or whatever. Is there a way to save just the worksheet to a stream, and not include the other sheets. I tried setting the other sheet Visible propery to VeryHidden, but that's just a UI visibility, so it doesn't work. If that's not possible, can I limit the PrintArea to only 1 page - couldn't see how – PandaWood May 04 '22 at 01:41

1 Answers1

1

Based on your follow-up comments, it sounds like the problem is with the expectation of IWorksheet.SaveToStream(...), or any of the other IWorksheet.Save*() methods.

These methods will only ever save just the specified IWorksheet when you are saving to a text-based data file format like FileFormat.CSV or UnicodeText (tab-delimited / *.txt). Saving to an Excel file format like FileFormat.OpenXMLWorkbook will result in the entire workbook (so all sheets) being saved, as there simply are too many potential interdependencies on other parts of a workbook to extract and save only one sheet (even if in your case you expect to only have simple values, and not any formulas referring to other sheets, defined names, etc.)

Right now, it looks like you are making a copy of your sheet in the same workbook as the source. In this case you should delete the source sheet prior to saving, which will leave the copied sheet. Do note that if this workbook has any other sheets, those will be persisted as well. You can delete a sheet via the ISheet.Delete() method.

If your source workbook does have a bunch of other sheets that you don't want persisted in your destination workbook, an alternative to copying in the same workbook would be to create a new workbook (Spreadsheet.Factory.GetWorkbook() method) and copy the source sheet into it, after or before the default "Sheet1" worksheet. You'd still need to delete the default "Sheet1" via the ISheet.Delete() method so that only your copied sheet remains.

Tim Andersen
  • 3,014
  • 1
  • 15
  • 11
  • Thanks yes, this did it. I went with the create new workbook method, I just have to close when I'm done. The tip on removing the default sheet is a good one, I didn't do that, but it worked anyway since I'm printing and it's empty, but probably should ```var tempWorkbook = Factory.GetWorkbook(); var sheetCopy = (IWorksheet) workbook.ActiveWorksheet.CopyBefore(tempWorkbook.ActiveWorksheet); sheetCopy.UsedRange.Value = sheetCopy.UsedRange.Value; using (var ms = new MemoryStream()) { sheetCopy.SaveToStream(ms, FileFormat.OpenXMLWorkbook); ``` – PandaWood May 09 '22 at 00:56