Silverlight, MVVM y WCF RIA Services: Notas de un proyecto real


Recientemente terminé el desarrollo de una aplicación en Silverlight usando varios de los principios discutidos en otros artículos (la mayoría traducidos) de este blog. La experiencia fue interesante y reveladora puesto que, aunque los artículos explican diversos temas y sus respectivos autores tienen pasta para enseñar los conceptos relativos a Silverlight, MVVM, y RIA, a la hora de llegada siempre hay áreas que no son discutidas. En especial es difícil encontrar artículos que discutan el diseño y construcción de un sistema completo, cubriendo los obstáculos encontrados y las correspondientes soluciones.

Una importante razón, imagino yo, es porque tales sistemas son en su mayoría comerciales , con todas sus implicaciones económicas y legales. Otra es que un sistema usado en el mundo real, tiende a ser específico para el problema que resuelve y no se presta para ser usado como ejemplo general.

En mi caso, aunque el sistema que desarrollé incluye el despliegue de información confidencial, los mecanismos usados no son particularmente novedosos o dignos de protección. En fin, prácticamente todo el código está basado en conocimiento disponible al público en general. Así que, luego que algunos cambios en el modelo, es decir, los datos usados, es posible presentar un ejemplo libre de secretos comerciales.

Por otra parte, aunque el sistema se acomoda cierta situación en particular, muchos de los patrones, técnicas e ideas usadas, son aplicables a sistemas más generales, y me parece que pueden ser de utilidad para los que comienzan a aventurarse en el mundo de comunicaciones asincrónicas de Silverlight.

En este y algunos artículos futuros, voy desarrollar una aplicación desde cero, discutiendo los problemas encontrados, los recursos disponibles, y las soluciones usadas. Aunque muchas de las decisiones tienen sólidos fundamentos técnicos, es también común encontrar múltiples posibles formas de atacar el problema. Por lo tanto, los criterios, razones, y decisiones tomadas no han de tomarse como axiomas o edictos. Si otro enfoque o técnica les parece más apropiada, ¡enhorabuena! Una de los aspectos más atrayentes de la programación es la maleabilidad de las soluciones usadas.

En cuanto a complejidad, la aplicación es pequeña y simple. Parecida a los ejemplos usados por Brad Abrams o Shawn Wildermuth. Sin embargo, y esto es por supuesto sólo mi opinión, este ejemplo tiene un sabor más realista puesto que fue creada para uso comercial y es actualmente usada por cientos de personas.

Al resolver los problemas y obstáculos normales en su diseño e implementación, tuve que ir más allá del los ejemplos o “recetas” comunes. Alguna veces encontré material en la red luego de una enconada búsqueda. En otras ocasiones, hallé herramientas creadas por desarrolladores que pasaron por circunstancias similares. Finalmente, en algunas situaciones tuve que ingeniármelas para poder seguir adelante. Algunos de los problemas, técnicas y herramientas que voy a considerar son:


  • Orden de creación de los diferentes aspectos del MVVM
  • Distribución de responsabilidades en componentes
  • Reorganización del código (refactoring)
  • Reorganización de la aplicación
  • Comandos y mensajes (usando RelayCommand y Messenger de MVVMLight)
  • Estilización del control de gráficos del Silverlight Toolkit
  • Impresión usando jerarquías visuales virtuales
  • Autenticación y autorización
  • Paginado de datos
  • Uso de procedimientos almacenados con Entity Framework


La lista es larga, algunos de los temas son complejos, y el tiempo limitado, por lo que se me hace que va a tomar un rato cubrir el material.


Planeamiento

Requerimientos

