Cambiando de nombre a Window1

renamingFile

Uno de los primeros problemas con los que se encuentra un diseñador o programador de WPF es qué hacer con Window1. Como ventana principal de la aplicación, lo más común es que queramos darle otro nombre que deje clara su funcionalidad, pero no es tan sencillo. El primer paso es renombrar el fichero desde el Explorador de soluciones. Después tenemos que modificar el nombre del archivo en 3 sitios distintos:

  • Window1.xaml. Tendremos que modificar el x:Class, que hace referencia al nombre completo de la clase parcial donde se almacena el código de la ventana.
  • Window1.xaml.cs. Tanto el nombre de la clase como su constructor deben ser modificados.
  • App.xaml. Este es el punto que la mayoría de la gente olvida y que más problemas termina dando, puesto que no se nos ocurre pensar en las referencias a Window1 fuera de la propia clase. Además, el proyecto compilará perfectamente, pero nos dará una IOException diciendo que no puedo encontrar el recurso window1.xaml. La razón es que dentro de App.xaml especificamos la ventana principal de la aplicación con el atributo StartupUri que, si no lo modificamos, conservará el valor Window1.xaml.

Una vez modificados estos tres ficheros, nuestro proyecto funcionará perfectamente y no tendremos que volver a ver Window1 por ningún sitio.


Rock Tip. Dudo mucho que un grupo como AC/DC necesite introducción, menos aun después del impresionante concierto de este viernes en el Vicente Calderón, así que os dejaré con uno de sus grandes éxitos, You Shook Me All Night Long. Enjoy!!

Teclado en pantalla con WPF

ScreenKeyboardEn algunas de nuestras aplicaciones es posible que necesitemos controlar de forma muy fina la entrada de datos por parte del usuario, o que no dispongamos de un teclado físico. Con WPF podemos crear de forma sencilla un teclado en pantalla que se maneje con el ratón o de forma táctil. Lo primero de todo será crear nuestra aplicación WPF y añadirle un TextBox y varios botones.

La aplicación resultante la podéis ver aquí a la izquierda…os servirá para daros cuenta de que esto no va de diseño, sino de programación. Además al final del post hay un link para que podáis descargárosla y comprobar lo sencilla que es.

Es interesante utilizar un TextBox en lugar de otro control de texto como una Label o un TextBlock, puesto que así tendremos soporte para mostrarle al usuario la posición del cursor (caret) mientras edita el texto. Una vez hecho esto, necesitamos gestionar una serie de temas para que el teclado funcione correctamente. Lo primero de todo, manejaremos el click de los botones para añadir texto al TextBox:

private void KeyboardPanel_Click(object sender, RoutedEventArgs e)
{
Button button = (Button)e.Source;
Text.AppendText(button.Content.ToString());
}

Una vez hecho esto, solo nos quedaría hacer que el campo de texto muestre la posición del cursor mientras se esta editando. Para ello, en el constructor de nuestra ventana añadiremos estas dos líneas después del InitializeComponent:

this.InitializeComponent();

Text.CaretIndex = 0;
Text.Focus();

La primera línea sitúa la posición del cursor en el 0, ya que de no hacerlo el TextBox no la gestionará correctamente. La segunda línea le da el foco de tal manera que muestre el cursor. Si probamos nuestra aplicación ahora veremos que aun nos queda un problema por resolver. Al hacer click en cualquiera de los botones para añadir texto, el TextBox perderá el foco, perdiendo así la funcionalidad del cursor. Para evitar esto hay varios métodos: hacer que los botones no puedan recibir el foco (Focusable=false), hacer que en cada click el TextBox recupere el foco…Lo que haremos será algo muy sencillo: evitar que el TextBox pierda el foco. Añadimos al constructor la siguiente linea:

Text.PreviewLostKeyboardFocus += new KeyboardFocusChangedEventHandler(Text_PreviewLostKeyboardFocus);

Manejando el evento PreviewLostKeyboardFocus podemos realizar las acciones que deseemos antes de que el control pierda el foco. Y lo que deseamos es…

void Text_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
e.Handled = true;
}

Marcar el evento como manejado. Con algo tan simple como esto evitamos que el control pierda realmente el foco, y tenemos nuestro teclado listo para su uso.


