1. Introduction

Microsoft Visual Studio Tools for Office est un outil intégré "out-of-the-box" dans Visual Studio depuis la version 2008. Il permet de créer des add-in qui viennent se greffer dans les différents produits Office (Word, Excel, Visio...). Il est toutefois important de mentionner que les versions Express de Visual Studio ne permettent pas de développer des add-in pour la solution Office.

Cet article traite du développement d'add-in pour Excel 2007 à partir de Visual Studio 2010.

2. Les premiers pas

2.1. Créer le projet

Pour créer un nouveau projet d'add-in, il suffit d'aller dans File -> New -> Project et de suivre l'arborescence Visual C# -> Office.

Créer un nouveau projet d'add-in Excel 2007
Créer un nouveau projet d'add-in Excel 2007

2.2. Créer un ribbon à l'aide du designer

Il s'agit ici de créer un ribbon qui apparaitra dans Excel et de pouvoir agencer ses composants graphiques. Pour ajouter un ribbon lié à l'add-in, il faut faire clic droit sur le projet (dans le Solution Explorer) -> Add -> New Item. Il suffira ensuite de choisir Ribbon (Visual designer).

Création d'un nouveau ribbon
Création d'un nouveau ribbon

Le programmeur peut maintenant réaliser l'interface graphique du ribbon. La création visuelle d'un ribbon est réalisée de manière tout à fait analogue à celle des Windows Forms. D'ailleurs, les composants graphiques disponibles pour les ribbons sont très similaires à ceux utilisés dans les Windows Forms.

Le lecteur notera également la présence des composants abstraits (BackGroundWorker, Timer...) qui sont également présents dans l'éditeur de Windows Forms. Plus généralement, toutes les classes du framework .NET peuvent être utilisées dans l'add-in.

Pour la suite du tutoriel, nous invitons le lecteur à réaliser l'interface graphique suivante :

Votre premier ribbon
Votre premier ribbon

Ici, "Afficher" est un bouton et "Il n'y a rien ici" est un label. Une brève description des composants graphiques principaux est disponible à la section suivante.

2.3. Les composants graphiques usuels

2.3.1. Le groupe

Les groupes sont les briques de base d'un add-in Office car ils jouent le rôle de conteneur pour les autres composants. Les autres composants graphiques ne peuvent effectivement pas exister en dehors d'un groupe.

Un groupe vide
Un groupe vide

Il n'est pas nécessaire (et il n'est pas possible !) de redimensionner soi-même la taille d'un groupe. En effet, celle-ci est automatiquement ajustée pour que tous les composants soient visibles.

2.3.2. Le label

