Imagen para determinar la altura de la cabecera
Other Blogs
Developer Cave
Our Blogs > Español > La Cueva de Desarrollo y Colaboración
Personalizar estilos en SharePoint 2010

Después de haber perdido algo de tiempo buscando como personalizar estilos en MOSS 2010, decidí ponerme a leer el coreV4.css y ver que es lo que tenemos por ahí.

Cuando digo “crear estilos personalizados” me refiero a esos estilos que vienen en el Ribbon cuando nos ponemos a editar texto en una página:

styles

 

En SharePoint 2007 se podían asociar al elemento RichHTLMField de esta forma: http://www.sharepointconfig.com/2007/05/customising-the-richhtmlfield-styles-menu/

 

Ahora en MOSS 2010 para mi gusto lo han mejorado porque estos estilos personalizados no van asociados a un elemento, sino a todos, es decir, que si definimos un estilo en nuestra página css estará disponible para todos los contenedores de texto de nuestro sitio.

Para definir un estilo basta con crearse una clase css con este formato:

.ms-rteStyle-Solid-Normal
{
    -ms-name:"Solid Normal";
    font-family: Arial, Segoe UI, Verdana, sans-serif;
    font-size: 10pt;
    color:black;   
    font-weight:normal;
}

.

- Es muy importante que el inicio de la clase sea “.ms-rteStyle” y luego lo demás ya como queramos, porque de lo contrario no aparecerá en la pestaña de estilos.

- También es importante la etiqueta –ms-name ya que ese nombre es el que se mostrará en el combo para elegirlo.

Si echamos un vistazo en el fichero corev4.css también vemos que existen otros estilos personalizados para componentes como DIVS, TABLAS, H1, H2, etc…:

DIV.ms-rteElement-Callout1
{
-ms-name:"Callout 1";
color:660000;
background-color:#fef4e4;
float:left;
width:25em;
padding:10px;
border:1px solid #FD9F08;
}

 

También podemos crearnos estilos personalizados para estos, pero recordad, siempre respetando el inicio de la clase “.ms-rteElement”, etc…

 

Y esto es todo!

 

Saludos!

Habilitar las Sesiones en SharePoint 2010

La historia surge al hacer una migración de WebParts de SharePoint 2007 a SharePoint 2010, uno de los WebParts llevaba una imagen “Captcha” que se genera automáticamente y guarda el número en Sesion.

A la hora de probar este WebPart con SharePoint 2010: “Runtime Error”, que por cierto MOSS 2010 no me ha dicho el error en cuestion lo he tenido que buscar en la 14 (lo que era la antigua 12), ya saben “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\LOGS”.

En fin, el error que me aparece es:

System.Web.HttpException: Session state can only be used when enableSessionState is set to true, either in a configuration file or in the Page directive. Please also make sure that System.Web.SessionStateModule or a custom session state module is included in the <configuration>\<system.web>\<httpModules> section in the application configuration.    at System.Web.UI.Page.get_Session()…   

Así que manos a la obra, me toca habilitar las sesiones en también en SharePoint 2010. Por lo que abrimos el web.config de la aplicación y seguimos estos pasos:

1. Poner el módulo bajo la sección: <configuration>\<system.web>\<httpModules>

<add name="Session" type="System.Web.SessionState.SessionStateModule"/>

2. Habilitar la sesión de estado en las páginas

<pages enableSessionState="true"  …>

3. Comentar la línea del web.config que elimina el objeto Session

<modules runAllManagedModulesForAllRequests="true">
      <remove name="AnonymousIdentification" />
      <remove name="FileAuthorization" />
      <remove name="Profile" />
      <remove name="WebDAVModule" />
      <!--<remove name="Session" />—>

 

Y ya está. Eso sí, no se con que finalidad habrán quitado el objeto sesión con SharePoint 2010. Así que si esto ha tenido efectos colaterales y algo va mal probando ya os comento.

Saludos!

Aviso de instalación para la beta pública de SharePoint 2010

