Développer un add-in Word pour SharePoint
Date de publication : 20/12/2008
Par
stephane eyskens (SharePoint) (Blog)
Mes outils CodePlex
Dans cet article, vous découvrirez comment récupérer des données d'une ferme SharePoint dans un document Word au travers
d'un exemple simple.
I. Pré-requis
II. Introduction
III. L'exemple en image
IV. Avant de commencer....
V. Création du projet pas à pas
V-A. Création du projet Visual Studio 2008
V-B. Ajout de la référence Web
V-C. Ajout du task pane
V-D. Ajout du ruban
VI. Tester le projet
VI. Téléchargement
I. Pré-requis
Les pré-requis pour pouvoir recréer le projet présenté dans cet article sont :
- disposer d'en environnement SharePoint 2007
- disposer de Visual Studio 2008
- connaître un peu .NET :). Aucune connaissance de SharePoint n'est nécessaire. Le niveau de l'article est très simple.
II. Introduction
SharePoint étant au centre des produits Office, son interaction avec ceux-ci ne va cesser de croître. En plus
de bénéficier des intégrations standards, vous avez la possibilité de créer vos propres add-ins pour effectuer toutes
sortes d'opérations. Le but de cet article est de vous présenter un exemple dont le scénario est le suivant :
Vous disposez d'une liste de clients dans SharePoint contenant leurs coordonnées et adresses. Vous souhaitez pouvoir
récupérer facilement celles-ci lorsque vous créez un document Word destiné à être envoyé à vos clients.
Bien que simpliste, cet exemple fournit néanmoins les bases nécessaires pour appréhender l'interaction entre Office et SharePoint.
III. L'exemple en image
La liste des clients stockés dans SharePoint :
Le ruban Word avec un bouton permettant d'ouvrir le custom task pane :
Le custom task pane permettant d'effectuer une recherche dans la liste des clients et d'effectuer un choix.
Enfin, la fiche client qui est insérée dans le document lorsque le choix est fait.
IV. Avant de commencer....
Avant de commencer à réaliser le projet pas à pas, il me paraît intéressant de s'attarder une minute sur
l'environnement architectural dans lequel évolue un add-in Office s'il est en interaction avec un serveur SharePoint.
Dans l'hypothèse où l'add-in va chercher directement ses données dans SharePoint, le contexte d'exécution se déroulera dans un
environnement client-serveur simple. Même si cela paraît évident, ceci force donc le développeur à faire appel aux services web de SharePoint ou
à développer son propre service et à le déployer au sein de la ferme.
En effet, l'API SharePoint ne peut être utilisée dans ce contexte car les clients Office sont externes à la ferme SharePoint. Ceci a pour impact de compliquer
un peu la tâche :) car les services web standard sont plus difficiles à manipuler que l'API.
Donc, en conclusion, lorsque vous développez un add-in Office qui doit interagir avec SharePoint, vous avez deux possibilités :
- Utiliser les services web standard de SharePoint
- Développer votre propre service web si les besoins en terme d'interaction ne peuvent pas être couverts facilement par l''utilisation des services standard. Si vous optez pour ce choix, vous devrez également penser à déployer votre service sur tous les frontaux de la ferme.
V. Création du projet pas à pas
Dans cet article, nous utiliserons le service web standard lists.asmx proposé par SharePoint pour récupérer les fiches clients.
V-A. Création du projet Visual Studio 2008
Démarrez Visual Studio 2008 et créez un nouveau projet de type Word add-in comme illustré ci-dessous :
Le projet crée automatiquement la classe principale nommée ThisAddin.cs contenant certaines méthodes. Ajoutez ce code
dans la méthode ThisAddin_Startup
Word.Document DocumentWord = Globals.ThisAddIn.Application.ActiveDocument as Word.Document;
Globals.ThisAddIn.CustomTaskPanes.Add(
new ClientControl(), "Controle Client", DocumentWord.ActiveWindow);
|
Il s'agit simplement d'ajouter le contrôle utilisateur ClientControl dans la collection de taskpanes de l'add-in. Nous
créerons ce contrôle un peu plus loin dans cet article.
V-B. Ajout de la référence Web
Le projet doit communiquer avec le service standard lists.asmx de SharePoint. Il faut donc ajouter une référence web.
Cliquez sur References puis sur Add Service Reference.
Cliquez sur le bouton Advanced :
Et ensuite sur Add Web Reference :
Et insérez-y vos paramètres, c'est à dire http://votre site SP/_vti_bin/lists.asmx et SPService comme nom de référence et terminez
en cliquant sur Add Reference.
V-C. Ajout du task pane
Le task pane n'est qu'un simple contrôle utilisateur. Il est utilisé pour présenter l'interface graphique à l'utilisateur.
Cliquez sur le bouton droit de votre projet et choisissez Ajouter puis Nouvel Elément. Ensuite, procédez
comme illustré :
Disposez à présent quelques contrôles afin d'obtenir ceci :
- (1) : TextBox, Nom : SiteUrl
- (2) : TextBox, Nom : Nom
- (3) : TextBox, Nom : Prenom
- (4) : Button, Nom : OkBtn
- (5) : ComboBox, Nom : ComboClients
- (6) : Label, Nom : NbClients
Double-cliquez sur le bouton OkBtn et ajoutez ce code :
DataTable TableClients = new DataTable();
TableClients.Columns.Add("ID");
TableClients.Columns.Add("Nom Complet");
TableClients.Rows.Add("", "");
try
{
XmlNode Items = GetListItems(
string.Format(
"<Where><Or><Contains><FieldRef Name=\"Nom\" />
<Value Type=\"Text\">{0}</Value></Contains><Contains>
<FieldRef Name=\"Pr_x00e9_nom\" />
<Value Type=\"Text\">{1}</Value></Contains></Or></Where>",
Nom.Text, Prenom.Text));
XmlNodeList Clients = Items.SelectNodes(
string.Format("{0}{1}",
"//*[local-name() = 'data' and namespace-uri() = 'urn:schemas-microsoft-com:rowset']",
"/*[local-name() = 'row' and namespace-uri() = '#RowsetSchema']"));
NbClients.Text = string.Format("Nombre de clients : {0}", Clients.Count);
if (Clients.Count > 0)
{
for (int i = 0; i < Clients.Count; i++)
{
TableClients.Rows.Add(
Clients[i].Attributes["ows_ID"].Value,
string.Format("{0} {1}",
Clients[i].Attributes["ows_Nom"].Value,
Clients[i].Attributes["ows_Pr_x00e9_nom"].Value
));
}
TableClients.AcceptChanges();
}
}
catch (SoapException WebSrvEx)
{
MessageBox.Show(
string.Format(
"Problème de communication avec le service lists.asmx : {0}",
WebSrvEx.Message));
}
ComboClients.DisplayMember = "Nom Complet";
ComboClients.ValueMember = "ID";
ComboClients.DataSource = TableClients;
|
Ce code crée une datatable pour stocker le retour du service web auquel il envoie une requête CAML.
Cette requête CAML correspond au SQL suivant :
SELECT Nom,Prenom,Adresse FROM Clients WHERE Nom LIKE '%..%' OR Prenom LIKE '%...%'
|
Ensuite, le retour est traité par XPATH et la datatable est remplie et liée au ComboBox. Ce code fait appel à la méthode
GetListItems qu'il nous faut encore implémenter. Insérez le code suivant au dessus de la méthode OkBtn_Click().
private XmlNode GetListItems(string SpQuery)
{
SPListService.Lists SPService = new SPListService.Lists();
SPService.Url = SiteUrl.Text + "_vti_bin/lists.asmx";
SPService.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
XmlNode Lists = SPService.GetListCollection();
XPathNavigator Navigator = Lists.CreateNavigator();
XPathNavigator ClientAdresse =
Navigator.SelectSingleNode(string.Format("//*[@Title='{0}']", ListName));
if (ClientAdresse != null)
{
XmlDocument Doc = new XmlDocument();
XmlNode NoeudViewFields =
Doc.CreateNode(XmlNodeType.Element, "ViewFields", "");
XmlNode QueryOptionsNode =
Doc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
QueryOptionsNode.InnerXml = "<IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns>";
XmlNode SearchQuery = Doc.CreateNode(
XmlNodeType.Element, "Query", "");
NoeudViewFields.InnerXml = "<FieldRef Name='ID'/><FieldRef Name='Nom'/><FieldRef Name='Pr_x00e9_nom'/>";
SearchQuery.InnerXml = SpQuery;
XmlNode Items = SPService.GetListItems(ListName, null, SearchQuery, NoeudViewFields, null, QueryOptionsNode, null);
return Items;
}
else
{
MessageBox.Show("La liste d'adresse n'a pu être trouvée");
}
return null;
}
|
Cette méthode communique avec le service web lists.asmx et exécute la requête SpQuery passée en argument en ayant
au prélable construit tous les noeuds XML requis pour communiquer avec le service. Notez qu'aucun contrôle spécifique n'est effectué sur
l'URL du site contenue dans la zone de texte SiteUrl afin de ne pas alourdir la lisibilité. Bien sûr, dans un contexte réel, vous devriez
impérativement rendre ce code plus robuste.
Ajoutez à présent en en-tête de classe les deux constantes utilisées par GetListItems :
const string XmlNs = "";
const string ListName = "Clients";
|
Enfin, il ne reste plus qu'à associer un évènement au ComboBox afin d'insérer la fiche client dans le document lorsqu'une entrée
est sélectionnée par l'utilisateur. Double-cliquez sur le ComboBox et insérez ce code :
StringBuilder FicheClient=null;
if (!String.IsNullOrEmpty(ComboClients.SelectedValue.ToString()))
{
FicheClient = new StringBuilder();
try
{
XmlNode Items =
GetListItems(
string.Format(
"<Where><Eq><FieldRef Name=\"ID\" /><Value Type=\"Counter\">{0}</Value></Eq></Where>",
ComboClients.SelectedValue.ToString()));
XmlNodeList Clients = Items.SelectNodes(
string.Format("{0}{1}",
"//*[local-name() = 'data' and namespace-uri() = 'urn:schemas-microsoft-com:rowset']",
"/*[local-name() = 'row' and namespace-uri() = '#RowsetSchema']"));
if (Clients != null && Clients.Count == 1)
{
FicheClient.AppendFormat("Nom : {0}\r\n", Clients[0].Attributes["ows_Nom"].Value);
FicheClient.AppendFormat("Prénom : {0}\r\n", Clients[0].Attributes["ows_Pr_x00e9_nom"].Value);
FicheClient.AppendFormat("Adresse : {0}\r\n", Clients[0].Attributes["ows_Adresse"].Value);
Word.Range currentRange = Globals.ThisAddIn.Application.Selection.Range;
currentRange.Text = FicheClient.ToString();
}
else
{
MessageBox.Show("Problème lors de la réception de la fiche client");
}
}
catch (SoapException WebSrvEx)
{
MessageBox.Show(
string.Format(
"Problème de communication avec le service lists.asmx : {0}",
WebSrvEx.Message));
}
}
|
L'ID du client est retourné par le ComboBox. Cette méthode exécute donc GetListItems pour récupérer la fiche client
correspondante à l'ID sélectionné. Ensuite, cette fiche est insérée dans le document.
V-D. Ajout du ruban
Ajoutez un ruban en cliquant sur votre projet avec le bouton droit et choisissez Ajouter puis Nouvel Elément. Ensuite,
procédez comme illustré :
Ajoutez ensuite un bouton au ruban et ajoutez-lui le code suivant :
CustomTaskPane ClientCtrl = Globals.ThisAddIn.CustomTaskPanes[0];
if (ClientCtrl != null)
{
ClientCtrl.Visible = !ClientCtrl.Visible;
}
|
Le but étant simplement d'afficher ou de masquer le task pane.
Note: pour associer une image Office à votre bouton, vous pouvez utiliser un outil très pratique
ici. L'outil
en question est le
VSTO_PTRibbonIDs.exe qui permet de parcourir la galerie d'images et de récupérer leur ID.
VI. Tester le projet
Pour tester l'addin, il suffit de démarrer le projet depuis Visual Studio. Word démarre automatiquement et le ruban est ajouté. Pour "nettoyer",
il faut faire un Clean depuis Visual Studio.
Notez que ceci n'est pas suffisant pour déployer l'add-in sur des machines clientes. Pour ce faire, vous devrez créer un projet d'installation.
VI. Téléchargement
Le projet ainsi qu'un template de la liste utilisée (template en anglais) sont disponibles en téléchargement
ici.


Copyright © stephane eyskens. Aucune reproduction, même partielle, ne peut être faite
de ce site et de l'ensemble de son contenu : textes, documents, images, etc
sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.