C#.NET : Add Scrollbar to Excel Worksheet - c#

I need to add a scrollbar to worksheet and link cell to it using Microsoft.Office.Interop.Excel library and C#.NET.
The correspoding VBA code is like this:
ActiveSheet.ScrollBars.Add(545.25, 172.5, 398.25, 24.75).Select
With Selection
.Value = 0
.Min = 0
.Max = 100
.SmallChange = 1
.LargeChange = 10
.LinkedCell = "$A$1"
.Display3DShading = True
End With
I tried the below code, it added Scrollbar but not working as expected and also unable to link cell to it.
oSheet.Shapes.AddOLEObject("Forms.ScrollBar.1", Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, 545.25, 172.5, 398.25, 24.75);
My C#.NET Code adds scrollbar as an object to Excel, where as i need it as a control. It seems there is a difference in it.
Actual Result using my C#.NET code is attached as image below
But the Expected result is attached as image below:

I found the solution Here.
Yes earlier I was adding ActiveX Object in place of Control. The below code works fine.
using Excel = Microsoft.Office.Interop.Excel;
:
:
Excel.ControlFormat Scrollbar = oSheet.Shapes.AddFormControl(Excel.XlFormControl.xlScrollBar, 545, 172, 398, 24).ControlFormat;
Scrollbar.Value = 0;
Scrollbar.Min = 0;
Scrollbar.Max=100;
Scrollbar.SmallChange = 1;
Scrollbar.LargeChange = 10;
Scrollbar.LinkedCell = "$A$1";

Related

Excel OLEObject button loses click event after clicking a few times

I was trying to create an Excel button in a sheet from a C# code, using a C# event hander for the button, so I don't have to involve VBA and text scripts; and I found this great solution from #
Dummy yoyo that works but "only for a while".
The solution is simple: add a shape, get it as an ole object, get the ole as a button and add a click event:
int i = 1;
private void CreateButton()
{
Microsoft.Office.Interop.Excel.Worksheet sheet = #get a sheet from Excel
sheet.Shapes.AddOLEObject("Forms.CommandButton.1", Type.Missing, false, false, Type.Missing, Type.Missing, Type.Missing, 10, 10, 100, 30);
Microsoft.Office.Interop.Excel.OLEObject oleShape = sheet.OLEObjects(1);
Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
button.Caption = "Custom Buttom" + i;
button.Click += Button_Click;
i++; //for future use, see below
}
private void Button_Click()
{
MessageBox.Show("It works!");
}
The problem:
Now, the first time I click the button on the sheet, it works! The second time "might" work. The more clicks the less chance of it working. Inevitably, the button "loses" the click event and just does nothing. I can't figure out why, what can be causing this.
I even tried to recreate the button every click with:
private void Button_Click()
{
MessageBox.Show("It Works!");
sheet.Shapes.Item(1).Delete();
CreateButton();
}
I can see the button is being recreated because of the i++ that shows in the button's caption. Even though, some clicks later, even the newly created button simply does nothing when clicked.
What can be going on? How can I solve this?
Edit:
A partial solution was found, as #Hans Passant suggested: if I keep the shape, the ole object and the button as static members outside the method, the garbage collector doesn't kill them. Nevertheless, I would like to save, close and reopen the sheet and still get the events.
Great solutions could be:
Identifying why it happens and solving it
Suggesting another way of creating the button using a c# click handler
Making it possible to save this sheet, close and reopen it with the events still attached.
A few more details:
I am creating a new Excel application from C# code and taking the first sheet of the first workbook.
This is not a VSTO Addin, I don't have access to the Globals.Factory, although I'd love to be able to get an instance of this factory and try Microsoft.Office.Tools.Worksheet methods to add controls.
My project is inevitably a class library consumed by another non-related software
The sheet must be saved and reopened later independently from the source project.
The sheet is populated before adding the button, also via C# code.
Visual Studio debugger is able to step into the button's event handler without any special action
Following way every time I click on this button not getting any issue.
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
int i = 1;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
//add data
xlWorkSheet.Cells[1, 1] = "";
xlWorkSheet.Cells[1, 2] = "Student1";
xlWorkSheet.Cells[1, 3] = "Student2";
xlWorkSheet.Cells[1, 4] = "Student3";
xlWorkSheet.Cells[2, 1] = "Term1";
xlWorkSheet.Cells[2, 2] = "80";
xlWorkSheet.Cells[2, 3] = "65";
xlWorkSheet.Cells[2, 4] = "45";
xlWorkSheet.Cells[3, 1] = "Term2";
xlWorkSheet.Cells[3, 2] = "78";
xlWorkSheet.Cells[3, 3] = "72";
xlWorkSheet.Cells[3, 4] = "60";
xlApp.Visible = true;
#region
xlWorkSheet.Shapes.AddOLEObject("Forms.CommandButton.1", Type.Missing, false, false, Type.Missing, Type.Missing, Type.Missing, 10, 10, 100, 30);
Microsoft.Office.Interop.Excel.OLEObject oleShape = xlWorkSheet.OLEObjects(1);
Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
button.Caption = "Custom Buttom" +i ;
button.Click += Button_Click;
i++;
#endregion
}
private void Button_Click()
{
MessageBox.Show("It works!");
}
but sometime button seems not clickable or not fire click even. see below screenshot.
Message show already, but we do not see it in top of the worksheet. too many time click on the button it may happened. so if you do not see the dialog just open it from taskbar.
Reopen: Controls that are added at run time are not persisted when the document or workbook is saved and closed. The exact behavior is different for host controls and Windows Forms controls. In both cases, you can add code to your solution to re-create the controls when the user reopens the document.
xlApp = new Excel.Application();
string workbookPath = #"c:/Book.xlsx";
xlWorkBook = xlApp.Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
xlApp.Visible = true;
Microsoft.Office.Interop.Excel.OLEObject oleShape = xlWorkSheet.OLEObjects(1);
Microsoft.Vbe.Interop.Forms.CommandButton button = oleShape.Object;
button.Caption = "Custom Buttom" + i;
button.Click += Button_Click;
i++;
NB: Microsoft Excel 2013, project reference Microsoft office 15.0 object Library and VS 2022 work perfectly but Excel 2016 has this issue you are telling about. so I think this issue has come from
Microsoft Office specific version.
if you want to make it count clicks try this..
const btn = document.querySelector('.btn');
btn.onclick = Counter;
const clicks = document.querySelector('.clicks');
clicks.id = document.querySelector('clicks');
var a = 0;
function Counter() {
a += 1;
clicks.innerHTML = a;
}
const reset = document.querySelector('.reset');
reset.onclick = resetCounter;
function resetCounter() {
a = 0;
clicks.innerHTML = a;
}