Le label est un composant destiné à l'affichage de texte. Le texte à afficher se trouve dans la propriété Label du Label. Aucun évènement n'est associé à ce composant (i.e. il ne peut intercepter aucune action venant de la part de l'utilisateur (passage de la souris sur le composant, clic, etc.)).

2.3.3. Le Button

Ce composant n'a aucune caractéristique particulière. Il ne peut intercepter qu'un évènement de type clic simple.

2.3.4. Le ToggleButton

Plus exotique que son homologue Button, il est capable d'être poussé et dispose par conséquent d'une propriété Checked. Celle-ci permet de savoir ou de définir si le bouton est poussé. Tout comme le composant Button, le ToggleButton n'est capable d'intercepter que les simples clics.

Un ToggleButton poussé
Un ToggleButton poussé

2.3.5. La CheckBox

Ce composant de base (également présent dans les Windows Forms) permet à l'utilisateur de cocher une case. La CheckBox dispose également d'un label placé à côté de la case à cocher. Ce composant ne permet d'intercepter que des clics simples.

Il est utile de remarquer que le ToggleButton et la CheckBox sont équivalents du point de vue des fonctionnalités. Cependant, l'utilisateur moyen est généralement plus habitué aux CheckBox.

2.3.6. L'EditBox

L'EditBox est essentiellement une zone de saisie de texte. Il dispose d'un évènement TextChanged permettant d'exécuter certaines instructions lorsque l'utilisateur a modifié le texte contenu dans celui-ci.

Le lecteur remarquera une différence essentielle entre le composant graphique Textbox des Windows Forms et le composant EditBox pour les solutions Office : dans ce dernier, un label est disposé à gauche de la zone de saisie de texte.

2.3.7. Les autres composants

Il existe d'autres composants graphiques pour les solutions Office. Néanmoins, ils ne seront pas présentés ici puisqu'ils présentent de fortes similitudes avec les composants Windows Forms et leur découverte reste aisée.

2.4. Task Panes

Concrètement, les Task Panes sont des panels sur lesquels sont disposés des composants graphiques. Par défaut, les Task Panes apparaissent à droite du tableau Excel.

Un exemple de Task Pane
Un exemple de Task Pane

2.4.1. Réalisation d'un Task Pane

La création d'un Task Pane repose sur un UserControl. La figure ci-dessous montre comment créer un tel contrôle.

Créer un UserControl
Créer un UserControl

L'interface graphique et le code du UserControl sont produits de la même manière qu'avec les Windows Forms classiques. Le code exemple ci-dessous correspond au Task Pane présenté sur la figure en section 2.4. Le programme se contente d'écrire un texte donné dans la cellule spécifiée.

 
Sélectionnez

private void btnWrite_Click(object sender, EventArgs e)
        {
            Excel._Worksheet currWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Worksheets[1];
            // Cellule dans laquelle il faut écrire
            Excel.Range cell = currWorkSheet.get_Range(TBCell.Text);
            // Ecriture du texte
            cell.Value2 = TBNewText.Text;
        }

Dans le code ci-dessus, btnWrite est le bouton "Ecrire", TBCell est la textBox dans laquelle la cellule où le texte doit être écrit est spécifiée et TBNewtexte est la TextBox contenant le texte à afficher.

Il faut également instancier et afficher le Task Pane. Le code suivant décrit cette opération :

Instanciation et affichage d'un Task Pane
Sélectionnez

using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Ribbon;

namespace ExcelAddIn1
{
    public partial class MainRib
    {

        private CustomUserControl customUserControl;
        private Microsoft.Office.Tools.CustomTaskPane customTaskPane;

        private void MainRib_Load(object sender, RibbonUIEventArgs e)
        {
            // Construction de l'usercontrol
            customUserControl = new CustomUserControl();
            // Ajout du Task Pane avec comme titre "Un exemple de Task Pane"
            customTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(customUserControl, "Un exemple de Task Pane");
            // Le Task Pane est caché par défaut
        }

        private void btnAction_Click(object sender, RibbonControlEventArgs e)
        {
            // Rend visible le Task Pane
            customTaskPane.Visible = true;
        }
    }
}

Pour l'exemple, il a été décidé de créer une seule instance du Task Pane au chargement du ribbon et de ne l'afficher que lorsque l'utilisateur presse le bouton btnAction (un bouton placé dans un ribbon).

Le lecteur remarquera que si l'utilisateur ferme le Task Pane, son instance en mémoire ne disparait pas et il suffit par conséquent d'exécuter l'instruction customTaskPane.Visible = true; pour l'afficher de nouveau.

2.5. Accéder aux cellules, lignes et colonnes

Cette section reprend l'interface graphique réalisée précédemment (celle du Ribbon, pas celle des Task Panes).

Pour que Visual Studio génère le code de base correspondant à un clic sur le bouton, il suffit de double-cliquer sur celui-ci dans le designer.

Tout d'abord, afin d'éviter de devoir écrire des lignes de code kilométriques, il est utile de placer les lignes suivantes au début du fichier .cs du ribbon :

Quelques déclarations utiles
Sélectionnez

using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;

Le code pour accéder à une cellule est le suivant :

 
Sélectionnez

Excel._Worksheet mainWorkSheet;
Excel.Range cellA1;
mainWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
cellA1 = mainWorkSheet.Cells[1, 1];
cellA1.Value = "=4*6";

Tout d'abord, même si l'usage de mainWorkSheet et cellA1 est facultatif, il est utile de les déclarer pour :

  1. bénéficier de l'autocomplétion de Visual Studio ;
  2. éviter de devoir écrire de trop longues expressions susceptibles de dépasser de l'écran.

En effet, il est tout à fait possible d'écrire le code proposé ci-dessus de la façon suivante :

 
Sélectionnez

Globals.ThisAddIn.Application.Workbooks[1].Sheets[1].Cells[1, 1].Value = "=4*6" ;

Cependant, la longueur de la ligne de code produite est importante et l'autocomplétion proposée par Visual Studio s'arrête après .Sheets[1].

Ensuite, on remarquera l'usage de Globals.ThisAddIn.Application pour accéder à l'ensemble des feuilles de calcul, cellules, etc. Le lecteur remarquera également que, contrairement à ce qu'il a l'habitude de faire avec les tableaux, l'index 1 de Workbooks (ou Sheets, etc.) représente le premier classeur et non le second. En effet, si Workbooks fonctionnait comme un tableau standard, la première position serait atteinte à l'index 0 et non 1. Cette remarque reste valable pour des tableaux à deux indices comme Cells où la cellule A1 correspond à la position [1,1] et non [0,0].

Il est utile de remarquer qu'une instance de Excel.Range peut contenir plus d'une cellule (comme son nom le laisse entendre). Elle peut effectivement représenter une colonne, une ligne, une cellule isolée ou même un "bloc" de cellules.

Pour que l'objet représente une colonne complète, il suffit d'écrire :

Un Range qui représente une colonne
Sélectionnez

Excel._Worksheet mainWorkSheet;
Excel.Range cellRange;
mainWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
cellRange = mainWorkSheet.Columns[2]; // Représente la colonne B

Le code pour une ligne est le suivant :

Un Range qui représente une ligne
Sélectionnez

Excel._Worksheet mainWorkSheet;
Excel.Range cellRange;
mainWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
cellRange = mainWorkSheet.Rows[3]; // Représente la ligne 3

Le code pour un bloc de cellules peut s'écrire :

Un Range qui représente un bloc de cellules
Sélectionnez

Excel._Worksheet mainWorkSheet;
Excel.Range cellA1;
Excel.Range cellC6;
Excel.Range cellRange;
mainWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
cellA1 = mainWorkSheet.Cells[1, 1];
cellC6 = mainWorkSheet.Cells[6, 3];
cellRange = mainWorkSheet.get_Range(cellA1, cellC6);
cellRange.Value = "=4*6";

Ou encore (on évite ici de déclarer les objets cellA1 et cellC6) :

Un Range qui représente (encore) un bloc de cellules
Sélectionnez

Excel._Worksheet mainWorkSheet;
Excel.Range cellRange;
mainWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
cellRange = mainWorkSheet.get_Range(mainWorkSheet.Cells[1, 1], mainWorkSheet.Cells[6, 3]);
cellRange.Value = "=4*6";

On peut aussi le mettre sous la forme suivante :

Encore une autre façon de représenter un bloc de cellules
Sélectionnez

Excel._Worksheet mainWorkSheet;
Excel.Range cellRange;
mainWorkSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
cellRange = mainWorkSheet.get_Range("A1", "C6");
cellRange.Value = "=4*6";

Cependant, cette dernière forme est généralement moins performante que les deux premières car le programmeur dispose le plus souvent de la position des cellules sous la forme d'un couple (i,j). Il est alors nécessaire d'utiliser un StringBuilder pour convertir ce couple en un format de cellule du type [Une suite de lettres][Une suite de chiffres], ce qui ajoute une complexité inutile au code.

Le lecteur remarquera en exécutant les codes proposés que cellRange.Value = "=4*6" affiche "24" et non "=4*6" dans les cellules représentées par cellRange. Cela signifie qu'il est également possible d'utiliser les fonctions préfaites d'Excel telles que SUM, TRUNC, etc.

Le programmeur curieux se demande peut-être quelle est la différence entre cellRange.Value et cellRange.Value2. En fait, l'une des propriétés gère les types de données Currency et Date (Value) et l'autre non (Value2). Des informations supplémentaires sont disponibles sur http://support.microsoft.com/kb/213719/en-us.

2.6. Conclusion

La réalisation d'opérations rudimentaires sous Excel ne devrait maintenant plus poser de problème particulier au lecteur. La suite du tutoriel peut être vue comme une suite de "how-to". Néanmoins, il est clair que les tâches qu'un programmeur peut être amené à réaliser ne sont pas toutes décrites ci-dessous. Il faut donc acquérir une certaine intuition quand on cherche à effectuer une tâche bien précise. Pour cela, il est conseillé :

  1. de passer par des objets comme _WorkSheet, Range, etc. afin de bénéficier de l'autocomplétion et de pouvoir par conséquent naviguer à travers les propriétés et méthodes de l'objet ;
  2. de taper Excel. dans Visual Studio (pour activer l'autocomplétion) quand on cherche un objet qui représente quelque chose de particulier (un graphique, un style, etc.). Il est ainsi possible, grâce à l'autocomplétion, de naviguer dans la bibliothèque des objets disponibles ;
  3. d'utiliser la MSDN lorsqu'une classe, une méthode ou une propriété semble peu claire ;
  4. d'être critique vis-à-vis de la validité des objets fournis : certains ne fonctionnent pas comme ils doivent (un exemple sera donné dans la suite du tutoriel, en section 4.4.4) ;
  5. de réaliser que les énumérations propres à Excel commencent toujours par la séquence de lettres Xl.

3. Travailler avec les classeurs et feuilles de calcul

Cette section décrit quelques opérations courantes sur les workbooks et les worksheets.

3.1. Les workbooks (classeurs)

3.1.1. Ouvrir un classeur

Ouvrir un classeur
Sélectionnez

Globals.ThisAddIn.Application.Workbooks.Open("unWorkBook.xls");

Le classeur est ouvert dans une nouvelle instance d'Excel. Le classeur utilisé avant l'ouverture est donc conservé dans l'instance initiale d'Excel.

3.1.2. Fermer un classeur

Fermer un classeur (avec sauvegarde des changements)
Sélectionnez

Globals.ThisAddIn.Application.Workbooks[1].Close(true, @"C:\unWorkBook");
Fermer un classeur (sans sauvegarde des changements)
Sélectionnez

Globals.ThisAddIn.Application.Workbooks[1].Close(false, @"C:\unWorkBook");

Ici, le premier argument de la méthode Close permet de spécifier si le programme doit sauvegarder les changements non enregistrés du classeur avant de fermer celui-ci. Le deuxième argument permet de spécifier un chemin d'enregistrement si le fichier est nouveau (i.e. aucun fichier ne lui correspond sur le disque dur). Dans le cas d'un nouveau fichier, le classeur est toujours sauvegardé au format xlsx.

Il ne faut jamais écrire Globals.ThisAddIn.Application.Workbooks[1].Close(false, @"C:\unWorkBook.xlsx"); (on a écrit l'extension xlsx). L'instruction ci-dessus fait planter le programme car c'est celui-ci qui choisit le format d'enregistrement.

Fermer un workbook (avec choix de l'utilisateur d'enregistrer ou non le fichier)
Sélectionnez

Globals.ThisAddIn.Application.Workbooks[1].Close();

Dans l'exemple ci-dessus, l'utilisateur doit choisir s'il souhaite enregistrer le classeur et le cas échéant à quel emplacement celui-ci doit être sauvegardé.

3.1.3. Sauvegarder un classeur

Sauver un classeur existant
Sélectionnez

Globals.ThisAddIn.Application.Workbooks[1].Save();

L'instruction ci-dessus resauvegarde un classeur existant déjà sur le disque dur. Il ne faut donc pas utiliser cette instruction si c'est un nouveau classeur qui est ouvert (dans un tel cas, utiliser la méthode SaveAs décrite ci-dessous).

Sauver un classeur à un emplacement déterminé (Save As)
Sélectionnez

// Sauve le classeur sous C:\testWorkBook.xlsx.
Globals.ThisAddIn.Application.Workbooks[1].SaveAs(@"C:\testWorkBook", Excel.XlFileFormat.xlOpenXMLWorkbook);

Excel.XlFileFormat fournit une énumération qui permet de choisir parmi les différents formats de sauvegarde disponibles. Un tableau récapitulatif des formats disponibles se trouve sur http://msdn.microsoft.com/en-us/library/bb241279%28office.12%29.aspxhttp://msdn.microsoft.com/en-us/library/bb241279%28office.12%29.aspx.

Un commentaire disponible en accédant à la page internet http://msdn.microsoft.com/en-us/library/bb241279%28office.12%29.aspxhttp://msdn.microsoft.com/en-us/library/bb241279%28office.12%29.aspx indique qu'il n'est pas toujours possible d'ouvrir et/ou de sauver sous tous les formats répertoriés dans l'énumération XlFileFormat. Cependant, seuls les formats de fichier les plus exotiques ou les plus anciens peuvent poser problème. Une liste des formats non supportés pour l'écriture et/ou la lecture est incluse dans le commentaire susmentionné.

3.2. Les worksheets (feuilles de calcul)

3.2.1. Sélectionner une feuille de calcul

La sélection d'une feuille de calcul consiste à afficher celle-ci sur l'écran.

Sélectionner une feuille de calcul (méthode 1)
Sélectionnez

// Sélectionne la deuxième feuille de calcul dans l'ordre du classeur
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[2];
workSheet.Select();

La sélection se base ici sur la position de la feuille de calcul par rapport aux autres. Pour mieux comprendre ce que l'ordre d'une feuille de calcul représente, voici une illustration :

L'ordre des feuilles de calcul
L'ordre des feuilles de calcul

Sur l'image ci-dessus, la feuille de calcul Sheet1 est la première, suivie de Sheet2, Sheet3, etc. Ainsi, Workbooks[1].Sheets[2] renvoie à la deuxième feuille de calcul (Sheet2 dans l'exemple) du premier classeur ouvert.

Sélectionner une feuille de calcul (méthode 2)
Sélectionnez

// Sélectionne la feuille de calcul du premier classeur nommée "Sheet3"
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets["Sheet3"];
workSheet.Select();

La sélection se base ici sur le nom que porte la feuille de calcul. Cette deuxième méthode peut s'avérer plus fiable que son équivalent avec les index dans la mesure où l'utilisateur pourrait avoir envie de réorganiser l'ordre des feuilles de calcul. Cette difficulté est surmontée dans la deuxième méthode car le nom des feuilles de calcul restera inchangé (pour autant que l'utilisateur soit suffisamment discipliné...).

3.2.2. Redimensionner les lignes et colonnes

Il est également possible de redimensionner la largeur d'une colonne ou la hauteur d'une ligne.

Redimensionnement de la hauteur d'une ligne
Sélectionnez

// La première feuille de calcul
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
// La quatrième ligne
Excel.Range row = workSheet.Rows[4];
// On utilise l'objet RowHeight pour fixer la hauteur de la ligne
row.RowHeight = 120;

Il est nécessaire de passer par la propriété RowHeight. En effet, la propriété Height ne permet que la lecture de la hauteur de la ligne. Le code suivant marche également :

 
Sélectionnez

// La première feuille de calcul
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
// La première cellule de la quatrième ligne
Excel.Range row = workSheet.Cells[4,1];
// On utilise l'objet RowHeight pour fixer la hauteur de la ligne
row.RowHeight = 120;

Ce code montre qu'il est en fait possible de redimensionner la hauteur de la ligne associée à n'importe quelle cellule. Plus généralement, l'utilisation de l'interface Range permet de modifier la hauteur des lignes d'un "bloc de cellules". Cependant, ceci ne marche que si les lignes de ce "bloc de cellules" ont initialement la même hauteur. Dans le cas contraire, une erreur sera levée. Une discussion plus fine de ceci est disponible sur http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.rowheight.aspxhttp://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.rowheight.aspx

Redimensionnement de la largeur d'une colonne
Sélectionnez

// La première feuille de calcul
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[1];
// La troisième colonne
Excel.Range column = workSheet.Columns[3];
// On utilise l'objet RowHeight pour fixer la hauteur de la ligne
column.ColumnWidth = 80;

ColumnWidth est l'équivalent pour les colonnes de RowHeight pour les lignes.

Une différence essentielle entre RowHeight et ColumnWidth existe cependant. ColumnWidth = i attribue à la colonne une largeur correspondant à i fois la largeur d'un caractère dans le style Normal. En revanche, la propriété Width est exprimée en pixels tout comme RowHeight et Height. Pour plus d'informations : http://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.namedrange.columnwidth(VS.80).aspxhttp://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.namedrange.columnwidth(VS.80).aspx .

3.2.3. Ajouter une feuille de calcul à un classeur existant

 
Sélectionnez

// Classeur dans lequel insérer les nouvelles feuilles de calcul
Excel._Workbook workBook = Globals.ThisAddIn.Application.Workbooks[1];
// Feuille de calcul avant laquelle insérer les nouvelles feuilles de calcul
Excel._Worksheet befSheet = workBook.Sheets[2];
// Ajout de deux nouvelles feuilles de calcul avant la deuxième feuille de calcul
workBook.Sheets.Add(befSheet, Type.Missing, 2, Excel.XlSheetType.xlWorksheet);

L'ajout d'une feuille de calcul se fait par la méthode Add de workBook.Sheets. Celle-ci est très bien décrite dans la MSDN. Voir : http://msdn.microsoft.com/fr-fr/library/microsoft.office.interop.excel.sheets.add%28v=office.11%29.aspx

3.2.4. Supprimer une feuille de calcul d'un classeur existant

Suppression d'une feuille de calcul (code simplifié)
Sélectionnez

// La deuxième feuille de calcul du premier classeur
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[2];
workSheet.Delete();

Le code ci-dessus est une façon basique de supprimer une feuille de calcul. Cependant, il postule l'existence d'au moins deux feuilles de calcul. Cette hypothèse est vérifiée par le code suivant :

Suppression d'une feuille de calcul
Sélectionnez

// Nombre total de feuilles de calcul dans le premier classeur
int workSheetNb = Globals.ThisAddIn.Application.Workbooks[1].Sheets.Count;
// Vérification de l'existence de la feuille de calcul
if (workSheetNb > 1)
    {
        // La deuxième feuille de calcul du premier classeur
        Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets[2];
        workSheet.Delete();
    }

3.2.4.1. Suppression d'une feuille de calcul à partir de son nom

Une méthode générale de sélection des feuilles de calcul sur base de leurs noms est décrite ci-dessous. Ci-dessus, la propriété Count de Workbooks[1].Sheets a été utilisée afin de savoir si la feuille de calcul (donnée par son index) existe. Dans le cas où un nom est utilisé, il est clair qu'une telle technique n'est plus valable.

Tout d'abord, il faut introduire la ligne suivante au début du code source :

 
Sélectionnez

using System.Runtime.InteropServices;

Ceci fournira l'accès à la classe ComException. Celle-ci constitue la classe de base pour la gestion des exceptions dans Office (plus généralement, dans une application reposant sur l'architecture COM). Le code suivant permet de traiter l'exception voulue :

