Outlook Add-In - Enable/Disable Button during Runtime/from Code - outlook

Initial Situation:
We are developing an Add-in for Outlook 2010 in C# with VS.NET 2010 based on Framework 4.0, VSTO, DevExpress WinForm Controls. In Designer we have a Ribbon with a RibbonTab, then a RibbonGroup then a RibbonButton. We're consuming WebServices from within this Outlook Add-in.
Objective:
We need to enable/disable the RibbonButtons when the WebService is available/unavailable (from/out of the code)
we've found the following links:
Links
Ribbon Object Model Overview: http://msdn.microsoft.com/en-us/library/bb608623.aspx
Ribbon Overview: http://msdn.microsoft.com/en-us/library/bb386097.aspx
Walkthrough: Updating the Controls on a Ribbon at Run Time: http://msdn.microsoft.com/en-us/library/bb608628.aspx
After hours of trying to figure out how to implement this we deciced to post/ask this question here on SO. Does anybody have a sample code? We tried the IRibbonExtensibility and CreateRibbonExtensibilityObject => we added the RibbonTab, Group and Button and added a subscription to the Click Event => The Event is fired but not handled (in button_Click(...) => System.Diagnostics.Debugger.Break() is not breaking the code execution)
Thanks!
Christian

You'll want to invalidate the Ribbon at a fairly frequent rate in order to refresh the visibility of each tab/button. You can do this by subscribing to the Click event (as you've done) and then calling RibbonObject.Invalidate();. Then add a getEnabled="yourTestFunction" parameter to each button, with public bool yourTestFunction(Office.IRibbonControl control) (Defined in the Ribbon.cs file) returning whether the web service is available or not.
Keep in mind if the web service is down, each click could hang your application for the amount of time you set on your timeout in the web service check
Edit:
Just realized the _Click event isn't mapped in the Excel COM library, so here's a bit of code that will run each time the cell selection is changed (not as frequent as every click, but hopefully good enough).
ThisAddIn.cs:
public static Excel.Application e_application;
public static Office.IRibbonUI e_ribbon;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
e_application = this.Application;
e_application.SheetSelectionChange += new Excel.AppEvents_SheetSelectionChangeEventHandler(e_application_SheetSelectionChange);
}
void e_application_SheetSelectionChange(object Sh, Excel.Range Target)
{
e_ribbon.Invalidate();
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
e_application.SheetSelectionChange -= new Excel.AppEvents_SheetSelectionChangeEventHandler(e_application_SheetSelectionChange);
e_application = null;
}
Ribbon1.cs:
public void Ribbon_Load(Office.IRibbonUI ribbonUI)
{
this.ribbon = ribbonUI;
ThisAddIn.e_ribbon = ribbonUI; //Add this line
}
and
public bool getEnabledTest(Office.IRibbonControl control)
{
//Whatever you use to test your Web Service
//return false;
}
Ribbon1.xml:
<button id="WebService" label="Use The Web Service" onAction="executeWebService" getEnabled="getEnabledTest" />

The following article titled Adding Custom Dynamic Menus to the Office Fluent User Interface will point you in the right direction.
The below is an example of a dynamically created menu, you can modify the tutorial to fit your particular need.

ok, thanks for the tips. Finally i solved it like this:
i declared a static ribbon object like:
public static RibbonIet ribbon {get; set; }
in the load event of the Ribbon i assign the Ribbon (this) like:
Session.Common.ribbon = this;
now i can control the RibbonButton like:
Session.Common.ribbon.buttonCreateIncident.Enabled = true;
Since the webService call is running in a seperate thread, i had to use a MethodInvoker to change enable/disable the buttons. it goes like this:
If (InvokeRequired)
{
Invoke(new MethodInvoker(() => Session.Common.ribbon.buttonCreateIncident.Enabled = true));
}
maybe this is of help for someone else.

Related

Inconsistent Outlook Addin Event Firing