Volviendo al ejemplo, el sistema tiene dos fases principales: autenticación y consulta de datos. Uno de los requisitos es que únicamente usuarios autorizados pueden tener acceso a los datos. Esta información se encuentra en una simple tabla que asocia el nombre de usuario con el registro del cliente y otros aspectos contables. Lo ideal sería poder ir por la ruta fácil y usar el sistema ofrecido por ASP.NET para registro y autenticación de usuarios. Pero en este caso en particular el cliente ya tiene un mecanismo establecido y no desea cambiarlo. Por lo tanto hay que usar un sistema personalizado.

La otra fase principal del programa es la consulta de datos, con el modo de uso clásico donde el cliente puede digitar el número de factura y obtener información sobre los productos incluidos en el documento. Esta información proviene de otra base de datos asociada con el sistema contable principal de la compañía.

Finalmente, el esquema de la base de datos no está disponible para los desarrolladores. Cualquier consulta o manipulación se hace mediante procedimientos almacenados. Sin embargo, con el fin de aprovechar la generación de código combinada de Entity Framework y WCF RIA Services, lo que hice fue adaptar el modelo para que usara los procedimientos almacenados. Esto conlleva ciertas dificultades debido a que EF prefiere usar acceso directo a las tablas. Pero con un poco de esfuerzo es posible hacerlo.


Arquitectura

La infraestructura de WCF RIA provee excelentes herramientas para el manejo remoto de datos. Entre ellas se encuentran plantillas para generar aplicaciones completas que pueden servir de fundamento cuando uno desea crear un nuevo proyecto.

El problema de las plantillas es que necesitan ser muy generales. No es posible crear una plantilla que se adapte perfectamente a las necesidades específicas de ningún proyecto en particular. Como resultado, la solución generada termina siendo inadecuada para casi cualquier proyecto serio.

Una de las mayores desventajas es que la plantilla genera mucho código que, aunque al principio parece una gran ganancia en tiempo, termina siendo un problema cuando hay que adaptarlo al proyecto. Por ejemplo, la plantilla para generar la Aplicación de Negocios de Silverlight genera código para el registro automático de usuarios, incluyendo la habilidad para que los usuarios cambien su clave. Sin embargo, esta función es demasiado básica como para ser útil en un ámbito empresarial, y más compleja de lo esperado cuando se quiere adaptarla a situaciones fuera de lo común.


Separación de responsabilidades

Otro problema con las plantillas básicas de Visual Studio es que generan aplicaciones monolíticas donde toda la funcionalidad está conglomerada en un único proyecto. Ese tipo de diseño es apropiado para sistemas livianos o utilidades. No obstante en una aplicación empresarial puede ser más aconsejable dividirlo en segmentos con responsabilidades específicas y limitadas.


Diagrama de solución monolítica.


Nótese que se trata de la distribución de archivos fuente en proyectos y soluciones, no del diseño conceptual del sistema. Tal planeamiento físico es a veces relegado a un segundo plano, particularmente en aplicaciones que crecen de manera gradual. En un sistema pequeño el lío de organizar los diferentes componentes en proyectos separados es un trabajo con poca recompensa.

Esta es una de esas áreas donde hay que tener cuidado. A mí personalmente me gusta separar los sistemas en silos o capas de funcionalidad, tanto a nivel lógico como físico. A través de los años he comprobado que es más fácil mantenerlo y ejecutar pruebas. Sin embargo, siempre hay circunstancias en las que se puede aplicar una diferente estrategia (por ejemplo el sistema monolítico antes mencionado) con éxito.

En el caso específico de este ejemplo, la aplicación es pequeña, pero existe el plan de que expandir su rango de funciones en el futuro. Además, el departamento de desarrollo de software tiene media docena de ingenieros, por lo que es muy probable que en algunos casos varias personas trabajen en diferentes aspectos de la aplicación al mismo tiempo.

Como resultado, el sistema está divido en tres partes principales:

  • Aplicación Silverlight
  • Servicios RIA
  • Sitio de Web


Diagrama de solución segmentada.


