How to select an entire row and column after finding a cell? - c#

After searching for a value in an Excel range I need to select only the entire row and then get each value found in the columns of the row.
xlRange = xlWorksheet.Range[rangeStart, rangeStop];
var xlCell = xlRange.Find
(
valueToFind
, xlRange.Range[rangeStart]
, Excel.XlFindLookIn.xlValues
, Excel.XlLookAt.xlWhole
, Excel.XlSearchOrder.xlByColumns
, Microsoft.Office.Interop.Excel.XlSearchDirection.xlNext
, false
);
Going from the xlCell.get_Address() I need to get only the full row and maybe the full column of that found cell.

To get the full row or column of xlCell and their values, you can use this code:
var row = xlCell.EntireRow;
object[,] rowValues = row.Value2;
var col = xlCell.EntireColumn;
object[,] colValues = col.Value2;
Be aware that these values are pretty big arrays with the contents of the whole worksheet. If you want only the relevant ones, the following should to the trick:
var cells = xlWorksheet.Cells;
var used = xlWorksheet.UsedRange;
var rowCellFirst = cells[row.Row, 1];
var rowCellLast = cells[row.Row, used.Column + used.Columns.Count - 1];
object[,] rowValuesUsed = xlWorksheet.Range[rowCellFirst, rowCellLast].Value2;
var colCellFirst = cells[1, col.Column];
var colCellLast = cells[used.Row + used.Rows.Count - 1, col.Column];
object[,] colValuesUsed = xlWorksheet.Range[colCellFirst, colCellLast].Value2;

Related

How retrieve each specific column's values by looping through rows using C# from excel?

I am editing uploaded excel workbooks using C# with the same logic I used to do using VBA. I am using SyncFusion to open the workbooks but however, the code below is not letting me read the whole column to apply the logic. Why?
public void AppendID(string excelFilePath, HttpResponse response)
{
using (ExcelEngine excelEngine = new ExcelEngine())
{
IApplication application = excelEngine.Excel;
application.DefaultVersion = ExcelVersion.Excel2007;
IWorkbook workbook = application.Workbooks.Open(excelFilePath);
workbook.Version = ExcelVersion.Excel97to2003;
workbook.Allow3DRangesInDataValidation = true;
//Accessing worksheet via name
IWorksheet worksheet = workbook.Worksheets[2];
When I try to define the range, the error will appear "Two names not allowed".
var prismaID = worksheet.UsedRange["C15:C"].Value;
var type = worksheet.UsedRange["F15:F"].Value;
var placements = worksheet.UsedRange["I15:I"].Value;
if (!type.Contains("PKG"))
{
placements = placements + prismaID;
}
worksheet.Range["G7"].Text = "Testing";
workbook.SaveAs(excelFilePath);
workbook.Close();
}
}
Logic:
Let's say I have three columns and how to use the following logic to manipulate usedRange cells?
ID Condition Name Output
1 Yes Sarah Sarah(1)
2 No George George
3 Yes John(3) John(3)
The logics to apply:
Move the first column 'ID' to the end of the column 'Name' but
if Column 'Condition' contains 'No'then don't move the first column
or if it contains the same 'ID' already.
Here is the VBA code:
With xlSheet
LastRow = xlSheet.UsedRange.Rows.Count
Set target = .Range(.Cells(15, 9), .Cells(LastRow, 9))
values = target.Value
Set ptype=.Range(.Cells(15,6),.Cells(LastRow,6))
pvalues=ptype.Value
For i = LBound(values, 1) To UBound(values, 1)
'if Statement for test keywords
If InStr(1,pvalues(i,1),"Package")= 0 AND InStr(1,pvalues(i,1),"Roadblock")= 0 Then
If Instr(values(I,1),.Cells(i + 15 - LBound(values, 1), 3)) = 0 Then
'If InStr(1,values(i,1),"(")=0 Then
values(i, 1) = values(i, 1) & "(" & .Cells(i + 15 - LBound(values, 1), 3) & ")"
End If
End If
Next
target.Value = values
End With
Your requirement can be achieved by appending column ID with column Name using XlsIO.
Please refer below code snippet for the same.
Code Snippet:
for(int row = 1; row<= worksheet.Columns[1].Count; row++)
{
if (worksheet[row, 2].Value == "yes" && !worksheet[row, 3].Value.EndsWith(")"))
worksheet[row, 4].Value = worksheet[row, 3].Value + "(" + worksheet[row, 1].Value + ")";
else
worksheet[row, 4].Value = worksheet[row, 3].Value;
}
We have prepared simple sample and the sample can be downloaded from the following link.
Sample Link: http://www.syncfusion.com/downloads/support/directtrac/general/ze/Sample859524528.zip
I work for Syncfusion.
So I am working with templates in excel, and I developed this logic.
I create a coupling of the first row of column names and the rows using the first cell as the key to bind the data in groups to a multi value dictionary.
I use the below function, which can be adapted to skip rows before parsing allowing you to target the proper row for binding. Book is ExcelDataReader.AsDataSet()
public static MultiValueDictionary<string, ILookup<string, string>> ParseTemplate(string Sheet, ref List<string> keys)
{
int xskip = 0;
MultiValueDictionary<string, ILookup<string, string>> mvd = new MultiValueDictionary<string, ILookup<string, string>>();
var sheetRows = Book.Tables[Sheet];
//Parse First row
var FirstRow = sheetRows.Rows[0];
for (var Columns = 0; Columns < sheetRows.Columns.Count; Columns++)
{
if (xskip == 0)
{
xskip = 1;
continue;
}
keys.Add(FirstRow[Columns].ToString());
}
//Skip First Row
xskip = 0;
//Create a binding of first row and all subsequent rows
foreach (var row in sheetRows.Select().Skip(1))
{
//Make the key the first cell of each row
var key = row[0];
List<string> rows = new List<string>();
foreach (var item in row.ItemArray)
{
if (xskip == 0)
{
xskip = 1;
continue;
}
rows.Add(item.ToString());
}
mvd.Add(key.ToString(), keys.Zip(rows, (m, n) => new { Key = m, Value = n }).ToLookup(x => x.Key, y => y.Value));
xskip = 0;
}
return mvd;
}
}
//This is example of what a function to parse this could do.
foreach(var Key in mvd.Keys)
{
var KeywithValues = mvd[Key];
foreach(ColumnName in Keys)
{
KeywithValues[ColumnName].
}
}
Hope it helps.

