Select specific cell in Excel and go to next row - c#

Using C# how can I "jump" to a specific cell in an Excel spreadsheet and go to the next row? I need to populate an existing spreadsheet with data from a list. This is how I thought it would work:
Globals.LookupTable.Range["A2"].Select();
foreach (CFolderType ft in FolderTypes) {
Globals.LookupTable.Rows.Next.Value2 = ft.name;
}
This shall move down in column A and insert the values.

Something like this should do the work:
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.ApplicationClass();
excel.Workbooks.Add(System.Reflection.Missing.Value);
int rowIdx = 2;
foreach (CFolderType ft in FolderTypes)
{
Microsoft.Office.Interop.Excel.Range aCell = excel.get_Range("A" + rowIdx.ToString(), System.Reflection.Missing.Value);
aRange.Value = ft.name;
rowIdx++;
}

Related

C# unable to update spreadsheet table header values dynamically

I have a spreadsheet template which has a table (Table inserted into sheet from Insert tab) and when the user clicks on the export button these header values of the table should be updated by new values dynamically. For this I'm using c# and DocumentFormat.OpenXml library.
After exporting header values are getting updated in the spreadsheet table but when I open the excel document it says "We found problem with some content in '<>.xlsx' . Do you want us to recover as much as we can ? ".
Also, when I tried updating table rows other than header row, I wasn't getting above popup.
I have tried below approaches to update table header values.
Approach 1
using (SpreadsheetDocument document = SpreadsheetDocument.Open("test.xlsx", true))
{
WorkbookPart wbPart = document.WorkbookPart;
Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where(s => s.name =="Sheet1").FirstOrDefault();
WorksheetPart wsPart = (WorksheetPart) (wbPart.GetPartById(sheet.Id));
WorkSheet wSheet = wsPart.WorkSheet;
Row row = wSheet.Elements<Row>().Where(r => r.RowIndex ==1 ).FirstOrDefault();
Cell cell = row.Elements<Cell>().Where(c => string.Compare
(c.CellReference.Value, "A1" , true) == 0).First();
cell.CellValue = new CellValue("new Header");
cell.DataType = CellValues.String;
wbPart.WorkBook.save();
}
Approach 2
foreach(TableDefinitionPart tdp in wsPart.TableDefinitionParts )
{
QueryTablePart qtp= tdp .QueryTableParts.FirstOrDefault();
Table excelTable = tdp .Table;
int i = 0;
foreach(TableColumn col in excelTable.TableColumns)
{
col.name.Value = "Header"+i;
i++;
}
}

export data in a list and array to excel using c#

