Short version: what is the preferred approach for embedding controls in a PowerPoint slide that send events back to an application-level add-in? The controls need to work in slide show mode and in design mode.
Long version:
I recently was brought into development on a legacy add-in for PowerPoint that (in a nutshell) pulls data from remote data sources and draws corresponding charts on slides. The add-in is managed code (C#), but is NOT built with VSTO - it uses custom wrappers and a COM shim.
The charts periodically need to be refreshed, and our add-in has a Refresh button in the toolbar for this purpose. In cases where a chart can't render at all until refreshed, we also embed a MSForms.CommandButton on the slide itself (as an OLE object). We have used this approach in a similar Excel add-in with success.
Unfortunately, it does not work in PowerPoint: the click event on the button does not seem to reach our add-in. I have found some information online that supports this observation. I have also tested it with a MSForms.ComboBox instead of a button and that worked--the combo box's change event reaches our add-in and the refresh succeeds.
So it seems that I need to find an alternative way to have the button communicate with our add-in. I can think of a few approaches and am wondering if there is a best practice:
Have the button (or a similar shape) run a macro that calls code in our add-in. I've heard that this might not work when the slide is viewed in Design Mode, but haven't tested yet to confirm.
Embed an MSForms form in the slide as well, to capture the click event and pass it on to our add-in. Again, this is just a theory and is untested as of yet.
Use something else entirely - something tells me there has to be a "modern" way of doing this, I'm just not familiar enough with Office development to know what that is.
I'll add that migrating to VSTO or a similar technology (such as NetOffice) is an option, but we'd prefer to avoid that if possible. Thanks!
Related
I have created a C# VSTO add-in with Visual Studio 2019 that receives commands from a socket connection and it can insert text, modify buttons only in my ribbon using office Interop.
I want to know two things.
How can I get the name of all the ribbons (Home, Insert, Design,
....) programmatically?
Initiate a mouse click (for example click Bold button in the Home tab) on any other ribbons than the one I created.
For the 2nd question, I want to use office add-in only, not by simulating keypress/mouse event.
How can I get the name of all the ribbons (Home, Insert, Design, ....) programmatically?
There is no trivial way for getting this job done. You can try using Accessibility API. Microsoft Active Accessibility is a Component Object Model (COM)-based technology that improves the way accessibility aids work with applications running on Microsoft Windows. It provides dynamic-link libraries that are incorporated into the operating system as well as a COM interface and API elements that provide reliable methods for exposing information about UI elements.
Initiate a mouse click (for example click Bold button in the Home tab) on any other ribbons than the one I created.
You can use the CommandBars.ExecuteMso method which executes the control identified by the idMso parameter. This method is useful in cases where there is no object model for a particular command. Works on controls that are built-in buttons, toggleButtons, and splitButtons. On failure, it returns E_InvalidArg for an invalid idMso, and E_Fail for controls that are not enabled or not visible.
Application.CommandBars.ExecuteMso("Copy")
Accessibility API (as Eugene mentioned) is pretty much the only way to drive Outlook Ribbon and its controls. Keep in mind that since Microsoft has never documented the controls and their ids, they are subject to change between the versions.
If using Redemption (I am its author) is an option, it exposes SafeExplorer and SafeInspector objects that expose the ribbon and its controls using Accessibility and low level Windows API.
Redemption.SafeExplorer sExplorer = new Redemption.SafeExplorer();
sExplorer.Item = OutlookApplication.ActiveExplorer;
foreach (var tab in sExplorer.Ribbon.Tabs)
{
MessageBox.Show(tab);
}
Is it possible to handle button click events on a custom ribbon button from another application using interop?
So if I've created a Word 2010 application add-in which creates a custom tab with several buttons and then I instantiate a Word application from a C# win forms application using interop, how would I then go about wiring up to the button click events on my custom ribbon from the win forms app? With Word 2003 I could access the buttons through the CommandBars collection and then simply wire up to the click event.
After some further reading, I guess what I'm trying to do is find out how to get access to the Ribbon object model using interop. Is this possible?
[Edit]
For anyone that's interested. When I wrote this question I knew of another way to solve my problem, but it means a lot of extra work changing my existing implementation to upgrade from Office 2003 to Office 2010, and so I was hoping there would be away to access the Ribbon object model outside of a VSTO add-in.
My solution is to use an IpcChannel to make calls from the vsto add-in to my win-forms application. So my win-forms application initialises the Word instance and then opens up a server channel. In the vsto add-in I handle Application.DocumentOpen and if the document is owned by my application I open a client channel to my application. I can then make calls back to my win-forms app from the vsto add-in through the use of shared interfaces.
While this technique works, it does have some draw backs. If the calls through the ipc channel are synchronous then my application can't touch the word object because a deadlock occurs. Making asynchronous calls introduces other problems, but I found that I could block the Word window with a modal dialog without ending up deadlocked.
While this isn't an exact answer to my original question, it is an alternative and so I thought I would share this with anyone else having this problem.
If anyone does know how to access the Ribbon object model outside of VSTO I would still be interested to know how.
Edit: I finally discovered a code.msdn.microsoft.com project that incorporates native C# ribbon manipulation. Use that instead of any VBA business.
Original Post:
You don't need VSTO to access the ribbon programmatically. Visit Word Articles for a brief Word VBA example.
I'm certain there's a way to accomplish the same in C#, but I have yet to implement one. If I find one, I will be certain to share. (I previously contributed an answer that contains a C#-VBA workaround.)
I am currently diving into VSTO add-in development and ribbon customization for Word 2010. This works fine, but has a drawback: The ribbon customization should take place for only certain documents, but the IRibbonExtensibility.GetCustomUI() method is obviously called on application startup before any document is loaded. How can I accomplish this requirement?
You're right that it's only called once. About your only choice (and what's worked for me reasonably well), is to define EVERYTHING in your ribbon up front, then set the VISIBLE property to false or true as applicable depending on what doc is loaded, or whatever else is happening in your addin.
#drventure is right, you have to define your ribbon up front, then show/hide different buttons on the ribbon.
What might help you though is some of the features in a project I have been working on, VSTO Contrib, it allows you to create a ViewModel, which will be created for each open document, and it will discover and wire up the ribbon xml by convention.
In your case this would mean you can bind the ribbon buttons visibility to a property on the viewmodel, and you don't have to worry about keeping the window/documents syncronised. Have a read of http://jake.ginnivan.net/vsto-contrib/ribbon-factory and see if it will help you solve your problem with a heap less code =)
When a slideshow running in PowerPoint I want to control the movement (Next and Previous) of the slides. Of course it is possible with the > and < button on the keyboard, but is there any way in which I can have a custom application listening to the Next and Previous controls?
My custom application has nothing but 2 buttons, next and previous, when I click either, the button's event handler should pass the control to the PowerPoint application running the slideshow. And thus, PowerPoint will move the slideshow back or forward?
Somewhat similar to the way remote, wireless PowerPoint Presenters work on the s/w end.
Yeah, totally doable. The event you want is SlideShowNextSlide - you can read more about it here. For C# and PowerPoint-specific, this is a great article: How to handle PowerPoint events with Visual C# .NET.
Also, this search on SO turns up some good reading and things to watch out for. Finally, I don't know if C# has one, but there is a "Remotely Controlling PowerPoint" sample in both VS2008/VS2010 for VB.NET that is probably easy enough to port to C# - here's the info page on it.
I am investigating automated testing of an old Win32 application that used ActiveX controls. I am spiking use White (from Thougthworks) that uses Microsoft UIAutomation. I can find the AutomationElement related to the control, but how do I interact with it?
Spy++ sees the grid control as a single window, so I can't talk to rows, columns, or cells directly. How do I talk to the SSUltraGrid control from my test code?
Cheers
Nigel
The basic problem with some ActiveX and other custom controls like SSUltraGrid is what you mentioned, they're presented as just one window. So unless they've provided an API that makes them "friendly" to your GUI automation tool, you'll always face this challenge. Of course many companies offer newer versions of their products that are friendlier to UI Automation than before... perhaps upgrading the control is worthwhile...
Failing that... what the test engineers at my job have told me is that when they encounter that situation, if there are well known keystrokes to invoke the activity they desire, they send keystrokes to the control window. If they're lucky enough to have things in a fixed location, they might even be able to get away with sending mouse events. However, that's dicey at best.