Interception d'une exception dans Excel
Sélectionnez

try
    {
        Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets["unNom"];
        workSheet.Delete();
    }
catch (COMException exp)
    {
        if ((uint)exp.ErrorCode == 0x8002000B)
        {
            // Le code à exécuter si la feuille de calcul n'existe pas
            // ...
        }
    }

Comme suggéré ci-dessus, la nature de l'exception est donnée par un code d'erreur associé à l'objet exp (classe COMException). Une méthode pour déterminer le code qui correspond à une erreur donnée est décrite ci-dessous.

3.2.4.1.1. Détermination du code d'erreur associé à une action particulière

L'idée consiste à provoquer volontairement l'erreur et à récupérer le code correspondant dans le débogueur de Visual Studio. Pour déterminer le code d'erreur associé à la sélection d'une feuille de calcul qui n'existe pas, il suffit de créer un bouton avec les instructions suivantes pour le simple clic sur celui-ci :

 
Sélectionnez

private void btnAction_Click(object sender, RibbonControlEventArgs e)
{
	Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Workbooks[1].Sheets["unNomQuiNexistePas"];
}

En cliquant sur ce bouton, la fenêtre ci-dessous apparaît. Il suffit alors de copier-coller le code d'erreur et de l'insérer dans le code source.

Obtenir un code d'erreur avec le débogueur de Visual Studio
Obtenir un code d'erreur avec le débogueur de Visual Studio