On my development machine I have the FormInitializing and FormShowing events firing before RibbonLoad. I created a setup package in VS 2010 and installed on a vanilla Windows 7 Ultimate with Outlook 2010 installed.
The addin wasn't appearing on my meeting request form. So I setup remote debugger and to my astonishment the RibbonLoad is firing before the two form events mentioned above. A null exception is being throw b\c the code in the RibbonLoad relies on the FormRegion already being loaded. Can anyone offer any insight?
There is no defined order for certain Outlook events - the Ribbon UI and the Inspector UI are completely different components, despite them both being display in the same window. The Outlook runtime may trigger Ribbon and Inspector events in different orders. It would be your job to synchronize the two events (RibbonLoad and FormInitializing) if you need some initialization done. You cannot assume that the ordering will always be the same.
I notice this same behavior when ThisAddIn.Startup fires before ThisAddIn.CreateRibbonExtensibilityObject, but sometimes after depending on how Outlook triggers the sequencing. You can just use a static variable with sync locking to ensure your initialization code is only triggered once.
Here is an example I used to synchronize the Startup event with the RibbonLoad event:
public partial class ThisAddIn
{
static bool formInitialized = false;
static readonly object padLock = new Object();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
lock(padLock) { if (!formInitialized ) { InitializeForm(); } }
// startup code
}
private void InitializeForm()
{
// init code
formInitialized = true;
}
protected override IRibbonExtensibility CreateRibbonExtensibilityObject()
{
lock(padLock) { if (!formInitialized) InitializeForm(); }
// Create ribbon UI
}
}

Why is the DocumentSaved event not firing for a web site solution?

I've been trying to get a simple visual studio add in working. I just want to run a function on a file when a document is saved, but for some reason the event is not firing for web site solutions. It works as expected on normal projects.
Here is my code so far:
DocumentEvents docEvents;
Events events;
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
events = _applicationObject.Events;
docEvents = events.DocumentEvents;
docEvents.DocumentSaved += new _dispDocumentEvents_DocumentSavedEventHandler(docEvents_DocumentSaved);
}
void docEvents_DocumentSaved(Document document)
{
//do something here (doesn't reach this)
}
Any help would be appreciated, or even a pointer to a simple example project where the DocumentSaved event is working on web site solutions.
EDIT: I'm using Visual Studio 2010
Look at this (updated):
https://gordon-breuer.de/unknown/2010/08/19/visual-studio-2010-extension-unicode-converter-1-0-with-tutorial.html
It seems that you have to register your add id for handling certain file types.

C# - Is there any OnShapeMoved or OnShapeDeleted event in Visio?

I think the title or the question is clear enough. I saw something about the EventSink, but I found it difficult to use. Any hint?
The Visio Primary Interop Assembly exposes these events as C# events therefore you can simply hook the event with a delegate.
See this simple example:
namespace VisioEventsExample
{
using System;
using Microsoft.Office.Interop.Visio;
class Program
{
public static void Main(string[] args)
{
Application app = new Application();
Document doc = app.Documents.Add("");
Page page = doc.Pages[1];
// Setup event handles for the events you are intrested in.
// Shape deleted is easy.
page.BeforeShapeDelete +=
new EPage_BeforeShapeDeleteEventHandler(onBeforeShapeDelete);
// To find out if a shape has moved hook the cell changed event
// and then check to see if PinX or PinY changed.
page.CellChanged +=
new EPage_CellChangedEventHandler(onCellChanged);
// In C# 4 for you can simply do this:
//
// page.BeforeShapeDelete += onBeforeShapeDelete;
// page.CellChanged += onCellChanged;
// Now wait for the events.
Console.WriteLine("Wait for events. Press any key to stop.");
Console.ReadKey();
}
// This will be called when a shape sheet cell for a
// shape on the page is changed. To know if the shape
// was moved see of the pin was changed. This will
// fire twice if the shape is moved horizontally and
// vertically.
private static void onCellChanged(Cell cell)
{
if (cell.Name == "PinX" || cell.Name == "PinY")
{
Console.WriteLine(
string.Format("Shape {0} moved", cell.Shape.Name));
}
}
// This will be called when a shape is deleted from the page.
private static void onBeforeShapeDelete(Shape shape)
{
Console.WriteLine(string.Format("Shape deleted {0}", shape.Name));
}
}
}
If you haven't already downloaded the Visio SDK you should do so. Recent versions of the SDK it contains many useful examples include one called "Shape Add\Delete Event". If you have the 2010 version can browse the examples by going to Start Menu\Programs\Microsoft Office 2010 Developer Resources\Microsoft Visio 2010 SDK\Microsoft Visio Code Samples Library.
I believe that you have to implement EvenSink to get access to "ShapesDeleted", i.e.
(short)Microsoft.Office.Interop.Visio.VisEventCodes.visEvtCodeShapeDelete
the code above will help you if you are looking for the event "BeforeShapeDelete" not the "after"ShapeDelete ;)