Rock Tip. Poca gente hace canciones y videos tan divertidos como Electric Six. Lo mejor de todo es que además suenan realmente bien…y no tienen ninguna relación con el tema del post, para no perder la costumbre 😉 Cierran hoy Electric Six con Danger! High Voltage. Enjoy!!!

Los secretos del casting al descubierto

Visto lo animada que estuvo la discusión en el anterior post sobre los diferentes casts en C#, no podía dejar pasar la oportunidad de explicar un poco en que consistía el acertijo. Como algunos comentabais en los comentarios, las dos operaciones, as y cast explicito, son distintas en funcionalidad y también internamente. Vamos a ver por qué:

concursante = (Concursante)o;

En esa línea, intentaremos convertir el objeto o a Concursante. Si podemos, devolveremos un objeto de tipo concursante, si no podemos lanzaremos una excepción.

concursante = o as Concursante;

En esta otra línea, comprobaremos primero si el objeto es convertible a Concursante. Si lo es, lo convertiremos y devolveremos, si no lo es devolveremos null. Internamente, el operador as se convierte en una instrucción de tipo isinst, mientras que el cast directo se convierte en una instrucción castclass. Pero dejémonos de teoría y vamos a lo que nos interesa. Con un sencillo programa podemos comprobar cual de los dos es más rápido. Por ejemplo, así:

Concursante concursante = null;
object o = new Concursante();

ArrayList array = new ArrayList();

Stopwatch watch = new Stopwatch();
Console.WriteLine("Begin casting");

for (int i = 0; i < 100; i++)
{
    watch.Start();

    for (int j = 0; j < 10000000; j++)
    {
        concursante = (Concursante)o;
        concursante.Nombre = "Rosa";
    }

    watch.Stop();

    array.Add(watch.ElapsedMilliseconds);
    watch.Reset();
}

float ms = 0;

for (int i = 0; i < array.Count; i++)
{
    ms += float.Parse(array[i].ToString());
}

ms = ms / array.Count;

Console.WriteLine("Median elapsed time: {0} ms", ms);

Si, el programa tiene un poco mas de miga, pero tiene su sentido. Hemos de recordar que un casting, de una forma u otra, es una operación con un coste muy, muy pequeño por si sola. Para poder medirla con un poco de precisión, realizaremos diez millones de casting cien veces, y calcularemos la media. Ejecutado en mi portátil mientras escribo esto, el resultado es de unos cuantos milisegundos (40, 50…) en cada uno de los casos. Recordemos que estamos hablando del tiempo de ejecución de 10.000.000 operaciones. Lo curioso es que al ejecutar el mismo código en modo release o en modo debug, con o sin optimizaciones, nos dará resultados distintos. Qué es lo que esta pasando?

Esa será la respuesta que dejaré sin responder, por una sencilla razón. Mi compañero Luis Guerrero me ha prometido realizar un interesantísimo post sobre este mismo tema, metiéndose hasta el fondo del asunto con WinDBG. Así pues, le paso el testigo 😉


Rock Tip. Ya he nombrado por aquí a los finlandeses Turisas, pero es justo que después de verles la semana pasada en directo por segunda vez, vuelva a recordarlos. Con vosotros, Battle Metal. Enjoy!!

Los secretos del casting

Y no estamos hablando de los castings de Operación Triunfo o Gran Hermano, no. Os propongo pasar la tarde de hoy pensando en una de esas cosas que no dejan de ser interesantes pese a servir para bastante poco 😉

Seguro que todos los días mientras programáis os encontráis con situaciones en las que tenéis que convertir objetos de un tipo a otro, lo que se conoce como un casting (que no tiene nada que ver con concursos, por suerte). En C# las dos formas más comunes de realizarlo son con un cast explicito o utilizando el operador as:

object o = new Concursante();
Concursante concursante;

concursante = (Concursante)o; //Explicito
concursante = o as Concursante; //Operador as

Visto esto ya no haré ningún comentario, y me limitare a lanzar mi pregunta. Basaros simplemente en lo que sabéis de ambas operaciones y en vuestra intuición vale? La pregunta es…cual de las dos formas de realizar un cast es más rápida?

La respuesta, en breve, en esta misma cadena…o no 😉