La mayor diferencia es que los servicios RIA residen un su propio proyecto. En casos más elaborados, podría ser necesario dividirlos en varias unidades separadas. Pero por ahora un sólo proyecto es suficiente. Afortunadamente, WCF RIA y Visual Studio proveen los medios para crear este tipo de sistema de componentes separados. En este caso, la aplicación principal es creada usando la plantilla básica u otra similar, y los servicios RIA son luego anexados a la solución.


Creando la solución

Usando los criterios establecidos en la sección anterior, voy a usar la plantilla fundamental para una aplicación Silverlight. Sería posible usar la plantilla para Aplicaciones de Navegación de Silverlight u otra disponible que no incluya los servicios RIA, pero en este caso en particular, no se necesitan las facilidades de navegación. En vez de eso, la aplicación va a funcionar de forma parecida a los ejemplos originales de Silverlight donde es parte de un sitio de web más general.


El proyecto inicial se basa en la plantilla para una aplicación básica de Silverlight.


El asistente pregunta si queremos un sitio de web para hospedar la aplicación. Generalmente yo respondo que sí puesto que es fácil luego adaptar la páginas de web generadas por la plantilla. Además en proyectos basados en WCF RIA Services, es necesario hospedar los servicios en IIS, por lo que el sitio pre-generado nos da ciertas ventajas. En la sección de Opciones, es bueno asegurarse que la versión de Silverlight a usar es la cuarta.


El ejemplo usa un sitio preconfigurado por la plantilla y basado en ASP.NET MVC.


Puede que hayan notado que en vez del la aplicación ASP.NET de Web que normalmente ofrece el asistente de Visual Studio, para este caso escogí una aplicación de Web basada en MVC. Las razón es doble. Primero, el sitio de web tiene poca funcionalidad fuera de servir como portal de entrada y luego proveer la aplicación Silverlight, por lo que no vamos a necesitar controles u otros servicios provistos por ASP.NET (fuera de autenticación, pero ya cubriré eso más adelante). De hecho en el sistema original, el sitio general de la compañía está basado en PHP.

Segundo, MVC sigue una filosofía de diseño similar al patrón MVVM usado en la aplicación Silverlight. Ambos combinan bien juntos y se prestan de manera excelente para incorporar pruebas unitarias. De hecho, el asistente pregunta si deseamos crear un proyecto para alojar las pruebas unitarias. Estas no son para el cliente Silverlight, sino para el sito de Web. En caso de querer incluir pruebas para Silverlight, habrá que añadir manualmente un proyecto con ese fin.

En nuestro caso, el sitio de web no tiene otra función más que presentar una pantalla para autenticar el usuario, por lo que las pruebas son de poca utilidad. Sin embargo, con el fin de dejar al puerta abierta, decidí crear el proyecto de pruebas. Pueden notar que Visual Studio permite el uso de otros marcos de prueba además del provisto por defecto. Para usar MbUnit, la mejor opción es instalar Gallio.


El asistente da oportunidad de crear pruebas untiarias para la aplicación de Web.


Luego de creada la solución, éste es su aspecto en el explorador de Visual Studio:


Aspecto incial de la solución.


Añadiendo los servicios RIA

La aplicación está diseñada usando los servicios WCF RIA para proveer los datos al cliente. Esta es, de nuevo, una decisión algo arbitraria. No porque carezca de méritos, sino porque hay otras posible soluciones que son similares en utilidad. Por ejemplo, se podría haber usado WCF Data Services (conocidos anteriormente como ADO.NET Data Services), el WCF básico, o servicios comunes de web.

La principal ventaja a obtener en el uso de WCF RIA es la generación automática de código para proyectar al cliente datos originarios del servidor. Se puede asimilar a la forma en que Visual Studio general el código para crear la interfase gráfica de una aplicación de Windows tradicional. Sin embargo, en el caso de WCF RIA, hay más control sobre la forma en que el código es generado, y también es un poco más transparente.