4. Mise en forme des feuilles de calcul

4.1. Introduction

Cette section a pour but de présenter la mise en forme des tableaux Excel. La mise en forme d'un tableau englobe la gestion des couleurs, de la taille des cellules, de la forme des bordures, etc. Les exemples qui suivent ne concernent que certains aspects très généraux de la mise en page d'une feuille de calcul, il faudra donc généralement chercher soi-même la manière d'effectuer certaines opérations.

4.2. Les deux manières de personnaliser le style d'une cellule

Il existe deux manières d'affecter un style à une cellule. La première consiste à définir un nouveau style accessible également à l'utilisateur. Dans ce cas, les nouveaux styles (style1 style2, etc.) apparaissent dans la zone délimitée par un cadre rouge sur la figure ci-dessous :

Des styles personnalisés
Des styles personnalisés

Ils sont donc également applicables par l'utilisateur aux cellules de son choix.

Les styles standard d'Excel (Normal sur la figure ci-dessous) apparaissent également dans la zone définie par le rectangle rouge dans la figure ci-dessus. En fait, ceux-ci sont, du point de vue de la programmation, parfaitement identiques aux styles personnalisés. Il est donc possible de les modifier et de les appliquer sur les cellules voulues.

La deuxième méthode pour changer l'apparence des cellules est très similaire à la première mais est telle que les styles utilisés n'apparaissent plus dans la fenêtre des styles comme précédemment.

