Juanma Santoyo

En ocasiones me llaman friki

Introducción al componente ScatterView de Surface (1: ScatterViews con XAML)

| 16 Comentarios

El multitouch es probablemente una de las características más atractivas de Surface. Esto se debe a que plantea una serie de posibilidades al usuario que convierte su experiencia en algo mucho más intuitivo y sencillo.

El componente ScatterView es quizás uno de los mejores ejemplos de esto. Este es el primero de varios artículos en el que veremos cómo se usan y qué posiblides nos ofrecen.

Sobre el componente ScatterView

Un ScatterView representa un elemento que reacciona a los contactos sobre Surface y que se puede mover, rotar o redimensionar.

El ejemplo más clásico sería un puñado de fotografías. Cada una de esas fotografías puede ser un ScatterView.

Preparamos el proyecto

Antes de iniciar el Visual Studio, debemos haber iniciado el emulador de Surface que viene con el SDK. Si no lo has hecho así, cierra el Visual Studio y inícialo todo en el orden correcto.

Creamos el proyecto

Nuestro proyecto va a ser una aplicación para Surface basada en WPF. Lo llamaremos HelloScatterView.

Al crear nuestro proyecto se nos ha creado una ventana por defecto: SurfaceWindow1. La renombraremos, y le pondremos el nombre de “XamlSample“.

Añadimos unas imágenes

Para poder trabajar con los ScatterViews, necesitaremos algunas imágenes.

Dentro de nuestro proyecto Surface tenemos una carpeta llamada Resources. Crearemos otra carpeta en su interior llamada Img y ubicaremos ahí nuestras imágenes.

Añadir ScatterViews desde XAML

ScatterView simple con XAML

Comenzaremos usando los ScatterViews desde XAML. En realidad añadir un ScatterView es muy simple:

<s:ScatterView>
    <Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
</s:ScatterView>

Este es el código que añade un ScatterView. Fijaos en un detalle: añadir un ScatterView no es sólo añadir el nodo ScatterView, también es añadir el recurso que se manejará, en este caso la imagen. Y es que un ScatterView no es una imagen, sino la capacidad que tiene un elemento (en este caso una imagen) de ser rotado, redimensionado y movido.

El XAML completo de la ventana es este:

<s:SurfaceWindow 
    x:Class="HelloScatterView.SurfaceWindow1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    Title="HelloScatterView">
    <s:SurfaceWindow.Resources>
        <ImageBrush x:Key="WindowBackground" 
                  Stretch="None" Opacity="0.6" 
                  ImageSource="pack://application:,,,/Resources/WindowBackground.jpg"/>
    </s:SurfaceWindow.Resources>
    <s:ScatterView>
        <Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
    </s:ScatterView>
</s:SurfaceWindow>

Si ahora compilamos nuestro proyecto, podremos jugar un poco con nuestra foto sobre el emulador de Surface. Incluso, si conectas dos ratones por USB puedes simular multitouch.

Vamos a hacerlo un poco más espectacular añadiendo varias imágenes:

<s:ScatterView>
    <Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
    <Image Source="Resources/Img/kiyoumizu_dera.jpg"/>
    <Image Source="Resources/Img/laputa_robot.jpg"/>
    <Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
    <Image Source="Resources/Img/kiyoumizu_dera.jpg"/>
    <Image Source="Resources/Img/laputa_robot.jpg"/>
</s:ScatterView>

Scatterviews complejos con XAML

Probablemente ya te estés preguntando lo siguiente: ¿cómo determinar los parámetros por defecto de nuestro ScatterView? Vamos a ello.

La clave está en que la estructura que hemos usado ahora no acaba de ser la mejor. En realidad, nos está faltando crear un ScatterViewItem, que hasta el momento se estaba creando de forma automática para cada elemento en el ScatterView.

<s:ScatterView>
	<s:ScatterViewItem>
		<Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
	</s:ScatterViewItem>
</s:ScatterView>

En el nodo ScatterViewItem podemos establecer muchas propiedades que afectarán al comportamiento de nuestro ScatterView.

Algunas de esas propiedades son:

  • MinWidth, MaxWidth, MinHeight, MaxHeight: Máximos y mínimos de anchura y altura.
  • CanMove, CanRotate, CanScale: Activan o desactivan las capacidades de mover, rotar y redimensionar.
  • Width, Height, Center, Orientation: Valores iniciales para el ancho, el alto, la posición, y la rotación.
  • BorderBrush, BorderThikness: Color y grosor del borde.

Un ejemplo sencillo:

<s:ScatterView>
	<s:ScatterViewItem Center="512,384" Orientation="0">
		<Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Center="512,384" Orientation="60">
		<Image Source="Resources/Img/kiyoumizu_dera.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Center="512,384" Orientation="180">
		<Image Source="Resources/Img/laputa_robot.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Center="512,384" Orientation="240">
		<Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Center="512,384" Orientation="300">
		<Image Source="Resources/Img/kiyoumizu_dera.jpg"/>
	</s:ScatterViewItem>

	<s:ScatterViewItem Center="512,384" Orientation="360">
		<Image Source="Resources/Img/laputa_robot.jpg"/>
	</s:ScatterViewItem>
</s:ScatterView>

Aunque de hecho, podemos centralizar la mayoría de estas propiedades en un único nodo, como un estilo:

<s:ScatterView>
	<s:ScatterView.ItemContainerStyle>
		<Style TargetType="{x:Type s:ScatterViewItem}">
			<Setter Property="Center" Value="512,384"/>
			<Setter Property="BorderBrush" Value="Black"/>
			<Setter Property="BorderThickness" Value="3"/>
		</Style>
	</s:ScatterView.ItemContainerStyle>

	<s:ScatterViewItem Orientation="0">
		<Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Orientation="60">
		<Image Source="Resources/Img/kiyoumizu_dera.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Orientation="180">
		<Image Source="Resources/Img/laputa_robot.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Orientation="240">
		<Image Source="Resources/Img/fuente_tres_chorros.jpg"/>
	</s:ScatterViewItem>
	
	<s:ScatterViewItem Orientation="300">
		<Image Source="Resources/Img/kiyoumizu_dera.jpg"/>
	</s:ScatterViewItem>

	<s:ScatterViewItem Orientation="360">
		<Image Source="Resources/Img/laputa_robot.jpg"/>
	</s:ScatterViewItem>
</s:ScatterView>

Es todo por hoy

El componente ScatterView es sencillo de usar y proporciona una característica muy interesante a nuestras aplicaciones.

Cuando se trabaja para Surface, hay que tener muy en cuenta que los diversos usuarios se colocan alrededor de la mesa, por lo que no existe el derecho ni el revés. Los ScatterViews nos solucionarán este problema más de una vez.

En la siguiente parte del artículo, veremos cómo trabajar con ScatterViews desde C#.

Editado 7/5/2010:

Me comentaron que los códigos fuente en XAML tenían mal la sintaxis, y efectívamente; cuando he pasado a revisarlo así era. Ni idea de que pudo pasar… Bueno, ya están arreglados.

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

