I am trying to programmatically group (shift select) sheets in Excel using Open XML API. I know how to do it in Interop way like:
String[] sheetsToBeSelected = {"Sheet1","Sheet2","Sheet3"};
excel.Workbook workbook = ExcelApp.ActiveWorkbook;
excel.Sheets worksheets = workbook.Worksheets;
((excel.Sheets)worksheets.get_Item(sheetsToBeSelected)).Select();
Tried hard to translate it to Open XML API, but no luck. Please help.
Thanks.
Try setting the TabSelected property of SheetView. Here is the sample code
foreach(Sheet sht in myWorkBook.WorkBook.Descendants<Sheet>())
{
WorkSheetPart wrkShtPart = (WorkSheetPart)myWorkBook.GetPartById(sht.Id);
SheetViews shtViews = wrkShtPart.WorkSheet.GetFirstChild<SheetViews>();
SheetView shtView = shtViews.GetFirstChild<SheetView>();
shtView.TabSelected = null;
}
Related
I am trying to embed object into .xlsx document and copy sheets with embedded objects.
1. Copying sheets
This looks like straight forward issue. I have created method to copy the sheets:
static void CopySheetInsideWorkbook(string filename, string sheetName, string clonedSheetName)
{
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filename, true))
{
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
WorksheetPart sourceSheetPart = GetWorksheetPartByName(spreadsheetDocument, sheetName);
SpreadsheetDocument tempSheet =
SpreadsheetDocument.Create(new MemoryStream(), spreadsheetDocument.DocumentType);
WorkbookPart tempWorkbookPart = tempSheet.AddWorkbookPart();
WorksheetPart tempWorksheetPart = tempWorkbookPart.AddPart<WorksheetPart>(sourceSheetPart);
WorksheetPart clonedSheet = workbookPart.AddPart<WorksheetPart>(tempWorksheetPart);
Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
Sheet copiedSheet = new Sheet
{
Name = clonedSheetName,
Id = workbookPart.GetIdOfPart(clonedSheet),
SheetId = (uint) sheets.ChildElements.Count + 1
};
sheets.Append(copiedSheet);
workbookPart.Workbook.Save();
}
}
The ouput is as expected but the embedded files are copied as "Picture" rather than "Object". I unzipped .xlsx file and all looks legit ie. similar to the sheet I copied. Yet still the file cannot be opened on the copied sheet. All images, strings are displayed in correct way.
2. Embedding the object
What I understand I need to do is:
Convert object into oleObject - this will be separate fun.
Add DrawingsPart - It looks like it's read-only and I can only add ImagePart.
Embed Object
Connect both drawing and embedded object part toghether and allocate to some range in spreadsheet.
static void EmbedFileXlsx(string path, string embeddedFilePath, string placeholderImagePath)
{
using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(path, true))
{
WorksheetPart sourceSheetPart = GetWorksheetPartByName(spreadsheetDocument, "Test");
var imagePart = sourceSheetPart.AddImagePart(ImagePartType.Emf, "rId1");
imagePart.FeedData(File.Open(placeholderImagePath, FileMode.Open));
var embeddedObject =
sourceSheetPart.AddEmbeddedObjectPart(#"application/vnd.openxmlformats-officedocument.oleObject");
embeddedObject.FeedData(File.Open(embeddedFilePath, FileMode.Open));
spreadsheetDocument.Save();
}
}
This code just adds embedded objects into the file but does not create any type of relationship between them. This means that file is not visible on the spreadsheet.
I tried copying sheets using ClosedXML as well but unfortunately this is not supported nor the embedding.
I also managed to understand how I can copy sheet into new document with all embedded objects using .xml files inside spreadsheet but I do not think this would be much productive and I would like to achieve this using all the methods inside OpenXML. It looks everything is there but something is amiss.
I am no expert in this, but could this help you on your way?
spreadsheetDocument.CreateRelationshipToPart(SOME ID);
How do I convert a particular sheet to CSV from Excel using C# Interop? Does it default to the first sheet or can I specify?
This is the code i am using:
private void ConvertProgsToCSV()
{
Excel.Application app = new Excel.Application();
Excel.Workbook wb = app.Workbooks.Open(txtFname.Text);
wb.SaveAs(#"C:\Temp\output.csv", Excel.XlFileFormat.xlCSVWindows);
wb.Close(false);
app.Quit();
Console.WriteLine("Done!");
}
You have to open worksheet by it's name and Select it using Select() function:
xlSheet = (Excel.Worksheet)xlBook.Worksheets["Sheet1"];
xlSheet.Select(Type.Missing);
xlBook.SaveAs("C:\Filename.csv", Excel.XlFileFormat.xlCSV,Excel.XlSaveAsAccessMode.xlNoChange);
Assuming that xlSheet is of typeInterop.Excel.WorkSheet and xlBook is of type Interop.Excel.Workbook
You can refer to this links for more info:
How to: Programmatically Select Worksheets
Working with Worksheets
C# with Excel -- How to select a sheet?
I have had an issue for the last few hours trying to pull the sheet names from an excel workbook and display for selection in a combobox. I managed to get it to work but i'm a little concerned its crude and not very efficient.
private void btnChoose2_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openfileDialog1 = new OpenFileDialog();
if (openfileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
openLabel.Text = openfileDialog1.SafeFileName;
String filename = DialogResult.ToString();
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Visible = false;
excelApp.Workbooks.Open(openfileDialog1.FileName);
int rcountTag = excelApp.Sheets.Count - 1;
for (int i = 1; i <= rcountTag + 1; i++)
{
Microsoft.Office.Interop.Excel.Sheets excelSheets = excelApp.Worksheets;
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)
excelSheets.get_Item(i);
comboBoxMapping.Items.Insert(i - 1, worksheet.Name);
}
}
}
Any advice would be greatly appreciated.
You should look at using a 3rd party library for this that will make your life much easier than messing with interop.
Excel Data Reader
This will let you get all the sheet names and read data into a DataTable which then you can access however you want to get whatever data you need out of it. The GitHub Read Me page has simple examples that should solve your issue for you.
I would recommend EPPLUS if xlsx Excel format is to be dealt with.
Install epplus library from nuget package manager:
Then using OfficeOpenXml;
Get the list of sheet names:
ExcelPackage DocInv = new ExcelPackage(new FileInfo(ExcelDocument));
DocList = DocInv.Workbook.Worksheets.AsEnumerable().Select(x => x.Name).ToList();
using the example here How to Copy a Worksheet within a Workbook
I have successfully been able to clone/copy sheets in my excel file, however when I open the excel the 2nd sheet is the active(visible) sheet. I haven't been able to locate a property that could do thins.....Is there any way to specify what sheet is active?
I've tried to force it by opening and editing the first sheet in the file thinking it was the last edited sheet that was active but that didn't work either.
any help would be great. TIA
update: looking at the workbook.xml created when renaming the .xlsx to .zip I came accross the 'activeTab' property. made a quick change to my code and seems to work just fine
public void SetFirstSheetInFocus(String xlsxFile)
{
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(xlsxFile, true))
{
//Get a reference to access the main Workbook part, which contains all references
WorkbookPart _workbookPart = spreadSheet.WorkbookPart;
if (_workbookPart != null)
{
WorkbookView _workbookView = spreadSheet.WorkbookPart.Workbook.BookViews.ChildElements.First<WorkbookView>();
if (_workbookView != null)
{
_workbookView.ActiveTab = 0; // 0 for first or whatever tab you want to use
}
// Save the workbook.
_workbookPart.Workbook.Save();
}
}
}
If the name of your sheet is in the variable
sheetName
you can set the sheet with that name active like this:
using (var spreadsheetDoc = SpreadsheetDocument.Open(emptyHIPTemplatePath, true /* isEditable */, new OpenSettings { AutoSave = false }))
{
var workbookPart = spreadsheetDoc.WorkbookPart;
var workBook = spreadsheetDoc.WorkbookPart.Workbook;
var sheet = workBook.Descendants<Sheet>().FirstOrDefault(s => s.Name == sheetName);
var sheetIndex = workBook.Descendants<Sheet>().ToList().IndexOf(sheet);
var workBookView = workBook.Descendants<WorkbookView>().First();
workBookView.ActiveTab = Convert.ToUInt32(sheetIndex);
...
workBook.Save();
}
From Vincent Tan's book:
The SheetId property doesn't determine the order. The order of
appending the Sheet classes to the Sheets class, does.
When you add a sheet, it gets the next index, but a single sheet does not have an index. OpenXML gives it an index when you are done adding sheets. Again, from Vincent Tan's book:
Let's say you have 3 worksheets named Sheet1, Sheet2 and Sheet3.
However, when you appended the corresponding Sheet classes, you did it
as Sheet2, Sheet3 and Sheet1, in that order.
How can I find some value from cell and replace by new value in Excel?
I tryed this but it doesn't works:
Microsoft.Office.Interop.Excel.Application xlapp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wb =default(Microsoft.Office.Interop.Excel.Workbook);
wb = xlapp.Workbooks.Open(FileName.ToString());
wb.Worksheets[0].Cells.Replace("find","replace");
I would recommend you use NPOI which can be accessed either via codeplex or directly through Nuget in Visual Studio. It gives you the ability to easily upload, edit and create spreadsheets in .NET
Example of uploading a spreadsheet:
HSSFWorkbook hssfworkbook;
void InitializeWorkbook(string path)
{
//read the template via FileStream, it is suggested to use FileAccess.Read to prevent file lock.
//book1.xls is an Excel-2007-generated file, so some new unknown BIFF records are added.
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
{
hssfworkbook = new HSSFWorkbook(file);
}
}
You can then use the IRow and ICell collections of the spreadsheet to locate and edit the data you need before doing an export.
More examples can be found here
If interested, you can use GemBox.Spreadsheet for this, like so:
SpreadsheetInfo.SetLicense("FREE-LIMITED-KEY");
// Load your XLS, XLSX, ODS or CSV file.
ExcelFile wb = ExcelFile.Load(FileName.ToString());
ExcelWorksheet ws = wb.Worksheets[0];
// Replace all "find" occurances with "replace" text.
int row, column;
while(ws.Cells.FindText("find", out row, out column))
ws.Cells[row, column].ReplaceText("find", "replace");
// Save your XLS, XLSX, ODS or CSV file.
wb.Save(FileName.ToString());
Also you can find another searching in Excel example here.
All you have to do is replace
wb.Worksheets[0].Cells.Replace("find","replace");
with
wb.Worksheets[1].Cells.Replace("find","replace");