SharePoint: Como añadir programáticamente una Web Part “Custom” a una página (I)!

Como siempre suelo decir, pocas cosas hay que no se puedan hacer de forma programática en SharePoint :P. En este artículo os voy a enseñar como podemos agregar de forma programática una Web Part personalizada en una página de SharePoint. En concreto, vamos a ver como agregar la Web Part en el control de texto enriquecido de una página Wiki de un sitio de grupo:

  • Como siempre, lo primero que tenemos que hacer es añadir en nuestro proyecto los espacios de nombres necesarios. Dentro de los mismos, los más importantes son Microsoft.SharePoint.WebPartPages y System.Web.UI.WebControls.WebParts.
   1: using Microsoft.SharePoint;

   2: using SPWebPartPages = Microsoft.SharePoint.WebPartPages;

   3: using System.Web.UI.WebControls.WebParts;

   4: using System.Xml;

   5: using System.IO;

   6: using System.Globalization;

  • A continuación, para añadir una Web Part “Custom” en el texto enriquecido de una página Wiki tenemos que hacer lo siguiente:
    • En primer lugar crear una instancia de SPLimitedWebPartManager utilizando el método GetLimitedWebPartManager() de SPWeb al que únicamente tenemos que pasarle la Url relativa de la página Wiki dónde queremos añadir la WebPart.
    • A continuación creamos una instancia de WebPart utilizando un método personalizado que nos permite obtener la definición de la Web Part a añadir (el método lo tenéis más abajo).
    • Lo siguiente que vamos a hacer es crear un identificador único de la Web Part que luego utilizaremos para añadir la Web Part dentro del texto enriquecido de la página Wiki.
    • Añadimos la Web Part mediante el método AddWebPart() de SPLimitedWebPartManager. Este método necesita tres parámetros:
      • La Web Part a añadir.
      • La zona de Web Parts que en este caso es “wpz” que es una zona de Web Parts oculta presente tanto en páginas de tipo Wiki como en páginas de publicación y que se utiliza para añadir Web Parts que posteriormente referenciaremos en contenido de tipo texto enriquecido.
      • El índice de la Web Part, es decir, el orden en el que va a aparecer.
    • Accedemos a la página Wiki creando una instancia de tipo SPFile a partir del método GetFile() de SPWeb.
    • Y ahora viene la parte complicada: tenemos que añadir al texto enriquecido de la página Wiki el código HTML necesario en el que por una parte estructuremos el contenido y por otra hagamos referencia a la Web Part añadida en la zona “wpz”. Fijarmos como en el HTML estoy definiendo como voy a pintar la información en el texto enriquecido y como estoy referenciando la Web Part personalizad mediante el ID asignado a la misma. Si queréis conocer en detalle el porque de esta forma de añadir Web Parts a texto enriquecido, os recomiendo dos artículos de obligada lectura:
    • A continuación lo que hacemos es inyectar el código HTML dentro del WikiField de la página Wiki y actualizamos dicha página.
    • Finalmente, liberamos el objeto SPLimitedWebPartManager y listo, tras ejecutar este código podréis comprobar que la Web Part se añade dónde queréis en el control de texto enriquecido de la página Wiki.
   1: static void AddCustomWebPart()

   2: {

   3:     using (SPSite spsSitio = new SPSite("http://demo2010a:200/"))

   4:     {

   5:         using (SPWeb spwWeb = spsSitio.OpenWeb())

   6:         {

   7:             //WebPart Manager

   8:             SPWebPartPages.SPLimitedWebPartManager spwpmWebPartManager =

   9:                 spwWeb.GetLimitedWebPartManager("SitePages/ZonasTest.aspx",

  10:                     PersonalizationScope.Shared);

  11:  

  12:             //WebPart a añadir

  13:             WebPart wpToAdd = CreateWebPart(spwWeb, "SPSLWPDemos_SPSilverlightListInspectorWP.webpart", spwpmWebPartManager);

  14:  

  15:             //Guid para la WebPart

  16:             Guid storageKey = Guid.NewGuid();

  17:             string wpId = String.Format("g_{0}", storageKey.ToString().Replace('-', '_'));

  18:             wpToAdd.ID = wpId;

  19:  

  20:             spwpmWebPartManager.AddWebPart(wpToAdd, "wpz", 0);                              

  21:  

  22:             //Añadiendo WebPart en el texto enriquecido

  23:             SPFile spfWiki = spwWeb.GetFile(spwWeb.Url + "/SitePages/ZonasTest.aspx");

  24:             

  25:             string html = 

  26:                 String.Format(CultureInfo.InvariantCulture,

  27:                     "<div class=\"ms-rtestate-read ms-rte-wpbox\" contentEditable=\"false\"><div class=\"ms-rtestate-read {0}\" id=\"div_{0}\"></div></div>", 

  28:                     storageKey.ToString("D"));

  29:             spfWiki.Item[SPBuiltInFieldId.WikiField] = html;

  30:             spfWiki.Item.UpdateOverwriteVersion();

  31:             spwpmWebPartManager.Dispose();

  32:         }

  33:     }

  34: }

  • En cuanto al método CreateWebPart(), cómo veis simplemente permite devolver la Web Part en cuestión a partir de localizarla en la galería de Web Parts:
    • Mediante una consulta CAML obtenemos la referencia a la Web Part en cuestión.
    • Mediante un objeto XmlReader, obtenemos la definición de la Web Part.
    • Finalmente, mediante el método ImportWebPart() de SPLimitedWebPartManager creamos la instancia de Web Part que necesitamos.
   1: static WebPart CreateWebPart(SPWeb web, string webPartName, 

   2:     SPWebPartPages.SPLimitedWebPartManager manager)

   3: {

   4:     SPQuery query = new SPQuery();

   5:     query.Query = 

   6:         "<Where><Eq><FieldRef Name='FileLeafRef'/><Value Type='File'>" +

   7:         webPartName +

   8:         "</Value></Eq></Where>";

   9:      

  10:     //Galería de WebParts

  11:     SPList webPartGallery = null;

  12:     if (web.ParentWeb==null)

  13:     {

  14:         webPartGallery = web.GetCatalog(

  15:            SPListTemplateType.WebPartCatalog);

  16:     }

  17:     else

  18:     {

  19:         webPartGallery = web.Site.RootWeb.GetCatalog(

  20:            SPListTemplateType.WebPartCatalog);

  21:     }

  22:  

  23:     //Extraemos la WebPart de interés

  24:     SPListItemCollection webParts = webPartGallery.GetItems(query);

  25:  

  26:     //Extraemos la definición de la WebPArt

  27:     XmlReader xmlReader = new XmlTextReader(webParts[0].File.OpenBinaryStream());

  28:     string errorMessage;

  29:  

  30:     //Instancia de la WebPart

  31:     WebPart webPart = manager.ImportWebPart(xmlReader, out errorMessage);

  32:     //WebPart webPart=null;

  33:  

  34:     return webPart;

  35: }