(Traducido del original de Jie Li Technical Product Manager, SharePoint en http://blogs.msdn.com/opal/archive/2009/11/16/installation-notice-for-sharepoint-2010-public-beta.aspx)


[11/17 - actualizado con algunos detalles acerca de errores de instalación]

SharePoint 2010 se ha puesto a disposición para suscriptores MSDN y TechNet , y aquí hay algunos pasos que le gustaría seguir para obtener una instalación correcta. Pero tenga en cuenta: no se admite esta versión beta y no se puede actualizar la instalación a RTM cuando se publique. Esta versión beta sólo debe utilizarse para fines de evaluación.

Lea el artículo de requisito de hardware y software en TechNet.
Prepare un Windows Server 2008 x 64 con 8 GB de memoria. Windows Server 2008 R2 requiere una revisión que aún no se ha liberado para que la ejecución de aplicaciones de servicio por lo que no se recomienda utilizar R2 de momento. Ediciones de servidor Web no son compatibles.
Prepárese su AD. Crear una nueva cuenta para los servicios, por ejemplo <Dominio>\sp_admin.
1. Abra usuarios y equipos de Directorio Acrtivo
2. Haga clic derecho en dominio y seleccione "Delegar control"
3. Haga clic en siguiente
4. Haga clic en Agregar
5. Introduzca el nombre de objeto (es decir, <Dominio>\sp_admin)
6. Haga clic en Aceptar
7. Haga clic en siguiente
8. Seleccionar "Crear una tarea personalizada para delegar"
9. Haga clic en siguiente
10. Clic en “Verificación de Cambios de directorio de duplicación"
11. Haga clic en siguiente
12. Haga clic en finalizar

instalar revisión de WCF: una revisión que proporciona un método para apoyar la autenticación token sin cifrado de seguridad o transporte de mensajes en WCF está disponible para el .NET Framework 3.5 SP1 Windows Server 2008, (el vinculo para Windows Server 2008 R2 aún no está disponible). Tenga en cuenta la revisión de 2008 también se aplica a Vista, mientras que la revisión de 2008 R2 también se aplicará a Windows 7.
Si no dispone de esta revisión instalada, obtendrá el error "atributo No reconocido 'allowInsecureTransport'" en el registro de ULS. Y la mayoría de las aplicaciones de servicio no se ejecutarán correctamente.
Preparar entonro de SQL Server 2005/2008.

Si está en un servidor diferente, no olvide la configuración de Firewall de Windows. Para SQL Server en Windows 2008/R2, puede utilizar la siguiente secuencia de comandos (de KB968872)  para abrir todos los puertos necesarios. )(se debe ejecutar como proceso por lotes)

@echo =========  SQL Server Ports  ===================
@echo Enabling SQLServer default instance port 1433
netsh firewall set portopening TCP 1433 "SQLServer" 
@echo Enabling Dedicated Admin Connection port 1434
netsh firewall set portopening TCP 1434 "SQL Admin Connection" 
@echo Enabling conventional SQL Server Service Broker port 4022  
netsh firewall set portopening TCP 4022 "SQL Service Broker" 
@echo Enabling Transact-SQL Debugger/RPC port 135 
netsh firewall set portopening TCP 135 "SQL Debugger/RPC" 
@echo =========  Analysis Services Ports  ==============
@echo Enabling SSAS Default Instance port 2383
netsh firewall set portopening TCP 2383 "Analysis Services" 
@echo Enabling SQL Server Browser Service port 2382
netsh firewall set portopening TCP 2382 "SQL Browser" 
@echo =========  Misc Applications  ==============
@echo Enabling HTTP port 80 
netsh firewall set portopening TCP 80 "HTTP" 
@echo Enabling SSL port 443
netsh firewall set portopening TCP 443 "SSL" 
@echo Enabling port for SQL Server Browser Service's 'Browse' Button
netsh firewall set portopening UDP 1434 "SQL Browser" 
@echo Allowing multicast broadcast response on UDP (Browser Service Enumerations OK)
netsh firewall set multicastbroadcastresponse ENABLE 


Instalar los prerrequisitos siguientes

SQL Server 2005 SP3 y CU3

SQL Server 2008 SP1 y CU2

Ejecutar el instalador de Pre-Requisitos de la instalación de MOSS, para descargar e instalar componentes requeridos.

También puede descargarlos por separado.  Los vínculos también están disponibles en el artículo de su blog para descargarlos por separado.
Instale SharePoint utilizando la instalación de granja completa. No se recomienda instalación independiente  ya debe utilizarse sólo cuando desea instalar 2010 de SharePoint en Windows 7/vista con fines de desarrollo.
Siga el Asistente de configuración para todas las aplicaciones de servicio de instalación. Utilice el usuario que creó en el paso 3 como cuenta administrada de SharePoint para los servicios y aplicaciones web.
Lea sincronización de perfil de configuración para la sincronización de perfil de instalación. Dave Pae va a publicar pasos completos para la sincronización de perfiles  en el Blog del equipo de SharePoint.
Si utiliza SharePoint en DC, el siguiente comando de Windows PowerShell tendría que ejecutarse para habilitar el recinto de soluciones. (Sandboxed solutions)

$acl = Get-Acl HKLM:\System\CurrentControlSet\Control\ComputerName
$person = [System.Security.Principal.NTAccount]"Users"
$access = [System.Security.AccessControl.RegistryRights]::FullControl
$inheritance = [System.Security.AccessControl.InheritanceFlags]"ContainerInherit, ObjectInherit"
$propagation = [System.Security.AccessControl.PropagationFlags]::None
$type = [System.Security.AccessControl.AccessControlType]::Allow
$rule = New-Object System.Security.AccessControl.RegistryAccessRule($person, $access, $inheritance, $propagation, $type)
$acl.AddAccessRule($rule)
Set-Acl HKLM:\System\CurrentControlSet\Control\ComputerName $acl