Rock Tip. Visto que todo lo que hemos tenido por el momento en estos rock tips ha sido música en inglés creo que por una vez, aprovechando el cambio de temática del post, podríamos buscar otro idioma…como el alemán. Hoy cierra el post Rammstein con una de sus mejores canciones (IMHO) acompañada de un gran videoclip: Ich Will. Enjoy!!

Un sencillo menú en WPF: Recursos (II)

Dado que en el post anterior hablábamos sobre estilos y plantillas, vamos a ver un poco mas en detalle ahora como podemos estructurarlos y acceder a ellos de la mejor manera posible. En el proyecto (adjunto en la primera parte) vemos que en la ruta /Themes/Default.xaml encontramos un diccionario de recursos.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d">
    <!-- Resource dictionary entries should be defined here. -->
    <Style x:Key="ButtonFocusVisual">
        ...
    </Style>
    <LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
        ...
    </LinearGradientBrush>
    <SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>
    <Style x:Key="MenuButtonStyle" TargetType="{x:Type Button}">
        ...
    </Style>
</ResourceDictionary>

Como podemos ver, este diccionario de recursos contiene estilos, plantillas, brochas y demás recursos que utilizaremos a lo largo de toda nuestra aplicación. Es imprescindible que todos ellos tengan un atributo x:Key para poder ser referenciados desde nuestros elementos de interfaz. Para ello, primero necesitamos agregar a nuestro App.xaml una referencia al diccionario (o diccionarios) de recursos que queramos emplear.

<Application.Resources>
    <!-- Resources scoped at the Application level should be defined here. -->
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="ThemesDefault.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Una vez hecho esto, solo necesitamos aplicar el recurso deseado mediante la extensión de marcado DynamicResource en la propiedad que nosotros elijamos:

<StackPanel x:Name="LayoutRoot" Width="600" Height="66">
    <StackPanel x:Name="ButtonStack" Width="Auto" Orientation="Horizontal" HorizontalAlignment="Right" Height="26" ButtonBase.Click="ButtonStack_Click">
        <Button Content="Home" x:Name="HomeButton" Width="70" Style="{DynamicResource MenuButtonStyle}" Height="24" MouseEnter="ButtonStack_MouseEnter"/>
        ...
    </StackPanel>

No es necesario que especifiquemos un path al recurso, como haríamos con un binding al uso, dado que automáticamente se buscará el recurso en los diccionarios de recursos cargados en ese momento cuando sea necesario mostrarlo. Esa es la diferencia entre DynamicResource y su hermana StaticResource: mientras que DynamicResource cargará el recurso en el momento en que se muestra el elemento que lo referencia, StaticResource realiza esa asignación en el momento en el que se carga XAML. Esto podemos aprovecharlo para cargar y modificar recursos en tiempo de ejecución, como veremos en un próximo post.

Otro punto interesante en este sencillo ejemplo de un menú es el acceso a recursos dentro de la plantilla aplicada a un elemento. En nuestro caso, la plantilla que aplicamos a nuestros botones define una Storyboard que queremos utilizar. La manera de hacerlo es la siguiente:

private void DoButtonMouseOver(Button origin)
{
    Storyboard mouseOver = (Storyboard)origin.Template.Resources["MouseOver"];
    mouseOver.Begin(origin, origin.Template);
}

Como vemos, necesitamos una referencia al objeto Button para acceder a los recursos de su plantilla y buscar la Storyboard que nos interesa, para después llamar a su método Begin. La particularidad aquí es que no es suficiente con pasarle como argumento el botón, puesto que la animación trabaja con objetos de la plantilla y no es capaz de encontrarlos, saludándonos con una bonita InvalidOperationException. Para ello existe una sobrecarga del método Begin que recibe tanto el elemento sobre el que se inicia la animación como la plantilla que la contiene.


Rock Tip. Siguiendo mi rutina habitual de añadir canciones sin ninguna relación con lo relatado, os presento hoy uno de los grupos que mejor capturan la esencia del Shock Rock abanderado por KISS, el conjunto liderado por Blackie Lawless W.A.S.P., con su canción (de genial videoclip) Wild Child. Enjoy!!

La nueva MSDN

