2017-06-27 5 views
0

J'ai écrit le fichier Ribbon.xml pour un projet VSTO Excel. L'élément onglet ressemble à ceci:Modification de la propriété visible de l'onglet VSTO via l'événement Workbook_Open

<tab id="myId" idMso="TabAddIns" label="My Tab" visible="false"> 

Lorsqu'un classeur est ouvert, je veux l'onglet soit caché par défaut, ce qui est accompli par la propriété visible étant définie sur false. Ensuite, je souhaite modifier la propriété visible à true dans l'événement Workbook_Open. C'est là que je suis coincé. Je ne pense pas que ce serait difficile, mais j'ai passé quelques heures à chercher la réponse. Il semble que la plupart des exemples 1) basculer la visibilité d'un onglet par un button callback, ce qui n'est pas ce que je veux faire, ou 2) sont en mesure d'accéder au ribbon's properties, que je n'ai pas été capable de reproduire jusqu'à présent (bien que la plupart les ressources sont anciennes, donc je pense que MS a déménagé ces propriétés depuis).

Est-ce que quelqu'un sait comment changer facilement la propriété visible à true pour que l'onglet soit affiché?

Merci!

INFORMATIONS AVEC MISE À JOUR:

ThisAddIn.cs

namespace Doodles_Reporting 
{ 
    public partial class ThisAddIn 
    { 
     public RibbonApi ribbonApi; 


     private void ThisAddIn_Startup(object sender, System.EventArgs e) 
     { 
     } 

     private void ThisAddIn_Shutdown(object sender, System.EventArgs e) 
     { 
     } 

     protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject() 
     { 
      return new Ribbon(); 
     } 

     void Application_WorkbookOpen(Excel.Workbook Wb) 
     { 

      //first, check if there is an application/process for each workbook 
      Excel.Workbooks books = Globals.ThisAddIn.Application.Workbooks; 
      if (books.Count > 1) 
      { 
       try 
       { 
        //close workbook that was just opened and then reopen it with new process/application. 
        string filePath = Wb.FullName; 
        Wb.Close(); 
        Excel.Application excelApp = new Excel.Application(); 
        excelApp.Visible = true; 
        excelApp.DisplayFullScreen = true; 
        excelApp.Workbooks.Open(filePath); 
       } 
       catch (Exception ex) 
       { 
        MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK); 
       } 
      } 
      else 
      { 
       //second, check if the workbook is a Doodles workbook 
       try 
       { 
        DocumentProperties props = (DocumentProperties)Wb.CustomDocumentProperties; 
        var selectedTable = props["selectedTable"].Value; 
        configureDoodles(); 
       } 
       catch (Exception) 
       { 
       //THIS IS WHERE I WANT TO SET THE RIBBON VISIBILITY TO FALSE 
       } 
      } 
     } 

     private void configureDoodles() 
     { 
      RibbonApi.app = Globals.ThisAddIn.Application; 
      RibbonApi.wBookPropertiesConfig = new WorkbookPropertiesConfig(RibbonApi.app.ActiveWorkbook); 
      RibbonApi.presenter = new ExcelPresenter(RibbonApi.app.ActiveWorkbook); 
      ribbonApi = new RibbonApi(); 
     } 

     #region VSTO 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(ThisAddIn_Startup); 
      this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); 
      this.Application.WorkbookOpen += new Excel.AppEvents_WorkbookOpenEventHandler(Application_WorkbookOpen); 
     } 

     #endregion 
    } 
} 

Ribbon.cs

namespace Doodles_Reporting 
{ 
    [ComVisible(true)] 
    public class Ribbon : Office.IRibbonExtensibility 
    { 
     private Office.IRibbonUI ribbon; 

     public Ribbon() 
     { 
     } 

     #region IRibbonExtensibility Members 

     public string GetCustomUI(string ribbonID) 
     { 
      return GetResourceText("Doodles_Reporting.Ribbon.xml"); 
     } 

     #endregion 

     #region Ribbon Callbacks 
     //Create callback methods here. For more information about adding callback methods, visit http://go.microsoft.com/fwlink/?LinkID=271226 

     public void Ribbon_Load(Office.IRibbonUI ribbonUI) 
     { 
      this.ribbon = ribbonUI; 
     } 

     public bool toggleVisibility(Office.IRibbonControl control) 
     { 
      return (control.Id == "TabAddIns") ? true : false; 
     } 

