如何可靠地获取 Outlook 2013 插件中联系人上下文菜单的对象?
How can I reliably get the object of a contact context menu in an Outlook 2013 addin?
我在 the example in this article 之后的 Outlook 2013 中为 联系人 添加了一个上下文菜单条目。这是 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>
条目正确显示在菜单中,当我单击它时,我的事件处理程序被执行:
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");
}
referenced article 似乎表明上下文应该是 IMsoContactCard
,但这不是我得到的。打印出 context.GetType()
的行正在显示 System.__ComObject
.
This article here 似乎表明我应该能够将该对象转换成有用的东西,但是所有将其转换成合乎逻辑的东西的尝试(IMsoContactCard
、ContactItem
、 ContactCard
、_ContactItem
) 都失败了。
为了回避这个问题,我按照 the instructions in this article 尝试跟踪当前选择的项目。这实际上工作得很好,需要注意的是当前选择的项目并不总是上下文菜单适用的项目。
具体来说,我可以左键单击一个联系人,它会突出显示并且我的选择事件会触发。如果我然后右键单击 不同的联系人 以调出上下文菜单 而不是先左键单击它 ,那么该联系人将被勾勒出来但未突出显示,并且未触发我的选择事件。发生这种情况时,我最终将上下文菜单单击应用到错误的联系人。
如有任何建议或指导,我们将不胜感激。谢谢。
根据 Eugene Astafiev 提供的信息更新解决方案
根据下面提供的信息,我能够确定此特定回调的 Context
是 Microsoft.Office.Interop.Outlook.Selection
类型。然后我可以使用它来获取 ContactItem
如下:
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;
}
上下文对象的类型取决于您单击的位置和上下文菜单类型。要获取基础类型,您需要执行以下操作:
- 将对象转换为 IDispatch 接口。
- 使用 IDispatch 接口的 GetTypeInfo 方法获取 ITypeInfo 接口。
使用 ITypeInfo 接口的 GetDocumentation 方法获取类型名称。
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);
}
}
}
有关详细信息,请参阅 HowTo: get the actual type name behind System.__ComObject with Visual C# or VB.NET。
我在 the example in this article 之后的 Outlook 2013 中为 联系人 添加了一个上下文菜单条目。这是 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>
条目正确显示在菜单中,当我单击它时,我的事件处理程序被执行:
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");
}
referenced article 似乎表明上下文应该是 IMsoContactCard
,但这不是我得到的。打印出 context.GetType()
的行正在显示 System.__ComObject
.
This article here 似乎表明我应该能够将该对象转换成有用的东西,但是所有将其转换成合乎逻辑的东西的尝试(IMsoContactCard
、ContactItem
、 ContactCard
、_ContactItem
) 都失败了。
为了回避这个问题,我按照 the instructions in this article 尝试跟踪当前选择的项目。这实际上工作得很好,需要注意的是当前选择的项目并不总是上下文菜单适用的项目。
具体来说,我可以左键单击一个联系人,它会突出显示并且我的选择事件会触发。如果我然后右键单击 不同的联系人 以调出上下文菜单 而不是先左键单击它 ,那么该联系人将被勾勒出来但未突出显示,并且未触发我的选择事件。发生这种情况时,我最终将上下文菜单单击应用到错误的联系人。
如有任何建议或指导,我们将不胜感激。谢谢。
根据 Eugene Astafiev 提供的信息更新解决方案
根据下面提供的信息,我能够确定此特定回调的 Context
是 Microsoft.Office.Interop.Outlook.Selection
类型。然后我可以使用它来获取 ContactItem
如下:
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;
}
上下文对象的类型取决于您单击的位置和上下文菜单类型。要获取基础类型,您需要执行以下操作:
- 将对象转换为 IDispatch 接口。
- 使用 IDispatch 接口的 GetTypeInfo 方法获取 ITypeInfo 接口。
使用 ITypeInfo 接口的 GetDocumentation 方法获取类型名称。
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); } }
}
有关详细信息,请参阅 HowTo: get the actual type name behind System.__ComObject with Visual C# or VB.NET。