I've been pulling my hair out trying to set the value of a named range (in this case, a single named cell) using the ExcelPackage (3.0.1) library, it should be a simple as this:
ExcelNamedRange er = xlPackage.Workbook.Names["Customer"];
er.Value = "Foo Bar";
I'm obviously doing it wrong - has anyone got an example I can follow
Thanks
I looked for ExcelPackage documentation to see what type Names[] collection returns and found that documentatios will come soon, or at least that is what they said back in 2007.
I suggest you use EPPlus wich is a excel library (xlsx only) that have worked great to me.
official link
Now, to set a value for each cell in a named range:
ExcelWorksheet sheet = _openXmlPackage.Workbook.Worksheets["SheetName"];
using (ExcelNamedRange namedRange = sheet.Names["RangeName"])
{
for (int rowIndex = Start.Row; rowIndex <= namedRange.End.Row; rowIndex++)
{
for (int columnIndex = namedRange.Start.Column; columnIndex <= namedRange.End.Column; columnIndex++)
{
sheet.Cells[rowIndex, columnIndex].Value = "no more hair pulling";
}
}
}
I had to put in a work around using a cell value instead.
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
foreach (ExcelWorksheet worksheet in xlPackage.Workbook.Worksheets)
{
var dimension = worksheet.Dimension;
if (dimension == null) { continue; }
var cells = from row in Enumerable.Range(dimension.Start.Row, dimension.End.Row)
from column in Enumerable.Range(dimension.Start.Column, dimension.End.Column)
//where worksheet.Cells[row, column].Value.ToString() != String.Empty
select worksheet.Cells[row, column];
try
{
foreach (var excelCell in cells)
{
try
{
if (excelCell.Value.ToString().Equals("[Customer]")) { excelCell.Value = "Customer Name"; }
}
catch (Exception) { }
}
}
catch (Exception a) { Console.WriteLine(a.Message); }
}
Related
In a OOXML spreadsheet .xlsx you can through a linking formula fecth values from another spreadsheet and have them in your worksheet as values, that will always be updated when those values in another spreadsheet are updated.
I am using Open Xml SDK and I basically want to do what this does: https://www.e-iceblue.com/Tutorials/Spire.XLS/Spire.XLS-Program-Guide/Formula/Remove-Formulas-from-Cells-but-Keep-Values-in-Excel-in-C.html
How do I:
Find a value that has formula linking value to a cell in another spreadsheet
Replace the formula value with the actual cell value
Do this foreach cell in each worksheet in a spreadsheet
I have tried this so far: https://learn.microsoft.com/en-us/office/open-xml/how-to-retrieve-the-values-of-cells-in-a-spreadsheet
But I am recieving a NullRefereceneException each time the cell does not contain a formula or just any value. I have tried try-catch and several other ways to escape this exception, but it is not working.
But back to the challenge as outlined above; can anyone help me out?
Basic stuff such as using SOME DIRECTIVE, foreach loop, Open(), Save() I know how to do.
This worked for me:
public void Remove_CellReferences(string filepath)
{
using (SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(filepath, true))
{
// Delete all cell references in worksheet
List<WorksheetPart> worksheetparts = spreadsheet.WorkbookPart.WorksheetParts.ToList();
foreach (WorksheetPart part in worksheetparts)
{
Worksheet worksheet = part.Worksheet;
var rows = worksheet.GetFirstChild<SheetData>().Elements<Row>(); // Find all rows
foreach (var row in rows)
{
var cells = row.Elements<Cell>();
foreach (Cell cell in cells)
{
if (cell.CellFormula != null)
{
string formula = cell.CellFormula.InnerText;
if (formula.Length > 0)
{
string hit = formula.Substring(0, 1); // Transfer first 1 characters to string
if (hit == "[")
{
CellValue cellvalue = cell.CellValue; // Save current cell value
cell.CellFormula = null; // Remove RTD formula
// If cellvalue does not have a real value
if (cellvalue.Text == "#N/A")
{
cell.DataType = CellValues.String;
cell.CellValue = new CellValue("Invalid data removed");
}
else
{
cell.CellValue = cellvalue; // Insert saved cell value
}
}
}
}
}
}
}
// Delete all external link references
List<ExternalWorkbookPart> extwbParts = spreadsheet.WorkbookPart.ExternalWorkbookParts.ToList();
if (extwbParts.Count > 0)
{
foreach (ExternalWorkbookPart extpart in extwbParts)
{
var elements = extpart.ExternalLink.ChildElements.ToList();
foreach (var element in elements)
{
if (element.LocalName == "externalBook")
{
spreadsheet.WorkbookPart.DeletePart(extpart);
}
}
}
}
// Delete calculation chain
CalculationChainPart calc = spreadsheet.WorkbookPart.CalculationChainPart;
spreadsheet.WorkbookPart.DeletePart(calc);
}
}
I have this problem, I have installed ClosedXml:
I have an Excel file already created and populated, now I should find the blank line below the already populated one and write some data
Example:
[A, 1] = name;
[B, 1] = surname;
the next line will be empty and I will pass some variables to populate the cells going to the right.
OpenFileDialog FileExcel = new OpenFileDialog();
if (FileExcel.ShowDialog() == DialogResult.OK)
{
try
{
var sr = new StreamReader(FileExcel.FileName);
}
catch (SecurityException ex)
{
MessageBox.Show($"Security error.\n\nError message: {ex.Message}\n\n" +
$"Details:\n\n{ex.StackTrace}");
}
}
using (var excelWorkbook = new XLWorkbook(FileExcel.FileName))
{
var nonEmptyDataRows = excelWorkbook.Worksheet(Convert.ToInt32(comboBox1.SelectedItem)).RowsUsed();
foreach (var dataRow in nonEmptyDataRows)
{
//for row number check
if (dataRow.RowNumber() >= 1 && dataRow.RowNumber() <= 100)
{
}
}
}
Use row.Cells(false) instead of row.Cells(). It does not skip over unused cells. Then you can simply check of cell.Value() is empty
you can do something like that
int lastrow = worksheet.LastRowUsed().RowNumber();
var rows = worksheet.Rows(1, lastrow);
foreach (IXLRow row in rows)
{
foreach (IXLCell cell in row.Cells())
{
if (cell.IsEmpty())
{
//do something
}
}
}
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.
I want to loop through a column, and when i find an empty cell, or a cell containing a specific number, that entire row to be colored in.
What i have tried is this (and some variations of this), but it does not work:
xl.Range end = MySheet.Cells.SpecialCells(xl.XlCellType.xlCellTypeLastCell, Type.Missing);
xl.Range start = MySheet.get_Range("Q2", end );
if (start.Value == null)
{
start.EntireRow.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.Red);
}
Any sort of help or any good idea would be appreciated.
UPDATE :
Found the solution to this :
xl.Range first_range = MySheet.Cells.SpecialCells(xl.XlCellType.xlCellTypeLastCell, Type.Missing);
xl.Range usedRange = MySheet.get_Range("Q2", first_range);
xl.Range rows = usedRange.Rows;
int count = 0;
foreach (xl.Range row in rows)
{
if (count > 0)
{
xl.Range firstcell = row.Cells[1];
string firstCellValue = firstcell.Value as string;
if (string.IsNullOrEmpty(firstCellValue))
{
row.EntireRow.Interior.Color = System.Drawing.Color.Red;
}
}
count++;
}
when using for & foreach loops with big data like 10000 rows i get
"OutOfMemory " exception
so the best solution is using Lambda Expressions
//best practice access cell by number not by string
yourWorksheet.RangeUsed().Rows(r => string.IsNullOrWhiteSpace(r.Cell(1).Value.ToString()))
.ForEach(r => r.Style.Fill.SetBackgroundColor(XLColor.Red));
How to target Cell if I know its content (there are no duplicates in the xlsx document) using Office Open XML?
I mean I have xlsx sheet (template) and somewhere in it placed my "variable". For example "<<_time>>". I want to find that element (by "variable" name) and change the cell value (current time in this case).
Basic code:
FileInfo newFile = new FileInfo(#"...");
FileInfo template = new FileInfo(#"...");
using (ExcelPackage xlPackage = new ExcelPackage(newFile, template))
{
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets.First();
//need target Cell by it's value (must use for-loop?)
//worksheet.Cells[...].Value = "...";
xlPackage.Save();
}
Ok, I solved it by classic loop.
var start = worksheet.Dimension.Start;
var end = worksheet.Dimension.End;
for (int row = start.Row; row <= end.Row; row++)
{
for (int col = start.Column; col <= end.Column; col++)
{
string cellValue = worksheet.Cells[row, col].Text.ToString();
if (cellValue == "<<_time>>")
{
worksheet.Cells[row, col].Value = "..";
}
}
}