Passer au contenu principal

dnt91's Blog [MVP SharePoint]

Lancer la recherche
dnt91's Blog [MVP SharePoint]
  

 Me Contacter

MVP

 Blogs MS

  InfoPath Team Blog
  SharePoint Team Blog
  IE Team Blog
  Project Team Blog
  SharePoint Designer Team Blog
Bonjour et Bienvenue sur mon blog concernant les technologies Microsoft et notamment les produits & technologies SharePoint.
[SPDesigner 2007] Comment créer une page web dans un site SharePoint en 5 clics ?

Simple comme bonjour !

Positionnez vous sur la racine de votre site ou dans une bibliothèque de documents*.

Ici nous nous positionnons sur la bibliothèque « Pages », faites un clic droit > nouveau > ASPX (2 clics).

Donnez-lui ensuite un nom, puis double-cliquez dessus afin de l'ouvrir en mode édition dans SPDesigner.

Une fois sur la page sélectionnée, cliquez ensuite sur Format > Page maitre > Attacher la page maitre (2 clics)

Sélectionnez enfin la page maitre souhaitée, puis cliquez sur Ok (1 clic)

Et voila le résultat !

Et dans le navigateur, voici ce que ca donne :

Il ne vous reste plus qu'à y rajouter du contenu.

Je vous rappelle que SP Designer 2007 est gratuit depuis le 1er Avril 2009, alors profitez en.

Attention cependant à ne pas mettre ce logiciel entre toutes les mains, les conséquences pour vos sites pourraient désastreuses L. A consommer donc avec modération !

*Il est préférable de créer une page web dans une bibliothèque de documents plutôt qu'à la racine, car cela pour permet de pouvoir appliquer les même fonctionnalités à votre page web que celles liés à un document (gestion des autorisations, gestion du ciblage du contenu, versionning, extraction, etc.…)

[SP2007]Erreur : La période d’essai a expiré…. Mais pas à cause du SP2.

Depuis quelques temps, sur mon environnement de développement, je suis confronté à des bugs incessants de mon environnement SharePoint, celui-ci allant même jusqu'à m'interdire de rajouter mes webparts custom dans les galeries de collections de sites !

Le message d'erreur affiché est la période d'essai du produit a expiré, pourtant ma clé est bien une clé valide !

Cependant ce message ne s'affiche que lorsque j'essaye de réaliser des taches nécessitant des autorisations avancées, comme configurer des workflows sur des listes, ou encore ou me connecter à 1 site project server.

Ayant pris le temps d'auditer le problème, je me suis rendu compte (au bout d'un certain temps tout de meme !) que la légèreté avec laquelle je crée mes applications web (la plupart des paramètres est laissée par défaut), m'a amené à faire tourner mes sites sharepoint avec le compte SERVICE RESEAU au niveau de mes pools d'application, ce qui n'est pas toujours une bonne choses, car comme vous le savez, en fonction de vos actions, il faut mettre le bon compte dans le bon groupe, sinon ca ne passe pas tout simplement !

Dans ce scénario, en remplacant le SERVICE RESEAU par un compte qui est membre des groupes IIS_WPG et WSS_WPG, ca passe d'un coup sans problème J

La solution complète ici > http://blogs.msdn.com/murthygs/archive/2009/04/20/moss-2007-error-trial-period-for-this-product-has-expired.aspx

Et plus d'informations sur la configuration des comptes ici > http://technet.microsoft.com/en-us/library/cc263445.aspx

[SP2007]Quelques rappels C# 3.0 et leur utilisation dans SharePoint

Comme vous le savez tous, je suis quelqu'un qui apprécie particulièrement le partage de code source, et donc il m'arrive très fréquemment, d'envoyer des bouts de codes à des internautes en détresse, des clients ayant identifié un besoin qui me prend 5 min à régler, ou tout simplement sur mon blog.

Aujourd'hui encore, beaucoup (trop ??) de personnes me demandent de traduire mon code, car il n'arrive à le comprendre. Non pas que le code que je fournis soit trop compliqué, mais tout simplement parce qu'il tire pleinement partie des fonctionnalités de C# 3.0 et du .net 3.5 de manière générale.

Au départ, cela ne me posait aucun souci, mais avec le temps, je dois avouer que c'est de plus en plus contraignant, surtout lié au nombre de lignes supplémentaires à écrire en .net 2.0 et à la complexité que cela peut parfois rajouter, notamment lorsque l'on fait un usage intensif des divers Linq Providers.