En un artículo futuro voy a cubrir en más detalle las características de este mecanismo. Por el momento, me limito a crear el servicio de datos para la aplicación. Para ello, le agrego un nuevo componente a la solución. Tal como en Windows se pueden añadir bibliotecas de clases (DLLs), en Silverlight vamos ahora a crear una biblioteca configurada como servicio RIA:


Visual Studio provee una plantilla para crear bibliotecas de servicios RIA.


Al presionar OK, Visual Studio crea una nueva carpeta lógica en la que coloca dos proyectos, uno es la biblioteca que usará el cliente, y el otro la biblioteca que contiene el servicio en sí y que va a residir en el servidor:


La biblioteca RIA tiene dos partes, una para el cliente y otra para el servidor.



Para asociar la biblioteca con la aplicación principal, hay que agregar referencias a estos proyectos. En MD_Ejemplo_MVVM se añade una referencia a DataStore, y en MD_Ejemplo_MVVM.Web una referencia a DataStore.Web.

Volviendo a las ideas planteadas en la sección sobre la separación de responsabilidades, es posible obtener un resultado similar si al crear la aplicación usamos la plantilla de Aplicación de Negocios, o si al usar la plantilla básica de Silverlight escogemos crear el vínculo RIA entre el servidor y el cliente.


Los servicios RIA pueden ser incorporados en la aplicación principal.


De hecho, si examinamos las propiedades del proyecto cliente de la biblioteca que acabamos de crear, se puede ver que tiene el mismo tipo de vínculo:


La biblioteca de servicios RIA establece el mismo tipo de vínculo.


El valor adicional provisto por la plantilla de Aplicación de Negocios es la pre-configuración de facilidades de navegación y los servicios de autenticación y membrecía para usuarios.


Modelo de datos

La gran mayoría de las aplicaciones no sólo procesan información sino que también la almacenan para uso posterior. En un contexto corporativo, los datos pueden tener gran volumen y tener relaciones complejas entre sí. Es por eso que las bases de datos son comunes en este entorno.

Idealmente, este ejemplo presentaría un modelo de datos sofisticado y rico en interrelaciones. Sin embargo, puesto que soy un simple mortal, no me es posible dedicar el tiempo necesario. A modo de compensación, mi plan es investigar y discutir a través del tiempo tales sistemas enfocándome en algunos aspectos o facetas a la vez.

El sistema original usado como patrón para este ejemplo ofrece a los usuarios la habilidad de consultar datos técnicos sobre componentes electrónicos que hayan comprado. Por poner un ejemplo, si alguien compra un amplificador de audio, entonces puede digitar el número de serie o el número de factura y obtener las características eléctricas de ese dispositivo. Tales resultados son obtenidos al probar el aparato en la fábrica. Aunque el caso es interesante, no puedo usar tales datos por ser propiedad del fabricante (mi cliente), y por residir en una base de datos que no es asequible al público. Así que mi solución es crear un modelo de datos similar.

Tras un buscar en la red un rato, encontré varias fuentes de datos disponibles al público de los que se pueden crear bases de datos similares. Una es http://www.data.gov/ que provee toda clase de datos copilados por el gobierno de los Estados Unidos. Otro similar es http://data.un.org/ auspiciado por las Naciones Unidas. Aunque hay otros más decidí usar este último por ser más general considerando que la mayoría de los lectores de este blog son originarios de España y Latinoamérica.

El siguiente reto fue encontrar una base de datos que provea información interesante, pero al mismo tiempo minimizar controversias. Parámetros como salud, o educación pueden ser un poco incendiarios. Otros, como la deuda externa, deforestación, o crimen, son más que nada deprimentes. Al fin, uno que me pareció lo suficientemente neutral, aunque a veces un poco alarmante, fue el índice de crecimiento de la población en diferentes países. Al cabo los datos en sí son menos importantes que su formato o esquema, al menos en nuestro caso.

