Thursday, May 24, 2012

SharePoint 2010 LookUp Error

Hola de nuevo. Llega el momento de compartir la solución a un problema que viene desde la versión 2007 de SharePoint, y ahora la veo heredada en SP 2010. Es un problema que afecta principalmente en términos de estética, y algo que Microsoft debería solucionar cuanto antes.
Afortunadamente para la Plataforma, muchos desarrolladores han implementado soluciones al problema, así que los clientes no se asusten de ver esto:
Error DropDownList
Como se aprecia en la figura anterior, es evidente el problema, al desplegar los ítems del Combo, la información se despliega más abajo. En el caso de SharePoint 2010, donde muchos formularios se despliegan como Modal Popups, eso es aun, un problema mayor.
Hay explicaciones del por qué sucede lo anterior, pero la verdad es que debería corregirse pronto, y esencialmente tiene que ver con la cantidad de ítems presentados. De la imagen anterior lo que se tiene es una Lista de Noticias y una de Comentarios, relacionadas entre sí. De la imagen se aprecia que se está creando un comentario para una noticia seleccionada, pero el número de Noticias que han sido publicadas superan las 20. Es correcto, 20 es el valor a partir del cual este problema comienza a ocurrir, y en general es a causa de que internamente, SharePoint renderiza el control de manera diferente a como lo hace cuando tiene menos de 20 ítems en el campo de tipo LookUp de la lista comentarios, que se comporta en este caso como la lista hija. Para mayor información del problema visitar http://social.msdn.microsoft.com/Forums/en-US/sharepoint2010general/thread/64796605-bcbb-4a87-9d8d-9d609579577f/
Es bueno leer tales discusiones para tener una mejor aproximación del problema, y tener un mejor punto de partida para elegir la solución que más nos convenga.
Así que a continuación dejo una de esas soluciones, donde se propone hacer uso de JavaScript para corregir el problema:
  • Habiendo detectado el problema, se deberá desproteger y editar en modo avanzado el formulario ASPX donde se presenta el error utilizando SP Designer 2010. Para este caso es el formulario NewForm y EditForm.aspx. El primero permite crear un nuevo comentario, y el segundo Editar uno existente.
  • Suponiendo que vamos a usar NewForm.aspx, luego de la etiqueta de cierre </WebPartPages:ListFormWebPart> de la WebPart ListFormWebPart, se debe adicionar una WebPart de Editor de Contenido Web.
Combo2
  • Guarde la página NewForm.aspx y ábrala en su navegador Web, y ponga en modo de Edición la página.
  • En este momento puede agregar contenido a la WebPart de Editor de Contenido. En ese momento agregue el siguiente código JavaScript.
<script type="text/javascript">
$(document).ready(function () {
var columnName = "Noticia";
OverrideDropDownList(columnName);

function OverrideDropDownList(columnName) {       
  var lookupDDL = new DropDownList(columnName);
   if (lookupDDL.Type == "C") {                          
    lookupDDL.Obj.css('display', 'none');                
    lookupDDL.Obj.next("img").css('display', 'none');                
    // Construct the simple drop down field with change trigger                
    var tempDDLName = "tempDDLName_" + columnName;                
    if (lookupDDL.Obj.parent().find("select[ID='" + tempDDLName + "']").length == 0) {                        
     lookupDDL.Obj.parent().append("<select name='" + tempDDLName + "' id='" + tempDDLName + "' title='" + tempDDLName + "'></select>");
     lookupDDL.Obj.parent().find("select[ID='" + tempDDLName + "']").bind("change", function () {                                
     updateOriginalField(columnName, tempDDLName);                       
     });                
     }                
     var splittedChoices = lookupDDL.Obj.attr('choices').split("|");              
     var hiddenVal = $('input[name=' + lookupDDL.Obj.attr("optHid") + ']').val()                
     if (hiddenVal == "0") {                        
      hiddenVal = lookupDDL.Obj.attr("value")                
     }                 
     lookupDDL = new DropDownList(tempDDLName);               
     for (var i = 0; i < splittedChoices.length; i++) {                        
      var optionVal = splittedChoices[i];                        
      i++;                        
      var optionId = splittedChoices[i];                        
      var selected = (optionId == hiddenVal) ? " selected='selected'" : "";                        
      lookupDDL.Obj.append("<option" + selected + " value='" + optionId + "'>" + optionVal + "</option>");               
      }        
     }
    }
    function updateOriginalField(child, temp) {        
     var childSelect = new DropDownList(child);        
     var tempSelect = new DropDownList(temp);        
     childSelect.Obj.attr("value", tempSelect.Obj.find("option:selected").val());         
     var hiddenId = childSelect.Obj.attr("optHid");        
     $('input[name=' + hiddenId + ']').val(tempSelect.Obj.find("option:selected").val());
    }
    function DropDownList(colName) {       
     if ((this.Obj = $("select[Title='" + colName + "']")).html() != null) {        
      this.Type = "S";        
     } else if ((this.Obj = $("input[Title='" + colName + "']")).html() != null) {        
      this.Type = "C";       
     } else if ((this.Obj = $("select[ID$='SelectCandidate'][Title^='" + colName + " ']")).html() != null) {        
      this.Type = "M";        
     } else if ((this.Obj = $("select[ID$='SelectCandidate'][Title$=': " + colName + "']")).html() != null) {        
      this.Type = "M"; } else         this.Type = null; } }); </script>