L'objectif de ce post, est donc de vous proposer un rappel des nouveautés apportées par C# 3.0 à l'époque, et de commencer à migrer en douceur vers un modèle de développement orienté C# 4.0

Commencons donc sans plus tarder notre rappel C# 3.0 :

Les types implicites avec le mot clé var

Le mot clé var permet au développeur de laisser le soin au compilateur de déduire le type d'une variable, il évite ainsi au développeur, dans des situations « complexes » (notamment avec Linq) de se casser la tête à résoudre les types ou des situations avec un type de longueur kilométrique (merci les génériquesJ). Un simple mot clé var, combiné à l'utilisation de l'intellisense nous simplifie grandement la vie !

   1:  //au lieu d'écrire... (C# 2.0)
   2:  using (SPSite siteColl = new SPSite("http://ws2008dc01:10000")) {
   3:    using (SPWeb currentWeb = siteColl.OpenWeb()) {
   4:      foreach (SPList list in currentWeb.Lists) {
   5:        if (!list.Hidden) Console.WriteLine(list.Title);
   6:      }
   7:    }
   8:  }
   9:   
  10:  //...écrivez plutot (C# 3.0)
  11:  using (var siteColl = new SPSite("http://ws2008dc01:10000")) {
  12:    using (var currentWeb = siteColl.OpenWeb()) {
  13:      foreach (SPList list in currentWeb.Lists) {
  14:        if (!list.Hidden) Console.WriteLine(list.Title);
  15:      }
  16:    }
  17:  }

Les initialisateurs d'objets

Les initialisateurs d'objets permettent d'initialiser les propriétés publiques d'une classe, sans forcément passer par un constructeur, entrainant la plupart du temps un gain de temps considérable.

   1:  //au lieu d'écrire... (C# 2.0)
   2:  using (SPSite siteColl = new SPSite("http://ws2008dc01:10000")) {
   3:    siteColl.AllowUnsafeUpdates = true;
   4:    siteColl.CatchAccessDeniedException = true;
   5:    siteColl.PortalName = "My Portal";
   6:    siteColl.PortalUrl = "http://portal";
   7:                  
   8:    using (SPWeb currentWeb = siteColl.OpenWeb()) { }
   9:  }
  10:   
  11:  //...écrivez plutot (C# 3.0)
  12:  using (var siteColl = new SPSite("http://ws2008dc01:10000") {
  13:    AllowUnsafeUpdates = true, CatchAccessDeniedException = true,
  14:    PortalName = "My Portal", PortalUrl = "http://portal"
  15:  }) {
  16:    using (SPWeb currentWeb = siteColl.OpenWeb()) { }
  17:  }

Les méthodes d'extension

Les méthodes d'extension nous permettent d'étendre une classe existente en y rajoutant des méthodes à la volée.

   1:  //au lieu d'écrire... (C# 2.0 + beaucoup de farniente)
   2:  foreach (SPListItem item in cList.Items) { 
   3:    string title = item["Title"]==null?"":item["Title"].ToString();
   4:    string name= item["Name"]==null?"": item["Name"].ToString();
   5:   
   6:    XmlSerializer serializer = new XmlSerializer(typeof(Employee));
   7:    string data = (item["Employee"]==null)? "": item["Employee"].ToString();
   8:    if (data=="")throw new Exception("La colonne employee ne contient pas d'informations sérialisées.");
   9:    MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(data));
  10:    var employeeData = (Employee)serializer.Deserialize(stream);
  11:  }
  12:   
  13:   
  14:  //....écrivez plutot (C# 3.0)
  15:  foreach (SPListItem item in cList.Items) {
  16:    var title = item.IfNullReturnEmpty("Title");
  17:    var name = item.IfNullReturnEmpty("Name");
  18:    var employeeData = item.DeserializeAsEmployee("Employee");
  19:  }
  20:  //Avec en plus nos methodes d'extension
  21:  public static class Extensions {
  22:          
  23:    public static string IfNullReturnEmpty(this SPListItem item, string Column) {
  24:      return item[Column] == null ? "" : item[Column].ToString();
  25:    }
  26:   
  27:    public static Employee DeserializeAsEmployee(this SPListItem item, string Column) {
  28:      var serializer = new XmlSerializer(typeof(Employee));
  29:      var data = item.IfNullReturnEmpty(Column);
  30:      if (data == "") throw new Exception("La colonne employee ne contient pas d'informations sérialisées.");
  31:      var stream = new MemoryStream(Encoding.Default.GetBytes(data));
  32:      return (Employee)serializer.Deserialize(stream);
  33:    }
  34:  }