16 Comments

  1. Hola de nuevo

    Gracias por el artículo, muy bueno, pero aun con dudas

    no se si tenga que ver la version de visual Studio que tengo, es la 2008 professional, cuando genero un nuevo proycto de microsoft surface me da por default este código:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Windows.Threading;
    using Microsoft.Surface;
    using Microsoft.Surface.Presentation;
    using Microsoft.Surface.Presentation.Controls;

    namespace HelloScatterView
    {
    ///
    /// Interaction logic for SurfaceWindow1.xaml
    ///
    public partial class SurfaceWindow1 : SurfaceWindow
    {
    ///
    /// Default constructor.
    ///
    public SurfaceWindow1()
    {
    InitializeComponent();

    // Add handlers for Application activation events
    AddActivationHandlers();
    }

    ///
    /// Occurs when the window is about to close.
    ///
    ///
    protected override void OnClosed(EventArgs e)
    {
    base.OnClosed(e);

    // Remove handlers for Application activation events
    RemoveActivationHandlers();
    }

    ///
    /// Adds handlers for Application activation events.
    ///
    private void AddActivationHandlers()
    {
    // Subscribe to surface application activation events
    ApplicationLauncher.ApplicationActivated += OnApplicationActivated;
    ApplicationLauncher.ApplicationPreviewed += OnApplicationPreviewed;
    ApplicationLauncher.ApplicationDeactivated += OnApplicationDeactivated;
    }

    ///
    /// Removes handlers for Application activation events.
    ///
    private void RemoveActivationHandlers()
    {
    // Unsubscribe from surface application activation events
    ApplicationLauncher.ApplicationActivated -= OnApplicationActivated;
    ApplicationLauncher.ApplicationPreviewed -= OnApplicationPreviewed;
    ApplicationLauncher.ApplicationDeactivated -= OnApplicationDeactivated;
    }

    ///
    /// This is called when application has been activated.
    ///
    ///
    ///
    private void OnApplicationActivated(object sender, EventArgs e)
    {
    //TODO: enable audio, animations here
    }

    ///
    /// This is called when application is in preview mode.
    ///
    ///
    ///
    private void OnApplicationPreviewed(object sender, EventArgs e)
    {
    //TODO: Disable audio here if it is enabled

    //TODO: optionally enable animations here
    }

    ///
    /// This is called when application has been deactivated.
    ///
    ///
    ///
    private void OnApplicationDeactivated(object sender, EventArgs e)
    {
    //TODO: disable audio, animations here
    }
    }
    }

    al incluir el código que facilitas para agregar el sctatter view me marca algunos erroes.

    otra duda, donde encuntr l carpeta resources???

    gracias por tu tempo, buena tarde!!1 😀

  2. Hola!!!!

    ya me di un clavadsimo en todo esto, logre solucionar mis dudas, ahora solo una pregunta
    Sabes como hacer que se volteen las imagenes (como si le dieras vuelta a una carta en la mesa) estoy preparando un memorama y me seria de gran utilidad

    Un saludo y de nuevo gracias

  3. Hola!

    Ciértamente, aplicar un flip sobre un ScatterView es una solución muy interesante para interfaces táctiles como Surface.

    Debo confesar que aún no he podido documentarme sobre el efecto de flip, aunque una rápida búsqueda en Google me la llevado a un post interesante en los foros de microsoft:

    http://social.msdn.microsoft.com/Forums/en/surfaceappdevelopment/thread/edc68262-f1ae-4337-aa4d-b7beb8cfee44

    Espero que puedas sacarle partido ;).

  4. Lo consultare, estudiare y exprimire hasta donde pueda

    te agradezco un saludo

  5. Otra duda tal vez me termines odiando jeje

    sabes como dar funciones a los scatteview en c# con un click

    por ejemplo, que al dar click en una imagen se cambie el texto de unacaja e texo

    Gracias!!!!

  6. Hola.

    Algo he encontrado sobre el tema, puede que esto te sirva de ayuda:

    http://msdn.microsoft.com/en-us/library/ee804980%28v=Surface.10%29.aspx

  7. Hola de nuevo, todo corriendo de maravilla, agradeciendo los comentarios, me han ayudado, solo me falta, como se declaran las varibles?? deseo agregar un contador y para el siguiente proyecto necesito agregar mas.

    po jemplo que se guarde el nombre, que al presionar un boton x veces se guarde el numero que se guardo

    Gracias de nuevo!!!

  8. ¡Vaya! Por fín me haces una pregunta facil xD.

    Pues los contadores son sencillos, en el fondo es una aplicación orientada a objetos como otra cualquiera. Por ejemplo, si queremos contar las veces que se hace click en un boton:

    1. Primero creamos una variable global en la ventana que sea el contador:

    public class …
    {

    int contador = 0;

    2. Después, en el manejador del evento click del botón:

    public void Manejador_Click(…
    {

    this.contador ++;

    }

    Y no tiene más misterio que este. En cualquier momento puedes mirar que valor tiene el contador ya que es una propiedad global.

    Un saludo.

  9. Hola de nuevo… tal vez teburles, pero no le encontre como para el cotador, jeje no si me podrias yudar con otro ejempo ponendo todolo la clase??? graca :DD:D

  10. Nop, no me burlo por que yo no nací sabiendo hacer contadores xD.

    Hacer un pequeño ejemplo será sencillo, en unos días lo publicaré.

  11. hola de nuevo, ya me salieron lo contadores jeje gracias de nuevo!!!

    otra duda, sabes como incluir un timer???

    Ya me hasde soñar con tanta molestia je

  12. Pues mira, precisamente ayer aprendí sobre Timers.

    Mira, básicamente, si tu timer funciona de forma independiente, usa la clase Timer:
    http://msdn.microsoft.com/es-es/library/system.timers.timer%28VS.80%29.aspx

    Pero si quieres un timer donde puedas acceder a elementos de la interfaz gráfica y este tipo de cosas, necesitarás la clase DispatcherTimer.
    http://msdn.microsoft.com/en-us/library/ms615945%28v=VS.100%29.aspx

  13. Hola, Gracias por el timer, too bien 😀

    ahora ando trabajando en un proyecto mas serio, necesito sacar datos del directorio activo dela empresa y despegarlos enel surface, sabes ago de manejo de directorio activo?

    gracias.. de nuevo

  14. Hola.

    Bueno, ahí si que me pillas. La verdad es que no se mucho del tema xD.

  15. Hola, rato de no escribir

    estaba leyendo lo de directorio activo ultimamente y tratando de instalar en sdk en 64 bits, el directorio activo es posible hacerlo, pero se necesita hacerle una conexion con sql y despues leer los datos desde C#, algo complicado, pero empiezan a aparecer resultados… por fin!!! jeje

    espero saque nuevo articulo pronto

    Saludos!!!

  16. Pingback: Juanma Santoyo » Blog Archive » Introducción al componente ScatterView de Surface (2: ScatterViews con C#)

Deja un comentario

Los campos obligatorios están marcados con *.