Si usted va a utilizar aplicaciones de Web de Office en DC (ciertas aplicaciones Web de Office deben ser instaladas por separado, como un paquete de idioma o una actualización), los siguientes comandos necesitan ejecutarse para ello. Tenga en cuenta que en diferentes idiomas, nombres de servicio cliente podrían estar localizados. Puede utilizar Get-SPServiceApplications para averiguar los nombres y, a continuación, cambiar los nombres en la secuencia de comandos como sea necesario.

$e = Get-SPServiceApplication | where {$_.TypeName.Equals("Word Viewing Service Application")}
$e.WordServerIsSandboxed = $false
$e.WordServerIsSandboxed

$p = Get-SPServiceApplication | where {$_.TypeName.Equals("PowerPoint Service Application")}
$p.EnableSandboxedViewing = $false
$p.EnableSandboxedEditing = $false
$p.EnableSandboxedViewing
$p.EnableSandboxedEditing

In the server's c:\windows\system32\inetsrv\config\applicationHost.config
Add the line below in the end of the dynamicTypes.
<add mimeType="application/zip" enabled="false" />

IISRESET

Habilitar Developer Dashboard y configurarlo en On Demand para la resolución de problemas de rendimiento de página. Se puede hacer por STSADM o por el shell de administración de SharePoint 2010 (Windows PowerShell).

    1. STSADM: stsadm -o setproperty -pn developer-dashboard -pv OnDemand

    2. Windows PowerShell:

      $svc=[Microsoft.SharePoint.Administration.SPWebService]::ContentService

      $ddsetting=$svc.DeveloperDashboardSettings

      $ddsetting.DisplayLevel=[Microsoft.SharePoint.Administration.SPDeveloperDashboardLevel]::OnDemand

      $ddsetting.Update()

Ocultar campos vacíos en SharePoint

Cuando creamos una nueva página con SharePoint tenemos la opción de poner una imagen, un texto, un webpart,… siempre dependiendo del diseño de página que usemos para crear la nueva página. En la figura de abajo vemos como ese diseño de página tiene un control para rellenar el campo "Page Image" de la página, otro control para rellenar el campo "Page Content" de la página y luego un WebPartZone en el cual podemos añadir todos los WebParts que queramos.

 

El problema viene cuando queremos usar este diseño de página, pero por ejemplo no queremos poner imagen.

¿Por qué es un problema esto?

En control encargado de mostrar la imagen es:

<PublishingWebControls:RichImageField id="ImageFieldDisplay" FieldName="PublishingPageImage" runat="server"/>

 

En resumen, el control RichImageField es capaz de editar y mostrar el campo PublishingPageImage, el cual es una columna de sitio (site column) asociada al tipo de contenido (Content Type) que está usando el diseño de página (Page Layout) que hemos seleccionado para crear nuestra página nueva.

Este control tiene un problema (según mi opinión), que cuando no se selecciona ninguna imagen para mostrar muestra un espacio en blanco y por lo tanto ocupa espacio. Véase un ejemplo:

Pongo un texto de prueba y no pongo ninguna imagen

Y el resultado no es el esperado:

 

NOTA: Este problema NO existe en el control RichHtmlField que se encarga de mostrar un campo (o mejor, columna de sitio) de tipo HTML, en cuyo caso si el HTML no tiene texto no se muestra nada y no estropea nuestro diseño. Tampoco existe este problema con los WebPartZones, si no ponemos ningún WebPart no muestra nada.

 

¿Cómo solucionar este problema?

Para llegar a la solución, tenemos varias opciones desde soluciones JavaScript hasta un Control de servidor.

JavaScript:

Con JavaScript tenemos el inconveniente de asumir que el control RichImageField siempre va a estar dentro de un div con id="divImageLayout" o cualquier otro nombre. Además del inconveniente de dejar que el ordenador cliente gaste computación en arreglar fallos provocados por el ordenador servidor.

function hideIfblank()

{

    var ob = document.getElementById('divImageLayout');

    if (ob != null)

    {

        if (ob.firstChild.firstChild.innerHTML == "")

        {

            ob.style.display="none";

        }

    }            

}

 

Control de servidor:

Lo primero, decir que para realizar el control me he basado en esta web: http://social.msdn.microsoft.com/Forums/en-US/sharepointecm/thread/dcfc5fe2-5ee1-439a-af44-b59b5c6f59bd

Lo que hace básicamente es dado un nombre del campo a filtrar comprueba si es vacío y si lo es entonces no renderiza el control. Si no renderiza el control y el nuestro control RichImageControl es hijo de este, pues tampoco renderizará al hijo. Así de sencillo.

<CLSCompliant(False), _

ParseChildren(False), _

ToolboxData("<{0}:HideWhenBlank runat=server></{0}:HideWhenBlank>"), _