     public void onSomeEvent() 
     { 
      this.ribbon.InvalidateControl("TabAddIns"); 
     } 

     public void SignIn(Office.IRibbonControl ribbonUI) 
     { 
      Globals.ThisAddIn.ribbonApi.signIn(); 
     } 

     public void SqlCreatorFormLoad(Office.IRibbonControl ribbonUI) 
     { 
      Globals.ThisAddIn.ribbonApi.showSqlCreator(); 
     } 

     public void refreshData(Office.IRibbonControl ribbonUI) 
     { 
      Globals.ThisAddIn.ribbonApi.refreshData(); 
     } 

     public void drilldownSelectionLoad(Office.IRibbonControl ribbonUI) 
     { 
      Globals.ThisAddIn.ribbonApi.setDrilldownColumns(); 
     } 

     public void Drilldown(Office.IRibbonControl ribbonUI) 
     { 
      Globals.ThisAddIn.ribbonApi.drilldown(); 
     } 

     public void editProperties(Office.IRibbonControl ribbonUI) 
     { 

     } 

     #endregion 

     #region Helpers 

     private static string GetResourceText(string resourceName) 
     { 
      Assembly asm = Assembly.GetExecutingAssembly(); 
      string[] resourceNames = asm.GetManifestResourceNames(); 
      for (int i = 0; i < resourceNames.Length; ++i) 
      { 
       if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0) 
       { 
        using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i]))) 
        { 
         if (resourceReader != null) 
         { 
          return resourceReader.ReadToEnd(); 
         } 
        } 
       } 
      } 
      return null; 
     } 

     #endregion 
    } 
} 
+0

Qu'avez-vous essayé, et qu'est-ce qui ne fonctionne pas? Est-ce que vous ne pouvez pas obtenir une référence à l'onglet à partir du gestionnaire Workbook_Open (utilisez un champ statique), ou est-ce que cela ne fonctionne pas? – hoodaticus

+0

À droite, je ne peux pas obtenir une référence à l'onglet du gestionnaire Workbook_Open. Pardonnez ma question ignorante, mais quel devrait être le champ statique? Je suis également tombé sur ce lien (https://msdn.microsoft.com/en-us/library/bb772088.aspx), mais je n'arrive pas à trouver le nom de mon ruban sous Globals.Ribbons. – christopheralan88

+0

Qui tire en premier? 'Application_WorkbookOpen' ou' CreateRibbonExtensibilityObject'? –

Répondre

1

Le ruban est une bête drôle. Il est spécialement conçu pour vous interdire d'accéder directement à l'un de ses éléments et de vous interdire de les manipuler directement. Au lieu de cela, tout est accompli via des rappels. Je n'ai pas beaucoup d'expérience avec VSTO, mais je peux vous expliquer ce que vous feriez en C# ou C++ sans VSTO, et je crois que vous pouvez combler les lacunes.

  1. Définissez un rappel onLoad dans votre ruban XML. Excel appellera cette méthode (via IDispatch) lorsque le ruban est chargé pour la première fois.

    <customUI ... onLoad="OnRibbonLoaded"> 
    
  2. votre rappel Mettre en oeuvre onLoad, qui devrait stocker la référence IRibbonUI qui est fourni.

    public void OnRibbonLoaded(IRibbonUI ribbon) 
    { 
        this.ribbon = ribbon; 
    } 
    
  3. Pour les propriétés que vous souhaitez contrôler dynamiquement, définir un rappel dans le fichier XML du ruban.

    <tab ... getVisible="GetVisible"> 
    
  4. Implémentez votre rappel de visibilité. Si plusieurs parties de votre ruban utilisent le même rappel, l'instance IRibbonControl transmise à cette méthode peut être utilisée pour déterminer quel onglet/groupe/contrôle est interrogé.

    public bool GetVisible(IRibbonControl control) 
    { 
        // here is where you should determine if your tab/group/control should be visible, 
        return (some condition) ? true : false; 
    } 
    
  5. Chaque fois que vous décidez que vous souhaitez mettre à jour la visibilité, indiquer à Excel de re-requête propriétés de votre commande (par exemple appeler vos callbacks) en utilisant la référence IRibbonUI.

    void OnSomeEvent() 
    { 
        // you can tell Excel to update the entire ribbon 
        this.ribbon.Invalidate(); 
    
        // or you can tell Excel to update a single tab/group/control 
        this.ribbon.InvalidateControl("my_id"); 
    } 
    