O “Como obtener mas visitas en un blog gracias a un título levemente amarillista”. El caso es que no podemos hablar de una nueva MSDN, pero si de una nueva manera de acceder a su información de forma más sencilla y accesible. Microsoft mantiene diversas versiones de la MSDN para distintos soportes: dispositivos móviles, pantalla, impresión, etc. De un tiempo a esta parte se ha sumado una nueva versión “Low Bandwidth” creada para consumir menos ancho de banda. Para ello han eliminado gran cantidad de elementos pero intentando siempre mantener la información inalterable. El resultado? Una web mucho mas ligera y sencilla de consultar, como podéis comprobar vosotros mismos:

System.Object en la MSDN

System.Object en la MSDN Low Bandwidth

Para acceder a los artículos de MSDN de está forma solo tenéis que añadir a la URL la opción (loband) como en el segundo enlace, y además tendréis una opción en la esquina superior derecha de vuestras pantallas para establecerlo como modo por defecto.


Rock Tip. Danger Danger es un grupo de hard rock que por desgracia llego demasiado tarde, en esa triste época en la que aparecieron Nirvana y el grunge para acabar con todo lo bueno. Pese a todo, un grupo con un gran vocalista, un excelente guitarra y melodías muy pegadizas no puede quedar en el olvido (aunque de eso ya se encarga mi compañero Pablo Doval), así que rescatare para este post su clásico Rock America, que aunque suena bien en directo, suena mejor en un Corvette rojo descapotado…Enjoy!

Un sencillo menú en WPF: Estilos y Plantillas (I)

En el post anterior sobre la creación de un Motion Path desde Visual Studio, Julio Trujillo comentaba sobre la posibilidad de aplicar lo aprendido para la creación de un menú similar al de Silverlight.net. Lo que haremos será, en lugar de limitarnos a crear el menú, aprovecharlo para aprender alguna cosa nueva, en este caso, algo sobre estilos y plantillas.

Lo primero de todo es saber lo que es cada cosa. Un estilo (Style) no es mas que un conjunto de objetos de tipo Setter, pares de propiedad y valor, aplicados a los objetos de un tipo concreto. Es decir, un estilo nos permite definir un recurso compartido para mantener la coherencia de nuestra interfaz de usuario, abarcando tanto el aspecto visual (recursos, propiedades) como el comportamiento (triggers) de las instancias de un tipo concreto. Veámoslo con un ejemplo de nuestro proyecto.

    <Style x:Key="MenuButtonStyle" TargetType="{x:Type Button}">

<
Setter Property="HorizontalContentAlignment" Value="Center"/>
<
Setter Property="VerticalContentAlignment" Value="Center"/>
<
Setter Property="Padding" Value="1"/>
<
Setter Property="Template">
<
Setter.Value>
<
ControlTemplate TargetType="{x:Type Button}">
<
ControlTemplate.Resources>
<
Storyboard x:Key="MouseOver">…</Storyboard>
<
Storyboard x:Key="UnMouseOver">…</Storyboard>
<
Storyboard x:Key="Click">…</Storyboard>
<
Storyboard x:Key="UnClick">…</Storyboard>
</
ControlTemplate.Resources>
<
Grid x:Name="LayoutRoot">…</Grid>
</
ControlTemplate>
</
Setter.Value>
</
Setter>
</
Style>

Ahí podemos ver el estilo de los botones de nuestro menú (levemente editado para que no nos ocupe media página). Como vemos, le asignamos al estilo una clave (imprescindible para almacenarlo en un diccionario de recursos, como veremos después) y un tipo de destino, de manera que el estilo se aplicará automágicamente a todos los objetos de tipo Button. Además, establecemos las propiedades que queremos que compartan (alineación y padding entre otras) y la propiedad más interesante de todas: la plantilla (Template). Las plantillas controlan la estructura visual y el comportamiento de los controles en WPF, y son la clave de su flexibilidad a la hora de modificar el aspecto de nuestra aplicación. Si nos fijamos en el código anterior, dentro de la plantilla definimos una serie de recursos (storyboard) para su uso dentro de la misma, y le añadimos un Grid, con un contenido. En nuestro caso es el siguiente:

<Grid x:Name="LayoutRoot">
<
Rectangle Opacity="0" x:Name="MassiveGlow" StrokeThickness="0">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#00FFFFFF" Offset="0"/>
<
GradientStop Color="#BEFFFFFF" Offset="0.74"/>
<
GradientStop Color="#00FFFFFF" Offset="1"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
<
Rectangle Opacity="0" x:Name="Glow" StrokeThickness="0">
<
Rectangle.Fill>
<
LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<
GradientStop Color="#00FFFFFF" Offset="0"/>
<
GradientStop Color="#7FFFFFFF" Offset="0.74"/>
<
GradientStop Color="#00FFFFFF" Offset="1"/>
</
LinearGradientBrush>
</
Rectangle.Fill>
</
Rectangle>
<
Rectangle Opacity="0.795" HorizontalAlignment="Left" x:Name="LeftSeparator"
Width="1" Fill="#FFFFFFFF" Stroke="#FFFFFFFF" StrokeThickness="1"/>
<
Rectangle Opacity="0.795" HorizontalAlignment="Right" x:Name="RightSeparator"
Width="1" Fill="#FFFFFFFF" Stroke="#FFFFFFFF"/>
<
TextBlock HorizontalAlignment="Center" x:Name="NameTextBlockShadow"
VerticalAlignment="Center" FontSize="14" Foreground="#FF000000"
TextWrapping="Wrap" d:LayoutOverrides="Height"
Text="{TemplateBinding Content}" Margin="2,2,0,0"/>
<
TextBlock HorizontalAlignment="Center" x:Name="NameTextBlock"
VerticalAlignment="Center" FontSize="14" Foreground="#FFFFFFFF"
Text="{TemplateBinding Content}" TextWrapping="Wrap"/>
</
Grid>

Como podemos ver, dentro de ese Grid estamos redefiniendo por completo el aspecto visual de nuestro botón. Creamos dos rectángulos con un brillo para hacer efectos cuando el botón sea seleccionado, otros dos rectángulos como separadores laterales, y dos bloques de texto para el contenido del botón. Ya hemos visto como cambiar el aspecto visual de un elemento editando su estilo y su plantilla, y en el próximo post veremos como trabajar cómodamente con los recursos de nuestra aplicación.

 


 

Rock Tip. Aunque es muy común que un grupo musical realice versiones de otros temas adaptándolos con mayor o menor acierto a su estilo, no es tan común que un grupo metal, como los impactantes Turisas, se dedique a versionar a un grupo disco, como Boney M. Sin embargo, como de cambio de estilos precisamente estamos hablando, me parece mas que interesante resaltar este Rasputin. Enjoy!

Creando un Motion Path desde Visual Studio

En el post anterior vimos como crear un Motion Path desde Blend, y en este vamos a hacer lo mismo pero desde Visual Studio 2008, a base de código C#, como verdaderos programadores que somos. Comenzaremos creando un rectángulo idéntico al del ejemplo anterior.

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MotionPathVS.Window1"
x:Name="Window"
Title="Window1"
Width="640" Height="480">
<
Grid x:Name="LayoutRoot">
<
Rectangle HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Height="100"
Fill="#FFF50000" Stroke="#FF000000" x:Name="rect"/>
</
Grid>
</
Window>

Como vemos aquí, no necesitamos para nada el Path, que en nuestro primer ejemplo nos servía para establecer la ruta que seguiría el rectángulo. Y este será el único código XAML que veremos en este post, ya que toda la animación la construiremos, paso a paso, desde Visual Studio en C#. Así que empecemos. Lo primero que necesitamos es, valga la redundancia, crear la animación. Para ello crearemos un Storyboard al que añadiremos dos animaciones, una para desplazar el objeto por el eje X, otra para el eje Y.

Storyboard motion = new Storyboard();

DoubleAnimationUsingPath x = new DoubleAnimationUsingPath();
DoubleAnimationUsingPath y = new DoubleAnimationUsingPath();

motion.Children.Add(x);
motion.Children.Add(y);

Está animación tendrá que trabajar sobre la TranslateTransform del objeto que queremos desplazar, en este caso rect. Pero si nos fijamos en el código XAML, esa TranslateTransform no parece por ningún sitio, así que tendremos que crearla, asignársela a rect como RenderTransform y registrarla para que pueda ser utilizada por nuestra animación.