Du point de vue d'un utilisateur, la première méthode consiste à soi-même définir un nouveau style et la seconde à modifier le style des cellules une à une.

4.3. Les deux méthodes

4.3.1. La première méthode

4.3.1.1. L'objet Style

Dans le cadre de la première méthode, il faut toujours utiliser un objet d'interface "Style". Celui-ci permet de créer un nouveau style ou d'en éditer un déjà existant. Les codes suivants permettent d'effectuer des opérations standard sur cette interface.

Créer un nouveau style ayant pour intitulé 'unNouveauStyle'
Sélectionnez

Excel.Style currStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("unNouveauStyle");
// Dans la suite, on paramétrise le style (par exemple, définir la taille des bordures et leur couleur)
// ...
Acquérir l'accès un style déjà existant nommé 'unStyleExistantDeja'
Sélectionnez

Excel.Style currStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles["unStyleExistantDeja"];
Supprimer le style 'unStyleASupprimer'
Sélectionnez

Globals.ThisAddIn.Application.Workbooks[1].Styles["unStyleASupprimer"].Delete();
Assignation d'un style à une cellule (façon 1)
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// Première feuille de calcul (du premier classeur)
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Worksheets[1];
// Cellule B1
Excel.Range cell = workSheet.Cells[1, 2];
// Assignation du style
cell.Style = customStyle;
Assignation d'un style à une cellule (façon 2)
Sélectionnez