La línea var columnName = "Noticia"; debe adecuarla según el nombre de su campo. En este caso se llama Noticia el campo LookUp que relaciona la lista de comentarios con las noticias.
  • Es momento de terminar la edición de la página y probar el formulario NewForm.aspx para verificar que los ítems se despliegan de manera correcta.
Combo3
Espero sea de utilidad la anterior solución, la cual ha sido probada y validada para solucionar el problema en mención.



Wednesday, May 02, 2012

Control de Campo Personalizado en SharePoint 2010

Hola de nuevo. Cuantas veces hemos pensado en que una de las dolencias de SharePoint siempre ha sido no activar el control picker, que permite desplegar una ventana que fácilmente permita seleccionar elementos dados de alta en el sitio, que se encuentran por ejemplo en diferentes bibliotecas de documentos, como pueden ser: imágenes, videos, archivos en general, y que se obtenga la URL a dichos elementos, y esta quede guardada en una columna de una lista o una biblioteca?

La respuesta a este interrogante se conoce como los controles personalizados en SharePoint. Que es un mecanismo que permite que se puedan agregar tipos de campo especializados, que pueden ser reutilizados como cualquier tipo de columna, en listas o bibliotecas.

Esta entrada está dedicada a esa opción que SharePoint ofrece a través de programación .NET. Pongamos manos a la obra, y veamos cómo se puede implementar algo como  una columna de tipo picker que nos ayude a mejorar la experiencia de usuario. La siguiente imagen muestra dicho campo en funcionamiento:
Custom Control 1

En la imagen anterior se apreciaran claramente 2 campos que utilizan el control que desarrollaremos en esta entrada: Thumbnail y Url Video. La idea es poder seleccionar una imagen o un video y que en el campo respectivo quede asociada la URL a dicho recurso.
En general las listas en SharePoint hacen uso de conceptos generales que son requeridos para su funcionamiento, y que a su vez componen lo que se conoce como controles de campo personalizados. Entre estos conceptos se encuentran los que se conocen como campos (Fields), columnas de sitio y tipos de campos. Cada uno de esos campos o columnas de sitio, tienen o se constituyen por los tipos de campos: Texto, Enteros, Decimal, Fecha, LookUp, entre otros. Un tipo de campo personalizado, es lo que permite extender la plataforma SharePoint más allá de lo que ofrece, permitiendo así, generar soluciones ajustadas a los requerimientos de negocio. Un ejemplo podría ser un tipo de campo personalizado que dispare validaciones especiales acorde a la entrada de datos del usuario, que difícilmente podrá ser resuelto con facilidad con las funcionalidades por defecto de los tipos ya comentados.
Una de las cosas faltantes en las herramientas de desarrollo para SharePoint ofrecidas en VS. NET 2010 es una plantilla para crear tipos de campo personalizados, así que básicamente los pasos para iniciar una solución de este tipo es la siguiente:
  1. Crea un proyecto de SharePoint nuevo basado en la plantilla de Proyecto de SharePoint vacío.
  2. Cuando se haya creado tal proyecto adicionar una clase por cada tipo de campo personalizado que se piense crear.