TranslateTransform translate = new TranslateTransform(0,200);
this.RegisterName("Translate", translate);
rect.RenderTransform = translate;

El próximo paso es construir el path que queremos que recorra nuestra animación. En este caso utilizaremos una Curva de Bézier, partiendo del punto (0, 200), finalizando en (500, 300) y con el punto de control en (150, 0). Esto generará de forma bastante sencilla una curva sobre la que desplazaremos el objeto entre los dos puntos.

PathGeometry geometry = new PathGeometry();
PathFigure figure = new PathFigure();
figure.StartPoint = new Point(0,200);
figure.Segments.Add(new QuadraticBezierSegment(new Point(150, 0), new Point(500, 300), false));
geometry.Figures.Add(figure);

Con esto tenemos los elementos básicos que necesitamos: la animación, la ruta y el objeto. Lo único que nos queda es relacionarlos entre sí. Utilizamos los métodos estáticos de la clase Storyboard para establecer en cada una de las animaciones el objeto y la propiedad del mismo con la que trabajaran. Con SetTargetName indicamos que ambas animaciones trabajaran sobre la transformación que registramos antes, y con SetTargetProperty hacemos que cada una de ellas trabaje con el eje correspondiente.

Storyboard.SetTargetName(x, "Translate");
Storyboard.SetTargetProperty(x, new PropertyPath(TranslateTransform.XProperty));
Storyboard.SetTargetName(y, "Translate");
Storyboard.SetTargetProperty(y, new PropertyPath(TranslateTransform.YProperty));

Después, añadimos a cada una de las animaciones el path que creamos anteriormente, y les indicamos que tendrán que utilizar como fuente el eje que les toque.

x.PathGeometry = geometry;
y.PathGeometry = geometry;

x.Source = PathAnimationSource.X;
y.Source = PathAnimationSource.Y;

Por último, añadimos una serie de atributos, más o menos esenciales, para dar forma a nuestra animación. Establecemos la duración de la misma en un segundo, hacemos que se repita indefinidamente para poder observar el efecto, y establecemos un ratio de deceleración de 0’3. Esto sirve para indicarle a la animación que el primer 70% del tiempo debe mantener una velocidad constante, y el 30% final debe decelerar, dándole un aspecto más real.

y.Duration = TimeSpan.FromMilliseconds(1000);
x.Duration = TimeSpan.FromMilliseconds(1000);

y.DecelerationRatio = 0.3;
x.DecelerationRatio = 0.3;

motion.RepeatBehavior = RepeatBehavior.Forever;

Con esto tenemos ya nuestra animación lista (podéis verla en el proyecto adjunto), y con el mismo método podemos crear todo tipo de animaciones para aplicar a nuestros objetos, sin necesidad de depender de Blend para nada.


Rock Tip. Ya que en el anterior hablábamos de Heavy Metal clásico, que mejor que traer hoy a los que son a juicio de muchos los más grandes del género, Manowar. Desde luego, tienen el honor de ser los que más ruido hacen encima de un escenario. De su último disco, Gods of War, llega este King of Kings para cerrar este post. Enjoy!

Creando un Motion Path desde Blend

Reconozcámoslo. No tengamos miedo. Sabemos que es algo para lo que no estamos preparados, pero es así: a veces tendremos que hacer trabajo de diseñadores. No hay mas que hablar, llegara un momento en el que tendremos que remangarnos y abrir Expression Blend, y no queda bien que un programador hecho y derecho se ponga a llorar como un bebe al verlo. Paletas de colores, elementos visuales…yuyu mayúsculo. Hoy haremos algo tremendamente sencillo, tanto que casi nos dará vergüenza al verlo.

Utilizaremos la opción “Convert to Motion Path” para crear una asociación entre un UIElement y un Path, de tal manera que el primero se desplace de forma automágica siguiendo la ruta marcada por el segundo. Empezamos creando un horrible rectángulo rojo, que llamaremos rect, y un sencillo path que sigue una línea recta.

canvas

Despues, seleccionamos el path y elegimos en el menú de Blend la opción Object –> Path –> Convert to Motion Path.

 menu

Fácil, sencillo y para toda la familia. Vamos a echarle un ojo al XAML que genera, a ver si vemos algo interesante.

