Excel manipulation from C# - Set ActiveCell? - c#

What is the C# equilivant to this VB6 to setting of the active cell?
ActiveSheet.Range("L1").Select

Here's a sample piece of code:
Excel.Worksheet sht = (Excel.Worksheet)ActiveSheet;
sht.Cells[3, 3] = "HELLO";
You can also capture ranges:
Excel.Range rng = (Excel.Range)sht.Cells[3, 3];
I believe to you just the Select method as before to select a range, although I haven't tested this.
rng.Select();
You can obviously streamline this and chain these statements together, with the right casting. I don't want to hazard a guess here as I've not got a VSTO project open in from of me.
EDIT
You should also be able to get a range from the sheet using get_Range:
rng = sht.get_Range("A1", Type.Missing);
VSTO tends to return Objects most of the time, necessitating casts, but get_Range is an exception. Someone might be able to correct me as I am not a big user of VSTO (still VBA die-hard when it comes to Excel).

Related

Setting style in cells with conditional formatting in ClosedXML C#

There was a need to make conditional formatting of a cell with a histogram. Used ClosedXML but it didn't give the desired result.
It is necessary to solve the problem with both the gradient and negative numbers. Has anyone encountered something similar? I am attaching the code.
form_sheet.Cell("D37")
.AddConditionalFormat()
.DataBar(XLColor.FromArgb(68, 114, 196), false)
.Minimum(XLCFContentType.Number, -3)
.Maximum(XLCFContentType.Number, 3);
Ready to consider alternative solutions not through ClosedXML. The program will generate several dozen reports. All histograms will be in the same cells, so I also considered vbs, but I don’t have enough experience to write such a script that would change styles immediately for a bunch of documents.
Bit late to answer, might be helpful for others..
I also gone through the same gradient issue. Currently using ClosedXML it is not possible to generate conditional DataBar with solid color.
What am doing to resolve my issue is to generate the Excel as of now with ClosedXML and re-open the Excel again in Interop and add the DataBar in the respective cells using Interop.Excel.
I haven't fully rewrote the code using interop because performance wise we can't fully rely on interop as compared to ClosedXML, atleast for me.
Sample code for adding Databar using Interop
var excel = new Microsoft.Office.Interop.Excel.Application();
var workBooks = excel.Workbooks;
var workBook = workBooks.Add();
var workSheet = (Microsoft.Office.Interop.Excel.Worksheet)excel.ActiveSheet;
workSheet.Cells[1, "A"] = 10;
Microsoft.Office.Interop.Excel.Range range1 = workSheet.Cells[1, 1];
Microsoft.Office.Interop.Excel.Databar bar = (Microsoft.Office.Interop.Excel.Databar)range1.FormatConditions.AddDatabar();
bar.BarFillType = Microsoft.Office.Interop.Excel.XlDataBarFillType.xlDataBarFillSolid;
Thanks.

Most effective way to duplicate an Excel worksheet?

I am working on a project upgrading a WPF program that has to work with Excel sheets a lot. It's using Closedxml and Excel interop to manipulate Excel files and add data.
After some trace I found a function that's painfully slow. It use the same method as other similar function, but everything else is working quite fine. The problem is Closedxml.copyto() eats up 85% of processing power.
It's purpose simply is to take one Excel sheet as a template if there is new record that need to be printed. it will copy the first sheet to new sheet then write data into it.
If you have any idea on how to speed up this kind of process, Please let me know!
foreach (object[] row in rows)
{
if (Common.integer(row[0]) < from_no || Common.integer(row[0]) > to_no)
{
continue;
}
sheetNum++;
if (sheetNum != 1)
{
this part use 85% of process Power
sheet_edit.CopyTo(sheetNum.ToString());
sheet_edit = book.Worksheet(sheetNum);
}
sheet_edit.Name = row[0].ToString();
ct.ThrowIfCancellationRequested();
w.ReportProgress(progCnt * 100 / maxCnt);
progCnt++;}
Thank you very much!
PS: sorry for my bad English!
PS: To anyone who did downvote my question, Please tell me the reason? Is it Not helpful or ... other reason?
PS: I searched all day but i cant find any answer for this. There are quite some method but those all just dont fit my need.
using interop: not quite faster.
using openxml: it mean i have write more code and it not quite easy to intergrade to this program
using closedXML.copyRange: Sure quite faster but it doesnt copy columns width, row height,... it mean more code, mode process... So not quite faster.
I decided to use dianogtics.process(print) in the loop, that 1st sheet will be reused in every loop. It kind of faster, but we cant choose printer or printer setting... default printer and setting will be used automatically.
I can explain this to my customer and i think this is quite aceptable.
But i am still waiting for the answer.. I you happened to know how to fasten this kind of processs up, please let me know!!
ClosedXML has to copy each object (cell, style, picture, etc) from the source to the destination. If you have many thousands of cells, then this will consume your CPU cycles.
You should ensure that your source worksheet contains only the cells and styles that you really need. In my experience, I have seen many Excel templates that contain many unused styles and empty cells at bizarre worksheet addresses.
If I were you, I would recreate the template as far as possible in ClosedXML itself (even if just a once-off process). This will ensure that your template is as minimal as possible. ClosedXML doesn't support all features yet, so after you create the template, you may want to add elements (e.g. charts). Then use that saved template in your further processing. It should be much smaller and faster as the one you're using now (my guess).
Other options you could try: An .xlsx file is just a .zip package. You can look at the underlying XML inside the file and determine how many cells or styles there are to be copied.
You can also download the ClosedXML source and narrow down exactly which kind of element is taking up the resources.
Disclaimer: I'm a ClosedXML project maintainer.
Instead of using ClosedXml to copy the sheet , You can use the Excel Interop to do the same. Below is the sample code for copying the worksheet
Excel.Application xlApp = Marshal.GetActiveObject("Excel.Application") as Excel.Application;
Excel.Workbook xlWb = xlApp.ActiveWorkbook as Excel.Workbook;
Excel.Worksheet xlSht = xlWb.Sheets[1];
xlSht.Copy(Type.Missing, xlWb.Sheets[xlWb.Sheets.Count]);
xlWb.Sheets[xlWb.Sheets.Count].Name = "NEW SHEET";