A continuación se presenta la definición de la clase AssetUrlSelectorField que hereda de un tipo de campo base SPFieldText, que hace parte del desarrollo del control que se ha mostrado anteriormente:
class AssetUrlSelectorField: SPFieldText
    {
        // Methods
        public AssetUrlSelectorField(SPFieldCollection fields,string fieldName) : base(fields, fieldName)
        {}
        public AssetUrlSelectorField(SPFieldCollection fields,
        string typeName, string displayName) : base(fields, typeName, displayName)
        {}
        // Properties
        public override BaseFieldControl FieldRenderingControl
        {
            get
            {
                BaseFieldControl control = new AssetUrlSelectorFieldControl();
                control.FieldName = base.InternalName;
                return control;
            }
        }
    }

La clase AssetUrlSelectorField define el tipo de campo personalizado que vamos a utilizar en el desarrollo del control. Es muy importante y obligatorio implementar los dos constructores públicos, que son requeridos por SharePoint Foundation. Finalmente para este caso específico se ha sobrescrito una propiedad que esencialmente se encarga de retornar el control que definiremos en otra clase.
Ahora bien, hasta el momento hemos podido ver la definición base de nuestro campo personalizado. Pero adicionalmente podemos mejorar la experiencia de usuario con nuestro control, implementando lo que se conoce como un control de campo personalizado, que provee al usuario con una experiencia de edición personalizada. La definición e implementación de esta nueva clase se muestra a continuación:

class AssetUrlSelectorFieldControl : BaseFieldControl
    {
        protected AssetUrlSelector urlSelector;
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            // Set the value if this is a postback.
            if (this.Page.IsPostBack)
            {
                try
                {
                    this.ListItemFieldValue = urlSelector.AssetUrl;
                }
                catch (Exception ex)
                {
                    EventLog log = new EventLog();
                    if (!(log.Source == "Mi Log"))
                        log.Source = "Mi Log";
                    log.WriteEntry("Error en el Método OnLoad: " + ex.Message + "- InnerException: " + ex.InnerException + "- Source: " + ex.Source + "- StackTrace: " + ex.StackTrace,
                      EventLogEntryType.Error, 1);
                    throw;
                }
            }
        }
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            // Add the asset picker when in edit mode.
            try
            {
                urlSelector = new AssetUrlSelector();
                this.Controls.Add(urlSelector);
            }
            catch (Exception ex)
            {
                EventLog log = new EventLog();
                if (!(log.Source == "Mi Log"))
                    log.Source = "Mi Log";
                log.WriteEntry("Error en el Método CreateChildControls: " + ex.Message + "- InnerException: " + ex.InnerException + "- Source: " + ex.Source + "- StackTrace: " + ex.StackTrace,
                  EventLogEntryType.Error, 1);
                throw;
            }
        }
        public override object Value
        {
            get
            {
                this.EnsureChildControls();
                return urlSelector.AssetUrl;
            }
            set
            {
                this.EnsureChildControls();
                urlSelector.AssetUrl = (string)this.ItemFieldValue;
            }
        }
    }

La clase anterior es la que se ha invocado inicialmente en la clase AssetUrlSelectorField, en la propiedad sobrescrita FieldRenderingControl. Esta clase aprovecha la clase AssetUrlSelector  la cual es la que provee la funcionalidad de tipo picker usada en SharePoint por defecto. Para mayor información de dicha clase se puede consultar su documentación en MSDN http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.publishing.webcontrols.asseturlselector.aspx

Para evitar confusiones, los namespaces utilizados en las clases mostradas son:

using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Diagnostics;

