jueves, 31 de mayo de 2007 20:18
jonas
WPF: simulando Aero Glass en Windows XP
Uno de los grandes cambios de Windows XP a la versión de
Windows Vista es el nuevo sistema gráfico que éste último incorpora, el cual ha
sido denominado Aero. Se puede decir que Aero de divide en dos niveles, Aero
Basic que ya incorpora una diferencia sustancial respecto a la interfaz gráfica
de Windows XP y, Aero Glass (que no esta soportado por la versión “Home Basic”)
proporciona una funcionalidad mayor como la aplicación de efectos de cristal a
las ventanas o una gestión avanzada de las mismas, a parte de la experiencia
visual que puede resultar más o menos gratificante dependiendo de los gustos
particulares de cada uno.
Aero Glass hace que los bordes de nuestras ventanas hagan
uso de transparencias para dar la sensación de cómo si estuviésemos viendo a
través de un cristal, que tengamos vistas en miniatura de las aplicaciones que
aparecen minimizadas en la barra de tareas o Windows Flip y Flip 3D. Esta
funcionalidad queda expuesta a través de
DWM (Desktop Windows Management) que es quien se encarga de componer la
apariencia que tiene el escritorio en cada momento. Para poder ofrecer al usuario todo esto se
hace uso directo de las aceleradoras gráficas, aquí es donde aparece el WDDM (Windows
Display Diver Model), esta es la interfaz con la que DWM hace uso de los
recursos de las tarjetas gráficas, así que si no disponemos de una gráfica más
o menos reciente que soporte WDDM nos quedaremos sin "apreciar" todos estos
efectos visuales. Se puede trabajar directamente con DWM
pero es solo una posibilidad disponible para Vista, aun así, puesto que
disponemos del Framework 3.0 en Windows XP y haciendo uso de WPF podemos
simular este efecto de transparencia para los bordes de nuestras ventanas,
aunque eso sí, no con la misma espectacularidad.
Vamos a trabar con Blend, así que creamos un nuevo proyecto de aplicación y listos para empezar con esto. Lo primero que tenemos que hacer
es eliminar el típico marco de las aplicaciones de escritorio de XP. Para ello,
en el objeto Window activamos la propiedad AllowsTransaprency, esto hará que
automáticamente la propiedad WindowStyle cambie a None, a parte queremos darle
a nuestra ventana el aspecto de borde redondeado con lo que tendremos que
cambiar el valor de la propiedad Background a un color transparente así no aparecera un pico en las esquinas con el color de fondo de la ventana. El código
quedaría en xaml del siguiente modo:
AllowsTransparency="True"
WindowStyle="None"
Background="#00FFFFFF">
La ventana contiene un Grid en el que vamos a introducir un
objeto de tipo Border que hará de marco de nuestra ventana y que pintaremos con un degradado.
Para darle una apariencia más vistosa en realidad vamos a utilizar dos objetos
border con un degradado diferente cada uno, de este modo el degradado no
resultará tan "líneal", podemos usar los colores que más nos gusten y además
tendremos que hacer uso de la componente alfa de los colores que formen parte
del degradado para permitir ver lo que hay por detrás, es decir, darle transparencia al degradado. También modificaremos la
propiedad CornerRadius para suavizar las esquinas:
<Grid
x:Name="LayoutRoot">
<Border Margin="0,0,0,0" CornerRadius="5,5,5,5" ...>
<Border.Background>
<LinearGradientBrush>
…
</LinearGradientBrush>
</Border.Background>
</Border>
<Border Margin="0,0,0,0" CornerRadius="5,5,5,5" ...>
<Border.Background>
<LinearGradientBrush>
…
</LinearGradientBrush>
</Border.Background>
</Border>
</Grid>
El resultado es el siguiente:

Podemos observar como se ve lo que hay por detrás de lo que será nuestra ventana. El siguiente paso es definir el aérea cliente e incorporar
un icono, el titulo de la ventana y los botones para poder minimizar, maximizar
y cerrar. Se puede hacer de diferentes modos, pero lo haremos añadiendo un elemento
de tipo DockPanel al que llamaremos rootDockPanel que a su vez contendrá un Grid (llamado areaClienteGrid) para definir el area de cliente de la ventana y
otro DockPanel (llamado barraDockPanel) fijado en la parte superior (Top) del
primero para hacer de contenedor del titulo de la ventana y los botones para
minimizar, maximizar y cerrar. Un contenedor de tipo DockPanel coloca los
elementos que contiene en la parte de arriba, abajo, izquierda o derecha. Los
elementos se colocan según el orden que aparezcan en el código xaml pero también
podemos definir de forma explícita la ubicación de los elementos. Este
contenedor tiene una propiedad llamada LastChildFill mediante la que podemos
determinar si el último elemento agregado a DockPanel ocupa todo el espacio que
queda libre o no. Como dije antes, el contenerdor que alberga la barra de
titulo lo fijaremos en la parte superior y al tener activada la propiedad LastChildFill
el grid que representa el area de cliente ocupará el espacio restante
disponible.

En la imagen superior está la jerarquía completa de todos
los elementos que forman la ventana. El icono de la ventana y el titulo se
encuentran dentro de un StackPanel (llamado tituloStackPanel) que esta alineado
a la parte izquierda del elemento que lo contiene (barraDockPanel). El
StackPanel es un contenedor que premite colocar los elementos que contiene uno
seguido detrás de otro de forma tanto horizontal como vertical. Lo mismo
haríamos con el StackPanel (llamado botonesStackPanel) que contiene los botones
de minimizar, maximizar y cerrar. El resultado final es el siguiente:

Ahora solo nos queda añadir los eventos que nos permitan
interactuar con la ventana. Para permitir que la ventana cambie de tamaño basta
con establecer la propiedad ResizeMode a CanResizeWithGrip del objeto Window.
Para añadir un evento basta con seleccionar el elemento al que queremos
añadirle el evento y acceder a todos los eventos que tiene a través del panel
de propiedades de Blend. Haciendo doble click en uno de los eventos automáticamente
se lanza Visual Studio para añadir el código al evento. El código de todos los eventos es trivial, pero es
interesante ver el código del evento que permite desplazar la ventana por el
escritorio:
private void
borderTop_MouseLeftButtonDown(object sender,
System.Windows.Input.MouseButtonEventArgs e)
{
object o = e.OriginalSource;
if (o is Border)
this.DragMove();
}
WPF incorpora un nuevo modelo para la gestión de eventos que
permite que la respuesta a un evento se propague a través de la jerarquía de
controles. En el código de arriba lo que hacemos es controlar el origen del
evento para ver si fue el borde quien produjo el evento MuseLeftButtonDown. Si
no controlamos quien originó el evento y probamos a mover la ventana pinchando
en el área blanca, el grid, como esta en la jerarquía de otro objeto que si
controla ese mismo evento (el borde) la ventana se movería, pero ese no es el
resultado que deseamos.
A parte de lo ya expuesto, hay otras propiedades con las que
he jugado como margen, padding… para que los elementos tengan la apariencia y
la ubicación que deseaba pero las más importantes han sido decritas. Adjunto el
código para que le deis un vistazo a todo eso y juguéis con él, si os apetece.