Le mot clé this dans la signature de la méthode d'extension permet de déterminer le type auquel sera rattachée la méthode (ici les méthodes sont rattachées aux classes SPListItem).

Les types anonymes

A l'instar des méthodes anonymes, les types anonymes vont être intéressants lorsque l'on souhaite implémenter rapidement et localement un type.

   1:  //au lieu d'écrire... (C# 2.0)
   2:  public class Contact {
   3:    string m_firstName;
   4:    public string FistName {
   5:      get { return this.m_firstName; }
   6:      set { this.m_firstName = value; }
   7:    }
   8:   
   9:    string m_lastName;
  10:    public string LastName {
  11:      get { return this.m_lastName; }
  12:      set { this.m_lastName = value; }
  13:    }
  14:   
  15:    string m_company;
  16:    public string Company {
  17:      get { return this.m_company; }
  18:      set { this.m_company = value; }
  19:    }
  20:  }
  21:   
  22:  //puis
  23:  Contact appContact1 = new Contact();
  24:  appContact1.FistName = item["FirstName"].ToString();
  25:  appContact1.LastName = item["LastName"].ToString();
  26:  appContact1.Company = item["Company"].ToString();
  27:  string msg;
  28:  msg = string.Format("Contact {0} {1} of {2} has been added !", appContact1.FistName,
  29:    appContact1.LastName, appContact1.Company);
  30:   
  31:   
  32:  //...écrivez plutot (C# 3.0)
  33:  var appContact2 = new {
  34:    FirstName = item["FirstName"].ToString(), LastName = item["LastName"].ToString(),
  35:    Company = item["Company"].ToString()
  36:  };
  37:  msg = string.Format("Contact {0} {1} of {2} has been added !", appContact2.FistName,
  38:    appContact2.LastName, appContact2.Company);

Les expressions Lambda

Les expressions Lambda sont des fonctions anonymes.

   1:  //au lieu d'écrire... (C# 2.0)
   2:  SPSecurity.RunWithElevatedPrivileges(delegate() {
   3:    cItem["Created"] = DateTime.Now;
   4:    cItem.SystemUpdate();
   5:  });
   6:   
   7:  //...écrivez plutot (C# 3.0)
   8:  SPSecurity.RunWithElevatedPrivileges(() => {
   9:    cItem["Created"] = DateTime.Now;
  10:    cItem.SystemUpdate();
  11:  });

L'opérateur Lambda '=>' se lit 'conduit à'

Les propriétés automatiques

Les propriétés automiques vont partie des apports les plus appréciables. Plus besoin d'implémenter les champs de stockage pour vos propriétés, le compilateur sais désormais les gérer automatiquement !

Précisez simplement dans votre code l'accessibilité de votre propriété (get et/ou set), et le compilateur se chage du reste. Ainsi nous pouvons réécrire la classe Contact précédemment définie comme ceci :

   1:  public class Contact2 {
   2:    public string FirstName { get; set; }
   3:    public string LastName { get; set; }
   4:    public string Company { get; set; }
   5:  }

3 lignes !

Vraiment appréciable.

Les méthodes partielles

Un des mécanismes que j'utilise le moins.

Vous pouvez donc désormais utiliser le mot clé partial sur vos méthodes pour séparer la déclaration de votre méthode de l'implémentation dans plusieurs fichiers de code.

Linq

Une véritable révolution !

Linq est un modèle de requêtage de données qui permet d'unifier l'accès aux données.

Que vous souhaitiez récupérer des données stockées dans vos objets métiers ou dans votre base de données ou un fichier texte, ou, etc…

Vous pouvez utiliser Linq de manière totalement transparente et homogène ; ce dernier fait abstraction de la source de données sous-jacente.

   1:  //au lieu d'écrire... (C# 2.0)
   2:  List<SPListItem> specialItems = new List<SPListItem>();
   3:  foreach (SPListItem item in list.Items) {
   4:    if (item["Title"].ToString().StartsWith("special_"))
   5:      specialItems.Add(item);
   6:  }
   7:              
   8:   
   9:  //...écrivez plutot (C# 3.0)
  10:  var specialItem = from SPListItem item in list.Items
  11:                    where item["Title"].ToString().StartsWith("special_")
  12:                    select item;

voila, vous êtes désormais paré à écrire du code C# 3.0 dans vos développements SharePoint !

[SP2007]Besoin d’aide sur l’administration de fermes volumineuses ? ce webcast est pour vous !

Si vous avez une multitude de sites à gérer et que vous êtes à la recherche d'une méthode claire, simple et efficace, alors je vous propose de visualiser ce webcast le mardi 2 Juin à 11h, heure de Paris, durant lequel vous verrez comment Fabrice Romelard [MVP SharePoint] s'y prend.