// Première feuille de calcul (du premier classeur)
Excel._Worksheet workSheet = Globals.ThisAddIn.Application.Worksheets[1];
// Cellule B1
Excel.Range cell = workSheet.Cells[1, 2];
// Assignation du style
cell.Style = "customStyle";

Dans la deuxième façon, le nom du style est utilisé alors que dans la première, c'est un objet représentant le style qui est employé.

4.3.2. La deuxième méthode

La deuxième méthode travaille directement sur les propriétés de la cellule elle-même. Ainsi, si la couleur intérieure de la cellule A1 doit être changée, nous pouvons écrire

 
Sélectionnez

// Première feuille de calcul (du premier classeur)
Excel._Worksheet currWorkSheet = Globals.ThisAddIn.Application.Worksheets[1];
// Cellule A1
Excel.Range cell = currWorkSheet.Cells[1, 1];
// La couleur de fond de la cellule est maintenant rouge (Red).
cell.Interior.Color = System.Drawing.Color.Red;

La suite de ce tutoriel traite de quelques opérations particulières sur les styles. Celles-ci sont réalisées en utilisant la première méthode mais l'adaptation à la seconde est simple et presque immédiate.

4.4. Quelques opérations courantes sur les styles

4.4.1. La couleur de fond (background color)

Changer la couleur de fond d'un style
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// Couleur de fond jaune
customStyle.Interior.Color = System.Drawing.Color.Yellow;