Luego de hacer algo de magia con Excel, SlickEdit (mi editor favorito fuera de Visual Studio), y un poco de T-SQL, terminé con una base de datos que va ser nuestra fuente principal de información. El esquema de datos o estructura es como sigue:


Estructura de la base de datos para el ejemplo.


En el sistema original el usuario puede usar un número de factura para obtener datos sobre los dispositivos incluidos en el documento. La idea es ofrecerle una forma fácil de verificar la información sobre varios dispositivos de una sola vez. De otra forma, tendría de digitar el número de serie de cada componente.

Puesto que el usuario puede digital cualquier número de serie o de factura, es importante verificar que esté autorizado para ver la información que a solicitado. En el sistema original, la identidad del usuario está asociada con todas las facturas del cliente y estas con los dispositivos individuales. Este lazo es entonces consultado para cada número digitado.

Con el fin de simular una situación parecida, la base de datos incluye continentes como unidades de agrupación. De esta manera, el usuario puede especificar uno o más países para obtener unos pocos datos, o usar un continente para obtener los datos de un grupo predeterminado de naciones.

La tabla UserContinent provee el contexto para verificar la autorización del usuario. Cada usuario es asociado con los continentes al los que tiene acceso. Si solicita datos sobre países en continentes para los que no tiene autorización, entonces se le niega el acceso.


De seguro algunos notarán que estoy usando términos en inglés para nombrar las tablas. En los pasados meses, mientras traduzco artículos de autores angloparlantes, he vacilado entre traducir el código o dejarlo en inglés. Al final, el resultado de traducir el código deja una mezcla inconsistente de lenguajes que no es necesariamente más clara pero sí más fea. Por eso mi regla ahora es escribir el código en inglés pero los comentarios, cuando son necesarios, en español. De igual manera, con el fin de mantener consistencia en el código, las entidades de la base de datos tienen nombres en ingles. En cuanto a la información en la base de datos, sólo la encontré disponible en ese idioma, por lo que así se queda. Ni modo.


Los nombres de países son tal como los designa el CIA World Factbook. De igual manera, la división regional de países en continentes está basada en Wikipedia. Por cierto, aunque los llamé continentes, se trata más de grupos de países. Especialmente en las Américas. Yo sé que algunos de estos datos son polémicos. Si el nombre del país y el continente al que está asignado no son de su agrado, pueden hacer las correcciones necesarias en su copia de la base de datos.


La base de datos

En aplicaciones empresariales los datos generalmente residen en uno o más servidores asignados exclusivamente a la tarea de administrar su almacenaje. Por eso, lo común es configurar la solución con una conexión a la base de datos remota.

Para el ejemplo, lo práctico es incorporar la base de datos en el proyecto en forma de un archivo mdf que es manejado por SQL Server. Por una parte, al empaquetar la base de datos, el proyecto es más portátil. Por otro lado, el archivo puede ser usado con cualquier versión de SQL Server.

Aquí se presenta una de esas situaciones en las que hay que hacer una decisión que tenderá a definir el resto del proyecto. Aunque no es terriblemente importante en nuestro ejemplo, debemos decidir dónde incorporar la base de datos. Por el momento hay dos opciones razonables, DataStore.Web y MD_Ejemplo_MVVM.Web. Del modo en que yo lo veo, aunque DataStore.Web va a ser el consumidor de la base de datos, su producto es un DLL residente en el proyecto principal, MD_Ejemplo_MVVM.Web. Es posible también que luego tengamos otros DLLs que utilicen la base de datos por lo que el proyecto principal actúa como depósito central.

El resto de este artículo explica cómo incorporar la base de datos en el proyecto. El mecanismo es idéntico al usado en proyectos de web o de Windows por lo que si ya saben cómo hacerlo pueden ignorar la retahíla. De hecho, la solución resultante de la segunda parte ya tiene la base de datos incorporada.


Incorporando la base de datos a la solución

