2015-04-30 3 views
1

J'ajoute une entrée au menu contextuel pour un Contactez dans Outlook 2013 suivant the example in this article. Voici le XML:Comment obtenir de manière fiable l'objet d'un menu contextuel de contacts dans un addin Outlook 2013?

<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> 

L'entrée apparaît dans le menu correctement, et quand je clique, mon gestionnaire d'événements est exécuté:

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"); 
} 

Le referenced article semble indiquer que le contexte devrait être un IMsoContactCard, mais ce n'est pas ce que je reçois. La ligne qui imprime context.GetType() affiche System.__ComObject.

This article here semble indiquer que je devrais être en mesure de jeter cet objet dans quelque chose d'utile, mais toutes les tentatives de le jeter dans quelque chose de logique (IMsoContactCard, ContactItem, ContactCard, _ContactItem) ont échoué.

Dans une tentative de contourner le problème, j'ai essayé de garder une trace de l'élément actuellement sélectionné, selon the instructions in this article. Cela fonctionne en fait assez bien, avec la mise en garde que l'élément actuellement sélectionné est pas toujours l'élément auquel s'applique le menu contextuel. Pour élaborer, je peux faire un clic gauche sur un contact et il est en surbrillance et mon événement de sélection se déclenche. Si je fais un clic droit sur un différents contact pour faire apparaître le menu contextuel sans faire un clic gauche dessus d'abord, alors ce contact sera souligné mais pas en surbrillance, et mon événement de sélection n'est pas tiré. Lorsque cela se produit, je finis par appliquer le menu contextuel cliquez sur le mauvais contact.

Tout conseil ou orientation serait apprécié. Merci.


Mise à jour avec une solution basée sur les informations fournies par Eugene Astafiev

D'après les informations ci-dessous, j'ai pu comprendre que le Context de ce rappel particulier est de type Microsoft.Office.Interop.Outlook.Selection. Je peux ensuite utiliser pour obtenir le ContactItem comme suit:

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; 
} 

Répondre

2

Le type de l'objet de contexte dépend de l'endroit où vous avez cliqué et le type de menu contextuel. Pour obtenir le type sous-jacent, vous devez effectuer les opérations suivantes:

  1. Cast l'objet à l'interface IDispatch.
  2. Obtenez l'interface ITypeInfo à l'aide de la méthode GetTypeInfo de l'interface IDispatch.
  3. Obtient le nom du type en utilisant la méthode GetDocumentation de l'interface ITypeInfo.

    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); 
        } 
    } 
    

    }

Voir HowTo: get the actual type name behind System.__ComObject with Visual C# or VB.NET pour plus d'informations.

+0

Merci!C'est exactement ce que je cherchais. Je vais juste mentionner, pour les futurs lecteurs, que vous ** devez ** lire l'article référencé, parce que la fonction exemple fournie ici ne fonctionne pas sans quelques morceaux supplémentaires de code ajoutés autour de lui. J'ai accepté votre réponse et j'ai ajouté quelques informations à ma question. – danBhentschel

+0

J'ai ignoré les déclarations PInvoke parce que vous pouvez trouver le code requis sur le web (sans le projet exemple). –