Animación Gráfico de Barras con Silverlight

.Net Add comments
  • Estructura Proyecto Silverlight (2ª Parte)

La teoria esta muy bien para tomar un primer contacto con una nueva tecnología, pero no hay nada como ponerse con las manos en la masa, en nuestro caso en el teclado. Vamos a ello.

El ejemplo, como ya anticipamos, consistirá en generar un control Silverlight que contendrá un Gráfico de Barras, la cuales cambiaran su áltura en función de los valores asignados a cada una de ellas. Los valores serán introducidos en tres cajas de texto (simples componentes HTML).

Para empeza abrimos Visual Studio, y creamos un nuevo proyecto Silverlight. Si recordamos, la interfaz de nuestro control esta definida en un fichero con extension XAML. Aunque podríamos crear nuestro control editando directamente este fichero, vamos a hacer uso de Expression Design, herramienta que ofrece Microsoft para crear interfaces de un modo profesional. Como el uso de esta herramienta se escapa del ambito de este articulo, partiremos de un fichero XAML generado por Expression Design.

Fichero XAML:

Para empezar resumamos los elementos que podemos encontrarnos en un fichero XAML de Silverlight.

Clase Descripción
Canvas Es un objeto contenedor. En el podrémos añadir otros elementos e incluso otros objetos canvas.
Textblock Elemento que contiene texto, en una o varias lineas.
Image Elemento que puede mostrar una imagen(png,jpeg...)
Rectangle, Ellipse, Line, Polyline, Polygon Representa distintas figuras 2D
Path Representa figuras no geométricas
MediaElement Elemento que controla fichero de audio/video

Los elementos son posionados dentro del elemento canvas prinipal. La posicion de un objeto se especifica mediante las propiedades Top y Left, que son relativas al elemento canvas contenedor (un elemento con Top=0 y Left =0, tiene su origen en la esquina superior izquierda del objeto contenedor). Veamos como definimos un objeto rectángulo, que representa una barra de nuestro gráfica:

XML:
  1. <Rectangle x:Name="Barra2" Width="32.135" Height="146.948" Canvas.Left="175.901" Canvas.Top="301.882" Stretch="Fill" StrokeThickness="2" StrokeLineJoin="Round" Stroke="#FFFFFFFF">
  2.    <Rectangle.RenderTransform>
  3.       <TransformGroup>
  4.          <ScaleTransform ScaleX="1" ScaleY="-1"/>
  5.       </TransformGroup>
  6.    </Rectangle.RenderTransform>
  7.    <Rectangle.Fill>
  8.       <LinearGradientBrush StartPoint="0.413879,0.865686" EndPoint="0.413879,0.119879">
  9.          <LinearGradientBrush.GradientStops>
  10.             <GradientStop Color="#997BEB76" Offset="0"/>
  11.             <GradientStop Color="#DE088902" Offset="1"/>
  12.          </LinearGradientBrush.GradientStops>
  13.       </LinearGradientBrush>
  14.    </Rectangle.Fill>
  15. </Rectangle>

Detalles importantes:

  1. Le damos un nombre a los objetos. De esta manera podremos referirnos al los elemetos desde codigo.

  2. Posicionamos los elementos respecto al objeto Canvas contenedor, haciendo uso de las propiedades Top y Left de la clase Canvas.

Además podemos observar otra forma de especificar propiedades, como el usado para especificar el relleno de la figura (Rectangle.Fill). Como comentamos al principio del articulo, el fichero ha sido generado mediante una herramienta de diseño y unicamente se ha añadido codigo para definir animaciones y trasformaciones sobre los objetos.

Animaciones:

Definir una animación sobre un objeto no es complicado: se establece el estado inicial. el estado final, y la duracion de la animacion. Silverlight realiza el resto. Cuando definimos el estado incial y final, lo que hacemos es establecer el valor de una propiedad de objeto al comienzo de la animacion y cual será el valor que tenga esa propiedad al final.