La base de datos está disponible para descarga de manera separada. Luego de bajarla es importante descomprimir el archivo ZIP y remover el bloqueo impuesto por Windows 7 o Vista. De otra manera, Visual Studio va a tener un ataque cardíaco más adelante.


Los proyectos de aplicación de Web prefieren de manera enfática que los datos residan en la carpeta App_Data. Si crearon la solución usando ASP.NET MVC, entonces ya está presente. Si no, hay que crearla haciendo clic derecho en el proyecto MD_Ejemplo_MVVM.Web y seleccionando Agregar carpeta ASP.NET Folder->App_Data.

Asumiendo que ya tenemos App_Data, el siguiente paso es añadir la base de datos. Para ello se puede hacer clic derecho en la carpeta y seleccionar Agregar->Elemento existente.


La base de datos se puede añadir usando el menú de contexto o seleccionando Project->Add Existing Item en el menú principal.


Y navegar a donde pusimos los archivos de la base de datos.


La base de datos consiste en dos archivos, uno con los datos y otro con el historial de transacciones. Ambos son necesarios.


Por lo general, la base de datos incluye un archivo con extensión ldf que contiene el historial de transacciones efectuadas en la base de datos. Este registro puede incluir acciones todavía pendientes por lo que no es buena idea desecharlo.

Al seleccionar Agregar, Visual Studio copia los archivos a la carpeta App_Data y añade referencias al proyecto. Este es el resultado final:


La base de datos ya residente en la carpeta App_Data del proyecto de Web principal.


Ya está lista la solución básica. En los materiales asociados a este artículo he incluido versiones en C# y Visual Basic de la solución esqueleto sin tener la base de datos incorporada. Si desean saltarse el paso, pueden descargar la solución del artículo siguiente que cubre la creación del modelo de datos.

Etiquetas asignadas:
 