<Storyboard x:Key="MotionPath">
<
DoubleAnimationUsingPath BeginTime="00:00:00" Duration="00:00:02" Storyboard.TargetName="rect"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"
Source="X">
<
DoubleAnimationUsingPath.PathGeometry>
<
PathGeometry Figures="M25.5,166.5 L171,40 361,181 499,166.5"/>
</
DoubleAnimationUsingPath.PathGeometry>
</
DoubleAnimationUsingPath>
<
DoubleAnimationUsingPath BeginTime="00:00:00" Duration="00:00:02" Storyboard.TargetName="rect"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)"
Source="Y">
<
DoubleAnimationUsingPath.PathGeometry>
<
PathGeometry Figures="M25.5,166.5 L171,40 361,181 499,166.5"/>
</
DoubleAnimationUsingPath.PathGeometry>
</
DoubleAnimationUsingPath>
</
Storyboard>

Como vemos, la opción Convert to Motion Path nos crea automágicamente un Storyboard, con una duración de dos segundos, y dos DoubleAnimationUsingPath, que actuaran respectivamente sobre TranslateTransform.X y TranslateTransform.Y del objeto rect (el rectángulo rojo que queremos desplazar). Lo más interesante es que una vez creado el Storyboard, el Path que seleccionamos para crearlo se copia en ambas animaciones, y ya no es necesario que lo mantengamos en el árbol visual. Esto también conlleva que, si queremos modificar la ruta que seguirá nuestro elemento, tendremos que modificar la animación, no el path original. Para ello no tenemos mas que abrir la animación y seleccionar el elemento animado.

animation

 

 

 

Vemos como tenemos una animación de traslación, que podemos extender en el tiempo si queremos, y como tenemos también una línea punteada que nos indica el path que se esta siguiendo actualmente. Si quisiéramos modificarlo, sería tan sencillo como utilizar la herramienta Pen y añadirle un par de nodos, para posteriormente desplazarlos con la herramienta de selección directa.

animation2

Y con esto, ya hemos aprendido a hacer…una tontería. Tontería que, sin embargo, os servirá a vosotros para construir de manera sencilla animaciones mucho mas complejas, y a mí para poder hacer otro post explicando como hacer lo mismo desde Visual Studio 2008, con mucho mas texto, muchas menos imágenes y mucha mas diversión 😉


Rock Tip. Mis compañeros Pablo Álvarez y Octavio Hernández tienen la buena costumbre de cerrar sus (magníficos) posts con un (no menos magnífico) Rock Tip, recomendando grandes temas a menudo olvidados. Como yo no puedo ser menos, aquí va el de hoy. No nos vamos a remontar muy atrás en el tiempo, con un disco de este mismo año, aunque parezca salido de los 80…heavy metal clásico, venido de Polonia, y cantado por una mujer, Doro style. Crystal Viper, con su “The Anvil of Hate” cierran el post de hoy. Enjoy!

Search Connectors en Windows 7

Una de las nuevas características de Windows 7 es el soporte a la denominada Federated Search que nos permite, por ejemplo, agregar proveedores de busqueda a Windows Explorer para realizar consultas sobre sitios web (Search Connectors). Gracias a esta característica, podemos integrar en Windows Explorer nuestras busquedas en servicios tan diversos como Google, flickr, Wikipedia, etc. sin falta de abrir una ventana de nuestro navegador web. Es más, una vez realizada la busqueda podemos no solo consultar los resultados, sino abrirlos, imprimirlos y demas operaciones básicas. Podríamos, por ejemplo, buscar “Las Meninas” en la página web de la Wikipedia e imprimir el resultado sin falta de abrir nuestro navegador en ningún momento!

Microsoft ha publicado una guia para implementar Search Connectors, eso si, en ingles, que nos ayudara a crear los nuestros sin mucha dificultad, ya que en el fondo no son mas que un archivo xml de pocas lineas. Para que veais lo sencillo que es, he creado uno para realizar busquedas aqui, en geeks.ms. Si lo descomprimis y abris el archivo .osdx con cualquier editor de texto os dareis cuenta de lo sencillo que es 😉

Y recordad, esto solo funciona en Windows 7! Enjoy!