+0

Merci, Michael! Je comprends les étapes que vous avez définies, mais je pense que les choses se compliquent parce que je veux essentiellement que la méthode GetVisible soit appelée dans l'événement Workbook_Open. L'événement Workbook_Open se trouve dans la classe ThisAddIn, qui est instanciée automatiquement par le moteur d'exécution VSTO. Le ribbonUI est instancié par une méthode substituée, CreateRibbonExtensibilityObject, mais cette méthode n'instancie pas un champ dans la classe ThisAddIn. Il semble instancier une variable ribbonUI quelque part en interne. Donc, je suis coincé parce que je ne peux pas référencer le ruban de la classe ThisAddIn. – christopheralan88

1

Vous avez déjà toutes les pièces.En ThisAddin, vous remplacez CreateRibbonExtensibilityObject. Au lieu de renvoyer un new Ribbon, renvoyez un objet que vous gardez en attente.

public partial class ThisAddIn 
{ 
    private readonly Ribbon _ribbon = new Ribbon(); 

    protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject() 
    { 
     return this._ribbon; 
    } 
} 

Ensuite, soit ajouter une méthode Invalidate() publique (s) à cet objet, ou rendre public et appeler domaine IRibbonUI de cet objet Invalidate/InvalidateControl sur ce point. Je ferais probablement le premier. Ensuite, appelez ces méthodes publiques de Application_WorkbookOpen.

public partial class ThisAddIn 
{ 
    void Application_WorkbookOpen(Excel.Workbook Wb) 
    { 
     this._ribbon.Invalidate(); 
     this._ribbon.InvalidatePlayButton(); 
    } 
} 

Notez que vous pouvez combiner ces objets en un seul objet, si vous le souhaitez. Juste avoir ThisAddin mettre en œuvre Microsoft.Office.Core.IRibbonExtensibility et retourner this de CreateRibbonExtensibilityObject.

Cependant, la création d'un objet séparé présente certains avantages. Par exemple, il devient facile d'encapsuler votre ruban dans des méthodes et des propriétés publiques plus robustes. Par exemple:

public class Ribbon : Office.IRibbonExtensibility 
{ 
    private Office.IRibbonUI _ribbonUI; 

    private bool _isPlayButtonVisible = true; 

    // here's a property that makes it easy to update the visibility of the play button 
    public bool IsPlayButtonVisible 
    { 
     get { return this._isPlayButtonVisible; } 
     set 
     { 
      if (this._isPlayButtonVisible != value) 
      { 
       this._isPlayButtonVisible = value; 
       this._ribbonUI.InvalidateControl("PlayButton"); 
      } 
     } 
    } 

    // here's the callback that Excel will call 
    public bool GetIsPlayButtonVisible(IRibbonControl control) 
    { 
     return this.IsPlayButtonVisible 
    } 
} 
+0

Merci, Michael, mais Invalidate ne cache pas le contrôle, non? Il vide uniquement le cache du contrôle. Je pense que pour que cela fonctionne, je devrais avoir encore une méthode de rappel GetVisible qui mettrait à jour le champ _isPlayButtonVisible. Essentiellement, la méthode IsPlayButtonVisible deviendrait la méthode de rappel GetVisible, non? Et tout ce qu'il ferait est! _isPlayButtonVisible. – christopheralan88

+1

Oui, vous avez toujours besoin du rappel. Malheureusement, vous ne pouvez pas utiliser les propriétés comme callbacks, vous avez donc besoin d'une méthode 'GetVisible' ou' GetPlayButtonVisible'. Je mettrai à jour le dernier extrait de code. –

0

Ainsi, j'ai découvert que l'utilisation du concepteur de ruban simplifie grandement la tâche. Après avoir créé une nouvelle classe Ribbon Designer, la classe est ajoutée au modèle d'objet sous Globals.Ribbons. Tout cela signifie que cacher l'onglet devient aussi simple que je pensais que ce devrait être avec une ligne de code:

Globals.Ribbons.RibbonVisual.Doodles.Visible = false; 

RibbonVisual est le nom de la classe Ruban Designer j'ai créé et Doodles est le nom de l'onglet.

Je vais utiliser le Ribbon Designer à partir de maintenant lol: P.