Ca pourrait être très instructif, alors profitez en !

[SP] Débugger des webparts et autres joyeusetés sous SharePoint.

On me pose souvent la question au sujet du débugage sous SharePoint :

« Comment débugguer mes webparts sous sharepoint ? »

Ben tout simple ! Il suffit de positionner un point d'arrêt dans le code, compiler le projet en mode debug puis copier le fichier .dll dans le bin de mon application web.

Ensuite, dans visual studio, dans le menu Outils, sélectionnez Options. Selectionnez ensuite Débogage > Général, puis décochez l'option « Activer uniquement mon code (Managé seulement) ».

Ca y'est, c'est fait !

Une fois ceci réalisé, retournez dans visual studio, dans le menu outils, sélectionner Attacher au processus, puis sélectionner le processus w3wp

Puis lancer IE, se connecter à une page contenant mon composant pour déclencher le code et l'intercepter grâce à votre point d'arrêt.

Généralement la question qui suit est :

« Oui mais comment je fais si je déploie ma dll dans le GAC ou si je veux débugger des composants comme les event receivers qui nécessite un passage obligé par le GAC ? »

En fait, c'est exactement la même chose, sauf qu'il faut signer l'assembly avant de la déployer dans le GAC.

Un exemple ci-dessous avec un event receiver.

Bon courage dans vos développements J

[Windows Forms]Implémentation de l’impression dans vos applications

Implémenter l'impression dans vos applications revient à configurer 4 objets ; ces objets sont :

  • L'objet PrintDocument
  • L'objet PrintDialog
  • L'objet PrintPreviewDialog
  • L'objet PageSetupDialog

Voyons à présent chacun de ces objets et comment les combiner pour obtenir une fonctionnalité d'impression.

Vous pouvez récupérer le projet accompagnant cet article ici.

L'objet PrintDocument.

L'objet PrintDocument représente le document à imprimer ; pour lancer l'impression du document, il suffit d'appeler la méthode Print de l'objet PrintDocument ; cette méthode permet de lancer l'impression de notre document sur l'imprimante par défaut.

void PrintButton_Click(object sender, EventArgs e) {

docToPrint.Print();

}

Cependant, avant d'imprimer le document, il faut définir ce que l'on va imprimer. Pour cela, nous allons définir le contenu à imprimer dans l'événement PrintPage de l'objet PrintDocument.

Par exemple, pour imprimer le texte « Implémentation de l'impression », il nous faut le spécifier dans l'objet graphic récupéré à partir de l'événement PrintPage, comme ceci :

void docToPrint_PrintPage(object sender, PrintPageEventArgs e) {

e.Graphics.DrawString(

"Implémentation de l'impression",

new Font("Arial", 10), Brushes.Black, new PointF());

}

Voici le code complet du formulaire PrintDocumentForm permettant de mettre en œuvre ce mécanisme :

public class PrintDocumentForm : Form {

 

#region Variables & Properties

 

PrintDocument docToPrint;

Button PrintButton;

Panel panel;

 

#endregion

 

#region Création de notre formulaire

 

public PrintDocumentForm() {

this.Load += new EventHandler(PrintDocumentForm_Load);

docToPrint = new PrintDocument();

docToPrint.PrintPage += new PrintPageEventHandler(docToPrint_PrintPage);

PrintButton = new Button();

PrintButton.Text = "Print";

PrintButton.Click += new EventHandler(PrintButton_Click);

panel = new Panel();

}

 

void PrintDocumentForm_Load(object sender, EventArgs e) {

this.Controls.Add(panel);

panel.Controls.Add(PrintButton);

}

 

#endregion

 

#region Gestion de l'impression

 

/// <summary>

/// La méthode Print() permet de déclencher

/// l'impression du document

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

void PrintButton_Click(object sender, EventArgs e) {

docToPrint.Print();

}

 

/// <summary>

/// L'événement PrintPage() permet de spécifier le

/// document à imprimer en travaillant avec l'objet

/// Graphics.

/// </summary>

/// <param name="sender"></param>

/// <param name="e"></param>

void docToPrint_PrintPage(object sender, PrintPageEventArgs e) {

e.Graphics.DrawString(

"Implémentation de l'impression",

new Font("Arial", 10), Brushes.Black, new PointF());

}

 

#endregion

 

}

Et voici le résultat en utilisant comme imprimante par défaut une imprimante XPS