16 Respuestas a “Silverlight, MVVM y WCF RIA Services: Notas de un proyecto real”

  1. Sergio dice:

    Enhorabuena, muy interesante y didactico espero con muchas ganas el siguiente artículo

  2. Oscar dice:

    Felicidades, excelente artículo, gracias por compartir tus conocimientos y experiencias. Quiero descargar la base de datos pero no he podido, me baja el ejemplo MD_Ejemplo_MVVM_VB-Parte1.zip y no la incluye, gracias.

  3. David Mora dice:

    Sergio y Oscar: Gracias por los amables comentarios. Estoy trabajando en otras partes de la serie, aunque por límite de tiempo, no puedo publicarlas tan seguido como quisiera.

    Oscar: gracias por avisarme. Metí la pata en el enlace, pero ya lo corregí. Espero que puedas descargar la base de datos ahora.

  4. Juanma dice:

    Excelente artículo. Voy a seguir la serie sin ninguna duda!

  5. Alejandro dice:

    David Excelente curso. Directo al punto.
    Lo que mas importante me parece es que estás compartiendo la invaluable experiencia que da el uso de esta teconología en el ambito empresarial. Ya construiste una aplicación empresarial y que hoy en día tiene cientos, tal vez miles de usuarios conectados y que nos demuestra que perfectamente se puede hacer con Silverlight.
    Tengo una pequeña duda cómo resolviste el tema de los reportes, los formatos de facturas, reportes de contabilidad, exportación a excel o PDF?

    Muchas gracias

    • David Mora dice:

      Alejandro,

      Gracias por tu encomio.

      Respecto a las preguntas que haces, son todas muy buenas. La serie de artículos en la que estoy trabajando ahorita, va a cubrir ligeramente algunos de esos temas. Específicamente, el plan incluye describir mis aventuras al tratar de imprimir localmente una especie de reporte conteniendo una gráfica. Déjame decirte que la cosa no fue fácil, y de hecho, tuve que usar un par de trucos de los que no estoy muy orgulloso. :(

      De todos modos, lo que sí es cierto es que es importante considerar los puntos fuertes de Silverlight y los que no son tan sólidos. Por ejemplo, las tareas de generación de reportes complejos o archivos PDF puede ser mejor dejarlas al servidor. Hay aplicaciones en las que el cliente Silverlight debería ser más bien un componente de un sistema más amplio que incluya ASP.NET (por ejemplo) y hasta JavaScript. Casos como en los que se requiere alta concurrencia o reportes sofisticados son ejemplos de este tipo.

      De todos modos, vale la pena explorar la implementación de las operaciones que tu mencionas en Silverlight y las voy a añadir a mi lista de temas. Que los logre cubrir dependerá del tiempo que tenga disponible y del interés general reflejado por los estimados lectores del blog.

      Gracias de nuevo por tu nota.

  6. Juan Carlos dice:

    Hola.
    Me parecio un articulo excelente, me gustaria saber aproximadamente cuando seran posteados los proximos articulos de este tema.

    Gracias.

  7. saul dice:

    Te felicito, en estos momentos he leido todos tus articulos y me han ayudado mucho.

  8. Maya dice:

    Me parece muy interesante este blog y algunos articulos, el dia de ayer por casualidad encontre este blog, que por lo articulos que he leido van al grano.

  9. Ale dice:

    Articulo Pesimo.
    Perdi un monton de tiempo .
    No es un caso real completo
    No da soluciones

  10. Luara dice:

    estoy feliz con el blog, soy nueva en silverlight y me gusta lo claro de los conceptos. Es una buena forma de empezar. Gracias pot tu tiempo.

  11. Diego espinosa dice:

    La verdad lo mas prolijo e interesado por enseñar a la gente que vi, muy bueno, la verdad hace pila que trabajo con cosas en silverlight del lado del cliente, pero no he tocado nada de entity framework, creoque este ejemplo me va a permitir arrancar. Saludos desde uruguay.

  12. Javier dice:

    Estimado, Lo felicito por la dedicación que le has dado a los temas, espero que continúes ahondando un poco mas, ya que estoy apunto de tirar la esponja con silverlight, comencé como avión viendo tutoriales que solo hacían mención a diseño (xaml) y nada de codigo, ahora necesito comenzar mi proyecto empresarial en serio y veo que se me aclaran un poco mas las cosas, espero que me resulten los ejemplos, pero por favor no dejes botado el blog. Esperare y ojala no sea por mucho tiempo, si has visto temas como el manejo de reporteria, fusiones con documentos word, exportaciones en excel o pdf. bueno, no se puede dejar de lado el trabajo con librerias de clases.

    Saludos Desde Chile

  13. beginner dice:

    Fantastico trabajo el que estas realizando, a mi me sirvio de mucho para empezar con SilverLight

    Saludos desde España

  14. pedro dice:

    Gracias por tus aportes, me son de gran utilidad
    ojala y sigas con tu blog, saludos

Responder



Licencia de uso

El contenido de las traducciones está sujeto a los términos de protección de derechos de uso de los autores originales quienes han autorizado su publicación en este blog. Asegúrese de entender los terminos de la licencia de cada autor antes de usar tal contenido.

Mis propios artículos son publicados bajo los términos de la Licencia Reconocimiento-Compartir bajo la misma licencia 3.0 Estados Unidos de Creative Commons:

Creative Commons License
Blog de Maromas Digitales by Maromas Digitales, LLC is licensed under a Creative Commons Reconocimiento-Compartir bajo la misma licencia 3.0 Estados Unidos License.

License

The contents of all translated articles is subject to the copyright and licensing terms of the original authors and has been published here with their express permission. Verify the original author's licensing terms before using the contents of these articles.

My own articles are licensed under the Creative Commons Attribution-Share Alike 3.0 United States License:

Creative Commons License
Blog de Maromas Digitales by Maromas Digitales, LLC is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.