Un objeto animación en Silverlight trabaja solo sobre una propiedad, lo cual implica que una animación solo puede cambiar el valor de una propiedad. Para animar una propiedad, es decir, cambiar valor de la propiedad, necesitamos una clase Animación que soporte el tipo de datos de la propiedad que queremos animar. Por ejemplo, nuestro objeto Barra crecerá y decrecerá en función de un valor especificado. Para ello modificaremos la propiedad Height del objeto, por lo que animaremos dicha propiedad. Esta propiedad es de tipo Double, y necesitamos una animación que soporte este tipo de datos. Usaremos una animación de tipo DoubleAnimation. En cualquier caso Silverlight nos ofrece tres tipos de animaciones para actuar sobre distintos tipos de propiedades:

  • DoubleAnimation
  • ColorAnimation
  • PointAnimation

Dicho esto veamos como definiriamos nuestras animaciones:

XML:
  1. <Canvas.Resources>
  2.    <Storyboard x:Name="sb1">
  3.       <DoubleAnimation  x:Name="AnimacionBarra1" Storyboard.TargetName="Barra1"
  4.        Storyboard.TargetProperty="Height" From="0" To="192.2769" Duration="0:0:2"/>   
  5.     </Storyboard>
  6.     <Storyboard x:Name="sb2">
  7.       <DoubleAnimation  x:Name="AnimacionBarra2" Storyboard.TargetName="Barra2"
  8.        Storyboard.TargetProperty="Height" From="0" To="192.2769" Duration="0:0:2"/>
  9.     </Storyboard>
  10.     <Storyboard x:Name="sb3">
  11.       <DoubleAnimation  x:Name="AnimacionBarra3"  Storyboard.TargetName="Barra3"
  12.        Storyboard.TargetProperty="Height" From="0" To="192.2769" Duration="0:0:2"/>     
  13.     </Storyboard>
  14. </Canvas.Resources>

Bueno en este código hay algo mas que un objeto animación. Vayamos por partes. Todos los objetos Silverlight tienen una propiedad Resources, que no es mas que una colección de objetos que no son elementos. En este caso vamos a usar la propiedad Resources de nuestro Canvas principal, y le vamos a añadir nuestras animaciones. Añadimos nuestras animaciones a la coleccion Resources porque estan van a estar controlados desde nuestro código y no van a reponder a ningun evento (por ejemplo loaded) de la aplicación.

Pero claro un objeto Animación define unicamente un compormiento, necesitamos algo que controle la animación y además lo aplique a un objeto. Para eso tenemos los objetos StoryBoard. Además de ser un puente entre el objeto Barra y el objeto Animación nos proporciona metodos para pausar, activar y parar la animación. En un objeto Storyboard podemos agrupar varias animaciones y cada una puede actuar sobre un objeto distinto.

Transformaciones:

Un objeto Transform es un objeto que modifica la forma en que un elemento es dibujado, cambiando las coordenadas del sistema que usa. En nuestro ejemplo usamos un objeto Transform para las barras. Exactamente usamos un ScaleTrasnform con los valores scaleX=1 y scaleY=-1.

¿Qué sentido tiene esta trasnformación?. Cuando posicionamos nuestra barra, lo hacemos a traves de sus propiedades Top y Left, que son relativas al Canvas en el que está situado el elemento. Teniendo en cuenta que las Barras tendrán el mismo Top que la linea que define el eje X de la gráfica (por lo que tendrán este punto como origen), no es dificil imaginar que nuestra Barra se dibujará en sentido invertido al esperado. Para corregir esto le aplicamos una trasformacion que invierta el mapa de posicionamiento de nuestra barra en su sentido vertical.

Descargar Fichero Grafica.XAML

Antes de continuar viendo código y explicaciones, veamos el ejemplo en funcionamiento. 

Fichero CS

Como podemos ver, nuestra mini-aplicacion Silverlight está formada por:

  • un control Silverlight, que contiene una gráfica (con sus barras), y un boton.

  • una  zona de componentes HTML. 

Sigamos el flujo de nuestra aplicación.  Una vez se han introducidos valores en las cajas de texto, pulsamos el botón "Dibujar". Asi esta definido el boton en el fichero XAML.