Con las clases definidas, muy fáciles de entender por cualquier desarrollador a continuación se requiere de la creación y definición de un archivo XML que al momento de hacer el despliegue de la solución en el servidor de SharePoint permite identificar el control que podrá ser utilizado dentro del sitio que se requiera o esté disponible la característica. SharePoint 2010 mantiene estos archivos XML en la ruta TEMPLATE/XML, en la cual muchos de sus tipos de campo están definidos. El nombrado de dicho archivo debe comenzar con el nombre fldtypes_, y de ahí se completa acorde a cada necesidad, en este caso por ejemplo: fldtypes_AssetUrlSelectorCustomField.xml. El contenido de este archivo XML que debemos agregar manualmente al folder mapeado XML, se presenta a continuación:

<?xml version="1.0" encoding="utf-8"?>
<FieldTypes>
  <FieldType>
    <Field Name="TypeName">AssetUrlSelectorField</Field>
    <Field Name="ParentType">Text</Field>
    <Field Name="TypeDisplayName">Picker</Field>
    <Field Name="TypeShortDescription">Picker de Activos</Field>
    <Field Name="UserCreatable">TRUE</Field>
    <Field Name="ShowOnListCreate">TRUE</Field>
    <Field Name="ShowOnSurveyCreate">TRUE</Field>
    <Field Name="ShowOnDocumentLibraryCreate">TRUE</Field>
    <Field Name="ShowOnColumnTemplateCreate">TRUE</Field>
    <Field Name="FieldTypeClass">
      WebParts.AssetUrlSelectorCustomField.AssetUrlSelectorField,$SharePoint.Project.AssemblyFullName$
    </Field>
  </FieldType>
</FieldTypes>

La definición <Field Name="FieldTypeClass">
WebParts.AssetUrlSelectorCustomField.AssetUrlSelectorField,$SharePoint.Project.AssemblyFullName$
</Field> puede variar acorde a su implementación, por ejemplo el nombre del namespace, en este caso WebParts, que usted haya usado en su proyecto en Visual Studio .NET.

En general la solución debería verse así:
Custom Control 2
Debido a que se ha utilizado una carpeta mapeada (XML) a la ruta de SharePoint 2010 que se ha explicado mantiene los archivos XML, automáticamente VS.NET 2010 sabe donde desplegar el XML definido para esta solución.
Luego de hacer el despliegue con VS.NET 2010, se puede proceder navegar hasta una lista, crear una nueva columna y ahí deberá estar disponible el tipo de control personalizado, por ejemplo:
Custom Control 3

El título Picker de Activos es el que se definió en el valor de la propiedad TypeShortDescription.

En conclusión, aunque no se cuenta con una experiencia de desarrollo 100% definida en VS.NET 2010, los pasos para desarrollar un control de campo personalizado y un campo personalizado base, no son complejos, y realmente son la puerta a implementaciones mucho más avanzadas que permitan con mayor facilidad cumplir requerimientos de nuestros clientes, que suelen salirse de los límites de la funcionalidad por defecto de la Plataforma.

Tuesday, March 27, 2012

Información Interesante y de Valor para el día a día

Rápidamente quiero compartir mis últimas lecturas en español sobre temas de SharePoint. Una que ya conocía, los amigos de CompartiMOSS, revista en Español, únicamente relacionada con SharePoint http://www.gavd.net/servers/compartimoss/compartimoss_main.aspx

Seguidamente de SolidQ, un artículo muy bueno, bastante detallado sobre la aplicación de servicios de Web Analytics http://www.solidq.com/sqj/es/Pages/2011_September_Issue/Practicas-recomendadas-de-SharePoint-Creacion-y-configuracion-de-aplicaciones-de-servicio-con-y-sin-PowerShell-parte-2.aspx

Feliz lectura.

Tuesday, March 20, 2012

No se puede representar el formulario. Esto puede deberse a un problema en la configuración del Servicio de estado de Microsoft SharePoint Server