Public Class HideWhenBlank

    Inherits Microsoft.SharePoint.WebControls.SPSecurityTrimmedControl

    Implements INamingContainer

 

    Private m_FieldNameToCheck As String = ""

    <Category("Field"), _

    PersistenceMode(PersistenceMode.InnerProperty), _

    DesignerSerializationVisibility(DesignerSerializationVisibility.Content), _

    Description("Specifies the field name to check for hide his container control if it is blank.")> _

    Public Property FieldNameToCheck() As String

        Get

            Return m_FieldNameToCheck

        End Get

        Set(ByVal value As String)

            m_FieldNameToCheck = value

        End Set

    End Property

 

    Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)

        Dim item As SPListItem = Nothing

        If Not DesignMode Then

            If Not SPContext.Current Is Nothing Then

                item = SPContext.Current.ListItem

            End If

            If (FieldNameToCheck <> String.Empty) AndAlso (item IsNot Nothing) Then

                If CheckIfNullOrBlank(item(FieldNameToCheck)) = False Then

                    MyBase.Render(writer)

                End If

            End If

        Else

            MyBase.Render(writer)

        End If

    End Sub

 

    Private Function CheckIfNullOrBlank(ByVal data As Object) As Boolean

        If data Is Nothing OrElse data.ToString.Trim = String.Empty Then

            Return True

        Else

            Return False

        End If

    End Function

End Class

 

No obstante el uso de nuestro control personalizado será:

<CustomMOSSControl:HideWhenBlank runat="server" FieldNameToCheck="PublishingPageImage">
			

    <PublishingWebControls:RichImageField id="ImageFieldDisplay" FieldName="PublishingPageImage" runat="server"/>

</CustomMOSSControl:HideWhenBlank>
			

 

 

¿Más problemas?

J. Resulta nuestro control personalizado oculta el campo PublishingPageImage cuando este está vacío y como al crear la página está vacío, pues no lo muestra y no podemos añadir una nueva imagen . Para esto hay una solución que he sacado del siguiente post: http://blogs.msdn.com/ecm/archive/2007/02/21/using-field-value-controls-and-edit-mode-panels-to-tweak-your-page-rendering.aspx

Esta es la solución:

<PublishingWebControls:EditModePanel runat="EditModePanelImageDisplay" PageDisplayMode="Display">

    <CustomMOSSControl:HideWhenBlank runat="server" FieldNameToCheck="PublishingPageImage">

        <PublishingWebControls:RichImageField id="ImageFieldDisplay" FieldName="PublishingPageImage" runat="server"/>

    </CustomMOSSControl:HideWhenBlank>

</PublishingWebControls:EditModePanel>

<PublishingWebControls:EditModePanel runat="server" id="EditModePanelImage">

    <PublishingWebControls:RichImageField id="ImageFieldEdit" FieldName="PublishingPageImage" runat="server" />

</PublishingWebControls:EditModePanel>

Explicación:

Ponemos dos RichImageField con el campo PublishingPageImage asociado, el primero se encargará de mostrar la imagen en modo vista y el segundo se encargará de mostrarla en modo edición. Importante que el segundo sea el de edición, ya que si en una página hay dos RichImageField con el mismo campo asociado el valor que se toma al hacer Check-in de la página es el del último control.

El control EditModePanel sirve para que los controles que hay dentro de este, solamente se muestren en modo edición, es decir, cuando editamos la página. Excepto si el EditModePanel tiene la propiedad PageDisplayMode="Display", que actúa de forma inversa, el control de dentro solamente se muestra en modo vista y no en edición.

Con todo esto sabemos que el primer EditModePanel solamente se muestra en modo vista y siempre que el campo PublishingPageImage tenga alguna imagen, justo el comportamiento que queremos. Y el segundo EditModePanel será el encargado de configurar la imagen y se mostrará solamente en modo edición.

Ejemplos:

Vemos que ahora, en modo vista, el texto queda bien alineado y no hay espacios.

Vemos como en modo edición nos permite configurar la imagen (el segundo EditModePanel ya que el primero no se ve)

Y finalmente si protegemos la página y vamos al modo vista se ve la imagen (con el primer EditModePanel ya que el segundo no se ve por no estar en modo edición)

 

 

Espero que les sirva de ayuda!

Saludos!

 

 

Añadir un elemento a una biblioteca de documentos que tiene campos o columnas personalizadas

En MOSS 2007, podemos crear una biblioteca de documentos con campos personalizados, por ejemplo:

| Documento | Título | Resumen | Idioma |

El hecho de añadir nuevas columnas a una lista de documentos, influye a la hora de crear un nuevo ítem de la lista, ya que al cargar un documento podemos poner metadatos referidos a ese documento.