C# fill data to excel.range not working

I am using Microsoft.Office.Interop.Excel for writing data to excel
Now I'm using below code to fill data to a range of cells. Let's say from P10 to P20
Excel.Worksheet ps_sheet = //current worksheet
string[,] data = new string[11,1];
var r = ps_sheet.Range["P10", "P20"];
r.Value2 = data;
The above code is working properly, but if there's only one cell in the range (e.g. "P20" to "P20") the code won't work, the cell is showing the old data.
Excel.Worksheet ps_sheet = //current worksheet
string[,] data = new string[1,1];
var r = ps_sheet.Range["P20", "P20"];
r.Value2 = data;
The excel.range can have one cell only or have multiple cells, since I'm doing a loop.
Is there any reason why this situation happens and how to fix?
Use only one parameter, second parameter is optional
var r = ps_sheet.Range["P20"];
Worksheet.Range Property
I changed to below code and it works:
if (data.GetLength(0) == 1)
{
r = ps_sheet.Range["P10"];
r.Value2 = data[0, 1];
}
else
{
r = ps_sheet.Range["P10", "P20"];
r.Value2 = data;
}
I specially made a case if the data has only one row...
Don't know if there're any better ways to achieve this

How to copy Given no of cells from a perticular row in Excel using C#

As per my requirement, I am getting Row Number and Maximum column count. Now I have to copy (column count)Columns of Row(RowNumber) to a different sheet.
For Example.
RowNo = 2 and ColumnCount = 5
Now I have to copy first 5 cells of Row 2.
PS: Range("A2:E2") is not an option
if you wanna get the value of your sheet one by one, you can try this (based on your example row=2 and colCount=5)
dynamic activeRow = activeSheet.UsedRange.Rows[2, Type.Missing].Columns.Value2;
var firstCell = activeRow[1, 1].ToString();
var secondCell = activeRow[1, 2].ToString();
var thirdCell = activeRow[1, 3].ToString();
var forthCell = activeRow[1, 4].ToString();
var fifthCell = activeRow[1, 5].ToString();
and you can insert these value in a sheet like this:
sheet.Cells[row, col] = value;

Force EPPLUS to read as text