Hola de nuevo. Intentando configurar un WorkFlow de Aprobación de SharePoint 2010, puede recibirse el siguiente mensaje:
No se puede representar el formulario. Esto puede deberse a un problema en la configuración del Servicio de estado de Microsoft SharePoint Server. Para obtener más información, póngase en contacto con el administrador del servidor.
Desafortunadamente el mensaje no dice mucho, pero su solución es realmente rápida.
1. Se necesita acceso a la Administración Central
2. Ejecutar el Asistente de Configuración que provee SP 2010:
  • Navegue a la Administración Central
  • Haga clic en la opción Asistente de Configuración o Configuration Wizards
  • Inicie el asistente
  • Deberá solicitarsele que active el State Service, podría ya estar seleccionada, así que clic en Siguiente.
  • Salte el paso de configurar un nuevo Sitio. Puede aparecer un Error. Si vuelve a correr el Wizard y vuelve a saltarse la creación del Sitio verá que el Wizard finaliza correctamente.
  • Haga clic en el botón Finish

Ahora es momento de intentar nuevamente crear el WorkFlow de Aprobación de SP 2010.

Felíz WF!!

Friday, March 16, 2012

La validación del esquema encontró errores que no son de tipo de datos

Hola de nuevo. Trabajando en la solución de un problema en un formulario de InfoPath 2007, encontré una buena solución en un blog. No es mí costumbre pero se debe re-postear, porque realmente funciona lo que ahi se utiliza. Hice uso de la solución y el problema se solucionó.

El error original es el siguiente:
Microsoft.Office.InfoPath.Server.SolutionLifetime.SchemaValidationException: La validación del esquema encontró errores que no son de tipo de datos. en Microsoft.Office.InfoPath.Server.SolutionLifetime.SchemaValidation.Validate(Document document, XPathNavigator subtreeToValidate, XmlOperation operation) en Microsoft.Office.InfoPath.Server.DocumentLifetime.XmlNotificationManager.NodeChangedHandler(Object sender, DomEventArgs e) en Microsoft.Office.InfoPath.Server.Xml.DomEvents.FireQueuedEvents() en Microsoft.Office.InfoPath.Server.Xml.DomEvents.AtomicEvent.System.IDisposable.Dispose() en Microsoft.Office.InfoPath.Server.Xml.XPath.InfoPathXPathNavigator.SetValue(String value) en Microsoft.Office.InfoPath.Server.Xml.XPath.XPathNavigatorHost.<>c__DisplayClass1.b__0() en Microsoft.Office.InfoPath.Server.DocumentLifetime.OMExceptionManager.ExecuteOMCallWithExceptions(OMCall d, ExceptionFilter exceptionFilter) en Microsoft.Office.InfoPath.Server.DocumentLifetime.OMSecurityContext.ExecuteOMCall(Solution solution, SecurityLevel methodSecurityLevel, ExceptionFilter exceptionFilter, OMCall d) en Requerimiento_De_Compra.FormCode.Partida_Changed(Object sender, XmlEventArgs e)

La propuesta está en esta dirección, gracias a Share Notes por compartirla:

Solución

Felíz solución.

Friday, March 02, 2012

Implementando una WebPart XSLT en SharePoint Server 2010


Una de las características importantes con las que cuenta SharePoint, que puede considerarse como uno de sus pilares, son las WebParts, o conocidas también como Elementos Web.

Estos elementos Web permiten esencialmente desplegar información, la cual típicamente se encuentra almacenada en listas o bibliotecas de SharePoint. Pueden haber otras fuentes de datos, pero no son interés de esta entrada por ahora. Vamos a mostrar cómo usar una WebPart que consume información de una lista o biblioteca, y por medio de XSLT, manipular dicha información para mejorar el aspecto gráfico de la WebPart que por defecto, despliega la información de manera tabular, y con una presentación poco familiar para usuarios finales. Suponiendo que tenemos una biblioteca de activos multimedia en SharePoint Server 2010, vamos agregarla a una página de contenido que llamaremos XSLT.aspx, como un Elemento Web para desplegar los videos que ahí se han dado de alta.

  • Lo primero que hacemos es crear la página de contenido como una página de publicación o de elementos web. Luego editarla en modo avanzado en SharePoint Designer 2010.
  • A continuación agregamos en la zona correspondiente, a través de las siguientes opciones una vista de datos vacía: Insertar – Vista de Datos – Vista de Datos Vacía.
  • En este momento se debe poder visualizar una opción que permite seleccionar la fuente de datos para la vista de datos, la cual en este caso, será la biblioteca de activos multimedia. SharePoint Designer despliega una ventana que permite seleccionar de entre las listas y bibliotecas disponibles. En este caso tenemos una biblioteca llamada Videos.