Une des limites de notre méthode d'impression est le fait de ne pas pouvoir choisir notre boite de dialogue ; c'est l'objectif du composant PrintDialog

L'objet PrintDialog

Le composant Printdialog est une boite de dialogue modale donnant la possibilité à nos utilisateurs de sélectionner une imprimante.

Pour utiliser ce composant, il nous suffit d'appeler la méthode ShowDialog et de tester la valeur de retour DialogResult correspondant à l'action de l'utilisateur. Si l'utilisateur a cliqué sur OK, nous lançons l'impression, sinon nous ne faisons rien.

Pour cela, modifions le code la méthode PrintButton_Click afin de refléter tout ceci.

void PrintButton_Click(object sender, EventArgs e) {

if (dialogToShow.ShowDialog() == DialogResult.OK)

docToPrint.Print();

}

(Regardez le listing complet du formulaire PrintDialogForm pour l'exemple complet).

Et voici le résultat.

Maintenant que nous sommes capables de sélectionner l'imprimante à utiliser, voyons comment prévisualiser notre document avec de l'imprimer.

L'objet PrintPreview

L'objet PrintPreview est une boite de dialogue donnant la possibilité de prévisualiser un document tel qu'il sera à l'impression

Pour l'utiliser l'objet PrintPreview, affectez sa propriété Document au PrintDocument à prévisualiser, puis appelez la méthode ShowDialog()

void PreviewButton_Click(object sender, EventArgs e) {

previewToShow.Document = docToPrint;

previewToShow.ShowDialog();

}

(Regardez le listing complet de l'exemple PrintPreviewForm pour l'exemple complet)

Et voici le résultat

L'avantage de prévisualiser avant d'imprimer est que l'on se rend compte d'incohérence avant de gaspiller du papier (pensons à la nature J).

Ici, nous remarquons par exemple que les marges ne sont pas correctes ; il serait donc souhaitable de donner à l'utilisateur la possibilité d'ajuster ce genre de propriété ; l'objet PageSetupDialog en est responsable.

L'objet PageSetupDialog

Cet objet permet à l'utilisateur de modifier les paramètres d'impression liés au document.

Voici un exemple de code (le code complet se trouve dans le listing PageSetupForm) :

void SetupButton_Click(object sender, EventArgs e) {

docSetup.Document = docToPrint;

docSetup.PageSettings = new PageSettings();

docSetup.PrinterSettings = new PrinterSettings();

if (docSetup.ShowDialog() == DialogResult.OK) {

docToPrint.PrinterSettings = docSetup.PrinterSettings;

}

}

Et le résultat

Taches supplémentaires :

Vous pouvez déclencher des événements avant ou après l'impression en implémentant les événements BeginPrint et EndPrint de l'objet PrintDocument.

Par exemple, le code suivant affiche une MessageBox en fin d'impression pour notifier l'utilisateur :

void docToPrint_EndPrint(object sender, PrintEventArgs e) {

MessageBox.Show("Impression terminée !");

}

Vous pouvez également gérer l'impression sur plusieurs pages, en jouant avec les méthodes MeasureString(), DrawString(), SubString() et la propriété HasMorePage comme illustré ci-dessous (formulaire CompleteForm).

void PrintButton_Click(object sender, EventArgs e) {

if (dialogToShow.ShowDialog() == DialogResult.OK) {

//On initialise ici le texte à imprimer car

//la Methode Print_Page est appelée autant de

//fois que nécessaire jusque ca que la propriété

//PrintPageEventArgs.e.HasPage soit égale à false

txtToPrint = richTextBox.Text;

docToPrint.Print();

}

}

 

void docToPrint_PrintPage(object sender, PrintPageEventArgs e) {

var numberOfCharacters = 0;

var numberOfLines = 0;

//Police à utiliser

var fontToUse = richTextBox.Font;

//Rectangle définissant la zone d'impression

var rectangleToUse = e.MarginBounds;

var sizeToUse = rectangleToUse.Size;

 

//ne pas mettre ceci ici txtToPrint = richTextBox.Text;

//car on rentre dans une boucle infinie si le document

//contient plusieurs pages.

 

//On récupère le nombre de ligne grâce à la méthode

//MeasureString

e.Graphics.MeasureString(txtToPrint, fontToUse, sizeToUse,

StringFormat.GenericTypographic, out numberOfCharacters, out numberOfLines);

 

//On imprime une page...

e.Graphics.DrawString(txtToPrint, fontToUse, Brushes.Black, rectangleToUse,

StringFormat.GenericTypographic);

 

//...puis on supprime ce qui vient d'être imprimé.

txtToPrint = txtToPrint.Substring(numberOfCharacters);

 

// On vérifie si il reste du contenu à imprimer ; si oui

//la méthode Print_Page sera relancée.

e.HasMorePages = (txtToPrint.Length > 0);

}

Ca y'est, dorénavant vous avez toutes les bases nécessaires pour implémenter l'impression dans vos applications.

[Windows Forms] Gérer un seul événement pour plusieurs contrôles

Lorsque de diverses formations que j'ai l'occasion d'animer, chaque fois que je traite le sujet des event handlers et le fait que ces handlers peuvent être connectés à plusieurs évènements, une question revient assez souvent : « Comment récupérer la valeur du contrôle qui a déclenché l'évènement ».

Ce billet apporte donc la réponse à cette question, en travaillant sur un projet de type Windows application.

Commençons par créer un projet de type Windows forms et ajoutons-y 2 contrôles, un combo et un button.

Afin d'intercepter l'évènement par défaut du combo à savoir le « SelectedIndexChanged, rajoutons quelques items à notre combo.

A présent, nous allons rajouter les événements par défaut de nos contrôles ; pour cela, double-cliquons sur notre combo et notre button, puis rajoutons une MessageBox nous informant quels sont les évènements interceptés.

   1:  private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
   2:    MessageBox.Show("Evenement Combo");
   3:  }
   4:   
   5:  private void button1_Click(object sender, EventArgs e) {
   6:    MessageBox.Show("Evenement Button");
   7:  }