Para hacer esto mediante programación tenemos que seguir unos pasos:

  • Asumimos que a la biblioteca de documentos se le han añadido las columnas "Resumen" e "Idioma".

     

  • La colección de sitios se llama "prueba" y la biblioteca de documentos se llama "BibliotecaDocumentos".

     

  • Sabiendo esto ponemos este código:

    Using site As New SPSite("http://localhost")

    'Obtenemos la colección de sitios "prueba"

    Dim web As SPWeb = site.AllWebs("prueba")

    web.AllowUnsafeUpdates = True

    web.Lists.IncludeRootFolder = True 

    'Obtenemos la biblioteca de documentos desde la colección de sitios

    Dim libreriaDoc As SPList = web.Lists("BibliotecaDocumentos")

    'Creamos un array de bytes de prueba para generar el documento

    Dim arrayBytes() As Byte = Encoding.ASCII.GetBytes("Documento de prueba.")

    'Uploading the file to SharePoint doclib

    Dim docFile As SPFile = web.Files.Add(web.Url.ToString() & "/" & libreriaDoc.Title.ToString() & "/" & "Documento.txt", arrayBytes)

    With docFile

    'Modificamos los campos con los metadatos del documento

    .Item("Title") = "Título del documento nuevo"

    .Item("Resumen") = "Resumen del documento nuevo"

    .Item("Idioma") = "Español"

    'Importante hacer esto sin usar antes el método Update del objeto SPFile, ya que

    'de lo contrario se genera una versión del documento y ya tendríamos que hacer

    'CheckOut para poder modificarlo

    .Item.UpdateOverwriteVersion()

    'Esta es la primera versión que se genera del documento

    If .CheckOutStatus <> SPFile.SPCheckOutStatus.None Then

        .CheckIn("Documento y metadatos creados automáticamente", SPCheckinType.OverwriteCheckIn)

    End If

    End With

    End Using

 

  • Algunos problemas que me surgieron

    Al intentar añadir campos personalizados a una biblioteca de documentos me surgieron algunos problemas:

    • Hacer Update del SPFile antes de file.Item.UpdateOverwriteVersion()

      Al hacer el Update del ítem me lanza un error así:

      {"El nombre especificado ya está en uso. Un documento no puede tener el mismo nombre que otro documento o carpeta de esta biblioteca de documentos o carpeta. Haga clic en el botón Atrás del explorador y escriba otro nombre."}

      Este error es debido a que el Update del SPFile crea el ítem y luego el Update del ítem quiere sobreescribir.

 

Espero que les sirva de ayuda!

Saludos!

 

 

Error al abrir una página de MOSS debido a un WebPart

Hay ocasiones en las que estamos probando un WebPart y al volver a hacer deploy resulta que nos da un error la página debido al WebPart.

   

El problema no es el error, que ya trataremos nosotros de depurarlos y solucionarlo. El problema es que si estamos en un entorno de producción, no podemos ver lá página en modo edición para quitar el WebPart que está fallando y mostrar los demás contenidos de la página.

   

Solución:

Poniéndole a la URL de la página el parámetro "?contents=1". Podemos ver una vista de la página que nos muestra los webparts que tenemos disponibles y cuales están abiertos.

Por ejemplo: http://servidorMOSS/Paginas/inicio.aspx?contents=1

 

Nos saldrá una vista como la imagen de abajo, mostrándonos todos los WebPart activos y no activos. 

   

La opción Cerrar es equivalente a la cruz de cerrar de los webpart cuando estamos en la página en modo edición.

La opción Desproteger es necesaria para poder cerrar o eliminar un webpart.

   

Espero que les sirva de ayuda.

Saludos!

  

Algunas primicias de MOSS 2010
para no duplicar, esta vez Antonio nos ganó de mano
Invocar código de Silverlight C# o VB desde JavaScript y viceversa

Hay diferentes formas de incrustar una aplicación Silverlight en una Web, podemos ocupar toda la web con la aplicación, en cuyo caso no nos sería útil este manual. O podemos realizar varias aplicaciones colocadas en diferentes partes de nuestra web. Para los que necesiten que sus pequeñas aplicaciones Silverlight se comuniquen, están leyendo el manual idóneo.

 

Si pensamos un poco el funcionamiento de una aplicación Silverlight, al fin y al cabo tiene que poder llamar a funciones JavaScript, de lo contrario, ¿Cómo lanzaría un alert en una Web?¿Cómo sería capaz de responder a eventos?

Pues sí, debajo de la capa tan bonita que tenemos en Silverlight mediante la cual programamos todas las acciones producidas en la Web en código C# o VB hay unas bibliotecas que traducen ese C# o VB compilado a código entendible por la Web, por ejemplo, JavaScript.

 

Sin más explicaciones de arquitectura de Silverlight, cabe decir que Silverlight está preparado para ejecutar funciones JavaScript y para permitir que sus funciones sean invocadas desde código JavaScript.

 