Paso1

En la imagen se pueden observar los siguientes elementos:

  • La vista de datos vacía que se acaba de insertar en código se interpreta como

    <WebPartPages:DataFormWebPart><DataFields>
    </DataFields>
    </WebPartPages:DataFormWebPart>

  • En la ventana de Selector de Orígenes de Datos se puede observar la biblioteca que se quiere usar como fuente, en este caso Videos.

  • En este momento se puede seleccionar la biblioteca Videos y hacer clic en el botón Aceptar. En ese instante se debe activar la ventana Detalles del origen de datos, la cual despliega todos los campos disponibles en la biblioteca de Videos. En este caso vamos a desplegar el Título y el Thumbnail (Vista previa de la dirección URL de la imagen) asociados a cada ítem dentro de la biblioteca. Seleccionando los 2 campos al tiempo se puede proceder a arrastrar y soltar dichos campos en la WebPart agregada previamente.

Fields

  • Hasta este momento contamos ya con una DataFormWebPart conectada a una biblioteca llamada Videos, como fuente de datos. Ahora si se explora el código generado en SharePoint Designer, se aprecia que se tiene el tag <XSL>, lo cual indica que esta WebPart viene ya lista para ser modificada a través de dichos elementos.

DataFormWP

Se puede observar que ya se han agregado los campos Título y el Thumbnail como un elemento IMAGE. Si se hace clic sobre los campos se puede apreciar que son totalmente modificables como elementos HTML.

<td class="ms-vb">
<xsl:value-of select="@Title"/>
</td>
<td class="ms-vb">
<img border="0" src="{@AlternateThumbnailUrl}"

alt="{@AlternateThumbnailUrl.desc}"/>
</td>

Es momento entonces de realizar los cambios necesarios para que los elementos queden mejor organizados. Para esto vamos a requerir de una hoja de estilos personalizada con las siguientes clases:

.comun { font-size: 12px; line-height: 16px; margin: 0 0 13px; }
.comun h3,
.comun h4 { font-family: "Myriad Pro", sans-serif; text-align: left; }
.comun h3 a,
.comun h4 a { color: #00a2ec; font-size: 11px; font-weight: normal; }
.comun h3 { color: #003b71; font-size: 21px; line-height: 23px; padding: 10px 13px 7px; }
.comun h4 { color: #003b71; font-size: 15px;}
.comun h3 small,
.comun h4 small { margin: 0 0 0 6px; }
.comun small { color: #232323; font-size: 11px; font-style: italic; }
.comun a { color: #00a2ec; text-decoration: none; }
.comun a:hover { text-decoration: underline; }
.comun a small { color: #00a2ec; }
.comun p { margin: 0 0 7px; }
.comun ul { color: #0053a1; list-style-type: disc; margin: 0 0 10px 15px; }
.comun li { margin: 0 0 7px; }
.lateral { background: #fff url("lateral.gif") repeat-x left bottom; border: 1px solid #cbe3ab; width: 255px; }
.lateral h4 { background: #cbe3ab; border: 1px solid #e6e6e6; padding: 7px 13px; }

.contenido { padding: 10px 13px; }

.fix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
* html .fix { zoom: 1; } /* IE6 */
*:first-child+html .fix { zoom: 1; } /* IE7 */

.ver_mas { border-top: 1px dotted #b3b4b4; margin: 5px 0 0; padding: 7px 0 0; text-align: right; }


#video {}
#video ul { list-style-type: none; margin: 0 0 10px; }
#video li { color: #4f4e4e; }
#video img { border: 1px #2664a9 solid; float: left; margin: 0 7px 0 0; width: 76px; }

En la ruta de Activos del sitio se puede crear una carpeta llamada CSS y ahí crear un archivo, por ejemplo, estilos.css, donde se debe copiar el código anterior.

Luego de eso en la página maestra del sitio, de puede hacer referencia a la hoja de estilos así:

<SharePoint:CssRegistration name="/SiteAssets/CSS/estilos.css" After="corev4.css" runat="server"/>

  • Teniendo una hoja de estilos lista, es momento de aplicar los estilos a la WebPart que ya habíamos agregado para desplegar los videos. Lo primero que se debe ubicar es la siguiente sección de código:

<xsl:template name="dvt_1.rowview">
<tr>
<xsl:if test="position() mod 2 = 1">
<xsl:attribute name="class">ms-alternating</xsl:attribute>
</xsl:if>
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<td class="ms-vb" width="1%" nowrap="nowrap">
<span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
</td>
</xsl:if>
<td class="ms-vb">
<xsl:value-of select="@Title"/>
</td>
<td class="ms-vb">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</td>
</tr>
</xsl:template>

Este código debe entonces quedar así:

<xsl:template name="dvt_1.rowview">
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<span ddwrt:amkeyfield="ID" ddwrt:amkeyvalue="ddwrt:EscapeDelims(string(@ID))" ddwrt:ammode="view"></span>
</xsl:if>

<li class="clearfix">
<a href="#">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</a>
<p><xsl:value-of select="@Title"/></p>
</li>
</xsl:template>

  • Seguido entonces se debe ubicar la siguiente sección en el código:

<xsl:otherwise>
<table border="0" width="100%" cellpadding="2" cellspacing="0">
<tr valign="top">
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<th class="ms-vh" width="1%" nowrap="nowrap"></th>
</xsl:if>
<th class="ms-vh" nowrap="nowrap">Título</th>
<th class="ms-vh" nowrap="nowrap">Vista previa de la dirección URL de la imagen</th>
</tr>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$LastRow - $FirstRow + 1" />
</xsl:call-template>
</table>
</xsl:otherwise>

Se debe reemplazar por lo siguiente:

<xsl:otherwise>
<div class="comun lateral" id="video">
<h4>Videos</h4>
<xsl:if test="$dvt_1_automode = '1'" ddwrt:cf_ignore="1">
<th class="ms-vh" width="1%" nowrap="nowrap"></th>
</xsl:if>

<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows"/>
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$LastRow - $FirstRow + 1" />
</xsl:call-template>



</div>
</xsl:otherwise>

  • Luego de los cambios anteriores, se debe tener lo siguiente en modo de diseño en SharePoint Designer.

estilos

Como se puede observar no se tiene una imagen asociada al video. Pero suponiendo que no se tiene una imagen cargada, se puede hacer lo siguiente para usar la imagen por defecto de los videos que SharePoint ofrece.

  • Seleccione en la página en modo de diseño en SharePoint Designer la imagen que debe verse así en código.

<a href="#">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</a>

Se debe cambiar por lo siguiente:

<xsl:if test="@AlternateThumbnailUrl != ''">
<a href="#">
<img border="0" src="{@AlternateThumbnailUrl}" alt="{@AlternateThumbnailUrl.desc}"/>
</a>
</xsl:if>
<xsl:if test="@AlternateThumbnailUrl = ''">
<a href="#">
<img border="0" src="/_layouts/images/VideoPreview.png" alt="Video"/>
</a>
</xsl:if>

Se aprecia que cargaría una imagen por defecto en caso de que no se haya cargado un thumbnail asociado al video. En ese caso una imagen perteneciente al conjunto de imágenes de SharePoint 2010, llamada VideoPreview.png. Debe estarse viendo así la WebPart en el diseñador:

videos

  • Finalmente se guardan los cambios, y se puede visualizar el preview de la página XSLT.aspx a través del navegador Web, con lo que se tiene lo siguiente:

Preview

Por ahora esta entrada ha cumplido su objetivo, la tarea siguiente sería que podamos hacer clic en la imagen del video, pero que tenga asociada la URL al video y este se despliegue, por ejemplo en la misma página o en una nueva página. Para tener una idea pueden remitirse a una entrada donde se habla de algo similar, para tener más ideas.

Feliz WebPart XSLT rediseñada.