Rajoutons un 3ème handler qui intercepte le KeyPress.

Pour cela, commençons déjà par mettre la propriété KeyPreview à true au niveau de notre formulaire Form1, afin d'activer l'enregistrement des événements du clavier

Puis dans les évènements au niveau du formulaire, double-cliquons sur « KeyPress ».

Cette action crée un gestionnaire pour les évènements clavier « KeyPress » ; de même affichons l'évènement dans un MessageBox.

   1:  private void Form1_KeyPress(object sender, KeyPressEventArgs e)  {
   2:    MessageBox.Show("Evenement Clavier");
   3:  }

Jusqu'ici, pas de problème ; voici les différentes boites de dialogue que j'obtiens en cliquant respectivement sur mon combo, mon bouton et la touche espace :

 

Maintenant, implémentons un même gestionnaire pour tous ces événements ; dans votre code, rajoutez la méthode suivante :

   1:  private void TheSameEvent(object sender, EventArgs e) {
   2:    Type controlType = sender.GetType();
   3:    string control = controlType.ToString();
   4:    string eventType = e.GetType().ToString();
   5:              
   6:    MessageBox.Show(
   7:      string.Format("Evènement {0} déclenché par {1}", 
   8:      eventType, control));
   9:  }

Cette méthode possède la même signature que les méthodes précédentes, et nous utilisons ici les objets passés en paramètre pour récupérer notamment l'objet ayant déclenché l'évènement (le sender). Nous récupérons également le type du contrôle dans la variable controlType.

Pour le KeyPress, rajoutons ceci en plus :

   1:  private void TheSameEvent(object sender, KeyPressEventArgs e) {
   2:    TheSameEvent(sender, (EventArgs)e);
   3:  }

Il ne nous reste plus qu'à modifier dans la fenêtre des évènements le nom de notre méthode et d'y mentionner « TheSameEvent ».

Maintenant, si nous cliquons à nouveau respectivement sur mon combo, mon bouton et la touche espace, voici ce que j'obtiens :

 