I have a list of numbers in one class. I am trying to export the data in the list and the data in array[4,4] to Excel. I would like the list as one column with the header and the array as a table with headers (column name) and row names.
I did not find a proper solution to try
public void Data_to_Excel()
{
//start excel
NsExcel.Application excapp = new Microsoft.Office.Interop.Excel.Application();
//if you want to make excel visible
excapp.Visible = true;
//create a blank workbook
var workbook = excapp.Workbooks.Add(NsExcel.XlWBATemplate.xlWBATWorksheet);
//or open one - this is no pleasant, but yue're probably interested in the first parameter
string workbookPath = " filepath here ";
workbook = excapp.Workbooks.Open(workbookPath, 0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
//Not done yet. You have to work on a specific sheet - note the cast
//You may not have any sheets at all. Then you have to add one with NsExcel.Worksheet.Add()
var sheet = (NsExcel.Worksheet)workbook.Sheets[1]; //indexing starts from 1
//do something usefull: you select now an individual cell
//var range = sheet.get_Range("A1", "A1");
//range.Value2 = "test"; //Value2 is not a typo
//now the list
string cellName;
int counter = 1;
foreach (var item in Sim_Obj.Bottom_Rows_Count_Stack)
{
cellName = "A" + counter.ToString();
var range = sheet.get_Range(cellName, cellName);
range.Value2 = item.ToString();
++counter;
}
workbook.SaveAs("Cash_Surge_Sim_Results.xlsx");
}
I have the 20 results in the rich text box in a list.
I have table layout data in an array[4,4]
I want the array data as a table form in Excel and
the list data as one column.

Search entire workbook and fetch out values

In my excel workbook
The first sheet tab contains
Number Name Code Subject
100 Mark ABC Mathematics
101 John XYZ Physics
The second sheet tab contains
Number Name Code Subject
103 Mark DEF Chemistry
104 John GHI Biology
I want to pass the code(which is going to be unique) as a parameter and search the entire excel workbook
and fetch name and subject..
ie..select name,subject from myexcelworkbook where code='ABC'
I am able to get sheet names, column count etc. but not able to search thro' an entire excel workbook and get the required values
const string fileName="C:\\FileName.xls";
OleDbConnectionStringBuilder connectionStringBuilder = new OleDbConnectionStringBuilder();
connectionStringBuilder.Provider = "Microsoft.ACE.OLEDB.12.0";
connectionStringBuilder.DataSource = fileName;
connectionStringBuilder.Add("Mode", "Read");
const string extendedProperties = "Excel 12.0;IMEX=1;HDR=YES";
connectionStringBuilder.Add("Extended Properties", extendedProperties);
using (OleDbConnection objConn = new OleDbConnection(connectionStringBuilder.ConnectionString))
{
objConn.Open();
Microsoft.Office.Interop.Excel.Application xlsApp = new Microsoft.Office.Interop.Excel.Application();
Workbook wb = xlsApp.Workbooks.Open(fileName, 0, true, 5, "", "", true, XlPlatform.xlWindows, "\t", false, false, 0, true);
Sheets sheets = wb.Worksheets;
for (int i =1 ; i <= wb.Worksheets.Count; i++)
{
MessageBox.Show(wb.Sheets[i].Name.ToString()); - gives sheet names inside the workbook
}
Worksheet ws = (Worksheet)sheets.get_Item(1); - gives the elements of specified sheet tab
}
//To get elements inside a specific sheet of an excel workbook/get column names
OleDbCommand objCmdSelect = new OleDbCommand("SELECT * FROM [" + "Sheet1" + "$]", objConn);
OleDbDataAdapter objAdapter1 = new OleDbDataAdapter();
objAdapter1.SelectCommand = objCmdSelect;
DataSet objDataset1 = new DataSet();
objAdapter1.Fill(objDataset1);
string columnNames = string.Empty;
// For each DataTable, print the ColumnName. use dataset.Rows to iterate row data...
foreach (System.Data.DataTable table in objDataset1.Tables)
{
foreach (DataColumn column in table.Columns)
{
if (columnNames.Length > 0)
{
columnNames = columnNames + Environment.NewLine + column.ColumnName;
}
else
{
columnNames = column.ColumnName;
}
}
}
Can someone share some ideas, so that i can find out the unique data inside the excel workbook and fetch out the needed values based on that? thanks in advance.
If the workbooks are as structured as you indicate and you will be querying multiple students then, as #Andy G suggests, you might find it easiest to just get the data into some form of record set then you run your queries on it through Linq or SQL or whatever you prefer. As you aren't wishing to modify the Excel workbook at all this is probably a better approach.
Alternatively, you can use the Excel API, like you were also trying to use. You can enumerate through the worksheets, running a Find on each. A la:
internal void GetYourData()
{
//... code to get the relevant Workbook and relevant/new Excel Application
Tuple<string, string> pupil;
string searchTerm = "ABC";
//Get the cell of the match
Range match = FindFirstOccurrenceInWorkbook(workbook, searchTerm);
if (match != null)
{
//Do whatever - per your data structure, it is probably easiest to just use .Offset(row, column) property
pupil = new Tuple<string, string>((string)match.Offset(0, -1).Value, (string)match.Offset(0, 1).Value);
}
//... code to do whatever with your results
}
internal static Range FindFirstOccurrenceInWorkbook(Workbook workbook, string searchTerm)
{
if (workbook == null) throw new ArgumentNullException("workbook");
if (searchTerm == null) throw new ArgumentNullException("searchTerm");
Sheets wss = workbook.Worksheets;
Range match = null;
foreach (Worksheet ws in wss)
{
Range cells = ws.Cells;
//Add more args as needed - this is just an example
match = cells.Find(
what: searchTerm,
after: Type.Missing,
lookIn: XlFindLookIn.xlFormulas,
lookAt: XlLookAt.xlPart);
System.Runtime.InteropServices.Marshal.ReleaseComObject(cells);
System.Runtime.InteropServices.Marshal.ReleaseComObject(ws);
if (match != null)
{
break;
}
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(wss);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
return match;
}
Also, you can't use COM objects like you use without generating orphaned references -> this will prevent the Excel application from closing. You need to explicitly assign all object properties you want to use like Workbook.Worksheets to a variable then call System.Runtime.InteropServices.Marshal.ReleaseCOMObject(object) when the variable is about to go out of scope.

Selecting a range in a worksheet C#

I currently have the following code opening and reading in an excel spreadsheet:
var connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=Excel 12.0;", fileNameTextBox.Text);
var queryString = String.Format("SELECT * FROM [{0}]",DETAILS_SHEET_NAME);
var adapter = new OleDbDataAdapter(queryString, connectionString);
var ds = new DataSet();
adapter.Fill(ds, DETAILS_SHEET_NAME);
DataTable data = ds.Tables[DETAILS_SHEET_NAME];
dataGridView1.DataSource = data;
dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
This is all good and well except I'm not interested in the first row (Possibly first two rows as row 2 is headers) of the worksheet. How can I modify the select Query to select a range like I would in excel?
I'm interested in reading in say columns A-N in rows all rows from 2 onwards that contain data.
I also need to access a couple of specific cells on a different worksheet, I assume I have to build another adaptor with a different query string for each of those cells?
Modify Select statement including just the columns you need instead of wildcard "*" like in the following example:
("SELECT Column1, Column2 FROM DETAILS_SHEET_NAME");
You can apply additional logic in order to remove unnecessary rows, for example, a "paging solution" (i.e. selecting rows from N to M) like the following one:
Assuming the Database Table "TBL_ITEM" contains two columns (fields) of interest: “Item” column, representing the unique ID and “Rank”, which is used for sorting in ascending order, the general paging problem is stated as following: Select N-rows from the table ordered by Rank offsetting (i.e. skipping) (M-N) rows:
SELECT TOP N Item,
Rank FROM (SELECT TOP M Rank, Item FROM TBL_ITEM ORDER BY Rank)
AS [SUB_TAB] ORDER BY Rank DESC
This solution and its extensions/samples are thoroughly discussed in my article Pure SQL solution to Database Table Paging (link: http://www.codeproject.com/Tips/441079/Pure-SQL-solution-to-Database-Table-Paging)
Finally, you can use a code snippet shown below in Listing 2 to export a content of DataTable object in Excel file with plenty of customization features that could be added to a code;
Listing 2. Export DataTable to Excel File (2007/2010):
internal static bool Export2Excel(DataTable dataTable, bool Interactive)
{
object misValue = System.Reflection.Missing.Value;
// Note: don't include Microsoft.Office.Interop.Excel in reference (using),
// it will cause ambiguity w/System.Data: both have DataTable obj
Microsoft.Office.Interop.Excel.Application _appExcel = null;
Microsoft.Office.Interop.Excel.Workbook _excelWorkbook = null;
Microsoft.Office.Interop.Excel.Worksheet _excelWorksheet = null;
try
{
// excel app object
_appExcel = new Microsoft.Office.Interop.Excel.Application();
// make it visible to User if Interactive flag is set
_appExcel.Visible = Interactive;
// excel workbook object added to app
_excelWorkbook = _appExcel.Workbooks.Add(misValue);
_excelWorksheet = _appExcel.ActiveWorkbook.ActiveSheet
as Microsoft.Office.Interop.Excel.Worksheet;
// column names row (range obj)
Microsoft.Office.Interop.Excel.Range _columnsNameRange;
_columnsNameRange = _excelWorksheet.get_Range("A1", misValue);
_columnsNameRange = _columnsNameRange.get_Resize(1, dataTable.Columns.Count);
// data range obj
Microsoft.Office.Interop.Excel.Range _dataRange;
_dataRange = _excelWorksheet.get_Range("A2", misValue);
_dataRange = _dataRange.get_Resize(dataTable.Rows.Count, dataTable.Columns.Count);
// column names array to be assigned to columnNameRange
string[] _arrColumnNames = new string[dataTable.Columns.Count];
// 2d-array of data to be assigned to _dataRange
string[,] _arrData = new string[dataTable.Rows.Count, dataTable.Columns.Count];
// populate both arrays: _arrColumnNames and _arrData
// note: 2d-array structured as row[idx=0], col[idx=1]
for (int i = 0; i < dataTable.Columns.Count; i++)
{
for (int j = 0; j < dataTable.Rows.Count; j++)
{
_arrColumnNames[i] = dataTable.Columns[i].ColumnName;
_arrData[j, i] = dataTable.Rows[j][i].ToString();
}
}
//assign column names array to _columnsNameRange obj
_columnsNameRange.set_Value(misValue, _arrColumnNames);
//assign data array to _dataRange obj
_dataRange.set_Value(misValue, _arrData);
// save and close if Interactive flag not set
if (!Interactive)
{
// Excel 2010 - "14.0"
// Excel 2007 - "12.0"
string _ver = _appExcel.Version;
string _fileName ="TableExport_" +
DateTime.Today.ToString("yyyy_MM_dd") + "-" +
DateTime.Now.ToString("hh_mm_ss");
// check version and select file extension
if (_ver == "14.0" || _ver == "12.0") { _fileName += ".xlsx";}
else { _fileName += ".xls"; }
// save and close Excel workbook
_excelWorkbook.Close(true, "{DRIVE LETTER}:\\" + _fileName, misValue);
}
return true;
}
catch (Exception ex) { throw; }
finally
{
// quit excel app process
if (_appExcel != null)
{
_appExcel.UserControl = false;
_appExcel.Quit();
_appExcel = null;
misValue = null;
}
}
}
You can simply ask for no headers. Modify your connection string, add HDR=No.
For your second issue, I found this post, Maybe you'll find it helpful.

Editing an Excel Object embedded in a Word document in Excel

I need to embed an Excel document in a Word document. I used the answer on this SO question -> How can I embed any file type into Microsoft Word using OpenXml 2.0;
Everything works fine except that:
DrawAspect = OVML.OleDrawAspectValues.Icon lets you edit the Excel object by opening a new Excel instance. However, when I edit the data, it is not updated in the Word document.
DrawAspect = OVML.OleDrawAspectValues.Content lets you edit the Excel object directly in the Word document.
My question is, what do I have to change in the code so can I edit the Excel object in the new instance and have it properly reflected in the Word document? I tried everything to no avail.
Something tells me that DrawAspect = OVML.OleDrawAspectValues.Icon suggests that the object acts as an Icon, and changes cannot be properly reflected in this icon.
You could try a way I prorosed here:
How to insert an Image in WORD after a bookmark using OpenXML.
In short, use Open XML SDK 2.0 Productivity Tool (which is a part of Open XML SDK 2.0). Do whatever you need to do with document manually in MS Word. Then open this file in Open XML SDK 2.0 Productivity Tool. Then find the edits you are interested in to see how it is represented in OpenXML format , as well as how to do that programmaticaly.
Hope that helps!
UPDATED:
Okay - I have got better now what's the problem is... So in addition to my advice above I would recommend you to look at this threads on MSDN Forum:
How to modify the imbedded Excel in a Word document supplying chart
data
Embedded excel sheet in word
I let myself to repost the code sample (posted on MSDN Forum by Ji Zhou) just to avoid the deletion of original thread there.
Hope it is helpful enough to retrieve the Excel object from Word, change some cells and embed it back into Word.
public static void Main()
{
using (WordprocessingDocument wDoc = WordprocessingDocument.Open(#"D:\test.docx", true))
{
Stream stream = wDoc.MainDocumentPart.ChartParts.First().EmbeddedPackagePart.GetStream();
using (SpreadsheetDocument ssDoc = SpreadsheetDocument.Open(stream, true))
{
WorkbookPart wbPart = ssDoc.WorkbookPart;
Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
Where(s => s.Name == "Sheet1").FirstOrDefault();
if (theSheet != null)
{
Worksheet ws = ((WorksheetPart)(wbPart.GetPartById(theSheet.Id))).Worksheet;
Cell theCell = InsertCellInWorksheet("C", 2, ws);
theCell.CellValue = new CellValue("5");
theCell.DataType = new EnumValue<CellValues>(CellValues.Number);
ws.Save();
}
}
}
}
private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, Worksheet worksheet)
{
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
string cellReference = columnName + rowIndex;
Row row;
if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
{
row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
}
else
{
row = new Row() { RowIndex = rowIndex };
sheetData.Append(row);
}
if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
{
return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
}
else
{
Cell refCell = null;
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
{
refCell = cell;
break;
}
}
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
worksheet.Save();
return newCell;
}
}

Categories