XML:
  1. <Rectangle x:Name="Boton" Width="100" Height="40" Canvas.Left="230" Canvas.Top="50" Stretch="Fill" StrokeLineJoin="Bevel" Stroke="#FFFFFFFF"
  2.      MouseLeftButtonDown="OnClickLeftMouseDown" MouseLeftButtonUp="OnClickLeftMouseUp">
  3.      ...
  4. </Rectangle>
  5. <TextBlock Text="Dibujar" Canvas.Left="250" Canvas.Top=" 55" FontSize="16" FontStyle="Normal" FontWeight="Bold"
  6.      MouseLeftButtonDown="OnClickLeftMouseDown" MouseLeftButtonUp="OnClickLeftMouseUp" />

Eventos

En Silverlight no tenemos un evento onClick (evento de alto nivel), sino que tenemos los eventos MouseLeftButtonDown -acto de pulsar el boton- y MouseLeftButtonUp -acto de soltar el boton. Estos son algunos de los eventos que tienen los controles Silverlight.

  • GetFocus

  • KeyDown, KeyUp

  • Loaded

  • MouseEnter, MouseLeave, MouseLeftButtonDown, MouseLeftButtonUp

Para nuestro botón hemos definido las dos acciones, porque queremos realizar un cambio en el gradiente del relleno del botón. Asi estan definidos los manejadores de estos eventos:

C#:
  1. public void OnClickLeftMouseDown(object o, MouseEventArgs mouseEventArgs )
  2. {
  3.   //Cambiar colores del boton al pulsar
  4.   CambiarGradiente(Colors.White, Colors.Gray);
  5.  
  6. //Obtener valores de la caja de texto
  7.   int valor1 = ObtenerValorCajaTexto(1);
  8.   int valor2 = ObtenerValorCajaTexto(2);
  9.   int valor3 = ObtenerValorCajaTexto(3);
  10.  
  11. //Establecer valor de inicio de la animacion
  12.   AnimacionBarra1.SetValue(DoubleAnimation.FromProperty, Barra1.Height);
  13.   AnimacionBarra2.SetValue(DoubleAnimation.FromProperty, Barra2.Height);
  14.   AnimacionBarra3.SetValue(DoubleAnimation.FromProperty, Barra3.Height);
  15.  
  16. //Establecer altura de las barras
  17.   EstablecerAlturaBarra(Barra1, valor1);
  18.   EstablecerAlturaBarra(Barra2, valor2);
  19.   EstablecerAlturaBarra(Barra3, valor3);
  20.  
  21. //Establecer el valor de fin de la animacion
  22.   AnimacionBarra1.SetValue(DoubleAnimation.ToProperty, Barra1.Height);
  23.   AnimacionBarra2.SetValue(DoubleAnimation.ToProperty, Barra2.Height);
  24.   AnimacionBarra3.SetValue(DoubleAnimation.ToProperty, Barra3.Height);
  25.  
  26. //Ejecutar animaciones
  27.   sb1.Begin();
  28.   sb2.Begin();
  29.   sb3.Begin();
  30. }
  31.  
  32. public void OnClickLeftMouseUp(object o, MouseEventArgs mouseEventArgs)
  33. {
  34.   //Cambiar colores del boton al soltar el boton de raton
  35.   CambiarGradiente(Colors.Gray, Colors.White);
  36. }

Este es el flujo del evento OnClickLeftMouseDown:

  1. Se llama al método CambiarGradiente, que invierte los colores con lo que se forma el gradiente que pinta el  botón.

  2. Recuperamos los valores introducidos por el usuario.

  3. Establecemos el valor inicial de la animación, que será el valor actual de la propiedad Height de la barra.

  4. Calculamos el nuevo valor de la altura de cada una de las barras, proporcionalmente a la altura del Eje Y de la gráfica.

  5. Establecemos el valor final de la animación, que en este caso será la nueva altura calculada.

  6. Iniciamos la animación llamando al metodo Begin() de los objetos Storyboard.

 El manejador del evento MouseLeftButtonUp, lo único que hace es reestablecer los colores del botón llamando nuevamente al método CambiaGrandiete. Este método lo que hace es asignar a la propiedad "Fill" del botón un nuevo gradiente en función de los colores que recibe como parametros.

