Ok, so I'm trying to set the value of a cell with the excel interop library. I am able to do it with the following:
sheet.Cells[row, col] = value;
but it's terribly slow for how many I'm setting. So I'm trying to go this route:
Range excelRange = sheet.UsedRange;
excelRange.Cells.set_Item(row, col, value);
The code executes, but no data is put in the cell. Any suggestions on what I'm missing? Thanks!
Your first method should work fine for any reasonable (and a lot of unreasonable) amounts of cells, provided you have disabled screen updating (Application.ScreenUpdating = false). The Knowledgebase Article describing how to set cells using C# accesses by row and column as well.
Have you tried setting all of the values at once, rather than iterating through your array and setting one cell at a time? That way you only have to pass data over the COM boundary once, rather than once per cell.
Excel is very flexible in this regard. Try the following:
int[] intArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Range rng = excelApp.get_Range("A1", "J1");
rng.Value = intArray;
You should this faster than iterating over each of the cells you're wanting to set.
Other than that, turn off ScreenUpdated as Andy suggests and also consider setting calculation to manual until you've finished your copy process.
Simple solution but here you will need to install Package Microsoft.Office.Interop.Excel by writting in nuget console
Install-Package Microsoft.Office.Interop.Excel
//test excel file
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook workbook = excel.Workbooks.Open(System.Windows.Forms.Application.StartupPath + "/TrainedFaces/AttendanceLog.xlsx", ReadOnly: false, Editable: true);
Worksheet worksheet = workbook.Worksheets.Item[1] as Worksheet;
if (worksheet == null)
return;
var abc = worksheet.Cells[2, 1].Value;
Range row1 = worksheet.Rows.Cells[1, 1];
Range row2 = worksheet.Rows.Cells[2, 1];
row1.Value = "Test100";
row2.Value = "Test200";
excel.Application.ActiveWorkbook.Save();
excel.Application.Quit();
excel.Quit();
Please try
[excelWorksheet].Cells[1, 1] = "[String you want]";
Related
I have an Excel worksheet with some data. I also have a List of the column headers of the worksheet. The headers in the list are in a different order than the headers in the worksheet, and I need to reorder the Excel worksheet's columns to be the same order as the list.
List<string> dataset1Variables = new List<string>() { "Variable1", "Variable2", "Variable3", "Variable4" };
The headers of my Excel sheet may look like this:
Variable 3 | Variable 1 | Variable 4 | Variable 2
I have come across this code to shift columns but this is only for moving 1 column to a specific location. The list might be completely mixed up so I would need to shift many columns.
Excel.Range copyRange = xlWs.Range["C:C"];
Excel.Range insertRange = xlWs.Range["A:A"];
insertRange.Insert(Excel.XlInsertShiftDirection.xlShiftToRight,
copyRange.Cut());
What would be the best approach for doing this? Preferably using Interop.
If you have an empty row right above your worksheet with data, you can add matching formula right above headers. In below assuming your list is on Sheet2 range B2:B5 and your data headers start on Sheet1 range A2:D2
Excel.Workbook myBook = xlApp.Workbooks.Open(#"path\excel.xlsx");
Excel.Worksheet ws = myBook.Worksheets[1];
// You can use all dynamic ranges instead
// Excel.Range xlRng = ws.Range[ws.Cells[yourRow, firsColumn], ws.Cells[yourRow, lastColumn]];
Excel.Range xlRng = ws.Range[ws.Cells[1, 1], ws.Cells[1, 4]]; // ws.Range["A1:D1"];
xlRng.FormulaR1C1 = "=MATCH(R[-1]C,Sheet2!R2C2:$R5C2,0)";
// Below is how you can get full address for your list if it's in different workbook and replace Sheet2!R2C2:$R5C2 with rangeFullAddress
// string rangeFullAddress = xlRng.Address[true,true,Excel.XlReferenceStyle.xlR1C1,true];
xlRng.Calculate();
xlRng.Value = xlRng.Value;
After this you can just sort your data using Excel Sort by 1st row. After sorting your 1st row it would look like this: 1, 2, 3, 4. Then clear data on 1st row ws.Range["A1:D1"].Clear();.
Your sort key would be Key1: ws.Range["A1:D1"], here is c# sort example using c# to sort a column in excel only change Excel.XlSortOrientation and adjust for your range.
There are other ways to sort but this way you'll keep individual formats, comments of each cell within your data
I missed 1 important detail - that your list is not in Excel sheet, but you can add it to Excel, perhaps in temporary workbook or right on the same sheet:
object [,] columnHeaders = new object[3,0]; // or object[0,3]; if you'd like to add into 1 row
columnHeaders[0, 0] = "Variable1";
columnHeaders[1, 0] = "Variable2";
columnHeaders[2, 0] = "Variable3";
columnHeaders[3, 0] = "Variable4";
xlRng.FormulaR1C1 = columnHeaders; // xlRng would be in the above Sheet2!R2C2:$R5C2
I recently figured out how to write cell values in a range:
Excel.Range rng = (Excel.Range)xlWorkSheet.Range[xlWorkSheet.Cells[1, 1], xlWorkSheet.Cells[10, 10]];
rng.Value = new string[,] { ... };
which speeds up my app enourmous, but I would also like to be able to set a whole range of cell comments! I only found the possibility to make a comment on a range of cells. A single comment. But it does not seem that something for it exists in the api.
You can not set more than one cell comment at once, but you can copy comment from one cell and paste it to multiple cells:
var a1 = xlWorkSheet.Range("A1")
a1.ClearComments(); // just in case
a1.AddComment("some comment");
a1.Copy();
a1.Resize(10, 10).PasteSpecial(Excel.XlPasteType.xlPasteComments);
Similar to
EPPlus - Named Range is not populated
In his case, his ranges were at the workbook level but he was looking at the worksheet level.
My EP code shows a count of 0 ranges at the workbook level and 15 at the sheet level, as it should be.
Opening the worksheet.Names shows all 15, with proper names.
Retrieve a range, and the formula is correct with
"OFFSET(Sheet1!$A$33, 0, Sheet1!_CurrentMonth, 1, 55 -Sheet1!_CurrentMonth)", but almost everything else returns an exception on evaluation.
It reports 1 column, which is incorrect.
And the 'FullAddress' looks correct with "'Sheet1'!_Fund1Projected", but 'FullAddressAbsolute' gives "$#REF!$-1"
Lastly, I'm using a template, xltm, to create a spreadsheet, xlsm.
public static void CreateChart()
{
var excelFullPath = "C:\\Users\\username\\Documents\\Excel\\Templates\\";
var excelFileName = "LowCashBalanceChart.xlsm";
FileInfo newFile = new FileInfo(excelFullPath + excelFileName);
if (newFile.Exists)
newFile.Delete();
FileInfo template = new FileInfo(excelFullPath + "Sample Chart.xltm");
using (ExcelPackage xlPackage = new ExcelPackage(newFile, template))
{
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets["Sheet1"]; //xlPackage.Workbook.Worksheets.FirstOrDefault();
ExcelNamedRange namedRange;
namedRange = xlPackage.Workbook.Names["_Fund1Projected"]; // fails, no ranges at the WB level
namedRange = worksheet.Names["_Fund1Projected"]; // this one works
for (int rowIndex = namedRange.Start.Row; rowIndex <= namedRange.End.Row; rowIndex++) // Exception on range.Start
// 'namedRange.Start' threw an exception of type 'System.ArgumentOutOfRangeException'
{
for (int columnIndex = namedRange.Start.Column; columnIndex <= namedRange.End.Column; columnIndex++)
{
worksheet.Cells[rowIndex, columnIndex].Value = (rowIndex * 100 + columnIndex).ToString();
}
}
xlPackage.Save();
}
}
I looked at the code on GitHub, but nothing stands out.
Tried it with the ranges at the workbook level as well with the same results.
I solved my problem, I'll put answer here for anyone that may need it in the future.
I created a range for a 3x3 square.
Range1 = =Sheet1!$A$24:$C$26
I can write to that just fine. No exceptions.
But when we have ranges that have endpoints determined by values of other cells, it fails.
=OFFSET(Sheet1!$A$32, 0, Sheet1!_CurrentMonth, 1, 55 -Sheet1!_CurrentMonth)
The problem is that our named ranges are dynamic.
That’s why it was getting an exception.
The work-around is to not use dynamic ranges from EPPlus.
Just a little more C# code to handle the dynamic part instead of Excel handling it for you.
How can I move to the next row in Excel using C#. I'm using Office PIA v 14. When I used Range.Next property, it takes me to the cell immediately right to the range. How can I move to the next row? ie. the cell immediately below.
Range.Next returns a Range object that represents the next cell.
I'm not really the greatest expert alive but according to the documentation you should use Offset instead. http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.offset
Here is some pseudo code
var excelApp = this.Application;
int skipRows = 1;
int skipCells = 0;
var nextRange = excelApp.ActiveCell.Offset[skipRows, skipCells].Select();
Try the following code:
Range oRng = ws.get_Range(Column + (row +1), Type.Missing);
where ws is the worksheet object.
I'm working with an excel object in c#. I want to auto-fit the columns, but like this: I want the columns' width to be 5 bigger than what the AutoFit method set.
How can I get the width after AutoFit() is used?
How can I make the columns 5 bigger than this width?
If you wish to use the Selection object and have IntelliSense with early binding, you need to cast the Selection object to a Range first:
Excel.Range selectedRange = (Excel.Range)myExcelApp.Selection;
selectedRange.Columns.AutoFit();
foreach (Excel.Range column in selectedRange.Columns)
{
column.ColumnWidth = (double)column.ColumnWidth + 5;
}
-- Mike
Assuming that you are on cell A1 & have long text in it, following code will make the column Autofit and then increase the width by 5 characters.
Selection.Columns.Autofit
Selection.Columns(1).ColumnWidth = Selection.Columns(1).ColumnWidth + 5
Try to loop through your rows to get the text length of it:
var row = 1;
ws.Column(1).AutoFit(ws.Cells[row, 1].Text.Length + 5);
Where ws is your Worksheet:
var pck = new ExcelPackage();
var ws = pck.Workbook.Worksheets.Add("Plan1")
Try Like this,
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Sheet1");
//Load the datatable into the sheet, starting from cell A1. Print the column names on row 1
ws.Cells["A1"].LoadFromDataTable(data_table, true);
//Set full Sheet Auto Fit
ws.Cells[1, 1, data_table.Rows.Count, data_table.Columns.Count].AutoFitColumns();