问题
I am adding an entry to the context menu for a Contact in Outlook 2013 following the example in this article. Here is the XML:
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
<contextMenus>
<contextMenu idMso="ContextMenuContactItem">
<button id="MyContextMenuContactItem" label="Do something..." onAction="OnDoSomething" insertAfterMso="DialMenu"/>
</contextMenu>
</contextMenus>
</customUI>
The entry shows up in the menu properly, and when I click it, my event handler is executed:
public void OnDoSomething(IRibbonControl control)
{
object context = control.Context;
System.Diagnostics.Debug.WriteLine(context.GetType());
if ((context as IMsoContactCard) != null) System.Diagnostics.Debug.WriteLine("IMsoContactCard");
if ((context as ContactItem) != null) System.Diagnostics.Debug.WriteLine("ContactItem");
if ((context as ContactCard) != null) System.Diagnostics.Debug.WriteLine("ContactCard");
if ((context as _ContactItem) != null) System.Diagnostics.Debug.WriteLine("_ContactItem");
}
The referenced article seems to indicate that the context should be an IMsoContactCard
, but that's not what I'm getting. The line that prints out context.GetType()
is displaying System.__ComObject
.
This article here seems to indicate that I should be able to cast that object into something useful, but all of the attempts to cast it into something logical (IMsoContactCard
, ContactItem
, ContactCard
, _ContactItem
) have failed.
In an attempt to sidestep the problem, I tried keeping track of the currently selected item, as per the instructions in this article. This actually works fairly well, with the caveat that the currently selected item is not always the item that the context menu applies to.
To elaborate, I can left-click on a contact and it is highlighted and my selection event fires. If I then right-click on a different contact to bring up the context menu without left-clicking on it first, then that contact will be outlined but not highlighted, and my selection event is not fired. When this happens, I end up applying the context menu click to the wrong contact.
Any advice or direction would be appreciated. Thanks.
Update with a solution based on information provided by Eugene Astafiev
Based on the information provided below, I was able to figure out that the Context
of this particular callback is of type Microsoft.Office.Interop.Outlook.Selection
. I can then use this to get the ContactItem
as follows:
private ContactItem GetContactItemFromControlContext(IRibbonControl control)
{
var selection = control.Context as Selection;
if (selection != null && selection.Count == 1)
return selection[1] as ContactItem;
else
return null;
}
回答1:
The type of the Context object depends on the place where you clicked and the context menu type. To get the underlying type you need to do the following:
- Cast the object to the IDispatch interface.
- Get the ITypeInfo interface using the GetTypeInfo method of the IDispatch interface.
Get the type name using GetDocumentation method of the ITypeInfo interface.
public static string GetTypeName(object comObj) { if (comObj == null) return String.Empty; if (!Marshal.IsComObject(comObj)) //The specified object is not a COM object return String.Empty; IDispatch dispatch = comObj as IDispatch; if (dispatch == null) //The specified COM object doesn't support getting type information return String.Empty; ComTypes.ITypeInfo typeInfo = null; try { try { // obtain the ITypeInfo interface from the object dispatch.GetTypeInfo(0, 0, out typeInfo); } catch (Exception ex) { //Cannot get the ITypeInfo interface for the specified COM object return String.Empty; } string typeName = ""; string documentation, helpFile; int helpContext = -1; try { //retrieves the documentation string for the specified type description typeInfo.GetDocumentation(-1, out typeName, out documentation, out helpContext, out helpFile); } catch (Exception ex) { // Cannot extract ITypeInfo information return String.Empty; } return typeName; } catch (Exception ex) { // Unexpected error return String.Empty; } finally { if (typeInfo != null) Marshal.ReleaseComObject(typeInfo); } }
}
See HowTo: get the actual type name behind System.__ComObject with Visual C# or VB.NET for more information.
来源:https://stackoverflow.com/questions/29970060/how-can-i-reliably-get-the-object-of-a-contact-context-menu-in-an-outlook-2013-a