I want to copy/paste range at worksheet including the values/property(Strikethrough) in the cells to another new workbook.
I can't set this property at new sheet. Using Microsoft.Office.Interop.Excel; I cant copy this property like in the picture. How can I do it. 3 line in 1 cell with different property
public void WriteCellWithFont(int i, int j , _Excel.Range cell)
{
i++;
j++;
ws.Cells[i, j].Value2 = cell.Value2;
ws.Cells[i,j].Font.Strikethrough = true;
}
Try with PasteSpecial. Its like normal way of we use to keep formatting when paste.
// copy
Range cells1 = (Range)worksheet1.Cells[2, 3];
cells1.Copy();
// Paste
Range cells2= (Range)worksheet2.Cells[2, 3];
cells2.PasteSpecial(XlPasteType.xlPasteFormats);
Related
I have an Excel worksheet which has 50 Rows and 38 columns "Filled" with actual data but when I try to get the .UsedRange I am getting More than 1025 Rows and 250 columns as Used range! Please let me know how can I get only actual Used ranges with filled data and retrive the actual range data using Spreadsheetgear lib? I tried something like, but when user added some column, it's does not work.
var workbook = Factory.GetWorkbook(filePath);
var worksheet = workbook.Worksheets[0];
var cells = worksheet.UsedRange;
var headerCount = 0;
// get columns size
for (var columnCount = 0; columnCount <= range.ColumnCount; ++columnCount)
{
if (columnCount > headers.Length && string.IsNullOrEmpty(range[HeaderRow, columnCount].Text))
{
headerCount = columnCount - 1;
break;
}
}
SpreadsheetGear (and Excel itself) will include cells into the UsedRange that are empty but have formatting of some kind. For instance, if cell ABC123 has a custom NumberFormat, Font color or similar, the UsedRange will include that cell, thereby potentially blowing up your UsedRange A1:ABC123 even if the actual "value-populated" or "filled" portion of the worksheet is much smaller.
If this is a problem and you need to only include the portion of a sheet that is actually populated with cell values, below is one possible routine you might be able to use to only include cells that have cell values of some kind. It is written as an extension method off of IWorksheet to make utilization of it easier, and includes a bool flag that you can pass in so as to return either the "normal" UsedRange (including cells with other types of formatting) or the "altered" UsedRange discussed here:
public static class SGExtensionMethods
{
public static IRange GetUsedRange(this IWorksheet worksheet, bool ignoreEmptyCells)
{
IRange usedRange = worksheet.UsedRange;
if (!ignoreEmptyCells)
return usedRange;
// Find last row in used range with a cell containing data.
IRange foundCell = usedRange.Find("*", usedRange[0, 0], FindLookIn.Formulas,
LookAt.Part, SearchOrder.ByRows, SearchDirection.Previous, false);
int lastRow = foundCell?.Row ?? 0;
// Find last column in used range with a cell containing data.
foundCell = usedRange.Find("*", usedRange[0, 0], FindLookIn.Formulas,
LookAt.Part, SearchOrder.ByColumns, SearchDirection.Previous, false);
int lastCol = foundCell?.Column ?? 0;
// Return a new used range that clips of any empty rows/cols.
return worksheet.Cells[worksheet.UsedRange.Row, worksheet.UsedRange.Column, lastRow, lastCol];
}
}
A couple additional notes about this approach. It does generally take into account hidden rows or columns--meaning hidden rows or columns that have cell values will be included in the UsedRange. One exception / edge-case to this inclusion of hidden rows or columns is if AutoFilters is enabled on the worksheet. This puts the worksheet in a special "mode" that excludes hidden rows from search results. So if AutoFilters is enabled (in such cases IWorksheet.AutoFilterMode will be true), you may not be able to rely on this approach if the last row(s) or column(s) of the AutoFiltered range could possibly have been filtered out.
enter image description here
Here, there are four cells(A1,B1,C1,D1) have been merged, I would like to get the editable cell address(A1).
According to Excel A1 Cell able to edit, others not editable.
I could able to get merged cells count as 4 using below code.
Also I can get whether cell has been merged or not.
But not able to get the address of editable cell(A1) in merged cells.
Microsoft.Office.Interop.Excel.Application appl = null;
appl = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook wbk;
wbk = appl.Workbooks.Open("C:\\Users\\test\\Desktop\\test.xlsx");
Worksheet sheet = wbk.Worksheets.get_Item(1);
Range range = sheet.Cells[1, 2]; //B1 Cell
var a = range.Cells.MergeArea.Count; // can be able to get merged count cells
string b = range.Address;
**int ab = range.Cells.Areas.Count;**
Range ac = range.Cells.Areas.get_Item(1);
for (int i = 1; i <= 4; i++)
{
**if (sheet.Cells[1, i].Mergecells)** //merged cell
{
MessageBox.Show("Merged");
}
else //Unmerged cell
{
MessageBox.Show("UnMerged Cells");
}
}
wbk.Save();
wbk.Close(false);
appl.Quit();
The MergeArea property of a Range is again a Range. If you have a cell, just use something like the following to get the first (=top left) cell of the merged area (untested in C# as I don't have it available, but works in VBA and should also work for C#):
Range range = sheet.Cells[1, 2];
Range firstCell = range.MergeArea.Cells[1, 1];
This works even if a cell is not merged, MergeArea is always set, so on an unmerged cell range and firstCell would point to the same cell.
If I correctly understood your real need, please try the next approach. It is based on the fact that a merged area keeps the value in its first cell:
'your existing code...
if (sheet.Cells[1, i].Mergecells) //merged cell
{
MessageBox.Show(sheet.Cells[1, i].MergeArea.cells[1, 1].Value);
}
else //Unmerged cell
{
MessageBox.Show(sheet.Cells[1, i].Value);
}
'your existing code...
Here is the solution
string mergedCellsAddress = mergedRange.Address;
string[] firstMergedCell = mergedCellsAddress.Split(':');
string firstCell = firstMergedCell.GetValue(0).ToString().Replace("$", "");
This problem has me completely puzzled.
I have a Excel document which loads in just fine.
It has rows, columns and data and I want to iterate through the rows.
But EPPLus is odd.
I take the second row:
ExcelRange range1 = worksheet.Cells[2, worksheet.Dimension.Start.Column, 2, worksheet.Dimension.End.Column];
Which gives me {A2:D2} Splendid! so far so good but then I want the first cell of the row:
ExcelRange range2 = range1[1,1];
Which give me {A1} and to make matter worse, the value of range1 has also changed to {A1} instead of the row I selected.
How can I resolve this issue and take a ExcelRange from an ExcelRange?
This has me completely puzzled .... thanks for anyhelp
I did have the same problem, to get the correct start cell:
var range2 = worksheet.Cells[range1.Start.Row, range1.Start.Column];
And the same for the bottom right cell:
var range3 = worksheet.Cells[range1.End.Row, range1.End.Column];
If you look at the code behind the ExcelRange Indexer you will see that the get will actually set the base address (the nested else):
public ExcelRange this[string Address]
{
get
{
if (_worksheet.Names.ContainsKey(Address))
{
if (_worksheet.Names[Address].IsName)
{
return null;
}
else
{
base.Address = _worksheet.Names[Address].Address;
}
}
else
{
base.Address = Address;
}
_rtc = null;
return this;
}
}
Why they did it this way I am not sure (I assume there its an implementation detail). But that would explain why referencing another address changes the selected range. So, like Benexx said, have to do a direct reference from the Cells collection of the Worksheet.
You can use the Offset method to get a sub-range of an ExcelRange. This give you a new instance of ExcelRange and does not modify the original instance.
https://www.epplussoftware.com/docs/5.5/api/OfficeOpenXml.ExcelRangeBase.html#OfficeOpenXml_ExcelRangeBase_Offset_System_Int32_System_Int32_System_Int32_System_Int32_
Here is an example:
public static void AlternateRowColor(ExcelRange range)
{
for (var rowOffset = 1; rowOffset < range.Rows; rowOffset += 2)
{
using (var rowRange = range.Offset(rowOffset, 0, 1, range.Columns))
{
rowRange.Style.Fill.PatternType = ExcelFillStyle.Solid;
rowRange.Style.Fill.BackgroundColor.SetColor(Color.Cornsilk);
}
}
}
I have a Excel sheet that looks like this.
|A1|B1| "BLANK" |D1|E1|F1|
I.e. only the first row is populated and the third column is blank. I parse this in C# using interop.excel in the following way:
Excel.Application exApp = OpenExcel();
String mySheet = #"C:\c#\rapport.xlsx";
Excel.Workbook wb = exApp.Workbooks.Open(mySheet);
Excel.Worksheet ws = wb.Sheets[1];
Excel.Range row = ws.Rows[1];
I create a new range only containing the non-empty cells in row 1 by
Excel.Range rng = row.SpecialCells(Excel.XlCellType.xlCellTypeConstants);
Now: if I use rng.Select all the non-empty cells in my sheet is selected. And if I use rng.Count it will return 5, which is the number of non-empty cells in my sheet. But still when I print cell by cell using:
Console.WriteLine(rng[1,i].Value.ToString());
It shows that rng[1, 1-2] contains "A1 and B1", this is nice. But
rng[1, 3] is empty or null. And rng[1, 4-7] contains D1-F1.
How is this possible?
My main goal is to store all non-empty values in a string array. But I can't select the right values because my range rng is both empty and non-empty is some weird way.
Try using:
ws.Columns.ClearFormats();
ws.Rows.ClearFormats();
to be sure your Range excludes formatted but empty cells.
Another try could be to get :
Excel.Range rng = row.SpecialCells(Excel.XlCellType.xlCellTypeConstants,Type.Missing);
This solved it! However I didn't use the .Item method to store the values as Rory suggested suggested. Thnx Rory!
string[] str = new String[rng.Count];
int i = 0;
foreach (Excel.Range cell in rng.Cells)
{
str[i] = cell.Value.ToString();
i++;
}
for (int j = 0; j < str.Length; j++)
Console.WriteLine(str[j]);
I am using Com Interop and C#. I have to iterate through an Excel file looking for certain values in each of the rows (always in column 2). For some values I need to set the background colour of the row to red.
I am having trouble:
Reading the value in cell [i][2] for row i, and
Setting the background colour of this row.
Basically I am looking for something like this (which is the best I can find after much Googling):
// ws is the worksheet
for (int i = 1; i <= ws.Rows.Count; i++)
{
Range range = ws.Cells[i][2];
int count = Convert.ToInt32(range.Value2.ToString());
if (count >= 3)
{
Range chronic = ws.UsedRange.Rows[i];
chronic.EntireRow.Cells.Interior.Color = 0xFF0000;
}
}
Of course this doesn't work. I can't get past the first hurdle of just reading the cell. Any advice is appreciated.
Try this. The code assumes that the value in the column 2 cell is a number.
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
Missing noValue = Missing.Value;
Excel.Range conditionalCell;
foreach (Excel.Range usedRange in ws.UsedRange.Rows)
{
conditionalCell = usedRange.Cells[noValue, 2] as Excel.Range;
if (Convert.ToInt32(conditionalCell.Value2) >= 3)
{
usedRange.Cells.Interior.Color = Excel.XlRgbColor.rgbRed;
}
}