I'm developping an application to read xlsx files, do some validation and insert into database. Unfortunatelly when I try to read columns marked as numeric (fe with EAN-13 codes) I get miniumum value of an int.
The user doesn't see this because Excel displays it properly.
How can I make it read the file as plain text? I know I can use OLEBD for it, but I also need to edit the file dynamically, so epplus ExcelPackage is the best choice.
Here is code im using:
FileInfo file = new FileInfo(path);
MainExcel = new OfficeOpenXml.ExcelPackage(file);
{
var ws = MainExcel.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
for (var rowNum = 1; rowNum <= ws.Dimension.End.Row; rowNum++) //currently loading all file
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var row = tbl.NewRow();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
tbl.Rows.Add(row);
}
}
and that's how I enumerate columns
foreach (var firstRowCell in ws.Cells[3, 1, 3, ws.Dimension.End.Column])
{
System.Type typeString = System.Type.GetType("System.String") ;
tbl.Columns.Add( firstRowCell.Text , typeString );
}
For people whom it might concern, here is the file (works also for non google users):
https://drive.google.com/open?id=0B3kIzUcpOx-iMC1iY0VoLS1kU3M&authuser=0
I noticed that ExcelRange.value property is an array which contains all of the objects unformatted. But once you iterate over cells in ExcelRange and request cell.Text property, it has already been processed. Trying to modify ConditionalFormatting and DataValidation in ExcelRange does not help (f.e. AddContainsText()) - #EDIT--> Neither for an entire sheet :-(
I'd prefer NOT to cast ExcelRange.Value as Array, it's ugly and very conditional.
Apparently this is the solution (not complete code though, you have to add columns to datatable). I couldn't find the format string which specifies 'no formatting' in Epplus, but here you have it.
var ws = MainExcel.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
for (var rowNum = 1; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var array = wsRow.Value as object[,];
var row = tbl.NewRow();
int hhh =0;
foreach (var cell in wsRow)
{
cell.Style.Numberformat.Format = "#";
row[cell.Start.Column - 1] = cell.Text;
}
tbl.Rows.Add(row);
}
The cells in your file are custom-formatted as a fraction. Have you done this on purpose?
Anyway, if you want to keep this format, you can alternatively use cell.Value or cell.RichText.Text to get your 13-digit number.
Hope this helps.

NPOI apply font to entire row of cells

I'm using NPOI to export my data to excel. The problem is I found it really hard for any kind of graphical changes.
This is the method I'm using now to apply bold font to my cells.
//Create new Excel workbook
var workbook = new HSSFWorkbook();
//Create new Excel sheet
var sheet = workbook.CreateSheet();
//Create a header row
var headerRow = sheet.CreateRow(0);
var boldFont = workbook.CreateFont();
boldFont.FontHeightInPoints = 11;
boldFont.FontName = "Calibri";
boldFont.Boldweight = (short)NPOI.SS.UserModel.FontBoldWeight.Bold;
int cellCounter = 0;
//day
var cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Day");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont);
//month
cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Month");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont);
//year
cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Year");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont);
//machine name
cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Machine unique name");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont); //and so on
Is there a ,,cleaner" way to do this ? Now i have to manually add font for individual cells. I've tried many ways to do this on the internet and nothing seems to be working. Do you have a tested way to apply style to specific column or row ?
OffTopic: If not can you provide me with some good open source libraries with decent documentation and support that allow excel export (learning new dll is a pain but... :) what can you do)?
I'm doing something similar and modified my take on it closer for your use:
private string[] columnHeaders =
{
"Day",
"Month",
"Year",
"Machine Unique Name"
}
private void buildSheet(HSSFWorkbook wb, DataTable data, string sheetName)
{
var cHelp = wb.GetCreationHelper();
var sheet = wb.CreateSheet(sheetName);
HSSFFont hFont = (HSSFFont)wb.CreateFont();
hFont.FontHeightInPoints = 11;
hFont.FontName = "Calibri";
hFont.Boldweight = (short)NPOI.SS.UserModel.FontBoldWeight.Bold;
HSSFCellStyle hStyle = (HSSFCellStyle)wb.CreateCellStyle();
hStyle.SetFont(hFont);
IRow headerRow = sheet.CreateRow(1);
int cellCount = 1;
foreach (string str in columnHeaders)
{
HSSFCell cell = (HSSFCell)headerRow.CreateCell(cellCount);
cell.SetCellValue(cHelp.CreateRichTextString((str)));
cell.CellStyle = hStyle;
cellCount += 1;
}
This iterates over however many headers you want starting at the second cell (cellCount = 1) second row (sheet.CreateRow(1)).

Categories