Voy a ir poniendo pequeños ejemplos que irán formando una aplicación web, en la que habrá dos aplicaciones Silverlight comunicándose usando como puente las funciones JavaSript.

 

Los ejemplos los haré en C#, pero se dejarán los proyectos tanto para C# como para VB (a petición de mi amigo Dani Seara).

 

Requisitos (más info en http://silverlight.net/getstarted):
- Visual Studio 2008

-
Silverlight Tools Beta 2 for Visual Studio 2008
- Expression Blend 2.5 June Preview
- Silverlight 2 beta 2

 

1.       Invocar función JavaScript desde C# o VB

 

Supongamos este código JavaScript en una página HTML.

 

<script type="text/javascript">

   function mostrarPantalla(cadena)  

   {  

         alert(cadena);  

   }

</script>

 

Y una aplicación Silverlight con un botón que al pulsarlo ejecuta el siguiente código:

 

HtmlPage.Window.Invoke("mostrarPantalla", txtEnviar.Text);

 

Solamente con este código ya podemos invocar la función mostarPantalla de JavaScript desde C#. El resultado es:

 

Ejemplo1

Viendo esta función JavaScript tan sencilla, podríamos pensar que esa función la ejecuta cualquiera, pero ¿Qué pasa si lo que queremos pasar por parámetro no es un String sino un objeto .Net llamado Mensaje con su Nombre, Fecha y Texto?

Pues serializamos el objeto.

Serializar es el proceso de codificación de un objeto con el fin de transmitirlo en red (o en este caso de Silverlight a JavaScrip) en forma de una serie de bytes (serialización binaria) , o en formato texto legible por los humanos (XML o Json). 

En nuestro caso vamos a serializar en formato texto y de los formatos de texto el que menos ocupa  y el más fácil de deserializar por JavaScript es Json. Json es un formato que serializa los objetos de con la misma sintaxis con la que JavaScript crea los obetos.

Así que usando JSON estamos optimizando la cantidad de datos pasados por parámetro y el rendimiento de la deserialización.

 

Imaginemos que estamos haciendo un chat y necesitamos pasar un objeto Mensaje entre las dos aplicaciones Silverlight. Lo  primero es etiquetar la clase Mensaje con el atributo DataContract para indicar que la clase es serializable y las propiedades de la clase con el atributo DataMember por lo mismo. Estos dos atributos pertenecen al ensamblado System.Runtime.Serialization.

 

[DataContract]

public class Mensaje

{

[DataMember]

public string nombre { get; set; }

 

[DataMember]

public string fecha { get; set; }

 

[DataMember]

public string texto { get; set; }

}

 

Para serializar un objeto cualquiera en Json realizamos el siguiente método extensor (.Net Framework 3.5):

 

/// <summary>

/// Metodo extensor que serializa cualquier objeto en JSON

/// </summary>

/// <param name="obj"></param>

/// <returns></returns>

public static string ToJson(this object obj)

{

using (MemoryStream ms = new MemoryStream())

{

DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());

serializer.WriteObject(ms, obj);

ms.Position = 0;

using (StreamReader reader = new StreamReader(ms))

{

return reader.ReadToEnd();

}

}

}

Tener en cuenta que para poder usar la clase DataContractJsonSerializer tenemos que añadir al proyecto la referencia:

 

System.ServiceModel.Web => using System.Runtime.Serialization.Json;

 

Aunque parezca raro, el using de arriba va asociado con esa referencia, me costó bastante averiguarloJ.

 

Hasta ahora, ya sabemos cómo llamar desde Silverlight a una función JavaScript, incluso si los parámetros de la función son objetos complejos. Vamos a ver un ejemplo:

 

function enviarMensajeObjeto(mensaje)

{

//El formato JSON coincide que tiene la misma sintaxis que la

//creacion de objetos en JavaScript, por eso es facil crear el //objeto simplemente usando eval.

var jsMensaje = eval('(' + mensaje + ')');

 

alert(mensaje);

}

 

Esta función JavaScript de arriba recibe como parámetro un string con el objeto Mensaje serializado en Json y para guardarse el objeto en una variable de tipo Mensaje en JavaScript solamente tiene que usar la función eval, que evalúa una cadena de texto como si de código JavaScript se tratase.

 

private void enviarMensaje(Mensaje msg)

{

HtmlPage.Window.Invoke("enviarMensajeObjeto", msg.ToJson());

}

 

La función de Silverlight es simplemente una invocación a la función JavaScript serializando la variable msg, antes de enviarla como parámetro.

 

El resultado al invocar a la función enviarMensaje desde Silverlight es el Mensaje en Json:

 

Imagen2 

 


 

2.       Invocar función C# o VB  desde JavaScript

 

Ahora vamos a aprender lo contrario, queremos llamar desde JavaScript a una función Silverlight.

 

Para poder invocar una función Silverlight primero tendremos que poder referenciar al UserControl (Page) que es el objeto que tendrá el método que queremos invocar.