C#:
  1. private void CambiarGradiente(Color color1, Color color2)
  2. {
  3.     LinearGradientBrush lgb = new LinearGradientBrush();
  4.  
  5.     GradientStop gs_0 = new GradientStop();
  6.     GradientStop gs_1 = new GradientStop();
  7.  
  8.     gs_0.SetValue(GradientStop.ColorProperty, color1);
  9.     gs_0.Offset = 0;
  10.     gs_1.SetValue(GradientStop.ColorProperty, color2);
  11.     gs_1.Offset = 1;
  12.  
  13.     lgb.GradientStops.Add(gs_0);
  14.     lgb.GradientStops.Add(gs_1);
  15.  
  16.     Boton.Fill = lgb;
  17. }

 

Comunicación Silverlight - HTML

En este caso la comunicación se limita a obtener los valores introducidos por el usuario en unas cajas de texto. Para conseguir esto Silverlight incluye un conjunto de clases que definen los elementos HTML DOM. No vamos a profundizar en este punto, pero si decir que aunque en este caso nosotros vamos a simplemente leer un valor, podríamos hacer por ejemplo que el evento de un componente HTML sea  capturado por Siverlight. Veamos nuestra comunicacion:

C#:
  1. /// Lee el valor introducido en la caja de texto.
  2. /// En caso de no ser un numero devuelve 0<returns></returns>
  3. private int ObtenerValorCajaTexto(int nCaja)
  4. {
  5.   HtmlElement elemento = HtmlPage.Document.GetElementByID("valor" + nCaja);
  6.   int valor = 0;
  7.   try
  8.   {
  9.   valor = Convert.ToInt32(elemento.GetAttribute("value"));
  10.   }
  11.   catch
  12.   {
  13.   valor = 0;
  14.   elemento.SetAttribute("value","0");
  15.   }
  16.   return valor;
  17. }

Recuperamos un elemento input buscando por su "Id", para lo cual usamos el metodo GetElementById(value) del objeto Document,  que nos devuelve un  objeto de la clase HtmlElement. Asignar y obtener valores es trivial con los metodos GetAttribute y SetAttribute.

Un detalle que no devemos pasar por alto es el contenido de la funcion Page_loaded, que aunque tenga unicamente una sola linea,  es la encargada de inicializar todos los elementos de nuestro control. Si echamos un vistazo al XAML, cuando definimos el Canvas principal, le indicamos que tiene que hacer para inicializar el control, mediante la propiedad Loaded, la cual nos dirige al manejador de eventos Page_Loaded.

Descargar Proyecto Grafico de Barras

Bueno con esto doy por terminado el minitutorial de Silverligth, esperando no haberme dejado mucho en el tintero. En cualquier caso, gustosamente reponderé las dudas que pudieran surgir.

2 Responses to “Animación Gráfico de Barras con Silverlight”

  1. Mitdraug Says:

    Genial la introducción a Silverlight. El problema del que hablabas en el último post no se me reproduce en el servidor que utilizo (debe tener menores restricciones inicialmente que el tuyo), pero sin duda el “truco” para el despliegue puede salvarnos de más de un apuro, aunque coincido con que la solución administrativa es mucho más adecuada.

    Respecto a la entrada de hoy, que realmente es sobre la que quería hablar, me ha gustado mucho. Silverlight va a ser un motivo más para que Adobe se ponga las pilas con Flash, y JavaFX también está a punto de remontar con igual fuerza. Sin duda, Silverlight cuenta con la ventaja para los desarrolladores .Net de que no deberán cambiar de lenguaje para desarrollar aplicaciones enriquecidas para Internet, aunque una vez más nos vamos a meter en una “guerra” de tecnologías que sirven para lo mismo, y finalmente habrá que aprender más lenguajes o apostar por un vencedor (y esperar ganar).

    En cualquier caso, con tus artículos me ha picado la curiosidad por probar alguna que otra cosita con Silverlight, así que si consigo hacer algo ya te lo haré saber, en relación con la inquietud que han generado en mí tus post.

    Saludos.

  2. Enrique Mecalco Hernández Says:

    Thank you for your Attention

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Acceder

Switch to our mobile site