Globals.Ribbons empty on Outlook addin startup?

I'm creating a plugin for Outlook 2010 using VSTO 2010 and .NET 4. I am using the XML method to design my ribbon because I need the context-menu hooks. Unfortunately, though the ribbon is created before the Startup event handler of the addin is fired, I can't access the ribbon using Globals.Ribbons.MyRibbon in the handler! I have added the following in my Ribbon.cs code:
partial class ThisRibbonCollection : Microsoft.Office.Tools.Ribbon.RibbonReadOnlyCollection
{
internal MyRibbon MyRibbon
{
get { return this.GetRibbon<MyRibbon>(); }
}
}
But it seems that the RibbonReadOnlyCollection is empty when I try to access it from the startup event handler.
On the other hand, if I use the designer, I can access the collection with no problem. How do I add my new ribbon into the collection? I don't see any set methods or any instance of the ribbon collection that's tweakable.
Ribbons created with XML are not accessible using Globals.Ribbons. See this answer.
ThisAddIn
public Ribbon myRibbon;
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
Ribbon appointmentRibbon = new Ribbon();
myRibbon = appointmentRibbon; // save to local variable
IRibbonExtensibility ribbonExtensibility = appointmentRibbon;
return ribbonExtensibility;
}

How to see Word document text changes in ThisDocument_New()

I'm considering migration of all of our Word templates from VBA to VSTO and have the following question: How can I debug code in a VSTO project?
Unlike debugging in VBA, I can't see the results of code executing line-by-line when stepping through a procedure.
For example, I build a prototype Word document in VS 2019:
using ...;
namespace MyCompany.OfficeTemplates.MyTemplate
{
public partial class ThisDocument
{
private void ThisDocument_Startup(object sender, System.EventArgs e)
{
}
private void ThisDocument_Shutdown(object sender, System.EventArgs e)
{
}
private void ThisDocument_New()
{
var currentSelection = Application.Selection;
currentSelection.TypeText("This text was added by using code.");
}
#region VSTO Designer generated code
/// ...<summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisDocument_Startup);
this.Shutdown += new System.EventHandler(ThisDocument_Shutdown);
this.New += new Microsoft.Office.Interop.Word.DocumentEvents2_NewEventHandler(this.ThisDocument_New);
}
#endregion
}
}
I plan to put way more code (showing a dialog box, choosing customers, choosing language and other information) into the ThisDocument_New() event. Why is the text not inserted into the word document when I step over the command ...TypeText()... with the debugger?!?
Instead, It's inserted when debugger leaves ThisDocument_New()?
What am I missing and where else to put my code when ThisDocument_New() does not allow propper debugging?
That one cannot see what's happening during code execution is typical for VSTO. Debugging is different than with VBA - the results are only visible after the code has finished. Nothing can be done to change this - it's in the nature of the thing (.NET <-> COM interaction).
I struggled with this, myself, when starting with VSTO, and had to learn to work around it.
Generally, if during trouble-shooting it's necessary to see what's happening as it happens, I first test in VBA, then transfer that code to VSTO.
If it's necessary to check values being generated by code as it runs I stick some Debug.Print lines in that I can follow in the Visual Studio output window when stepping through the code.
It's also possible to track what's assigned to objects when stepping through the code.

Resources