Extra Excel Application Opening while creating powerpoint charts

I am creating charts in PowerPoint. The below code opens two excel applications. One opens in the background that is invisible. The second one opens after the method ends. I need to make sure second excel either never open ideally or I can close it after it opens.
I have tried the below things but none worked.
I have tried forcing GC, Manual ReleaseComObject, Killing Excel process
I have tried separating excel COM objects and forcing GC
private void BtnInsert_Click(object sender, EventArgs e)
{
var Addin = Globals.ThisAddIn;
Microsoft.Office.Interop.PowerPoint.Application activeApplication = Addin.Application;
DocumentWindow activeWindows = activeApplication.ActiveWindow;
Microsoft.Office.Interop.PowerPoint.View activeView = activeWindows.View;
Slide activeSlide = activeView.Slide;
Microsoft.Office.Interop.PowerPoint.Shapes slideShape = activeSlide.Shapes;
Microsoft.Office.Interop.PowerPoint.Shape shape = slideShape.AddChart2(-1, XlChartType.xl3DBarClustered, -1, -1, -1, -1, true);
Microsoft.Office.Interop.PowerPoint.Chart chart = shape.Chart;
//Access the chart data
Microsoft.Office.Interop.PowerPoint.ChartData chartData = chart.ChartData;
chartData.Activate();
//Create instance to Excel workbook to work with chart data
Workbook workbook = chartData.Workbook;
Microsoft.Office.Interop.Excel.Application workbookApplication = workbook.Application;
workbookApplication.Visible = false;
workbookApplication.WindowState = XlWindowState.xlMinimized;
//Accessing the data worksheet for chart
Worksheet worksheet = workbook.Worksheets[1];
// I am adding data here
// This is not required to reproduce this
chartData.BreakLink();
workbook.Close(true);
}
Also, note that this issue does not occur while updating data.
Remove chartData.Activate() and chartData.BreakLink() solves this.
Although online documentation says that chartdata.activate is required before accessing the workbook.
Otherwise, we will get a null reference.
I think the documentation is incorrect or it does not apply to vsto.

C# - Select Cell at Bottom Right corner