Pour finir, si nous souhaitons par exemple travailler au niveau de notre button dans notre méthode commune, voici comment il faut procéder :

   1:  private void TheSameEvent(object sender, EventArgs e) {
   2:    Type controlType = sender.GetType();
   3:    string control = controlType.ToString();
   4:    string eventType = e.GetType().ToString();
   5:              
   6:    MessageBox.Show(
   7:      string.Format("Evènement {0} déclenché par {1}", 
   8:      eventType, control));
   9:              
  10:    switch (controlType.ToString().ToLower()) {
  11:      case "system.windows.forms.button": 
  12:        ((Button)sender).Text = "Clicked"; break;
  13:      case "system.windows.forms.combobox":
  14:        ((ComboBox)sender).Items.Add("a new item"); break;
  15:      case "coforcert.windowsforms.events.form1":
  16:        Label label = new Label();
  17:        label.Text = "un label à rajouter au moment du runtime";
  18:        ((Form)sender).Controls.Add(label); break;
  19:      default: break;
  20:  }

Et voici le résultat après avoir implémenté tous les évènements.

Vous pouvez également récupérer le projet final ici.

[MSEvent]Microsoft Virtual Techdays 2009, Inscrivez vous !

Vous souhaitez assister gratuitement et à plus de 110 sessions vous présentant divers produits MS et ceux sans bouger de chez vous ?

Les Microsoft Virtual Techdays sont pour vous.

Les Microsoft Virtual Techdays, c'est 24h de live show sur des présentations se déroulant partout sur le globle, et ce le 1er Avril 2009.

Alors n'attend plus, inscris toi ici > http://www.msfttechdays.com/public/home.aspx

[SP]Ajouter des éléments à une liste SP à partir d’une base de données SQL grâce aux déclencheurs CLR et aux web services

Qui a dit que l'intégration du CLR dans le moteur de SGDB SQL Server ne servait à rien ?

Dans cet article, je vais vous montrer comment utiliser cette fonctionnalité pour ajouter des éléments à une liste SharePoint depuis une base de données SQL Server.

Création de notre liste exemple.

Nous allons dans un 1er temps créer notre liste exemple.

Pour cela, nous allons simplement partir d'une liste personnalisée, l'objectif étant de travailler sur un exemple simple, clair et concis.

Nommons notre liste ExempleMaj, et rajoutons lui une colonne de type texte nommée DB_ID

Création de notre base de données exemple.

A présent, créons la base de données que nous allons utiliser pour publier les données dans SharePoint

Pour cela, exécutez le script suivant :

   1:  CREATE DATABASE ExempleMaj_DB
   2:  GO
   3:   
   4:  USE [ExempleMaj_DB]
   5:  GO
   6:   
   7:  CREATE TABLE [dbo].[ExempleMaj](
   8:      [ID] [uniqueidentifier] NOT NULL,
   9:      [Title] [nvarchar](50) NULL,
  10:   CONSTRAINT [PK_ExempleMaj] PRIMARY KEY CLUSTERED 
  11:  (
  12:      [ID] ASC
  13:  )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  14:  ) ON [PRIMARY]
  15:   
  16:  GO
  17:   
  18:  ALTER TABLE [dbo].[ExempleMaj] ADD  CONSTRAINT [DF_ExempleMaj_ID]  DEFAULT (newid()) FOR [ID]
  19:  GO

Ce script crée une base de données nommée ExempleMaj_DB, qui contient une table ExempleMaj, qui à son tour contient 2 colonnes ; une colonne ID et une colonne Title.

Création de nos déclencheurs

C'est à ce moment que nous allons créer le code qui permettra de mettre à jour notre liste SharePoint à partir de notre base de données.

Pour cela, créons un projet de type SQL Server.

Puis rajoutons la directive using suivante :

   1:  using Microsoft.SqlServer.Server;

Ci-dessous, voici le code de notre trigger.

L'attribut Name spécifie le nom de notre trigger tel qu'il sera connu par SQL Server ; l'attribut Target précise la base de données cible et enfin, l'attribut Event précise le type d'événement qui sera capturé.

La 1ère partie de ce code va interroger la table spéciale « Inserted » afin de récupérer les enregistrements mis à jour

La 2ème partie du code fait appel au web service Lists de SharePoint pour rajouter la donnée insérée dans Sharepoint (il faut pour cela rajouter une web référence vers notre service web)

   1:  [SqlTrigger(Name = "Trig_Insert", Target = "ExempleMaj", Event = "FOR INSERT")]
   2:  public static void InsertTrigger() {
   3:    SqlTriggerContext context = SqlContext.TriggerContext;
   4:    Guid id = Guid.Empty;
   5:    string title = null;
   6:    if (context.TriggerAction == TriggerAction.Insert) {
   7:      string connectionString = "context connection=true";
   8:      DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
   9:      using (IDbConnection connection = factory.CreateConnection()) {
  10:        connection.ConnectionString = connectionString;
  11:        using (IDbCommand command = connection.CreateCommand()) {
  12:          command.CommandText = "select * from inserted";
  13:          command.CommandType = CommandType.Text;
  14:          connection.Open();
  15:          using (IDataReader reader = command.ExecuteReader()) {
  16:            while (reader.Read()) {
  17:              id = reader.GetGuid(0);
  18:              title = reader.GetString(1);
  19:            }
  20:          }
  21:        }
  22:      }
  23:    }
  24:    if (id!=Guid.Empty) {
  25:      Lists ws = new Lists();
  26:      ws.UseDefaultCredentials = true;
  27:      ws.Url = "http://ws2008dc01/dev/_vti_bin/lists.asmx";
  28:      string batch = string.Format(@"<Batch OnError='Continue'><Method ID='0' Cmd='New'>
  29:          <Field Name='DB_ID'>{0}</Field>
  30:        <Field Name='Title'>{1}</Field>
  31:        </Method></Batch>", id, title);
  32:      XmlDocument doc = new System.Xml.XmlDocument();
  33:      doc.LoadXml(batch);
  34:      XmlNode node = doc.DocumentElement;
  35:      try {
  36:        ws.UpdateListItems(m_ListName, node);
  37:      }
  38:      catch { }
  39:    }
  40:  }

A présent compilons notre projet.

Maintenant, si nous essayons d'importer notre assembly, tout le processus d'import se déroulement correctement, cependant, au moment de l'insertion d'une ligne, notre déclencheur va générer une exception telle que celle la.

En gros, étant donné que nous appelons un web service, SQL Server a besoin d'informations de sérialisation sur notre dll.

Il nous faut donc générer ces informations.

Puis tapez « sgen /a :SPTriggers.dll » afin de générer l'assembly SPTriggers.XmlSerializers.dll.

Ca y'est, maintenant tout est ok.

Import de notre assembly dans SQL Server

A ce stade, il ne nous reste plus qu'à importer notre assembly et créer notre trigger dans SQL Server comme suit :

   1:  -- Activation du CLR
   2:  sp_configure 'clr enabled', 1
   3:  go
   4:   
   5:  reconfigure
   6:  go
   7:   
   8:  -- Utilisation de notre base de données
   9:  use ExempleMaj_DB
  10:  go
  11:   
  12:  -- Modification du niveau de confiance de la base
  13:  ALTER DATABASE ExempleMaj_DB SET TRUSTWORTHY ON
  14:  go
  15:   
  16:  -- Import de l'assembly
  17:  drop trigger Trig_Insert
  18:  go
  19:  drop assembly TriggersAssembly
  20:  go
  21:   
  22:  CREATE ASSEMBLY TriggersAssembly
  23:  FROM
  24:  'C:\Users\Administrator\Documents\Visual Studio 2008\Projects\Coforcert.SharePoint\SPTriggers\bin\Debug\SPTriggers.dll'
  25:  WITH PERMISSION_SET = UNSAFE
  26:  GO
  27:   
  28:  -- Création de nos triggers
  29:  create trigger Trig_Insert
  30:  on dbo.ExempleMaj
  31:  for insert
  32:  as
  33:  external name TriggersAssembly.[Coforcert.SharePoint.Triggers.SPTriggers].InsertTrigger
  34:  go
  35:   
  36:  -- Obligatoire ici, car nous appelons un web service dans notre trigger.
  37:  CREATE ASSEMBLY TriggersAssemblyXml
  38:  FROM
  39:  'C:\Users\Administrator\Documents\Visual Studio 2008\Projects\Coforcert.SharePoint\SPTriggers\bin\Debug\SPTriggers.xmlserializers.dll'
  40:  WITH PERMISSION_SET = UNSAFE
  41:  Go

Maintenant, si nous saisissons des données dans notre table, ces dernières sont automatiquement rajoutées dans notre liste SharePoint.

Voila, c'est fait !

Attention :

Cet article a vocation uniquement de démonstrateur. En aucun cas, il ne doit être implémenté tel quel sur un serveur de production, car cela pourrait altérer considérablement les performances, si plusieurs utilisateurs insèrent régulièrement des données dans votre base de données. Dans ce cas, il faudrait adapter le code de cet article afin de passer par des jobs SharePoint à la place des déclencheurs.

Action Communautaire.

Lors d'une des dernières formations que j'ai eu l'occasion d'animer sur SQL Server, j'ai un le plaisir de côtoyer, parmi les participants, une personne vraiment formidable, qui met son temps libre à contribution d'aides humanitaires, et notamment de Solhimal.

Solhimal est une association visant à apporter une aide aux populations vivant en Inde et au Tibet.

En parrainant un jeune, vous lui offrez la possibilité de se faire soigner, nourrir, loger ou encore éduquer, et d'une manière plus simple, vous contribuez tout simplement au bonheur d'autrui.

En 2009, Microsoft a souhaité me récompenser pour mes contributions communautaires en me nommant MVP pour cette année, aujourd'hui c'est à mon tour de remercier au nom de tous ceux qui s'investissent, et qui s'activent aujourd'hui à aider les populations défavoriser afin que ces dernières puissent accéder à ce que nous appelons communément le « minimum vital ».

1 - 10 Suivant

 ‭(Masqué)‬ Liens d'administration

<