4.4.2. L'alignement du texte

Pour changer l'alignement du texte (i.e. sa position dans la cellule), il faut modifier d'une part l'alignement vertical et d'autre part l'alignement horizontal.

Changer l'alignement vertical
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// Le texte est écrit au bas de la cellule
customStyle.VerticalAlignment = Excel.XlVAlign.xlVAlignBottom;
Changer l'alignement horizontal
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// Le texte est écrit au milieu de la cellule (le milieu est ici envisagé au sens horizontal)
customStyle.HorizontalAlignment = Excel.XlHAlign.xlHAlignCenter;

L'alignement est totalement défini par les propriétés VerticalAlignement et HorizontalAlignement du style. Les énumérations XlVAlign (V pour vertical) et XlHAlign (H pour horizontal) fournissent tous les alignements possibles.

4.4.3. Personnaliser la police de caractères

4.4.3.1. Mise en forme de base : écriture en gras, italique et soulignage

Le code suivant montre comment écrire en gras, en italique et souligner du texte :

 
Sélectionnez

 // Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// Le texte est écrit en gras
customStyle.Font.Bold = true;
// Le texte est écrit en italique
customStyle.Font.Italic = true;
// Le texte est souligné
customStyle.Font.Underline = true;

4.4.3.2. Taille de la police

Changement de la taille de la police de caractères
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// Le texte est écrit en taille 18
customStyle.Font.Size = 18;

4.4.3.3. La couleur du texte

Changer la couleur du texte
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// La couleur du texte est vert foncé
customStyle.Font.Color = System.Drawing.Color.DarkGreen;

4.4.4. La gestion des bordures

Cette section montre comment personnaliser les bordures des cellules.

4.4.4.1. Introduction

Toute cellule contient six bordures : la bordure gauche, droite, supérieure, inférieure, en diagonale montante et en diagonale descendante.

Toutes les bordures sont représentées en orange sauf la supérieure
Toutes les bordures sont représentées en orange sauf la supérieure

Chaque bordure peut bien sûr être modifiée indépendamment des autres.

Une erreur dans l'énumération XlBordersIndex du framework nécessite un petit ajustement au niveau du code qui sera présenté dans la suite.