I am looking for a way to move my selected cell from the top left to the bottom right. I was trying to use xlDirection but that highlights everything and doesnt allow me to do a combination of movements.
A B C
1 4 7
2 5 8
3 6 9
I start at A and now only want to focus on 9. The size of the excels change so i cant specify the actual cell to look for each time.
I was hoping there are similar commands as Ctrl+Down or Ctrl+Right that would put me on the cell.
can't you send keystrokes to the object?
A reference for all key strokes can be found here:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.excel._application.sendkeys?view=excel-pia
public class Navigator
{
private Excel.Application excel;
private Excel.Workbook workbook;
public void NavigateToBottomRight(string filePath, string worksheetName)
{
excel = new Excel.Application();
excel.Visible = true;
workbook = excel.Workbooks.Open(filePath);
var worksheet = workbook.Worksheets.Cast<Excel.Worksheet>().FirstOrDefault(x => x.Name == worksheetName);
Excel.Range cell = worksheet.Cells[1, 1];
cell.Activate();
string controlRight = "^{Right}";
string controlDown = "^{Down}";
excel.SendKeys(controlRight, true);
excel.SendKeys(controlDown, true);
//Do other work here
workbook.Save();
excel.Quit();
}
}
Hope this helps!

how to get selection range from excel 2010?

i cant get selection range from excel. i am using below code block and i can get active sheet like this. but i need only selection range. how can i do this?
Microsoft.Office.Interop.Excel.Application ExApp = Globals.ThisAddIn.Application as Microsoft.Office.Interop.Excel.Application;
Microsoft.Office.Interop.Excel.Worksheet ExWorksheet = ExApp.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
Microsoft.Office.Interop.Excel.Range activeSheet = ExWorksheet.UsedRange as Microsoft.Office.Interop.Excel.Range;
thanks for advice.
The selection is a property of the Application, so you should use something like:
Microsoft.Office.Interop.Excel.Application ExApp = Globals.ThisAddIn.Application as Microsoft.Office.Interop.Excel.Application;
Microsoft.Office.Interop.Excel.Range SelectedRange = ExApp.Selection as Microsoft.Office.Interop.Excel.Range;
Just be careful that the object returned by Selection could be something different fromn a Range (e.g. it could be a Chart), so you should check for null values of SelectedRange.

Get Specific Text in a Range of Excel cells using C#

I am working in WPF application with excel . In that application i am having a column name as Bulk. That column contains two options like YES and NO as a text. Now i need to indicate the font as red color for YES option and Normal Black color for NO option.
I got the range of that particular column. But i dont know How shall i get the YES options and NO options seperately and also i need to color that options as per the need.
Here I mentioned my code :
foreach(Range Value in range.cells)
{
???????
???????
}
Any one pls tell me the solution of this. How shall i proceed this process. Thanks in Advance.
Try this
string strFileName = "D:\\test1.xlsx";
Microsoft.Office.Interop.Excel.Application ExcelObj = null;
ExcelObj = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook theWorkbook = ExcelObj.Workbooks.Open(strFileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Microsoft.Office.Interop.Excel.Sheets sheets = theWorkbook.Worksheets;
Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)sheets.get_Item(1);
Microsoft.Office.Interop.Excel.Range range = worksheet.get_Range("A11", "G21"); // Your requied range here
foreach (Microsoft.Office.Interop.Excel.Range cell in range.Cells)
{
if(cell.TextToString()=="Yes")
{
}
if(cell.TextToString()=="No")
{
}
}
For more information check here
http://msdn.microsoft.com/en-us/library/4zs9xy29(v=vs.80).aspx
Add this class to your project and change the namespace to yours and start using it to create what you want in coloring settings
as far as your YES/NO detection, you can do the following:
Microsoft.Office.Interop.Excel.Range range = myworksheet.UsedRange;
//Start iterating from 1 not zero, 1 is the first row after notation of the current coloumn
for (int i = 1; i <= range.Rows.Count; i++)
{
Microsoft.Office.Interop.Excel.Range myrange = myworksheet.get_Range(/*your column letter, ex: "A" or "B"*/ + i.ToString(), System.Reflection.Missing.Value);
string temp = myrange.Text;
if(temp.Contains("YES"))
{
//Do your YES logic
}
else if(temp.Contains("NO"))
{
//Do your No Logic
}
}
As for the Value check on the Cells, you can use the Class that Sherif Mahar Eaid Suggested,
When I use VBA to look for excel cells, I use something that looks more like this
' this is VB script though.
if (Range("A1").Value = "DesiredString") Then
Code
End If
I am almost certain that for cell objects there is a value get method on C#,
and for the colors, I think that
YourRange.Font.Color = System.Drawing.Color.Black.ToArgb();
will work...

Categories