Apply Formatting to Excel Named Range using Office.Interop C#

I'm trying to change the formatting for all Named Ranges in an Excel file but I'm getting an error: "unable to set the name property of the font class".
Sorry if this has been asked but I could not find any.
Here's my code. I'm sure I'm just missing something.
Thanks in advance!
Excel.Application xlsx = new Excel.Application();
Excel.Workbook wb = xlsx.Workbooks.Open(filepath, ReadOnly: false, Editable: true);
foreach (Excel.Name NamedRange in wb.Names)
{
//MessageBox.Show(NamedRange.Name.ToString());
NamedRange.RefersToRange.Cells.Font.Name = "Arial";
}
xlsx.Application.ActiveWorkbook.Save();
xlsx.Application.Quit();
xlsx.Quit();
When you see any error that resembles that one, it probably indicates that either the cell, the worksheet or the workbook itself is protected. Try to select the range manually (within Excel, not C#) and change the Font. My guess is you will get a similar error.
There are ways to unprotect within C#, but before heading down that path, evaluate the use case and see if that makes sense for what you are trying to do.
Or, check to see if the range is protected before executing your command. Something similar to this should work.
if (!NamedRange.RefersToRange.Locked)
NamedRange.RefersToRange.Cells.Font.Name = "Arial";
On a side note, Excel has pretty weak protection (by design), there are ways to hack the protection. Here is one example:
Alternatives to try/catch in VSTO

Does the function get_Range allow for ranges outside the current sheet?

I was wondering whether someone encountered this before, suppose we have the following piece of code:
Excel.Range vl_range = (Excel.Range)((Excel.Worksheet)Application.ActiveSheet).get_Range("A1");
This safely returns the range of A1. However, if we input the string "'new sheet'!$C$1", then it gives a HRESULT error.
But, this can be solved by, the following piece of code:
Excel.Range vl_range = (Excel.Range)(Application.get_Range("'new sheet'!$C$1"));
That does seem to work. Now I was wondering if I input "A1" just in the last line of code, would it automatically assume that I'm referring to the active sheet?
Can someone explain to me, why this seems to be different in VBA? Where I can define ranges easily using the Range method, even though I am in a sheet?
Is my conclusion correct or am I making a horrible mistake somewhere?
For anyone who is interested. I have tested the code and if we use:
Excel.Range vl_range = (Excel.Range)(Application.get_Range("C1"));
Excel automatically assumes that you are referring to the Activesheet.

Using EPPlus library to replace formulas by their values in Excel

I've read that Microsoft.Office.Interop.Excel would be the easiest way to replace formulas by their values in Excel but it requires to have Office installed. Since I will need to deploy on a Windows Server (2008 or 2012), I am looking for the best and/or simplest way to accomplish that using EPPlus.
Adding formulas is well documented, e.g.
currentWorksheet.Cells["C4"].Formula = "SUM(C2:C3)";
But I cannot find any example of replacing entire worksheets of formulas by their equivalent values. Basically the Copy followed by the Paste Special option in Excel.
I dont think there is any kind of function built into Epplus that will do that for you en masse. But you can take advantage of the fact that the Cells collection of the Worksheet only contains entries for cells with content. So something like this should not be too painful performance-wise:
currentWorksheet.Cells["C2"].Value = 5;
currentWorksheet.Cells["C3"].Value = 15;
currentWorksheet.Cells["C4"].Formula = "SUM(C2:C3)";
currentWorksheet.Cells["D2"].Value = 15;
currentWorksheet.Cells["D3"].Value = 25;
currentWorksheet.Cells["D4"].Formula = "SUM(D2:D3)";
//Calculate the formulas and the overwrite them with their values
currentWorksheet.Cells.Calculate();
foreach (var cell in currentWorksheet.Cells.Where(cell => cell.Formula != null))
cell.Value = cell.Value;
I know this is 3 years old, but if you're reading this now, EPPlus now has the function .ClearFormulas() that does just that, simply do
yourSheetHere.Calculate();
yourSheetHere.ClearFormulas();
and you're good to go.

Categories