Para referenciar desde Silverlight el UserControl tenemos que hacer varias cosas:

 

a)      Declarar la clase Page (UserControl) como ScriptableType y el/los métodos que queremos invocar desde JavaScript etiquetarlos con el atributo ScriptableMember:

 

[ScriptableType]

public partial class Page : UserControl

{

 

[ScriptableMember]

public void setMensaje(ScriptObject scriptPerson)

{

Mensaje mensaje = scriptPerson.ConvertTo<Mensaje>();

listaNombres.AddMensaje(mensaje);

}

//Constructor, resto de métodos, etc...

}

 

Nota:

Hay que hacer notar que el parámetro de la función setMensaje no es un objeto Mensaje, sino ScriptObject. Y es que todos los objetos que se vallan a pasar desde JavaScript son ScriptObject, aunque internamente tenga la misma estructura que el objeto Mensaje, de ahí que la conversión sea automática con el método ConverTo.

 

b)      Exponer la instancia del objeto Page al navegador y darle un nombre con el que será llamado desde JavaScript (Page también).

 

public Page()

{

InitializeComponent();

HtmlPage.RegisterScriptableObject("Page", this);

}

 

Una vez hecho esto ya podemos invocar al método setMensaje desde JavaScript con la siguiente función:

 

function enviarMensajeS1(mensaje)

{

//Se obtiene el objeto Silverlight con getElementByID

var silverlight1 = getSilverlight1();  

if(silverlight1)

{

//El formato JSON coincide que tiene la misma sintaxis que la

//creacion de objetos en JavaScript, por eso es facil crear el //objeto simplemente usando eval.

var jsMensaje = eval('(' + mensaje + ')');

 

//Llamada a la funcion de Silverlight 2

silverlight1.content.Page.setMensaje(jsMensaje);

}

}

 

Esta función será invocada desde la Aplicación Silverlight 2, se pasará como parámetro un objeto Mensaje serializado con Json, y la función creará el objeto Mensaje con eval y después llamará a la función setMensaje pasándole como parámetro el objeto creado por JavaScript que será de tipo (.Net)  ScriptObject.

 

 

Como conclusión de todo este documento, cabe destacar que todo esto explicado tiene muchas utilidades: comunicar dos aplicaciones Silverlight, o comunicar una aplicación Silverlight con una Flash, o simplemente Silverlight con JavaScript.

 

En concreto el ejemplo que he implementado es la comunicación de dos aplicaciones Silverlight y está tanto en C# como en VB.

 

 

Ejemplo Final

 

Interacción entre Silverlight y el DOM de Html

Para explicar la interacción entre Silverlight y Html vamos a construir una aplicación de ejemplo. Dicha aplicación Silverlight tendrá dos botones, uno para obtener el nombre de usuario, mostrarlo con un alert y otro para escribir un saludo con su nombre en un div html.

Vamos a ver paso a paso como se crea esta aplicación Silverligth.

Requisitos (mas info en http://silverlight.net/getstarted):
- Visual Studio 2008
- Silverlight Tools Beta 2 for Visual Studio 2008
- Expression Blend 2.5 June Preview
- Silverlight 2 beta 2

 1) Creamos un nuevo proyecto de Silverlight.

 

Crear nuevo proyecto silverlight

Cuando creamos un proyecto Silverlight nos pregunta si queremos crear un proyecto web que albergue la aplicación Silverlight o si se generrará al vuelo la pagina web que mostrará la aplicación Silverlight.

Le decimos que se cree dinámicamente (al vuelo)

Crear Web de Prueba al vuelo

 

2) Crear la página HTML que albergará la aplicación Silverlight

Para ello copiamos este código:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>Prueba de interacción entre DOM y Silverlight</title>
  <style type="text/css">
  html, body {
  height: 100%;
  overflow: auto;
  }
  body {
  padding: 0;
  margin: 0;
  }
  #silverlightControlHost {
  height: 100%;
  }
  </style>

</head>
<body>
  <div id="lineaInfo">Bienvenido <span id="nombreUsuario">jquinto</span></div>
  <div id="saludo"></div>
  <div id="silverlightControlHost">
  <object data="data:application/x-silverlight,"
  type
="application/x-silverlight-2-b2" width="100%" height="100%">
  <param name="source" value="Bin/Release/DomSilverlight.xap"/>
  <param name="background" value="white" />

<a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
  <img src="http://go.microsoft.com/fwlink/?LinkId=108181"
  alt
="Get Microsoft Silverlight" style="border-style: none"/>
  </a>
  </object>
  <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
  </div>
</body>
</html>

Y lo pegamos en un archivo que lo llamaremos "DomSilverlightTestPage.html" y lo guardaremos en la carpeta principal del proyecto:

Guardar la pagina de prueba en directorio del proyecto

 

Ahora para poder ejecutarlo en el proyecto como página de prueba tenemos que añadirlo:

Añadimos la pagina al proyecto

Y una vez añadido aparecerá así:

Página añadida al proyecto

A partir de ahora ya tenemos la página de prueba creada, con los dos div que nos interesan (uno para coger datos y otro para escribir datos desde Silverlight). Ahora vamos a hacer que el proyecto DomSilverlight cada vez que le damos a ejecutar (F5) ejecute esta página y no la que ejecuta predeterminadamente.

Vamos a las propiedades del proyecto:

Propiedades del proyecto

Y en la pestaña Debug cambiamos la acción de comienzo y ponemos la página que nos interesa:

Cambio de la página de prueba en el proyecto

NOTA: Hay que tener en cuenta que esa página la hemos creado nosotros y que tiene rutas establecidas por ejemplo, presupone que el archivo "DomSilverlight.xap" (que es la aplicación Silverlight comprimida) está en la ruta Bin/Release, por lo tanto solo funciona si el modo de ejecución que tenemos es release, si queremos ejecutar en Debug tenemos que cambiar esa ruta en el HTML de prueba.

 

3) El código de la aplicación.

El código se divide en dos archivos, como ya sabemos Silverlight, al igual que WPF, separa el diseño del código. El diseño estará en un fichero XAML y el código en este caso en su correspondiente fichero .cs (C#).

XAML: 

<UserControl x:Class="DomSilverlight.Page"
  xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
  Width
="400" Height="50">
  <Grid x:Name="LayoutRoot">
  <Grid.ColumnDefinitions>
  <ColumnDefinition Width="200px" />
  <ColumnDefinition Width="200px" />
  </Grid.ColumnDefinitions>

<Button x:Name="botonLeerDOM" Content="Obtener Nombre Usuario" Click="botonLeerDOM_Click" />
  <Button x:Name="botonEscribirDOM" Content="Poner saludo en HTML" Click="botonEscribirDOM_Click" Grid.Column="1"/>
  </Grid>
</UserControl> 

 

CS:

  using System;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows;

namespace DomSilverlight
{
  public partial class Page : UserControl
  {
  HtmlElement leer;
  HtmlElement escribir;
  string nombreUsuario = "";

public Page()
  {
  InitializeComponent();

//Obtengo los elementos HTML
  try
  {
  leer = HtmlPage.Document.GetElementById("nombreUsuario");
  escribir = HtmlPage.Document.GetElementById("saludo");
  }
  catch (Exception ex)
  {
  HtmlPage.Window.Alert("Error: " + ex.Message);
  }
  }

/// <summary>
  /// Interacción de DOM a Silverlight
  /// </summary>
  /// <param name=sender"></param>"
  /// <param name=e"></param>"
  private void botonLeerDOM_Click(object sender, RoutedEventArgs e)
  {
  try
  {
  nombreUsuario = leer.GetProperty("innerHTML").ToString();
  HtmlPage.Window.Alert("Nombre de Usuario: " + nombreUsuario);
  }
  catch (Exception ex)
  {
  HtmlPage.Window.Alert("Error: " + ex.Message);
  }
  }

/// <summary>
  /// Interacción de Silverlight a DOM
  /// </summary>
  /// <param name=sender"></param>"
  /// <param name=e"></param>"
  private void botonEscribirDOM_Click(object sender, RoutedEventArgs e)
  {
  try
  {
  escribir.SetProperty("innerHTML", "Hola mi nombre de usuario es " + nombreUsuario);

}
  catch (Exception ex)
  {
  HtmlPage.Window.Alert("Error: " + ex.Message);
  }
  }
  }
}

El resultado de todo esto es que cuando le damos en el VS2008 a ejecutar nos sale esto:

Si pulsamos el boton de obtener (desde HTML hacia Silverlight).

Boton de Obtener

Si pulsamos el boton de Poner (desde Silverlight hacia HTML).

De silverlight a HTML

 

Pues sabiendo esto ya podemos realizar la comunicación entre dos aplicaciones Silverlight usando como puente el HTML.

El proyecto completo esta aquí.

Presentación de Solid RAD

El pasado día 21 de abril en Madrid y el día 22 de abril en Barcelona tuvo lugar el evento Frameworks y herramientas RAD de código abierto y propietario para soluciones .NET. Donde presenté nuestro Solid RAD, una herramienta para el desarrollo rápido de aplicaciones centradas en datos con una arquitectura de dos y tres capas.

Si estáis interesados en Solid RAD Tenéis disponibles unos vídeos en mms://solidq.com/SolidRad .

NOTA: copiad y pegad mms://solidq.com/SolidRad en la barra de direcciones de IE para ver los vídeos.

1 - 10 Next

 ‭(Hidden)‬ Admin Links


¿Problemas técnicos? Contáctenos en webmaster@solidq.com o al 800 300 800 (desde España) o al +34 91 414 8950 (desde fuera de España)