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.
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).
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 :
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.
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.
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.
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.
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.
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 :
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 :
using
Excel =
Microsoft.
Office.
Interop.
Excel;
using
Office =
Microsoft.
Office.
Core;
Le code pour accéder à une cellule est le suivant :
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 :
- bénéficier de l'autocomplétion de Visual Studio ;
- é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 :
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 :
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 :
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 :
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) :
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 :
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é :
- 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 ;
- 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 ;
- d'utiliser la MSDN lorsqu'une classe, une méthode ou une propriété semble peu claire ;
- 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) ;
- 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▲
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▲
Globals.
ThisAddIn.
Application.
Workbooks[
1
].
Close
(
true
,
@"C:\unWorkBook"
);
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.
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▲
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).
// 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é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 :
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é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.
// 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 :
// 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
// 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▲
// 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▲
// 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 :
// 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 :
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 :
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 :
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.
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 :
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.
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)
// ...
Excel.
Style currStyle =
Globals.
ThisAddIn.
Application.
Workbooks[
1
].
Styles[
"unStyleExistantDeja"
];
Globals.
ThisAddIn.
Application.
Workbooks[
1
].
Styles[
"unStyleASupprimer"
].
Delete
(
);
// 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;
// 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
// 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)▲
// 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.
// 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;
// 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 :
// 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▲
// 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▲
// 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.
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 :
// 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 :
// 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.
// 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.
// 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;
// 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.