4.4.4.2. Modifier la totalité des bordures en même temps

Il est possible de modifier toutes les bordures en même temps. Le code suivant constitue un exemple :

 
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
// La couleur des bordures est orange foncé
// REMARQUE : Cette instruction fait aussi apparaitre toutes les bordures (et plus particulièrement
// les deux bordures diagonales)
customStyle.Borders.Color = System.Drawing.Color.DarkOrange;
// Le trait de la bordure est moyen
customStyle.Borders.Weight = Excel.XlBorderWeight.xlMedium;

Comme notifié dans les commentaires du code ci-dessus, manipuler les bordures les fait apparaitre. Plus particulièrement, modifier toutes les bordures à la fois mène à l'apparition des bordures diagonales. Ce comportement n'est généralement pas désiré dans la mesure où les bordures diagonales sont peu utilisées en pratique.

4.4.4.3. Modifier les bordures une à une

Il est également possible de modifier une seule bordure à la fois. Dans ce cas, il est clair qu'il faut être en mesure de sélectionner la bordure qui doit être traitée. Le code suivant décrit cette opération :

Sélectionner une bordure
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
/* NOTE : Erreur dans l'enum (XlBordersIndex) du framework
* Valeurs correctes : 
* xlEdgeLeft = 1,
* xlEdgeRight = 2,
* xlEdgeTop = 3,
* xlEdgeBottom = 4,
* xlDiagonalTop et XlDiagonalDown : l'enum marche correctement
*/
// La bordure de droite (xlEdgeRIGHT) est constituée d'une succession de points
customStyle.Borders[(Excel.XlBordersIndex)2].LineStyle = Excel.XlLineStyle.xlDot;

Comme mentionné précédemment, l'énumération XlBordersIndex n'est pas correcte. Il faut donc faire un cast dans Borders[(Excel.XlBordersIndex)2] pour avoir des valeurs correctes. Il est également très fortement conseillé d'inclure le commentaire NOTE : Erreur dans l'enum... afin que d'autres programmeurs soient en mesure de comprendre pourquoi Borders[(Excel.XlBordersIndex)2] est écrit au lieu de Borders[Excel.XlBordersIndex.xlEdgeRight].

4.4.4.4. Opérations sur les bordures

Les codes qui suivent décrivent comment personnaliser les bordures.

Changer le style de la ligne
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
/* NOTE : Erreur dans l'enum (XlBordersIndex) du framework
* Valeurs correctes : 
* xlEdgeLeft = 1,
* xlEdgeRight = 2,
* xlEdgeTop = 3,
* xlEdgeBottom = 4,
* xlDiagonalTop et XlDiagonalDown : l'enum marche correctement
*/
// La bordure de droite (xlEdgeRIGHT) est constituée d'une succession de points et de traits d'union (-.-.-.)
customStyle.Borders[(Excel.XlBordersIndex)2].LineStyle = Excel.XlLineStyle.xlDashDot;

Les types de lignes sont contenus dans l'énumération XlLineStyle. En particulier, XlLineStyle.xlLineStyleNone rend la bordure invisible.

Modifier l'épaisseur du trait constituant une bordure
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
/* NOTE : Erreur dans l'enum (XlBordersIndex) du framework
* Valeurs correctes : 
* xlEdgeLeft = 1,
* xlEdgeRight = 2,
* xlEdgeTop = 3,
* xlEdgeBottom = 4,
* xlDiagonalTop et XlDiagonalDown : l'enum marche correctement
*/
// L'épaisseur de la bordure de droite (xlEdgeRIGHT) est très petite (xlHairline == la plus petite épaisseur disponible)
customStyle.Borders[(Excel.XlBordersIndex)2].Weight = Excel.XlBorderWeight.xlHairline;
Colorier une bordure
Sélectionnez

// Création du nouveau style
Excel.Style customStyle = Globals.ThisAddIn.Application.Workbooks[1].Styles.Add("customStyle");
/* NOTE : Erreur dans l'enum (XlBordersIndex) du framework
* Valeurs correctes : 
* xlEdgeLeft = 1,
* xlEdgeRight = 2,
* xlEdgeTop = 3,
* xlEdgeBottom = 4,
* xlDiagonalTop et XlDiagonalDown : l'enum marche correctement
*/
// La bordure de gauche est de couleur rouge
customStyle.Borders[(Excel.XlBordersIndex)1].Color = System.Drawing.Color.Red;

5. Remerciements

Merci à Claude LELOUP pour la relecture de cet article.