0% encontró este documento útil (0 votos)
258 vistas

WPF

WPF permite dos modelos de aplicación: 1) Aplicaciones de Windows tradicionales que se encapsulan en una clase Application y 2) Aplicaciones de navegación que funcionan de forma similar a sitios web, permitiendo navegar entre páginas mediante enlaces. WPF también provee clases y eventos para controlar el ciclo de vida, navegación y estado de las aplicaciones.

Cargado por

renness_777
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
258 vistas

WPF

WPF permite dos modelos de aplicación: 1) Aplicaciones de Windows tradicionales que se encapsulan en una clase Application y 2) Aplicaciones de navegación que funcionan de forma similar a sitios web, permitiendo navegar entre páginas mediante enlaces. WPF también provee clases y eventos para controlar el ciclo de vida, navegación y estado de las aplicaciones.

Cargado por

renness_777
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 114

Apartado IV:

Windows
Presentation
Foundation
por Luis Alfonso Rey

296 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 297

Prlogo
Apartado IV
Para mi mujer y mis hijos, que son mi inspiracin para hacer todos los das,
lo que hago.
Dado el carcter introductorio y no enciclopdico del libro, las siguientes
pginas pretenden ser una presentacin ms o menos detallada de lo que es
WPF pero no exhaustiva. Esto sita este libro en el mbito de los manuales
prcticos y no en el de los libros de referencia.
La segunda advertencia que hay que realizar es que todos los ejemplos del
libro han sido realizados con la versin de Visual Studio 2010 ltimate y esto
puede presentar alguna discrepancia si se trata de seguir el libro con versiones
diferentes, evidentemente si estas lo son en cuanto a la versin, en ocasiones
estas discrepancias pueden ser ms evidentes.
Dicho esto y antes de entrar en materia, vamos a explicar qu es WPF. Muchos
de los lectores ya lo sabrn en mayor o menor medida, razn por la cual estn
leyendo este libro, pero para aquellos que no lo tengan claro empezaremos
diciendo que Windows Presentation Foundation es una tecnologa para crear
Gua prctica de desarrollo de aplicaciones Windows en .NET

298 | Windows Presentation Foundation

interfaces de aplicacin, que trata de aunar los diferentes interfaces posibles


(formularios, 3D y Web) mediante una sola API de programacin.
La primera versin de WPF se lanza dentro del Framework 3.0 de .NET, pero
en las sucesivas versiones 3.5, 3.5 SP 1 y 4.0 se van incluyendo novedades, no
solo a nivel tecnolgico sino tambin de producto, bsicamente en Visual Stuio
y Blend, que nos permiten paulatinamente mejorar la experiencia de
desarrollo, que inicialmente era muy pobre, hasta en convertirla en algo
bastante sencillo, agradable y potente.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 299

El Modelo De
Aplicacin
Al empezar lo mejor es hacerlo por el principio, y este en Windows es hablar de
qu tipo de aplicaciones se pueden crear con WPF.
Estas pueden ser bsicamente dos, aplicaciones Windows y aplicaciones de
Navegacin.

Aplicaciones de Windows
Las primeras son ms convencionales y en cuanto al modelo de aplicacin se
puede decir que muy similares a sus primas de WinForms.
Las aplicaciones Windows est encapsuladas en una clase de tipo Application,
esta clase es la responsable de crear y gestionar la vida de la aplicacin,
devolver los cdigos de salida, procesar los parmetros de lnea y en ocasiones
gestionar la navegacin.

Gua prctica de desarrollo de aplicaciones Windows en .NET

300 | Windows Presentation Foundation

La aplicacin se ejecuta mediante el mtodo Run que lanza el evento StartUp.


Durante la vida de la aplicacin el usuario puede intercambiar la aplicacin
activa, la cual posee el foco, y esto puede provocar el lanzamiento de los
eventos Deativated, cuando se pierde el foco y Activated, cuando se vuelve a
obtener.
Otro evento sumamente til relacionado con la aplicacin es
DispatcherUnhandledException, dicho evento el lanzado antes de que una
excepcin no manejada sea transmitida al usuario causando con ello la
inestabilidad de la aplicacin.
El proceso de cierre es quiz el ms complejo, ya que involucra el mtodo
Shutdown que cierra la aplicacin, as como varios eventos como Exit que es
lanzado cuando la aplicacin trata de cerrarse, dndonos la oportunidad a
travs de la estructura ExitEventArgs y la propiedad ApplicationExitCode de
devolver un cdigo de salida. Adems las aplicaciones se pueden cerrar por
sucesos indirectos, como por ejemplo que la sesin de la mquina se cierre.
Para este caso la aplicacin nos provee de un evento SessionEnding que
mediante la estructura SessionEndingCancelEventArgs nos permite cancelar
el cierre de sesin programticamente.
Para ilustrar lo anterior lo nico que tenemos que hacer es crear un nuevo
proyecto de tipo XAML application, visualizar la ventana de propiedades en
Visual Studio, buscar y abrir el archivo App.xaml o Application.xaml y
depositar el cursor sobre la tag de Xml <Application. Una vez hecho esto en la
ventana de propiedades podemos observar las propiedades y eventos de la
aplicacin, precisamente en el evento Exit situaremos el siguiente cdigo:
Visual Basic.NET
Private Sub Application_Exit(ByVal sender As
System.Object, ByVal e As
System.Windows.ExitEventArgs) Handles MyBase.Exit
MessageBox.Show("Adios")

EndSub
C#
private void Application_Exit(object sender,
ExitEventArgs e)
{
MessageBox.Show("Adios");

}
Tras la ejecucin la aplicacin mostrar un cartel cada vez que la cerremos.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 301

Aplicaciones de navegacin
Las aplicaciones de navegacin son un nuevo modelo de aplicaciones
propuestas por WPF que pueden resultar muy interesantes. Se caracterizan
fundamentalmente por el estilo que tienen de transitar entre su ventanas, o
tambin llamadas pginas. El trnsito se produce de una manera muy similar a
como se produce en las aplicaciones Web, mediante enlaces y mtodos que nos
remiten a una URI. Adems estas aplicaciones tambin tienen un servicio de
navegacin que recuerda los sitios visitados y nos permite retornar a ellos,
del mismo modo que en una aplicacin Web.
Habitualmente estas aplicaciones se ejecutan dentro del navegador, usando en
algunos casos los propios controles para manejar resortes de su mecanismo de
navegacin. Esto merece una explicacin ms detallada, que la aplicacin se
ejecute dentro del navegador no significa que sea una aplicacin Web. De
hecho no lo es en absoluto, es una aplicacin Windows que se ejecuta alojada
en el navegador y que necesita, como las aplicaciones Windows, que el
Framework se encuentre instalado en la mquina. En esto difieren de las
aplicaciones Silverlight, que se ejecutan dentro del mbito del navegador pero
no necesitan el Framework sino un Plug-in que hace las veces de ejecutor.
Adems tambin se consideran aplicaciones de navegacin aquellas
aplicaciones Windows de WPF pero que hacen uso de la clase
PageFunction<t> o PageFunction(Of t).
Para ejemplificar estas aplicaciones podemos crear una nueva WPF
Application y en ella agregar una nueva Page Function. Dentro de la etiqueta
<Grid> podemos situar el siguiente cdigo:
XAML

<TextBlock>Pruebadenavegacin</TextBlock>
Posteriormente en la ventana principal MainWindow.xaml depositar un nuevo
botn desde la ToolBox y tras hacer doble clic sobre l, insertar en el cuerpo
del gestor del evento asociado:
Visual Basic.NET
Private Sub Button1_Click(ByVal sender As
System.Object, ByVal e As
System.Windows.RoutedEventArgs) Handles Button1.Click
Dim wizard As New NavigationWindow()
wizard.Source = New Uri("PageFunction1.xaml",
UriKind.Relative)
wizard.ShowDialog()

EndSub
Gua prctica de desarrollo de aplicaciones Windows en .NET

302 | Windows Presentation Foundation

C#
private void button1_Click(object sender,
RoutedEventArgs e)
{
NavigationWindow wizard = new
NavigationWindow();
wizard.Source = new Uri("PageFunction1.xaml",
UriKind.Relative);
wizard.ShowDialog();

}
En el caso de las aplicaciones de navegacin la clase Application se sustituye
por su derivada NavigationApplication que nos provee de los servicios y
miembros necesarios para articular una aplicacin de navegacin.
El primer miembro del que hablaremos ser una propiedad, StartUpURI que
nos permite especificar la pgina de inicio de la aplicacin. Para dar soporte a
la posterior navegacin la aplicacin contiene un NavigationService. Este
servicio no controla la pgina que actualmente se est mostrando sino el
camino que se ha seguido para alcanzarla. Acceder a l es algo oscuro, se hace
a travs del mtodo GetNavigationService que exige un parmetro de tipo
DependantObject, que ahora es precipitado explicar pero, que para entenderlo
rpidamente es un objeto de WPF. En ese sentido el mecanismo ms fcil de
satisfacer este parmetro es utilizando un formulario o un control dentro de
este. Una vez obtenido este servicio l nos provee de mtodos como GoBack o
GoFoward para movernos por el historial o Navigate que nos permite dar un
salto incondicional a una pgina cualquiera de la aplicacin.
De vuelta a la NavigationApplication no debemos olvidar que esta nos
provee de ciertos eventos para controlar la navegacin como Navigating,
Navigated, NavigationProgress, NavigationFailed, NavigationStopped y
LoadCompleted, todos ellos destinados a controlar los diferentes estados por
los que pasa la aplicacin tanto durante la navegacin como en funcin del
resultado de esta.
Para crear una de estas aplicaciones hemos de seleccionar una plantilla
diferente, en concreto WPF Browser Application. Un cdigo de ejemplo para la
invocacin de un mtodo de navegacin podra ser este:
Visual Basic .NET

NavigationService.GetNavigationService(Me).Navigate(New
Uri("Page1.xaml",UriKind.Relative))

C#

NavigationService.GetNavigationService(this).Navigate(new
Uri("Page1.xaml",UriKind.Relative));
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 303

Conclusin
WPF nos ofrece diferentes modelos de aplicacin, que nos permiten
adaptarnos mejor a situaciones en las cuales un interfaz es mejor entendido, o
presenta ventajas que nos permiten mejorar procedimientos como el
despliegue o el control de la seguridad.

A continuacin
En el captulo siguiente trataremos la especificacin XAML, que nos servir
para que de manera declarativa podamos crear interfaces. Adems trataremos
algunos aspectos bsicos de XML con el fin de facilitar la compresin de aquel
lector que est menos familiarizado con ellos.

Gua prctica de desarrollo de aplicaciones Windows en .NET

304 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windo
ows Presenttation Foun
ndation | 305

XA
AML
L
En ell epgrafe an
nterior hemo
os comprobaado como un
na determinada
caraccterstica differencia susttancialmentte WPF del resto
r
de apliccaciones .NE
ET,
el XA
AML. Digo diferencia
d
au
unque existe n otros tipos de aplicaciiones que
utilizzan formulacciones simila
ares. Sin em
mbargo es inn
negable que a simple vissta
el XA
AML se aplicca de manera nica a estte tipo de prroyectos.
Pero,, qu es exa
actamente XAML?,
X
puess un acrnim
mo de eXten
nsible
Appliication Mark
kup Langua
age esto es, u
un XML para
a definir aplicaciones. L
Las
defin
ne a modo dee formato de
e serializacin de objeto
os, lo que quiere decir qu
ue
nosottros escribim
mos un XML
L que posterriormente seer ledo e in
nterpretado de
form
ma que cada elemento
e
de
entro de l see
conveertir en un objeto denttro de la
aplicaacin, y gen
neralmente dentro
d
de un
na
ventaana o pgina
a.
Este proceso pueede sonar mu
uy similar al que
se prroduce con el
e HTML porrque de hech
ho lo
es. Esspecficamente se han buscado
b
las
ventaajas de cada uno de los entornos
e
de
desarrrollo para conformar
c
WPF
W y en estte caso la ven
ntaja princip
pal es la
separracin efectiiva que nos permite
p
estee modelo, dee forma que desarrollad
dor y
dise
ador pueda
an trabajar sobre la mism
ma ventana de manera separada
s
y
coinccidente o no, en el tiemp
po.

Gua prctica de
e desarrolllo de aplica
aciones Win
ndows en .N
NET

306 | Window
ws Presenta
ation Found
dation

Ms een detalle un
n fichero XA
AML es un fiichero XML
L y aunque ca
asi todo el
mund
do compren
nde bien cm
mo funciona un fichero XML
X
aqu va
amos a inverrtir
unas lneas para que posterio
ormente tod
do se entiend
da correctam
mente.

XM
ML
Fueraa de explicacciones hist
ricas, podem
mos decir qu
ue un fichero
o XML es un
n
fichero de texto formado
f
porr marcas y q
que al menoss ha de estarr bien
form
mado.
bien formado
o se entiend
de:
Por b
1.

Q
Que los docu
umentos han
n de manten
ner una estru
uctura estrictamente
jeerrquica.

2. Q
Que los docu
umentos han
n de tener un
n solo elemeento raz.
3. Q
Que los atrib
butos siemprre deben maarcar su conttenido entre
e comillas.
4. Q
Que es sensib
ble a maysculas y min
sculas.

Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windows Presentation Foundation | 307

Representacin
En XAML tienen representacin casi todas las clases relacionadas con WPF, y
se usan por tanto para establecer que objetos van a componer una ventana, por
ejemplo.
Dentro de un archivo XAML los elementos representan objetos mientras que
los atributos propiedades. Esto sera por tanto un botn con una anchura de
30 y de color Rojo:
XAML
<Button Width=30 Background="Red" />

Sin embargo esta sintaxis tambin sera vlida:


XAML
<Button>
<Button.Background>
Red
</Button.Background>
</Button>

En este caso la propiedad est representada como un elemento anidado y no


como un atributo. Esto es as para poder insertar adems de contenidos
simples en las propiedades, valores mucho ms complejos:
XAML
<Button>
<Button.Background>
<LnearGradientBrush>
<GradientStopCollection>
<GradientStop Offset="0"
Color="White" />
<GradientStop Offset="1"
Color="Red" />
</GradientStopCollection>
</LnearGradientBrush>
</Button.Background>
</Button>

Adems como se puede ver en ocasiones el nombre de la propiedad est


precedido por el de la clase Button.Background y en otras no.
GradientStopCollection generalmente quiere decir que la propiedad cuando va
precedida es que es una propiedad de la clase u objeto, mientras que en el
segundo es tan solo un contenido compatible con el exigido por el tipo de la
propiedad.
Gua prctica de desarrollo de aplicaciones Windows en .NET

308 | Windows Presentation Foundation

Existen tambin otro tipo de propiedades bastante curiosas, echemos un


vistazo al ejemplo:
XAML
<Grid>
<Button x:Name=Button1 Grid.Column=0/>
</Grid>

La propiedad x:Name en realidad es la propiedad Name, como cabra esperar,


pero originalmente la especificacin XAML estableca unas cuantas
propiedades que se encontraban precedidas por x: (actualmente ya no es
necesario escribir x:), estas propiedades generalmente estaban referidas con la
meta-programacin.
Cosa diferente es la propiedad Grid.Column, que para una persona que
comience a usar esta tecnologa puede resultar de lo ms extraa. Se conocen
por el nombre de attached properties o propiedades adjuntas, que
bsicamente permite incluir propiedades definidas en una clase, en este caso
Grid, en otras, el botn. Con ello conseguimos que el botn reaccione
contextualmente en este caso al situarse en una columna numerada con 0 y
definida en el Grid que lo contiene.

Sistema de propiedades y eventos


Conseguir el efecto de las attached properties as como otras muchas ventajas
como el binding, los estilos, etc. Se debe principalmente a las conocidas como
Dependency Properties. Las propiedades dependientes son propiedades que
estn respaldadas por lo que se conoce como WPF Property System y podran
definirse como, propiedades que se computan teniendo en cuenta elementos
externos, como estilos, otras propiedades, la situacin del control, etc. As si
un botn se encuentra dentro de un panel que modifica su posicin o tamao
al aplicarle alguna lgica de distribucin, las propiedades que tienen que ver
con estas caractersticas del control se vern afectadas por el panel y su lgica
de distribucin.
Una propiedad dependiente tiene un aspecto como este:
Visual Basic .NET
Public Shared ReadOnly NombreProperty As
DependencyProperty =
DependencyProperty.Register("Nombre",
GetType(Tipo))
Public Property Nombre() As Tipo
Get
Return CType(GetValue(NombreProperty), Tipo)
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 309


End Get
Set(ByVal value As Tipo)
SetValue(NombreProperty, value)
End Set
End Property

C#
public static readonly DependencyProperty
NombreProperty =
DependencyProperty.Register(
"Nombre", typeof(Tipo),
);
public bool Nombre
{
get { return (Tipo)GetValue(NombreProperty); }
set { SetValue(NombreProperty, value); }
}

Como se puede observar la propiedad se declara de manera similar, la


diferencia estriba en que el campo de respaldo es muy extrao. De hecho
siempre es DependencyProperty, este tipo es el tipo que permite que el valor
de la propiedad est respaldado en el sistema de propiedades. Luego en la
propia definicin hay que especificar el tipo y como se ve, establecer un
nombre al cual asociarlo, de esta manera podemos tener ms de un campo del
mismo tipo.
Adems el nombre del campo suele ser idntico al nombre de la propiedad que
lo usa, esto es una convencin, ms la frmula Property.
Acceder al valor de este campo tampoco es sencillo, leerlo se logra mediante el
mtodo GetValue, que devuelve un objeto que luego deberemos de convertir al
tipo deseado. Escribir por tanto se hace mediante otro mtodo llamado
SetValue. Pero, de dnde salen estos mtodos? Bien salen de la clase
DependencyObject, clase de la cual es obligatorio que descienda cualquier
clase que pretenda tener propiedades dependientes.
Otra de las rarezas de WPF son los Routed Events. Si una propiedad
dependiente nos permite propiedades que tienen en cuenta el entorno a la
hora de calcularse, un evento enrutado es muy similar en concepto pero
referido a los eventos. Sin embargo la razn es si cabe ms fcil de entender.
XAML
<Grid>
<Button x:Name=Button1 Grid.Column=0/>
</Grid>

Gua prctica de desarrollo de aplicaciones Windows en .NET

310 | Windows
s Presentattion Found
dation

Pensemos por un
n momento una situacin que es mu
uy comn en
n WPF y en
otross sistemas dee programaccin, un botn dentro dee un panel. Comnment
C
te
en cu
ualquier sisteema de prog
gramacin aal hacer clic sobre
s
el bot
n no tenem
mos
dudaa de que el evvento a gestiionar es el C
Click del bot
n. Esto es as
a porque
estam
mos ante lo que
q se llama
a un evento d
directo, slo
o salta en el receptor
r
dirrecto
del eestmulo.
Sin eembargo esto
o no es as en
n los eventoos enrutadoss. En estos ell estmulo ess
propaagado a lo la
argo de todo
os los controoles de la jerarqua, o sea
a, en el ejem
mplo
tanto
o en el botn
n como en ell panel. Peroo para qu sirve
s
esto? Esto
E
permitee
articu
ular una carracterstica de
d WPF que es la capacidad de crearr controles
comp
plejos anidan
ndo otros ms
m simples, cosa que exploraremos ms adelan
nte.
De heecho y para complicarlo
o ms, la estrrategia de prropagacin no es para
todoss los eventoss igual. En algunos
a
casoos ante el clicc al botn el estmulo seera
enviaado primero
o al contened
dor ms geneeral, el paneel, denomina
ando esta
estraategia Tunneel y en ocasio
ones al conteenedor ms concreto, denominandoo en
este ccaso Bubble.

Com
nmente loss eventos de tipo Tunneel se nombra
an empezand
do por la
palab
bra Preview.. Los eventos enrutados tambin suelen ir en pa
arejas, as all
PreviiewMouseLeftButtonDo
own le correesponde un MouseLeftB
M
ButtonDown
n.
Cuan
ndo sobre un
n control se produce
p
un estmulo, po
or ejemplo un
u clic, este ees
propaagado primeero siguiend
do la estrateggia Tunnel, para
p
luego continuar
c
coon la
Bubb
ble. Todas ellla comparte
en la misma instancia dee evento que
e se propagaa a lo
largo
o de todos los eventos.

Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windows Presentation Foundation | 311

Esta cadena se puede finalizar, dando el evento por gestionado, en algn punto
tan solo estableciendo la propiedad Handled a True, propiedad localizada en la
estructura EventArgs correspondiente del evento.
Visual Basic .NET
Public Shared ReadOnly EventoEvent As RoutedEvent =
EventManager.RegisterRoutedEvent("Evento",
RoutingStrategy.Bubble, GetType(RoutedEventHandler),
GetType(TipoClase))
Public Custom Event Evento As RoutedEventHandler
AddHandler(ByVal value As RoutedEventHandler)
Me.AddHandler(EventoEvent, value)
End AddHandler
RemoveHandler(ByVal value As RoutedEventHandler)
Me.RemoveHandler(EventoEvent, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As
RoutedEventArgs)
Me.RaiseEvent(e)
End RaiseEvent
End Event

C#
public static readonly RoutedEvent EventoEvent =
EventManager.RegisterRoutedEvent(
"Evento", RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(TipoClase));
public event RoutedEventHandler Evento
{
add { AddHandler(EventoEvent, value); }
remove { RemoveHandler(EventoEvent, value); }
}

Como se puede comprobar la analoga entre la declaracin del evento y de la


propiedad son muy similares, si acaso destacar que el tipo en este caso es
RoutedEvent, que se incluye como ltimo parmetro de la clusula register, el
tipo de la clase que contiene el evento y que los eventos para acceder al campo
son AddHandler y RemoveHandler, como por otro lado cabra esperar.

Gua prctica de desarrollo de aplicaciones Windows en .NET

312 | Windows Presentation Foundation

Controles y sus propiedades ms


comunes
Como la mayora de los sistemas de programacin, el nmero de controles ha
crecido tanto que es prcticamente imposible ni tan siquiera mencionarlos, sin
embargo sigue siendo necesario conocer algunos para poder comenzar. An a
riesgo de convertir esto en una enumeracin, vamos a mencionar algunos aqu
y posteriormente dedicaremos algunas lneas a explicar propiedades y eventos
comunes y situar al lector con un conocimiento inicial suficiente para
comprender los ejemplos siguientes. Tmese si se quiere esta seccin como
una seccin de posterior consulta.

Layout

Los controles Layout se utilizan para controlar el tamao, la posicin y la


disposicin de los elementos hijos.

Border

Dibuja un borde, un fondo o ambos alrededor de otro elemento.

Canvas

Define un rea donde posicionar elementos por coordenadas relativas al


control canvas.

DockPanel

Define un rea donde situar elementos horizontal o verticalmente, relativos a


otros.

Grid

Define una rejilla donde situar los controles en funcin de filas y columnas.

GroupBox

Es un control que contiene otros controles definiendo para ello un borde y una
cabecera.

ScrollViewer

Es un rea capaz de hacer scroll con los elementos que contiene.

StackPanel

Distribuye los elementos apilndolos vertical y horizontalmente.

Viewbox

Define un rea que puede escalar un elemento para encajar en un


determinado espacio.

Window

Permite la creacin, configuracin y gestin de la vida de las ventanas y los


dilogos.

WrapPanel

Sita los elementos en una sola lnea de forma que cuando se alcanza el final
de esta se produce una ruptura para ocupar la siguiente.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 313

Botones

Los botones son uno de los elementos ms bsicos en el diseo de UI y nos


permiten realizar acciones pulsando sobre ellos.

Button

Representa un botn que reacciona al clic del ratn.

RepeatButton

Representa un botn que emite peridicamente un clic desde que se presiona


hasta el momento en que se libera.

Datos

Los controles de datos se usan para mostrar informacin desde un origen de


datos.

DataGrid

Es un control que nos permite mostrar conjuntos de datos de manera tabular.

ListView

Es un control que nos permite mostrar elementos como una lista de datos.

TreeView

Muestra datos en una estructura jerrquica en donde los elementos se pueden


desplegar o colapsar.

Fecha

Controles de datos para mostrar y seleccionar fechas.

Calendar

Es un control que te permite seleccionar una fecha mostrando un calendario.

DatePicker

Es un control que te permite seleccionar una fecha mostrando un combo que


al ser desplegado muestra un calendario.

Mens

Los mens se usan para agrupar acciones o proveer de ayuda visual.

ContextMenu

Representa un men que provee funcionalidad contextual a un determinado


control.

Menu

Representa un men que agrupa las acciones globales para toda una
aplicacin.

ToolBar

Provee de un contenedor para un grupo de comandos o controles.

Seleccin

Estos controles posibilitan que el usuario seleccione una o ms opciones.

CheckBox

Representa un control que se puede seleccionar o no.


Gua prctica de desarrollo de aplicaciones Windows en .NET

314 | Windows Presentation Foundation

ComboBox

Es un control que permite seleccionar de una lista desplegable.

ListBox

Es un control que nos permite seleccionar uno o ms elementos de una lista.

RadioButton

Representa un control que se puede seleccionar o no y que puede ser asociado


con otro RadioButton para hacer seleccin exclusiva.

Slider

Representa un control que nos permite selecciona un valor dentro de un rango


utilizando una barra de desplazamiento.

Navegacin

Mejoran o extienden la navegacin de una aplicacin.

Frame

Control que soporta navegacin.

Hyperlink

Elemento que provee capacidades de almacenamiento de vnculos entre


elementos navegables.

Page

Encapsula el contenido de una pgina que puede ser navegada por IE.

NavigationWin Representa una ventana que soporta navegacin.


dow
TabControl

Dilogo

Representa un control que contiene mltiples elementos que ocupan el mismo


espacio en la pantalla.

Los dilogos encapsulan funcionalidad de configuracin o seleccin como


en el caso de la impresin.

OpenFileDialog Dilogo para la seleccin de archivos para su posterior apertura.


PrintDialog

Dilogo para la configuracin de la impresora.

SaveFileDialog

Dilogo para la seleccin de archivos para su posterior guardado.

Informacin de
usuario

Proveen informacin o claridad a una aplicacin. Normalmente no se


puede interactar con ellos.

AccessText

Permite especificar un carcter como tecla de acceso.

Label

Control que permite mostrar un texto y aporta una tecla de acceso.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 315

Popup

Es una ventana de tipo pop-up (emergente).

ProgressBar

Indica el progreso de una operacin.

StatusBar

Muestra informacin en una barra horizontal en una ventana.

TextBlock

Control muy ligero para mostrar texto.

ToolTip

Crea una ventana emergente que muestra informacin sobre un elemento .

Documentos

Controles especializados para ver documentos, optimizando


procesos de lectura-

DocumentViewer

Sirve para mostrar documentos fijos por pginas.

FlowDocumentPageViewer

Sirve para mostrar documentos de flujo mostrando una pgina


por vez.

FlowDocumentReader

Sirve para mostrar documentos de flujo en un control con varios


mecanismos de muestra incorporados.

FlowDocumentScrollViewer Sirve para mostrar documentos de flujo en modo de scroll


continuo.
StickyNoteControl

Control que permite a los usuarios adjuntar texto o anotaciones


manuscritas a los documentos.

Input

Controles para la insercin de texto u otro tipo de datos.

TextBox

Control para la insercin de texto plano, sin formato.

RichTextBox

Control para la insercin de documentos de texto enriquecido.

PasswordBox

Control para la insercin de contraseas, con los caracteres


enmascarados.

Medios

Controles con Soporte para video, audio y los formatos de imagen ms


populares.

Image

Control para mostrar imgenes.


Gua prctica de desarrollo de aplicaciones Windows en .NET

316 | Windows Presentation Foundation

MediaElement

Elemento destinado a reproducir video y audio, local o con soporte para


streaming.

SoundPlayerAction Es una TriggerAction que puede reproducir ficheros wav.

Algunos de estos controles sern tratados posteriormente con ms detalle


como los encargados de gestionar el Layout o los documentos, otros sern
reiteradamente revisitados como los botones o los elementos de Input. Casi
todos ellos tienen una serie de propiedades caractersticas de las cuales
depende su funcionamiento y otras ms generales con el tamao, mrgenes,
etc. Como por ejemplo estas:
Opacity

Indica el nivel de transparencia de un control.

Cursor

Indica, de todos lo disponibles, el icono de cursor que se ver cuando el


cursor del ratn est sobre el control.

Visibility

Indica si un control es visible, invisible o est colapsado.

Width, Height

Dimensiones de control.

MinWidth,
MaxWidth,
MinHeight,
MaxHeight

Dimensiones mximas y mnimas que ocupa un control. Habitualmente


usadas para salvaguardar el Layout de la aplicacin.

Margin

Espacio externo de separacin del control con los controles circundantes.

Padding

Espacio interno de separacin del control con su contenido.

UseLayoutRounding Establece cuando un control y su contenido, aplicar lgica de redondeo


en el dibujo de los vrtices.

Por otro lado adems de propiedades existen tambin eventos comunes a la


mayora de los controles, como por ejemplo:
GotMouseCapture

Bubble

Se produce cuando se captura el ratn.

LostMouseCapture

Bubble

Se produce cuando se pierde el ratn.

MouseLeftButtonUp

Bubble

Se produce cuando se suelta el botn izquierdo del


ratn.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 317

MouseLeftButtonDown

Bubble

Se produce cuando se aprieta el botn izquierdo del


ratn.

MouseRightButtonUp

Bubble

Se produce cuando se suelta el botn derecho del


ratn.

MouseRightButtonDown

Bubble

Se produce cuando se aprieta el botn derecho del


ratn.

MouseMove

Bubble

Se produce cuando se mueve el ratn.

MouseWheel

Bubble

Se produce cuando se mueve la rueda del ratn.

PreviewMouseLeftButtonUp

Tunnel

Se produce cuando se suelta el botn izquierdo del


ratn.

PreviewMouseLeftButtonDow
n

Tunnel

Se produce cuando se aprieta el botn izquierdo del


ratn.

PreviewMouseRightButtonUp

Tunnel

Se produce cuando se suelta el botn derecho del


ratn.

PreviewMouseRightButtonDo
wn

Tunnel

Se produce cuando se aprieta el botn derecho del


ratn.

PreviewMouseMove

Tunnel

Se produce cuando se mueve el ratn.

PreviewMouseWheel

Tunnel

Se produce cuando se mueve la rueda del ratn.

GotFocus

Bubble

Se produce cuando se captura el cursor.

LostFocus

Bubble

Se produce cuando se pierde el cursor.

KeyUp

Bubble

Se produce cuando se suelta una tecla del teclado.

KeyDown

Bubble

Se produce cuando se aprieta una tecla del teclado.

TextInput

Bubble

Se produce cuando se obtiene texto.

PreviewKeyUp

Tunnel

Se produce cuando se suelta una tecla del teclado.

PreviewKeyDown

Tunnel

Se produce cuando se aprieta una tecla del teclado.

PreviewTextInput

Tunnel

Se produce cuando se obtiene texto.

Gua prctica de desarrollo de aplicaciones Windows en .NET

318 | Windows Presentation Foundation

Conclusin
WPF logra una separacin efectiva entre desarrolladores y diseadores lo que
permite que ambos trabajen al mismo tiempo sin colisionar. Adems nos
provee de propiedades dependientes o eventos enrutados. Todas estas
caractersticas conforman una API de desarrollo consistente y que adems de
ofrecernos numerosas aportaciones tecnolgicas nos aade un mundo nuevo
en cuanto al desarrollo en equipo.

A continuacin
Los diferentes dispositivos a los que se puede aplicar WPF producen que la
adaptacin a las diferentes pantallas sea crtica. Es por esa razn entre otras,
que necesitamos un potente sistema de gestin y racionalizacin de los
espacios. En el siguiente captulo veremos en que consiste.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 319

Paneles Y
Layout
En WPF el diseo y la distribucin de los elementos son, si cabe, ms
importantes que otros sistemas de programacin. El principal motivo es que
tanto el diseo como la distribucin de los elementos son uno de los
principales motivos por los que realizamos proyectos en WPF.
En estas lneas no vamos a adentrarnos en estos conceptos como tal, diseo y
distribucin de los controles, ya que quedan fuera del mbito de este libro pero
s que intentaremos sentar unas bases de conocimiento para que las
experiencias anteriores con otros sistemas de programacin se puedan
reutilizar con WPF.
El primer concepto que tenemos que tener claro es que cada elemento en WPF
ocupa un rectngulo de espacio al ser mostrado. El tamao de este rectngulo
se computa a travs de una suma de factores, propiedades de diseo, espacio
disponible, panel contenedor, etc.
El tamao de cualquier objeto se puede recuperar a travs de clase
LayoutInformation y su mtodo GetLayoutSlot.

Gua prctica de desarrollo de aplicaciones Windows en .NET

320 | Window
ws Presentation Found
dation

WPF
F entiende ell Layout com
mo un processo recursivo
o en el que to
odos los
elementos se possicionan, dim
mensionan y dibujan. Esste sistema se
s encarga d
de
realizzar este a lo largo de tod
dos los elemeentos y sus contenidos,
c
completand
do
as laa presentaci
n.
La fu
uncionalidad
d antes descrrita es de esp
pecial comp
plejidad en lo
os paneles, yya
que eestos a difereencia del ressto de comp onentes sueelen contener multitud d
de
hijos, elementos contendidos en su interrior, que disstribuir.
mentos y en especial
e
los paneles proveen de dos mtodos
Para eso los elem
MeassureOverrid
de y ArrangeeOverride qu
que nos perm
miten realiza
ar los clculoos
oporttunos. El pro
oceso vendrra a ser as:
1.

U
Un elemento
o comienza midiendo
m
su
us propiedad
des bsicas.

2. D
Despus se evalan
e
las propiedades
p
heredadas de
d Framewo
orkElement,,
ccomo Width,, Height y Margin.
M
3. S
Se aplica la l
gica concre
eta de Panell.
4. E
El contenido
o se organiza
a despus dee medir todo
os los elemen
ntos
secundarios.
Se dibujan lo
os elementoss contenidoss.
5. S

Pa
aneles
Los eelementos ms
m importan
ntes dentro d
F
del desarrolllo de un diseo en WPF
son lo
os paneles. Estos
E
nos prroporcionan
n diferentes lgicas
l
de diistribucin qque
correectamente ap
plicadas, pueden simpliificar mucho
o la
confeeccin de intterfaces. Es por esta razzn que un
estud
dio de las differentes opcciones es sum
mamente tiil.
El prrimero de loss paneles a estudiar
e
es eel Canvas. Este
E
panel se caracterriza por perm
mitirnos disttribuir
librem
mente a lo la
argo y ancho
o del espacioo que ocupa los
difereentes elemeentos conten
nidos, hacien
ndo uso de la
as
propiiedades asocciadas Canv
vas.Top, Can
nvas.Left,
Canv
vas.Right y Canvas.Bott
C
tom.

Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windo
ows Presen
ntation Foundation | 321

XAML
L
s>
<Canvas
<But
tton x:Nam
me=Button
n1 Canvas
s.Top=10

Canvas.Left=10
/>
</Canva
as>

El Do
ockPanel es un panel en
n donde los eelementos see
pued
den distribuiir bien asocia
ados a lo larrgo de cualquiera
de los lados del panel,
p
bien ocupando
o
toodo el espaciio libre
restaante.
Cuen
nta con una propiedad
p
asociada DocckPanel.Docck, que
le ind
dica a cada elemento
e
com
mo se ha dee distribuir y una
propiiedad depen
ndiente LasttFillChild, qu
ue indica qu
ue se
debe hacer con el
e ltimo elem
mento inserrtado en el panel,
p
si ocu
upar con l todo
t
el espacio disponib
ble o no.

XAML
L
anel>
<DockPa
<But
tton x:Nam
me=Button
n1
DockPan
nel.Dock=
Top />
</DockP
Panel >

El Grrid es un pan
nel con la ca
apacidad de dividir su esspacio
en fillas y column
nas, situando
o en las celd
das resultanttes los
elementos.
umnas tenem
mos las
Para definir la fillas y las colu
propiiedades Row
wDefinitionss y ColumnD
Definitions,
form
muladas como
o sendas collecciones de RowDefinittion y
Colum
mnDefinitio
on respectiva
amente. En una fila el dato
d
ms iimportante a definir es la altura as RowDefinittion
cuentta con una propiedad
p
Height,
H
mien
ntras que las ColumnDeffinition tieneen
la pro
opiedad Wid
dth. En amb
bos casos la p
propiedad puede
p
ser esp
pecificada o no.
En esste ltimo ca
aso se consid
derar que lla dimensin
n especificad
da es Auto, eesto
es au
utodimension
nada, depen
ndiente del ttamao del contenido.
c
Tambin,
T
y
adem
ms de introd
ducir un enttero correspoondiente a la medida de
eseada,
podeemos especifficar * (asterrisco). En esste caso la diimensin de
e la fila o
colum
mna se comp
putar como
o una parte p
proporciona
al del espacio
o disponiblee, de
esta fforma si ten
nemos dos co
olumnas de aanchura * en
n un Grid, el
e asterisco
equivvaldr a la mitad
m
y si son
n tres a un teercio.
La co
osa se puedee complicar con
c los multtiplicadores,, que son n
meros enterros
que p
pueden aparrecer antes de
d los asterisscos. Cuando
o lo hacen no
n slo
multiiplican el tam
mao sino que
q aumentaan el nmero
o de partes en
e que divid
dir el
espaccio. De esa manera
m
un Grid
G
con doss columnas, la primera con
c dos
Gua prctica de
e desarrolllo de aplica
aciones Win
ndows en .N
NET

322 | Window
ws Presentattion Found
dation

asterriscos y la segunda con un


u asterisco computarn
n, la primera
a como dos
tercio
os y la segun
nda como un
n tercio.
A la h
hora de situa
ar por tanto un elementto hemos de decirle que fila y que
colum
mna, o si no asumir el valor
v
por deefecto en ella
as, o sea 0. Para
P
esto
utilizzaremos las propiedades
p
s asociadas G
Grid.Column y Grid.Row. Adems
podeemos decirle a un elemen
nto que se exxpanda por ms de una columna o ffila
utilizzando las pro
opiedades Grid.Column
G
nSpan y Grid
d.RowSpan..
XAML
L
<Grid>
<
<RowDefini
tions>
<Row
wDefinitio
on />
<Row
wDefinitio
on />
<
</RowDefin
nitions>
<
<ColumnDef
finitions>
>
<ColumnDefini tion Widt
th=*/>
<ColumnDefini tion Widt
th=* />
<ColumnDefini tion Widt
th=* />
<
</ColumnDe
efinitions
s>
<But
tton x:Nam
me=Button
n1 Grid.C
Column=0

Grid.Co
olumnSpan=
=2 Grid.
.Row=0/>
>
</Grid>
>

El Sta
ackPanel ess un panel qu
ue permite aapilar los
elementos conten
nidos con un
na orientaciin. Para
estab
blecer esta siimplemente hay que esp
pecificar su
propiiedad Orien
ntation a horrizontal o veertical.
XAML
L
Panel Orie
entation=
Vertical
>
<StackP
<But
tton x:Nam
me=Button
n1
<But
tton x:Nam
me=Button
n2
</Stack
kPanel >

/>
/>

Por
ltimo el WrrapPanel es un panel qu
ue dispone lo
os
elementos como si de escritu
ura se tratarra, de izquierrda a
dereccha. Cuando
o se alcanza el lmite porr la derecha el
panel parte la ln
nea de eleme
entos e inauggura una nu
ueva
lneaa. Tambin se puede cam
mbiar la orieentacin con
n la
propiiedad Orien
ntation.
XAML
L
anel Orien
ntation=H
Horizontal
l>
<WrapPa
<But
tton x:Nam
me=Button
n1
<But
tton x:Nam
me=Button
n2
<But
tton x:Nam
me=Button
n3
</WrapP
Panel >

/>
/>
/>

Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windows Presentation Foundation | 323

Conclusin
La distribucin de los elementos dentro de una aplicacin es una de las tareas
que tiene ms importancia, ya que de ella pueden depender desde la usabilidad
hasta la comprensin que de ella hagan los usuarios. Con WPF contamos con
un conjunto de paneles que nos permiten crear "Layouts" regulares sin
necesidad de crear complejos diseos, tan slo utilizando estos paneles y la
capacidad anidatoria de WPF.

A continuacin
Los datos son lo ms importante de una aplicacin, y la comunicacin de estos
al usuario la misin principal de un interfaz. WPF como cualquier otra API de
interfaz posee un mecanismo para hacerlo automticamente. A continuacin
veremos este mecanismo.

Gua prctica de desarrollo de aplicaciones Windows en .NET

324 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 325

Databinding y
Recursos
El Databinding es un proceso por el cual dos objetos sincronizan una de sus
propiedades entre si. Por ejemplo si en una aplicacin tenemos un objeto de
clase Persona la propiedad Nombre puede estar sincronizada con la propiedad
Text de un Textbox de manera automtica.
Esto es muy conveniente porque cualquier cambio que se produzca tanto en el
nombre como a travs del Textbox ser, inmediatamente comunicado
evitndonos as el enojoso proceso de detectarlo nosotros, as como la
correspondiente instruccin de asignacin.
Y esto no es una tontera, ya que en un formulario medio el nmero de estas
asignaciones puede llegar a ser bastante grande, complicando el cdigo y
evidentemente su mantenimiento.

Gua prctica de desarrollo de aplicaciones Windows en .NET

326 | Windows Presentation Foundation

Los interfaces
El cmo de este proceso involucra varios mecanismos as como diferentes tipos
de objetos que pueden verse involucrados desde el punto de vista de WPF.
Esto ltimo es importante y cabe resaltarlo de manera especial, lo que se
expondr a continuacin es solo vlido para WPF, otros mecanismos tanto en
.NET como fuera de la plataforma funcionan de manera distinta.
Para una rpida comprensin seguiremos con el ejemplo planteado en la
introduccin.
En este ejemplo podemos detectar dos procesos:
1.

Si el Textbox es modificado ha de comunicar al objeto el cambio.

2. Si el Nombre es modificado ha de comunicar al Textbox el cambio.


El primer proceso se lleva a cabo de manera automtica por ser la propiedad
Text una propiedad dependiente. Esto es muy importante ya que aquellas
propiedades que no sean dependientes, aunque se encuentren en una clase de
tipo DependencyObject caern dentro del segundo caso. Por tanto si queremos
crear un control WPF que soporte Databinding en sus propiedades basta con
que estas sean dependientes.
El segundo caso est diseado para que clases comunes soporten enlaces con
controles WPF. El mecanismo de sincronizacin es simple. Dotar a estas clases
de un evento que salte cada vez que se produzca una modificacin en las
propiedades. Para que esto funcione hemos de cumplir algunas normas:
1.

Que el evento sea conocido por los controles, por lo que la manera ms
eficaz es enmarcarlo dentro de un interfaz. Este es
INotifyPropertyChanged, interfaz que posee un solo miembro
PropertyChanged, evento diseado para saltar cuando se produce una
modificacin en los datos de una propiedad.

2. Que este interfaz sea implementado por la clase de datos, en el ejemplo


persona. Esta tarea es sumamente fcil porque Visual Studio tiene
procesos automatizados para hacerlo automticamente y al slo contener
un evento no es necesario dotar de cdigo a la implementacin.
3. Elevar correctamente el evento en la clase de datos. Esto es tan sencillo
como pensar dnde se modifica la propiedad Nombre? Pues como todas
las propiedades, en el mtodo set de su implementacin, ah debe ser
elevado el evento. Esta es la razn por la que el binding slo se puede
aplicar a propiedades, porque son las que poseen un mtodo set.
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 327

C#
class Persona: INotifyPropertyChanged
{
string nombre;
public string Nombre
{
get { return nombre; }
set {
nombre = value;
OnPropertyChanged("Nombre");
}
}
public event PropertyChangedEventHandler
PropertyChanged;
private void OnPropertyChanged (string
property)
{
if (PropertyChanged != null)
PropertyChanged(this, new
PropertyChangedEventArgs(property));
}
}
Visual Basic.NET
Class Persona
Implements INotifyPropertyChanged
Private m_nombre As String
Public Property Nombre() As String
Get
Return m_nombre
End Get
Set
m_nombre = value
OnPropertyChanged("Nombre")
End Set
End Property
Public Event PropertyChanged As
PropertyChangedEventHandler
Private Sub OnPropertyChanged([property] As
String)
RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs([property]))
End Sub
End Class
Gua prctica de desarrollo de aplicaciones Windows en .NET

328 | Windows Presentation Foundation

El lector se habr dado cuenta de que este enlace se establece entre una clase y
un control nicos, es lo que se conoce como Databinding simple. Pero existe
tambin el Databinding mltiple, entre una lista de personas y un Listbox, por
ejemplo. En este caso no slo el contenido de la propiedad ha de ser tenido en
cuenta. En control necesita se avisado tambin cuando cambie la lista, por
ejemplo cuando se aadan o quiten personas.
Es por esto que existe el interfaz INotifyCollectionChanged que funciona de
manera anloga pero para las colecciones. Sin embargo no analizaremos en
detalle este interfaz, porque se antoja bastante menos til.
De un lado existen colecciones como ObservableCollection<t> u
ObservableCollection(Of t) que ya lo tienen implementado, por otro DataSets,
tablas de entidades y ObjectQuerys tambin lo implementan. De forma que no
es probable que el lector necesite implementarlo, sirvan estas lneas como
prueba de existencia de este interfaz.

Las expresiones de binding


Si bien antes se plantearon las condiciones que haban de cumplir los objetos
que pueden participar en un Databinding, el hecho de poder no implica
participar. Es decir que tener una clase persona y un control no significa que
hayan de estar relacionados. Esta relacin se establece mediante las
expresiones de binding.
Antes de avanzar en el conocimiento de estas expresiones hemos de decir que
las expresiones de Databinding se pueden expresar de manera imperativa, es
decir por cdigo.
C#
Persona p = new Persona();
Binding binding = new Binding(Nombre);
binding.Source = p;
binding.Mode = BindingMode.OneWay;
myTextBox.SetBinding(TextBox.TextProperty, binding);
Visual Basic.NET
Dim p As New Persona()
Dim binding As New Binding(Nombre)
binding.Source = p
binding.Mode = BindingMode.OneWay
myTextBox.SetBinding(TextBox.TextProperty, binding)

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 329

Este cdigo establece la relacin entre las dos clases y es bastante fcil de
entender, si bien la tercera lnea merece una explicacin.
Esta lnea establece el modo de enlace, que nos permite establecer tres tipos de
relaciones:
1.

TwoWay, el control y el objeto pueden ser el origen de una modificacin y


se sincronizan mutuamente.

2. OneWay, slo el objeto puede modificarse y sincronizar, el control perder


cualquier cambio que se realice sobre l.
3. OneTime, el objeto se sincronizar con el control una sola vez,
comnmente en el momento en que el control es mostrado.
4. OneWayToSource, slo el control puede sincronizarse, sera la inversa de
OneWay.
5. Default, se establece en funcin del control, si este es bidirecional como el
Textbox ser TwoWay y si es una Label OneWay.
De cualquier manera el cdigo anterior no es muy conveniente, porque
establecer los enlaces en cdigo los hace menos accesibles dentro del Mare
Magnum de cdigo de la aplicacin, incrementando la dificultad adems.
Es por esto que se utilizan las expresiones. Estas no son ms que un pedazo de
texto con una sintaxis que se insertan en XAML.
La sintaxis es bien simple, todas las expresiones se enmarcan entre dos llaves,
llevan la palabra Binding y a continuacin y de manera opcional una serie de
pares nombre\valor separados por comas, para establecer la informacin del
enlace:
XAML
<TextBox Text="{Binding Source=P, Path=Nombre,
Mode=OneWay}" />
<TextBox Text="{Binding Path=Nombre, Mode=OneWay}"
<TextBox Text="{Binding Path=Nombre}"
<ListBox ItemsSource="{Binding}"

/>

/>

/>

El nmero de especificaciones que se pueden hacer es numerosa e incluso esta


ltima, sin prcticamente informacin es posible. En este punto nos vamos a
ocupar de las ms importantes.
Gua prctica de desarrollo de aplicaciones Windows en .NET

330 | Windows Presentation Foundation

1.

Source, indica el objeto origen de datos por su nombre, si el objeto es un


control se puede sustituir por ElementName.

2. Path, indica la propiedad, el nombre proviene de que puede ser una


propiedad simple o proveniente de navegacin, o sea, Nombre o
Direccin.Calle.
3. Mode, nos permite establecer el modo del binding.
Hemos de resear tambin que la primera de las lneas es incorrecta, y slo
est mencionada a efectos de ejemplo. La razn es que no es posible hacer
referencia a una variable definida en cdigo desde el XAML.
El proceso de conectar cdigo con XAML sera bastante incmodo de no ser
porque existen dos soluciones, por un lado la incorporacin de un espacio de
nombres como un espacio de nombres XML, esta solucin ser tratada ms
adelante. La segunda es el DataContext y ser tratada en el siguiente punto.

DataContext
La propiedad DataContext es una propiedad definida en la clase
FrameworkElement. Esta clase es el antecesor primero de todas las clases de
WPF. Esto quiere decir que cualquier elemento puede disponer de ella, pero
por qu es tan importante?
Podramos decir que la propiedad DataContext es un origen de datos por
defecto, es decir que en caso de que en una expresin de binding no
establezcamos un Source, el DataContext actuar en su lugar.
La ventaja principal de usar el DataContext es que este es parte del interfaz
principal de la clase al contrario del Source. Dicho en cristiano, al ser
DataContext una propiedad de la clase se puede asignar desde cdigo,
mientras que Source es una propiedad de la expresin que cuando menos es
mucho ms complicado de asignar.
En resumen el cdigo anterior quedara as:
C#
Persona p = new Persona();
TextBox1.DataContext = p;
Visual Basic.NET
Dim p As New Persona()
TextBox1.DataContext = p
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 331

XAML
<TextBox x:Name=TextBox1 Text="{Binding
Path=Nombre}" />

Con esto conseguiramos sincronizar la propiedad Text del TextBox con la


propiedad Nombre de la variable p. Una cosa importante se desprende de la
instruccin de asignacin del DataContext, a ella accedemos mediante el
nombre del TextBox y para que esto sea posible el TextBox ha de tener
nombre, es por eso que en la instruccin XAML hemos tenido que especificar
la propiedad x:Name. Si no, no hubiera sido posible acceder a ella.
Otra cosa importante en cuanto al DataContext es que establece un mbito de
enlace, esto significa que si establecemos el DataContext de un panel que
contiene un TextBox, este compartir DataContext con el panel por el mero
hecho de estar dentro de l. A menos que establezcamos tambin el
DataContext del TextBox. Segn esto esta lneas produciran una salida
similar.
C#
Persona p = new Persona();
Grid1.DataContext = p;
Visual Basic.NET
Dim p As New Persona()
Grid1.DataContext = p
XAML
<Grid x:Name=Grid1>
<TextBox Text="{Binding Path=Nombre}"
</Grid>

/>

El binding mltiple
Hasta ahora nos hemos ocupado del binding simple, pero ya es hora de
ocuparnos de mltiple.
Este es un binding que se establece entre una coleccin, lista, tabla, etc. y un
control como el ListBox, el ComboBox o el DataGrid.
Estos controles poseen la capacidad de mostrar un conjunto de datos y no slo
uno.

Gua prctica de desarrollo de aplicaciones Windows en .NET

332 | Windows Presentation Foundation

Todos estos controles poseen una propiedad comn que les permite funcionar,
la propiedad ItemsSource. Esta propiedad se encarga de establecer la coleccin
que sirve de origen para los datos.
Tambin es posible establecer la propiedad ItemsSource mediante una
expresin, en concreto la expresin {Binding}. Esta expresin establecida en la
propiedad informa que el DataContext establecido ms prximo se asigna sin
restricciones como ItemsSource.
Evidentemente el DataContext ha de contener una coleccin, de no ser as el
enlace no funcionara.
Otra propiedad que tienen los controles de binding mltiple es
IsSynchronizedWithCurrentItem. Esta propiedad booleana es muy importante
ya que informa al control de cual es su entorno de binding. Para entender esto
debemos entender como funciona el binding de las colecciones.
Cuando enlazamos una coleccin con una serie de elementos de binding
simple, estos crean una clase de intermediacin que necesariamente
implementa el interfaz ICollectionView. Se utiliza esta clase de intermediacin
a fin de soportar el ordenamiento y el filtrado sin necesidad de modificar la
coleccin origen.
De cualquier modo, todos los controles de binding simple comparten View. No
es as con los de binding mltiple, cada uno de ellos inaugura un nuevo View
para su uso exclusivo. La consecuencia principal de esto es que si tenemos un
TextBox mostrando el Nombre de la persona actual y al mismo tiempo una
ListBox mostrando la lista completa de las personas, ambos elementos no
estarn sincronizados, o sea cambiando el elemento seleccionado en el ListBox
no cambiar el nombre que se muestra en el TextBox.
Sin embargo si establecemos la propiedad IsSynchronizedWithCurrentItem a
True esta sincronizacin si tendr lugar. Esto es as porque el ListBox se
sumar al View que utilizan los TextBoxes.
Finalmente nos resta revisar algunos de los controles de binding mltiple. No
es posible hacerlo con todos porque sera un trabajo muy largo y no aportara
demasiado as que nos centraremos en un par de ellos, el ListBox y el
DataGrid.
El ListBox es capaz automticamente de mostrar una coleccin de cadenas, sin
embargo cuando la coleccin es de objetos esto no es tan simple.
Para poder mostrar estos elementos caben dos estrategias, la plantilla de
datos, que revisaremos en el captulo dedicado a las plantillas o mediante las
propiedades DisplayMemberPath que nos permite establecer la propiedad o
ruta del dato a mostrar y SelectedValuePath que nos permite establecer la
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 333

propiedad o ruta del valor a seleccionar. Por ejemplo, DisplayMemberPath


puede ser el nombre del pas y el SelectedValuePath cdigo, comnmente ms
til a la hora de procesar.
C#
LeftListBox.ItemsSource = LoadListBoxData();
private ArrayList LoadListBoxData()
{
ArrayList itemsList = new ArrayList();
itemsList.Add("Coffie");
itemsList.Add("Tea");
itemsList.Add("Orange Juice");
itemsList.Add("Milk");
itemsList.Add("Mango Shake");
itemsList.Add("Iced Tea");
itemsList.Add("Soda");
itemsList.Add("Water");
return itemsList;
}
Visual Basic.NET
LeftListBox.ItemsSource = LoadListBoxData()
Private Function LoadListBoxData() As ArrayList
Dim itemsList As New ArrayList()
itemsList.Add("Coffie")
itemsList.Add("Tea")
itemsList.Add("Orange Juice")
itemsList.Add("Milk")
itemsList.Add("Mango Shake")
itemsList.Add("Iced Tea")
itemsList.Add("Soda")
itemsList.Add("Water")
Return itemsList
End Function
XAML
<ListBox Margin="11,13,355,11" Name="LeftListBox" />

El DataGrid es un control que muestra datos en celdas generadas por la


interseccin de filas y columnas. El nmero de filas depende directamente de
la coleccin de datos, son las columnas por tanto las que nos permiten
especificar que datos mostrar de cada uno de los elementos.
La propiedad AutoGeneratedColumns crea las columnas de manera
automtica. Pero si queremos restringir los datos a mostrar podemos
desactivar esta propiedad y agregar estas columnas de manera manual a travs
de la propiedad de coleccin Columns. Estas columnas poseen una propiedad
Binding para introducir una expresin de binding. Adems existen varios tipos
de columnas, de texto, CheckBox, y de plantillas que tambin nos permitirn
introducir plantillas de datos como los ListBoxes.
Gua prctica de desarrollo de aplicaciones Windows en .NET

334 | Windows Presentation Foundation

XAML
<DataGrid ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn x:Name="iDColumn"
Binding="{Binding Path=ID}" Header="ID" />
<DataGridTextColumn
x:Name="nombreColumn" Binding="{Binding Path=Nombre}"
Header="Nombre" />
<DataGridTextColumn
x:Name="apellidosColumn" Binding="{Binding
Path=Apellidos}" Header="Apellidos" />
</DataGrid.Columns>
</DataGrid>

Conversores
Hasta ahora hemos estado jugando con ventaja cuando nos referimos al
binding. Bsicamente y de manera implcita hemos estado enlazando
propiedades compatibles, es decir, que comparten tipo o cuyos tipos son
compatibles, pero esto no tiene por que ser as.
En ocasiones cuando dos propiedades se relacionan por binding los tipos de
ambas no son idnticos ni compatibles por lo que necesitamos un conversor.
Un conversor no es ni ms ni menos que una clase que implementa un
interfaz, IValueConverter, y que es utilizado como intermediador de las
operaciones de binding, antes de que el contenido de una propiedad se
sincronice con otra se pasa por el conversor a fin de que los datos de ambas
propiedades sean compatibles.
C#
public enum AgeGroups
{
Young = 18,
Mature = 60,
Old = 150
}
[ValueConversion(typeof(int), typeof(string))]
public class AgeConverter : IValueConverter
{
public object Convert(object value, System.Type
targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 335


dynamic number =
System.Convert.ToInt32(value);
if (number < AgeGroups.Young) {
return AgeGroups.Young.ToString();
} else if (number < AgeGroups.Mature) {
return AgeGroups.Mature.ToString();
} else {
return AgeGroups.Old.ToString();
}
}
public object ConvertBack(object value,
System.Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return
System.Convert.ToInt32(Enum.Parse(typeof(AgeGroups),
value));
}
}
VisualBasic.NET
Public Enum AgeGroups
Young = 18
Mature = 60
Old = 150
End Enum
<ValueConversion(GetType(Integer), GetType(String))>
Public Class AgeConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object,
ByVal targetType As System.Type, ByVal parameter As
Object, ByVal culture As
System.Globalization.CultureInfo) As Object Implements
System.Windows.Data.IValueConverter.Convert
Dim number = System.Convert.ToInt32(value)
If number < AgeGroups.Young Then
Return AgeGroups.Young.ToString()
ElseIf number < AgeGroups.Mature Then
Return AgeGroups.Mature.ToString()
Else
Return AgeGroups.Old.ToString()
End If
End Function
Public Function ConvertBack(ByVal value As Object,
ByVal targetType As System.Type, ByVal parameter As
Object, ByVal culture As
System.Globalization.CultureInfo) As Object Implements
System.Windows.Data.IValueConverter.ConvertBack
Gua prctica de desarrollo de aplicaciones Windows en .NET

336 | Windows Presentation Foundation


Return
System.Convert.ToInt32([Enum].Parse(GetType(AgeGroups)
, value))
End Function
End Class

Como se puede ver en el ejemplo hemos codificado un conversor entre un tipo


enumerado AgeGroups y los enteros, de forma que los datos de numricos
sean interpretados elemento distribuidor entre los diferentes valores del
enumerado y viceversa. As una edad de menos de 18 ser considerada como
Young, entre 18 y 60 Mature y mas de 60 Old.
Para ello simplemente hemos creado una clase calificada por el atributo
ValueConversion, que informa de que tipo, el situado como primer
parmetro, es el origen y cual, el segundo, es el destino y que implementa el
interfaz IValueConverter, que define dos mtodos Convert que recibe como
parmetro un value del tipo origen y devuelve el valor equivalente del tipo
destino y un mtodo ConvertBack que realiza justo la operacin inversa.
Pero una vez codificado esto no es ms que una clase, qu debemos hacer
para usarlo en una expresin concreta? Las expresiones de binding adems de
Path y Source tambin poseen la propiedad Converter. En esta se puede
especificar cul es el conversor usado. Pero cmo? Lo primero que nos damos
cuenta es que la clase del conversor no es visible desde XAML, esto quiere
decir que o bien asignamos el conversor a travs de cdigo, o bien hacemos
posible su referencia desde el XAML.
Es esta segunda opcin la ms razonable y para ello lo que tenemos que hacer
es ampliar el rango de XAML vlido, como lo haramos si estuviramos
creando un nuevo control. Para ello lo nico que tenemos que hacer es definir
un nuevo espacio de nombres XML a nivel del contenedor deseado, que nos va
a permitir acoger estas nuevas marcas dentro de su mbito. En el ejemplo:
XAML
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/pr
esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication2"
Title="MainWindow" Height="350" Width="525">

La sentencia xmlns:app="clr-namespace:WpfApplication2" nos indica que el


espacio de nombres XML de nombre app, es de tipo cdigo e importa las clases
definidas en el espacio de nombres de cdigo clr-namespace, de nombre
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 337

WpfApplication2. Este espacio de nombres ha de estar accesible directamente


o como referencia en la aplicacin, y todas la clases pblicas declaradas en l
pasan automticamente a ser referenciables desde el XAML, lo cual no quiere
decir que se puedan incluir en cualquier parte.
Obviamente una clase que no sea un control no podr ser situada en un lugar
destinado a controles como este es el caso. Un conversor es una clase de
gestin que WPF no sabe como pintar y si queremos insertarla en marcado
deberamos hacerlo all donde efecta la accin para la que ha sido concebida
convertir, o sea asignada a la propiedad Converter de la expresin de binding,
algo similar a esto {Binding Path=Edad, Converter=app:AgeConverter}.
Desgraciadamente esto no devolver un error debido a que app no es visible
dentro de una expresin de binding, luego la solucin que tenemos es la
siguiente, primero declaramos en cdigo nuestro conversor en el nico sitio
posible, los recursos, que veremos un poquito ms adelante en este mismo
captulo:
XAML
<Window.Resources>
<app:AgeConverter x:Key="AgeConverter1" />
</Window.Resources>

Despus y utilizando un binding de recursos podemos asignar el conversor por


su clave:
XAML
<ComboBox Height="23" HorizontalAlignment="Left"
Margin="12,155,0,0" Name="ComboBox1"
VerticalAlignment="Top" Width="120" Text="{Binding
Path=Edad, Converter={StaticResource AgeConverter1}}"
/>

En cualquier caso se recomienda al lector revisitar esta seccin una vez se haya
ledo los epgrafes relacionados con recursos.

Validacin
La validacin es el proceso por el cual el dato se prueba correcto antes de ser
definitivamente asignado por un proceso de binding.
Este proceso de validacin se puede llevar a cabo de varias maneras, con el fin
de que utilicemos la que ms nos convenga.
Gua prctica de desarrollo de aplicaciones Windows en .NET

338 | Windows Presentation Foundation

El primer camino es el conocido como validacin mediante propiedades y


bsicamente consiste en que en las propiedades de la clase de datos elevemos
un excepcin, si es que no se hace ya, cuando la informacin no cumpla unos
criterios de validez. El quid de la cuestin se encuentra en la expresin de
databinding.
Adems de los correspondientes Source, Path, etc. debemos, si queremos que
el proceso de binding interprete estas excepciones como procesos de
validacin y no como excepciones comunes, que hacer constar en las
expresiones de binding las siguientes especificaciones:
XAML
Text="{Binding Edad, Mode=TwoWay,
NotifyOnValidationError=True,
ValidatesOnExceptions=true}"

Donde NotifyOnValidationError informa a la expresin que debe elevar el


evento de validacin cuando se produzca una operacin de sincronizacin.
ValidatesOnExceptions determina que las excepciones durante el proceso de
binding deben ser tomadas como errores de validacin.
Otra manera es hacer implementar a nuestra clase de datos el interfaz
IdataErrorInfo. Este interfaz obliga a toda clase que lo implemente a declarar
dos propiedades Error y una propiedad indexada, this en C# e Item en Visual
Basic.NET.
La propiedad Error est destinada a recoger un mensaje de error general,
mientras que la propiedad indexada, nos permite introducir un mensaje por
propiedad, ya que son los nombres de estas los que se utilizan como indexador.
C#
public class Persona: INotifyPropertyChanged,
IDataErrorInfo
{
private string _nombre;
public string Nombre
{
get { return _nombre; }
set {
if (value.Length > 0)
{
_nombre = value;
OnPropertyChanged("Nombre");
}
else errors.Add("Nombre", "Nombre no
puede estar vaco");
}
}
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 339


private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(p));
}
}
public event PropertyChangedEventHandler
PropertyChanged;
Dictionary<string, string> errors = new
Dictionary<string,string>();
public string Error
{
get { return string.Format("Hay {0} en
total", errors.Count); }
}
public string this[string columnName]
{
get { return errors[columnName]; }
}
}
Visual Basic.NET
Public Class Persona
Implements INotifyPropertyChanged
Implements IDataErrorInfo
Private _nombre As String
Public Property Nombre() As String
Get
Return _nombre
End Get
Set
If value.Length > 0 Then
_nombre = value
OnPropertyChanged("Nombre")
Else
errors.Add("Nombre", "Nombre no
puede estar vaco")
End If
End Set
End Property
Private Bus OnPropertyChanged(p As String)
RaiseEvent PropertyChanged(Me, New
PropertyChangedEventArgs(p))
End Sub
Public Event PropertyChanged As
PropertyChangedEventHandler
Private errors As New Dictionary(Of String,
String)()
Public ReadOnly Property [Error]() As String
Get
Return String.Format("Hay {0} en
Gua prctica de desarrollo de aplicaciones Windows en .NET

340 | Windows Presentation Foundation


total", errors.Count)
End Get
End Property
Public Default ReadOnly Property Item(columnName
As String) As String
Get
Return errors(columnName)
End Get
End Property
End Class

En este ejemplo podemos ver como se valida una propiedad que es evaluada
para que la longitud no sea menor que 0. Para que la expresin sea sensible a
estos errores hemos de habilitar ValidatesOnDataErrors en vez de el
ValidatesOnExceptions anterior, aunque sean perfectamente compatibles.
XAML
Text="{Binding Nombre, Mode=TwoWay,
ValidatesOnDataErrors=True,
NotifyOnValidationError=True}"

Tambin es posible implementar el interfaz InotifyDataErrorInfo muy similar


al IdataErrorInfo pero con extructura de ejecucin asncrona.
Pero sin duda el mecanismo ms popular de validacin son las reglas de
validacin.
Este mecanismo consiste en crear clases que desciendan de la clase
ValidationRule y que permiten luego ser aadidas a cualquier expresin de
binding. Es esta capacidad de reutilizacin lo que las hace tan populares.
Por otro lado la implementacin es realmente sencilla, solo hemos de
sobrecargar en la clase el mtodo Validate, que recibe un objeto y devuelve un
ValidationResult, clase que nos permite determinar si el resultado fue positivo
o negativo y devolver tambin un mensaje.
La inclusin en la expresin de binding se puede hacer mediante la misma
tcnica que el conversor, simplemente importando el espacio de nombres clr
como xml y listo.
C#
public class NewRule : ValidationRule
{
public override ValidationResult Validate(object
value, CultureInfo cultureInfo)
{
}
}

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 341


Visual Basic.NET
Public Class NewRule
Inherits ValidationRule
Public Overrides Function Validate(value As Object,
cultureInfo As CultureInfo) As ValidationResult
End Function
End Class

XAML
<TextBox>
<TextBox.Text>
<Binding Path="Age"
UpdateSourceTrigger="PropertyChanged" >
<Binding.ValidationRules>
<c:NewRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>

Integracin con Visual Studio


Visual Studio se ha destacado como una herramienta, potente, cmoda y
productiva en lo referente a la programacin .NET en general, pero con WPF el
tratamiento ha sido diferente que con otras tecnologas como Windows
Communication Foundation o Windows Workflow Foundation.
La primera experiencia de desarrollo sobre WPF la tuvimos con VS2005 y no
fue precisamente placentera. El producto no soportaba el desarrollo de WPF,
como era lgico por otra parte ya que fue diseado para programar slo sobre
la versin 2.0 del Framework, as que debamos instalar unos Add-Ons que
nos aportaban poco ms, un previsualizador de XAML que permita obtener
una imagen del XAML que bamos codificando y que sola fallar a poco que
utilizramos una caracterstica poco comn. De otro lado tambin nos
permita el uso de un editor de propiedades que tan slo era de utilidad para
conocer el catlogo de propiedades, ya que su edicin era realmente imposible
en casi cualquier propiedad que se saliera de lo habitual. Adems no
contemplaba los eventos.
En VS2008 se mejoraron algunas cosas como la fiabilidad del visualizador o la
inclusin de los eventos en el editor de propiedades, pero la edicin visual
segua cuando menos siendo incmoda.

Gua prctica de desarrollo de aplicaciones Windows en .NET

342 | Window
ws Presentattion Found
dation

Todo
o esto se agra
avaba especcialmente en
n el caso del binding, ya que no exissta
ning
n tipo de siimplificacin
n y ayuda en
n lo que posiiblemente se
e pueda
consiiderar el meecanismo m
s difcil de ttoda la tecno
ologa.
Aforttunadamentte esto ha cambiado en V
VS2010. Son
n muchas lass mejoras qu
ue
se haan incorpora
ado, pero en lo tocante aal binding so
on bsicamente dos: el
edito
or de expresiiones y los orgenes de d
datos.
.
El ed
ditor de exprresiones sim
mplifica drstticamente ell clculo de expresiones
e
Como
o podemos ver
v en la
prim
mera imagen el editor noss
perm
mite estableccer la mayora
de lass opciones de
d binding
mediiante un edittor visual. Lo
cual ees sumamen
nte til porq
que
si bieen los bindin
ngs sencilloss
son ffciles de esttablecer por
cdiggo, los meno
os evidentes
pued
den ser basta
ante difciless.
Tamb
bin podemo
os observar
que eel origen de datos, en la propiedad S
Source se pu
uede establecer sin
probllemas ya pro
ovengan estos de una baase de datoss, de otro ele
emento denttro
del in
nterfaz o de un recurso, como verem
mos un poco
o ms adelan
nte en este
mism
mo captulo.
Es taambin posib
ble establece
er el resto dee parmetro
os de las expresiones de
bindiing a travs del editor. Como
C
se ve een la segund
da imagen po
odemos
estab
blecer la prop
piedad Path
h que se nos mostrar co
ontextualizada al Sourcee
que h
hayamos eleegido. Tambiin se nos peermitir seleeccionar el conversor
c
dee las
propiiedades de formato,
f
mo
odo
y valiidacin.
La seegunda de la
as
integgraciones qu
ue nos aporta
a
VS ess la integracin con la
ventaana de Orgeenes de Dato
os.
Cuan
ndo incluimo
os en nuestrro
proyeecto un Data
aSet o un
ObjecctContext (E
Entity
Fram
mework) estee
autom
mticamente se asocia con
c
la ven
nta de orgenes de datoss e
Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windo
ows Presenttation Foun
ndation | 343

inmeediatamente se publican
n tanto sus taablas u ObjeectQuerys co
omo los
difereentes campo
os/propieda
ades que con
ntienen. De esta
e
manera con un simp
mple
pulsaar y arrastra
ar podemos depositar
d
loss diferentes controles en
n el formulaario.
Adem
ms esta ven
ntana nos permite selecccionar el con
ntrol de edicin, que porr
ejemplo en el casso de una tab
bla puede seer un DataG
Grid, un ListV
View o un
conju
unto de conttroles que co
onforman un
n editor tipo
o ficha.

ms esta ven
ntana no slo
o inserta con
ntroles sino que
Adem
la auttomatizacin incluye la insercin deel cdigo pa
ara
rellen
nar el DataS
Set o abrir el ObjectConttext. Al haceer
esto iinserta tamb
bin un elem
mento en el m
marcado, en
n
concrreto en el rrea de recurssos que es un
n
ColleectionViewSo
ource que se
er, junto coon los
DataP
Providers, el
e objetivo de
e nuestro sigguiente puntto.

Da
ataPrrovide
ers y
Co
ollecc
cionViewSo
ource
e
Cuan
ndo hablamo
os del bindin
ng mltiple h
hablamos ta
ambin de la
a estructura
interna que este tena, de com
mo cada colleccin creab
ba un IColle
ectionView y de
como
o este objeto
o era necesarrio para inteermediar a fiin de soportar ordenacin y
filtraado, ahora ab
bordaremos como.

Gua prctica de
e desarrolllo de aplica
aciones Win
ndows en .N
NET

344 | Windows Presentation Foundation

CollectionViewSource es una clase que puede funcionar como esttica o


dinmica, esto nos permite que a travs del mtodo esttico GetDefaultView
obtengamos el objeto ICollectionView o nos permite insertarla en marcado,
como referimos en el apartado anterior para enlazar de manera declarativa con
los controles.
Es el primer aspecto que nos va a ocupar, ya que la manipulacin del
ICollectionView nos va a permitir el filtrado y ordenado programtico.
El mtodo GetDefaultView admite un parmetro, que ha de ser una coleccin y
nos devuelve un objeto que implementa el interfaz ICollectionView.
Este interfaz obliga a la clase que lo implementa, sea cual sea, a tener los
siguiente miembros entre otros:

MoveCurrentToFirst, sita el elemento seleccionado de la coleccin como


el primero.

MoveCurrentToLast , sita el elemento seleccionado de la coleccin como


el ltimo.

MoveCurrentToNext, sita el elemento seleccionado de la coleccin como


el siguiente al actual.

MoveCurrentToPrevious, sita el elemento seleccionado de la coleccin


como el anterior al actual.

CurrentItem, nos da acceso al elemento actual.

SortDescriptions, coleccin de elementos SortDescription que al ser


creados solicitan el nombre de una propiedad y una direccin con las
cuales ordenar la vista. Al ser una coleccin el orden de entrada establece
el criterio de aplicacin de los diferentes elementos de orden.

Filter, es una propiedad de tipo Predicate<Object> o Predicate(Of Object),


que bsicamente quiere decir que el dato a asignar es un delegado, el cual
recibe un objeto, que ser cada uno de los objetos de la coleccin, y
devuelve un dato booleano de forma que verdadero equivale a que el dato
no se filtra, falso a que si.

C#
...
ICollectionView cv;
public ICollectionView CV
{
get {
if (cv == null)
cv =
CollectionViewSource.GetDefaultView(this.Resources["li
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 345


sta"]);
return cv;
}
}
private void Button_Click(object sender,
RoutedEventArgs e)
{
CV.MoveCurrentToFirst();
}
...
private void Button_Click_4(object sender,
RoutedEventArgs e)
{
if (CV.SortDescriptions.Count > 0)
{
CV.SortDescriptions.Clear();
}
else
{
CV.SortDescriptions.Add(new SortDescription {
PropertyName = "Apellidos",
Direction =
ListSortDirection.Descending });
}
}
private void Button_Click_5(object sender,
RoutedEventArgs e)
{
CV.Filter = delegate(object item)
{
return ((Persona)item).Nombre.Length > 5;
};
}

Visual Basic.NET
...
Private m_cv As ICollectionView
Public ReadOnly Property CV() As ICollectionView
Get
If m_cv Is Nothing Then
m_cv =
CollectionViewSource.GetDefaultView(Me.Resources("list
a"))
End If
Return m_cv
End Get
End Property

Gua prctica de desarrollo de aplicaciones Windows en .NET

346 | Windows Presentation Foundation


Private Sub Button_Click(sender As Object, e As
RoutedEventArgs)
CV.MoveCurrentToFirst()
End Sub
...
Private Sub Button_Click_4(sender As Object, e As
RoutedEventArgs)
If CV.SortDescriptions.Count > 0 Then
CV.SortDescriptions.Clear()
Else
CV.SortDescriptions.Add(New
SortDescription() With { _
Key .PropertyName = "Apellidos", _
Key .Direction =
ListSortDirection.Descending _
})
End If
End Sub
Private Sub Button_Click_5(sender As Object, e As
RoutedEventArgs)
CV.Filter = Function(item As Object)
DirectCast(item, Persona).Nombre.Length > 5
End Sub

El CollectionViewSource tambin puede funcionar como un elemento


insertado en XAML que nos facilite el enlace mediante los editores y
herramientas de Visual Studio, pero no es el nico, tambin disponemos de los
DataProviders.
Un DataProvider existe para precisamente poder insertar un objeto de
intermediacin en el marcado que nos permita insertar fcilmente los datos de
un objeto o un XML en los interfaces creados por WPF.
Existen dos tipos:
1.

ObjectDataProvider, que permite insertar objectos definidos en cdigo a


travs de su propiedad ObjectInstance establece el objeto que deseamos, y
con MethodName y MethodParameters el mtodo a ejecutar.

2. XMLDataProvider, que permite a travs de su propiedad Source cargar un


XML y utilizarlo como origen de datos. Este caso es especialmente
interesante porque es el nico en que el origen de datos no es un objecto o
una coleccin de ellos.
Como vemos el XMLDataProvider es ciertamente especial, tanto que modifica
la expresin de binding transformando la propiedad Path en XPath, en la cual
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 347

se hace constar una propiedad en una expresin basada en XPath como


podemos ver en el siguiente ejemplo:
XAML
<TextBox Text={Binding XPath=@Nombre} />

Recursos
Los recursos son uno de los elementos ms importantes de WPF. De hecho ya
hemos visto que nos permiten cosas como introducir elementos no visuales en
marcado, pero adems de esto en los siguientes captulos veremos muchos ms
usos que nos mostrarn el potencial de los recursos en WPF. Ahora toca
explicar qu son y cmo afectan al binding.
Los recursos corresponden a la propiedad Resources que se define en la clase
FrameworkElement. Esto significa que estn disponibles en todos los
elementos que de ella descienden, de facto en todas las clases de WPF.
Esta propiedad est formulada como del tipo ResourceDictionary. Este tipo
vendra a ser lo mismo que un diccionario de objetos cuyas claves tambin son
objetos. Esto quiere decir que tenemos una coleccin cuyos elementos tienen
cada uno una clave y un valor que son objetos.
Debido a esto en los recursos se puede guardar cualquier cosa, lo que los hace
muy verstiles, pero adems los recursos tiene una forma de funcionar que les
permite en tiempo de ejecucin comportarse casi como si fueran una
propiedad creada a partir de toda la jerarqua de elementos en XAML. Esto
quiere decir que si tenemos un botn dentro de un panel y a su vez el panel
dentro de una ventana, y accedisemos en el botn a los recursos mediante
una expresin de binding, esta buscara el origen de datos en los recursos del
botn, si no en el panel y por ltimo en la ventana hasta encontrarlo.
Comportamiento este muy similar al de los DataContext.
Las expresiones de binding de recursos son muy sencillas, como todas ellas
van enmarcadas por sendas llaves para a continuacin cambiar la palabra
binding por StaticResource o DynamicResource. La nica propiedad que
ambas tienen es ResourceKey que indica, por su nombre el recurso al que nos
queremos referir.
XAML
<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/pr
Gua prctica de desarrollo de aplicaciones Windows en .NET

348 | Windows Presentation Foundation


esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</Page.Resources>
<StackPanel>
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Left" FontSize="36"
Foreground="{StaticResource MyBrush}" Text="Text"
Margin="20" />
</StackPanel>
</Page>

Como se puede ver en el ejemplo hemos creado un recurso de tipo brocha con
el que luego establecemos el color de la fuente de un TextBlock. Una de las
cosas importantes que hay que recalcar en el caso de los recursos, es que todos
ellos han de establecer la propiedad x:Key, ya no porque de otra manera no se
podran asignar, si no porque estos elementos bsicamente representan una
coleccin en la que la propiedad Key es obligatoria y si no se asigna la clase
correspondiente, ResourceDictionary, no se podra crear.

Conclusin
Los procesos de binding estn diseados para facilitarnos el cdigo, una
correcta inclusin de ellos puede hacer que nuestro cdigo se reduzca
considerablemente, al tiempo que delegamos tareas pesadas en el propio
sistema. WPF nos permite hacer uso de un motor de binding muy potente.

A Continuacin
Los comandos son un buen recurso, disponible en WPF, para crear
funcionalidad y asignarla de manera consistente a mltiples controles y de
manera consistente a lo largo de nuestro interfaz. En el siguiente captulo
veremos por qu.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 349

Comandos
Podramos describir los comandos como pedazos de funcionalidad que se
pueden asignar a determinados tipos de controles, botones y mens, pero que
adems estn asociados con un gesto de entrada, bsicamente una
combinacin de teclas, ratn y/o lpiz ptico.
Esto en principio puede parecer bastante trivial, pero fundamentalmente nos
permite crear funcionalidad de manera consistente que luego pueda ser
desplegada y utilizada a lo largo de la aplicacin, o debidamente empaquetada
en otras aplicaciones.
De hecho un comando puede establecerse a nivel de control o de aplicacin, y
estos ltimos quedan debidamente registrados para poder ser invocados desde
cualquier lado en la aplicacin.

Redefinir un comando
En el modelo de objetos de WPF ya se incluyen la definicin de diferentes
comandos, por ejemplo ApplicationCommands, NavigationCommands,
MediaCommands, EditingCommands y ComponentCommands. En algunos
casos estos comandos contienen ya una funcionalidad asociada, pero en otras

Gua prctica de desarrollo de aplicaciones Windows en .NET

350 | Windows Presentation Foundation

no. En cualquier caso ser capaz de dotar a un comando ya existente de


funcionalidad ajustada a nuestra aplicacin es muy til.
De hecho estos comandos no slo ya existen sino que estn vinculados a los
eventos de sistema y combinaciones de teclas ms comunes. Esto simplifica
significativamente adaptar las aplicaciones y sus respuestas a lo esperado.
La clave para redefinir un comando ya existente es recrear su
CommandBinding. Esta clase se encarga de asociar un ICommand con un
ExecutedRoutedEventHandler. Posteriormente este CommandBinding hay
que agregarlo a la coleccin CommandBindings de cualquier descendiente de
UIElement.
UIElement es el descendiente de todos los elementos de interfaz en WPF, estas
clases se caracterizan por poder interactuar con el usuario.
C#
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CommandBinding cb = new
CommandBinding(ApplicationCommands.Close, new
ExecutedRoutedEventHandler(Salir));
this.CommandBindings.Add(cb);
}
private void Salir(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
}
Visual Basic.NET
Public Partial Class MainWindow
Inherits Window
Public Sub New()
InitializeComponent()
Dim cb As New
CommandBinding(ApplicationCommands.Close, New
ExecutedRoutedEventHandler(AddressOf Salir))
Me.CommandBindings.Add(cb)
End Sub
Private Sub Salir(sender As Object, e As
ExecutedRoutedEventArgs)
Application.Current.Shutdown()
End Sub
End Class

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 351

Como se puede ver en el ejemplo sobrecargamos el comando existente Close


con el mtodo Salir, que bsicamente cierra la aplicacin.
Esto bsicamente cerrar la aplicacin cuanto reciba la seal adecuada. Lo
importante de este comando es que adems se puede conectar con algunos
controles utilizando la propiedad Command. Esta est disponible
especficamente en los botones y en los MenuItems.
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu>
<MenuItem Header="Archivo">
<MenuItem Header="Salir"
Command="ApplicationCommands.Close" />
</MenuItem>
</Menu>
<ToolBarTray Grid.Row="1">
<ToolBar>
<Button Content="Salir"
Command="Close" />
</ToolBar>
</ToolBarTray>
<TextBox x:Name="Texto" Grid.Row="2"
AcceptsReturn="True" />
</Grid>

Crear un comando nuevo


Si el comando es nuevo debemos hacer alguna tarea aadida. Bsicamente al
no disponer de una clase de comando necesitamos una. Opcionalmente
adems necesitaramos tambin un gesto asociado al comando y por ltimo
deberamos asociar el comando con los diferentes elementos en el interfaz,
teniendo en cuenta que el comando al no pertenecer a la API por defecto
necesitamos incluirlo en el marcado.
Como primera tarea debemos crear un comando, que es el resultado de una
clase comn y corriente hacerle implementar el interfaz ICommand o
simplemente de crear una variable de tipo RoutedCommand:

Gua prctica de desarrollo de aplicaciones Windows en .NET

352 | Windows Presentation Foundation

C#
RoutedCommand abrir;
InputGestureCollection gesto = new
InputGestureCollection();gesto.Add(new
KeyGesture(Key.L, ModifierKeys.Alt));abrir = new
RoutedCommand("Abrir", typeof(Application), gesto);
Visual Basic.NET
Dim abrir As RoutedCommand
Dim gesto As New InputGestureCollection()
gesto.Add(New KeyGesture(Key.L, ModifierKeys.Alt))
abrir = New RoutedCommand("Abrir",
GetType(Application), gesto)

Adems en el ejemplo tambin podemos ver como se crea una coleccin de


gestos, a la que se agrega una determinada combinacin de teclas, alt+L en
concreto, y como se vincula con el comando.
Para asignar el comando a un control lo podemos hacer de dos maneras, la
primera tan sencilla como asignar el comando a la propiedad Command del
control:
C#
MenuAbrir.Command = abrir;
Visual Basic.NET
MenuAbrir.Command = abrir

La segunda es incluir nuestro espacio de nombres en el marcado y enlazar el


comando en marcado. Esto funcionar obviamente si el comando est definido
como una clase, de lo contrario el sistema no interpretar que este pueda
introducirse en marcado:
C#
class AbrirCommand: ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
Application.Current.Shutdown();
}
}

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 353

Visual Basic.NET
Class AbrirCommand
Implements ICommand
Public Function CanExecute(parameter As Object)
As Boolean
Return True
End Function
Public Event CanExecuteChanged As EventHandler
Public Sub Execute(parameter As Object)
Application.Current.Shutdown()
End Sub
End Class
XAML
<Window x:Class="EjercicioVI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/pr
esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:miapp="clr-namespace:EjercicioVI"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<miapp:AbrirCommand x:Key="comando" />
</Grid.Resources>
<Menu>
<MenuItem Header="Archivo">
<MenuItem Header="Salir"
Command="{StaticResource comando}" />
</MenuItem>
</Menu>
<ToolBarTray Grid.Row="1">
<ToolBar>
<Button Content="Salir"
Command="{StaticResource comando}" />
</ToolBar>
</ToolBarTray>
<TextBox x:Name="Texto" Grid.Row="2"
AcceptsReturn="True" />
</Grid>
</Window>

Para introducir la clase en el marcado continuamos la estrategia que seguimos


anteriomente con el conversor. Introducir el espacio de nombres XML y
declarar el comando como un recurso, que como vimos es posible porque los
recursos pueden ser cualquier objeto y enlazarlo mediante binding con la
propiedad Command en marcado. Recordar que hay que hacerlo as porque
Gua prctica de desarrollo de aplicaciones Windows en .NET

354 | Windows Presentation Foundation

como contenido de una propiedad en marcado no se pueden introducir


espacios de nombres XML.

Comandos en los nuevos


controles
En ocasiones los comandos no pueden ser asociados a la coleccin
CommandBindings. Es muy tpico por ejemplo que esto sea as en la
construccin de controles nuevos, y se debe fundamentalmente a que se accede
desde el lado inadecuado.
C#
public class Comentario : ContentControl
{
static Comentario()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Coment
ario), new
FrameworkPropertyMetadata(typeof(Comentario)));
CommandManager.RegisterClassCommandBinding(typeof(Come
ntario), new CommandBinding(_ocultar, ocultando));
CommandManager.RegisterClassInputBinding(typeof(Coment
ario), new InputBinding(_ocultar, new
MouseGesture(MouseAction.LeftClick)));
}

}
Visual Basic.NET
Public Class Comentario
Inherits ContentControl
Shared Sub New()
DefaultStyleKeyProperty.OverrideMetadata(GetType
(Comentario), New
FrameworkPropertyMetadata(GetType(Comentario)))
CommandManager.RegisterClassCommandBinding(GetTy
pe(Comentario), New CommandBinding(_ocultar,
ocultando))
CommandManager.RegisterClassInputBinding(GetType
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 355


(Comentario), New InputBinding(_ocultar, New
MouseGesture(MouseAction.LeftClick)))
End Sub
...
End Class

Como se puede ver en el ejemplo la clase est registrando el comando en el


constructor de la clase, que no puede acceder a la propiedad
CommandBindings porque esta no es una propiedad de clase. Para estos casos
se tiene la clase CommandManager, que nos provee de dos mtodos
RegisterClassCommandBinding, que registra un CommandBinding asociada
con una clase que suele ser la clase del control normalmente y
RetisterClassInputBinding, que nos permite asociar al comando un gesto.

Comandos en 4.0
En la versin 4.0 del Framework se han incluido algunas caractersticas
nuevas para el trabajo con comandos, para la simplificacin del proceso.
En concreto se ha creado la etiqueta KeyBinding. Que se sita en una coleccin de recursos, ya que no es visual y es capaz de enlazar con un comando
escrito como propiedad de la ventana a la que pertenece, y esto, y aqu viene el
ahorro, sin necesidad de insertar en marcado el espacio de nombres XML.
C#
public partial class MainWindow : Window
{
public EHCommand Comando { get; set; }
public MainWindow()
{
...
}
}
Visual Basic.NET
Public Partial Class MainWindow
Inherits Window
Public Property Comando() As EHCommand
Get
Return m_Comando
End Get
Set
m_Comando = Value
End Set
Gua prctica de desarrollo de aplicaciones Windows en .NET

356 | Windows Presentation Foundation


End Property
Private m_Comando As EHCommand
Public Sub New()
...
End Sub
End Class
XAML
<Window x:Class="EjercicioIII.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/pr
esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.InputBindings>
<KeyBinding Command="{Binding Comando}"
Gesture="CTRL+D" />
</Window.InputBindings>
<Grid>
<Button Content="Pulsa me..."
Command="{Binding Comando}" Width="100" Height="30" />
</Grid>
</Window>

A Continuacin
Los comandos nos ayudan a definir funcionalidad de una manera muy regular
y exportable, que sin duda permite crear un interfaz de conexin entre las
ventanas de la aplicacin y la lgica de negocio.
Esto adems permite que de manera extraordinariamente rpida podamos
realizar drsticos rediseos o propagar la solucin a un error encontrado
inmediatamente.

A Continuacin
XAML al igual que HTML es compatible con un sistema de estilos, que nos
permite variar rpidamente los estilos de una aplicacin. Adems veremos que
es una plantilla, que de manera sorprendente nos va a permitir redibujar
cualquier control a nuestro antojo.
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 357

Estilos Y
Plantillas
Cuando Microsoft decidi crear WPF varias fueron las cosas en las que se
inspir. Pero quiz una de las ms significativas fue el desarrollo web y las
tecnologas para hacerlo.
Efectivamente la idea del marcado no era nueva, as como la separacin
efectiva entre interfaz y lgica de interfaz. Estas caractersticas ya se haban
utilizado en el desarrollo web. Pero se quiso ir ms all y se introdujo tambin
una tcnica de plantillas para emular lo que en el mbito web hace CSS.
Adems, y no contentos con ello, se ha incluido un sistema de plantillas que
bien podra emular el comportamiento de los controles de servidor ASP.NET.
Estos controles se definen en el servidor, pero dado que no pertenecen a la
especificacin estndar de HTML, los navegadores no saben pintarlos. La
solucin se encuentra en que estos mtodos poseen un mtodo llamado
Render que se ejecuta antes de que la pgina sea servida, insertando el HTML
equivalente al control.
Algo similar hacen los controles en WPF. Cada control tiene lo que se conoce
como una plantilla que es un conjunto de Visuales que son insertados en el
Gua prctica de desarrollo de aplicaciones Windows en .NET

358 | Windows Presentation Foundation

lugar del control. La diferencia es que el control de por si no se puede pintar


pero los visuales si.
Las plantillas pueden pintar todo el control o slo una parte, por ejemplo es
habitual que controles como el ListBox tenga una plantilla para ellos y otra
para sus elementos.

Estilos
En WPF entendemos por estilo una determinada configuracin en cuanto a las
propiedades de un objeto de una determinada clase. Cuando esta
configuracin se asigna, todos los valores se asignan, transmitiendo al objeto
un estado concreto.
Un estilo en WPF consiste bsicamente en una serie de asignaciones
establecidas por una tag <setter> dentro de una tag <style>.
XAML
<Button>
<Button.Style>
<Style>
<Setter Property="VerticalAlignment"
Value="Center" />
</Style>
</Button.Style>
</Button>

En el ejemplo anterior podemos comprobar como un botn tiene asignado en


su propiedad Style un estilo, que establece su propiedad VerticalAlignment a
Center. Esto produce exactamente el mismo efecto que si hubiramos
asignado la propiedad directamente. Para qu sirve entonces?. Bueno, los
estilos se pueden definir como recursos y asignarse discriminalmente
mediante binding de recursos.
XAML
<Grid>
<Grid.Resources>
<Style x:Key="EstiloBoton">
<Setter Property="VerticalAlignment"
Value="Center" />
</Style>
</Grid.Resources>
<Button Style="{StaticResource EstiloBoton}"/>
<Grid>

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 359

En esta configuracin la asignacin se convierte en muy apropiada si tenemos


ms de un botn dentro del mbito, en este caso un grid, porque ahorramos
cdigo en cuanto el estilo establezca ms de una propiedad, adems de ahorrar
en consistencia, hay poca probabilidad de olvidar alguna asignacin.
Sin embargo cualquier observador que haya probado estos cdigos habr visto
que el Intellisense de VS al ir introduciendo las tag setter y establecer la
propiedad Property, nos sale una lista de propiedades cuando menos
incompleta. Esto se debe a que todos los estilos se crean para una clase
concreta que ha de ser especificada implcitamente, porque si no el sistema
entender que es para la clase FrameworkElement, y solo mostrar sus
propiedades.
Para poder cambiar la clase a la que va dirigida un estilo hemos de especificar
la propiedad TargetType en la que haremos constar, por su nombre, la clase.
XAML
<Grid>
<Grid.Resources>
<Style x:Key="EstiloBoton"
TargetType="Button">
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="Background" Value="Red"
/>
</Style>
</Grid.Resources>
<Button Style="{StaticResource EstiloBoton}"/>
<Grid>

Como vemos en el ejemplo ya podemos establecer propiedades de la clase


Button insisto, no por el Intellisense solamente, sino porque el sistema
entiende que el estilo va dirigido a los botones.
Otra manera ms especifica de asignar propiedades de una clase es la de hacer
constar la clase precediendo al nombre de la propiedad en el Setter. De esta
manera evitamos tener que atribuir un tipo a todo el tipo y podemos crear
estilos de aplicacin mltiple.
XAML
<Grid>
<Grid.Resources>
<Style x:Key="EstiloBoton">
<Setter
Property="FrameworkElement.VerticalAlignment"
Value="Center" />
<Setter Property="Button.Background"
Value="Red" />
<Setter Property="RadioButton.IsChecked"
Gua prctica de desarrollo de aplicaciones Windows en .NET

360 | Windows Presentation Foundation


Value="True" />
</Style>
</Grid.Resources>
<Button Style="{StaticResource EstiloBoton}"/>
<RadioButton Style="{StaticResource
EstiloBoton}"/>
<Grid>

Otra caracterstica interesante es que el estilo, cuando se encuentra definido


dentro de los recursos acepta una convencin especial, en ausencia de la
propiedad x:Key (de ah la expresin convencin, porque como dijimos en el
captulo de recursos no se pueden tener elementos en ellos sin x:Key) los
estilos se convierten en estilos de asignacin automtica para todos aquellos
elementos cuya clase coincida y caigan dentro de su mbito.
XAML
<Grid>
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="VerticalAlignment"
Value="Center" />
<Setter Property="Background" Value="Red"
/>
</Style>
</Grid.Resources>
<Button />
<Grid>

Esta seccin de cdigo producira la misma salida que el anterior aunque no


existe una asignacin especfica.
La ltima de las caractersticas bsicas que vamos a comentar sobre los estilos
es la herencia. Esta caracterstica se soporta y produce, convenientemente
usada, un ahorro de esfuerzo en la creacin de estilos consistentes para todos
los elementos de la aplicacin. Esto quiere decir que si diseamos
correctamente nuestros estilos pueden evitarnos trabajo, ya que podemos
definir estilos desde lo ms general a lo ms concreto, que paulatinamente
asignen las propiedades en una jerarqua de estilos que nos evite cdigo
reiterado. Para que un estilo pueda heredar de otro simplemente tenemos que
hacer constar en su propiedad BaseOn, que estilo ha de ser su antecesor.
XAML
<Grid>
<Grid.Resources>
<Style x:Key="EstiloGeneral">
<Setter
Property="FrameworkElement.VerticalAlignment"
Value="Center" />
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 361


</Style>
<Style x:Key="EstiloBoton"
BasedOn="{StaticResource EstiloGeneral}">
<Setter Property="Button.Background"
Value="Red" />
</Style>
<Style x:Key="EstiloRadio"
BasedOn="{StaticResource EstiloBoton}">
<Setter
Property="RadioButton.IsChecked" Value="True" />
</Style>
</Grid.Resources>
<Button Style="{StaticResource EstiloBoton}"/>
<RadioButton Style="{StaticResource
EstiloRadio}"/>
<Grid>

Plantillas de datos
A diferencia de un estilo una plantilla no persigue asignar una determinada
configuracin a varias de las propiedades de un objeto, sino slo a una de ellas.
En el caso de las plantillas de datos a la propiedad ItemTemplate.
Esta propiedad es donde reside la plantilla que se va a aplicar cuando se dibuje
un elemento de un objeto que pueda mostrar varios elementos, como por
ejemplo un ListBox.
Tomemos un proyecto con estas dos clases definidas:
C#
public class Persona
{
public string Nombre { get; set; }
public string Apellidos { get; set; }
}
public class ListaPersonas : List<Persona>
{
}
Visual Basic.NET
Public Class Persona
Property Nombre As String
Property Apellidos As String
End Class
Public Class ListaPersonas
Gua prctica de desarrollo de aplicaciones Windows en .NET

362 | Windows Presentation Foundation


Inherits List(Of Persona)
End Class

Y una ventana cuyo XAML es el siguiente:


XAML
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/pr
esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:app="clr-namespace:WpfApplication4"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<app:ListaPersonas x:Key="lista">
<app:Persona Nombre="Pepe"
Apellidos="Sanchez" />
<app:Persona Nombre="Jose"
Apellidos="Martinez" />
</app:ListaPersonas>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{StaticResource lista}"
/>
</Grid>
</Window>

Obtendremos un ListBox con una serie de elementos que nos mostrarn en vez
del nombre y los apellidos, el nombre completamente calificado de la clase
Persona.
Si queremos que esto suceda de otra manera uno de los caminos que podemos
tomar es la de la plantilla de elementos. Para ello en la propiedad
ItemTemplate hay que hacer constar un DataTemplate.
XAML
<ListBox ItemsSource="{StaticResource lista}">
<ListBox.ItemTemplate>
<DataTemplate>
<Ellipse Width="10" Height="10" Fill="Red" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Como podemos ver ahora, y tras la aplicacin de la plantilla en vez del nombre
de la clase lo que aparece son unos crculos rojos. Eso es porque la plantilla
contiene eso en un crculo. Pero evidentemente lo que queremos es que
aparezcan los nombres y los apellidos, as que como es una plantilla de
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 363

elementos, el DataContext de la plantilla ser cada uno de los elementos la


lista, por lo que ahora podemos introducir expresiones de binding
contextualizadas al elemento al que se le aplica la plantilla.
XAML
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="10" Height="10" Fill="Red" />
<TextBlock Text="{Binding Path=Nombre}" />
</StackPanel>
</DataTemplate>

As ya podemos ver el nombre junto al crculo.


Evidentemente la plantilla al igual que los estilos se puede situar en los
recursos. De esta manera si queremos aplicrsela a ms de un ListBox es
mucho ms fcil.
Por otro lado, y al igual que los estilos hay una manera para que la plantilla se
aplique all donde haga falta sin necesidad de aplicarla explcitamente, es
asignando la propiedad DataType que acta como el TargetType en los estilos,
pero en este caso refirindose al tipo de dato (clase) del cual depende, en este
caso persona.
XAML
<Window.Resources>
...
<DataTemplate DataType="{x:Type app:Persona}">
<StackPanel Orientation="Horizontal">
<Ellipse Width="10" Height="10" Fill="Red" />
<TextBlock Text="{Binding Path=Nombre}" />
</StackPanel>
</DataTemplate>
</Window.Resources>

Plantillas de controles
Si las plantillas de datos estn diseadas para aplicarse all donde el dato las
necesita, las plantillas de controles estn especficamente diseadas para
repintar todo un control. Tomemos un botn:
XAML
<ControlTemplate x:Key="plantilla"
TargetType="Button">
<Border Width="{TemplateBinding Width}"
Gua prctica de desarrollo de aplicaciones Windows en .NET

364 | Windows Presentation Foundation


Height="{TemplateBinding Height}" BorderThickness="1"
BorderBrush="{TemplateBinding Foreground}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="80*"/>
</Grid.ColumnDefinitions>
<Rectangle Fill="{TemplateBinding Background}"
Grid.Column="0" />
<ContentPresenter Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>

Si definimos una plantilla como la anterior cambiaremos por completo su


aspecto al asignrsela mediante el correspondiente binding de recurso.
Cosas interesantes que podemos observar en la plantilla son:
1.

El tipo de la plantilla no es DataTemplate sino ControlTemplate, y ha de


ser as porque pretendemos redefinir el control por completo, al menos en
su aspecto.

2. Evidentemente existen datos del control que vamos a necesitar en el


diseo de la plantilla, por ejemplo sus dimensiones, si no el aspecto se
puede ver seriamente afectado. Para ello tenemos un binding especial para
plantillas, el TemplateBinding que acompaado del nombre de la
propiedad nos permite enlazar con cualquier propiedad.
3. Para que este binding funcione necesitamos establecer el TargetType
correspondiente, porque igual que en los estilos las plantillas sin tipo
piensan estar diseadas para la clase FrameworkElement.
4. El control puede tener contenido, que como sabemos puede ser un texto,
una imagen o cualquier tipo de panel y con l un nmero ilimitado de
elementos WPF. Para que las plantillas puedan representarlo y no
simplemente cubrirlo existe el marcador ControlTemplate, que all donde
se ponga reinsertar el contenido original del control.
Sin embargo la diferencia entre estilos y plantillas reside en que estas ltimas
no pueden ser de manera automtica como si lo hacen los estilos. Si
prescindimos de la propiedad x:Key en una plantilla recibiremos un error en la
compilacin. Ahora no podemos negar que si esto se pudiera hacer sera
sumamente til, ya que nos permitira cambiar el aspecto de todos los botones
de una ventana o incluso de una aplicacin.
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 365

Pues no temamos conseguir este efecto, es sumamente fcil ya que lo nico


que hay que hacer es crear un estilo que contenga una plantilla. Esto es posible
porque a fin de cuentas una plantilla no es ms que el contenido de una
propiedad, Template.
XAML
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate x:Key="plantilla"
TargetType="Button">
<Border Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" BorderThickness="1"
BorderBrush="{TemplateBinding Foreground}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="80*"/>
</Grid.ColumnDefinitions>
<Rectangle Fill="{TemplateBinding Background}"
Grid.Column="0" />
<ContentPresenter Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Triggers
Si aplicamos el estilo anterior a un botn o conjunto de botones obtendremos
una desagradable desilusin, si bien es cierto que el estilo del botn est
completamente cambiado hemos perdido en el proceso la interactividad. Ya no
parece pulsarse cuando hacemos clic. Una solucin a este problema puede ser
agregar al estilo lo siguiente:
XAML
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Red" />
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
Gua prctica de desarrollo de aplicaciones Windows en .NET

366 | Windows Presentation Foundation

Como podemos comprobar al pulsar ahora el botn su color cambia a rojo,


pero por qu?
Esto se debe a los Trigger, en espaol disparador, que como vemos establece
como si fuera un estilo alternativo o aplicable slo en determinadas ocasiones,
estas que el propio Trigger establece. En el ejemplo cuando la propiedad
IsPressed est a True.
De hecho estos Triggers nos permiten unas posibilidades ilimitadas. Para
empezar en cuanto a la deteccin, adems del Trigger tenemos:

MultiTrigger que cuenta con la propiedad Conditions que nos permite


establecer ms de una condicin.

DataTrigger que en vez de Property tiene Binding lo que nos permite


vincular acciones a datos, por ejemplo cambiar el color de una celda, fila o
columna de DataGrid en virtud de un valor.

MultiDataTrigger, misma idea que el MultiTrigger pero aplicada a los


DataTriggers.

Adems de estos tipos tenemos otro que nos resultar muy til el
EventTrigger. Es este un disparador que se vincula a un RoutedEvent,
detectando cuando este es elevado por el control. Si lo tratamos de manera
separada se debe a que su contenido no puede ser en ningn caso una serie de
Setters, ya que slo admite animaciones a travs de lo que se conoce como
StoryBoard.
Toda vez que las animaciones sern tratadas ms adelante pospondremos
hasta entonces la profundizacin en estos eventos.

Recursos compartidos y temas


Como hemos visto a lo largo de todo el captulo los estilos y las plantillas nos
dan un nmero ilimitado de posibilidades de personalizar nuestras
aplicaciones hasta lmites insospechados hasta ahora.
Adems las personalizaciones no tienen por qu estar vinculadas al objeto en
concreto, si no que depositadas en recursos pueden aplicarse a todos los
elementos de un determinado mbito: control, panel, ventana, pgina,... y
aplicacin. Si existe un diccionario de recursos vinculado a la aplicacin y
adems es jerrquicamente superior a todo lo dems. Por lo que si definimos
algo a ese nivel se aplicar a todos los elementos.
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 367

Esto nos da una excelente oportunidad de tratar el aspecto visual de una


aplicacin como algo unificado y separado incluso del propio diseo del layout
de la aplicacin.
El problema suele ser que un diccionario de recursos que pretenda contener
todos los estilos de una aplicacin se volvera un Mare magnum imposible de
manejar. Es ah donde entra la propiedad MergedDictionaries de la clase
ResourceDictionary.
Esta propiedad se define como una coleccin de diccionarios, que nos permite
definir un diccionario como suma de otros. Esto se traduce en la prctica en
que, como podemos ver, VS nos permite agregar diccionarios de recursos a
nuestros proyectos, pero claro slo uno de ellos es el de la aplicacin, ahora
bien, con la propiedad MergedDictionaries simplemente podemos cargar todos
diccionarios que queramos sin sobrecargar el de aplicacin. Basta con abrir el
archivo App.xaml y agregar al Application.Resources lo siguiente:
XAML
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="" />
</ResourceDictionary>
</Application.Resources>

Haciendo constar en Source la ruta al archivo de diccionario y por supuesto


insertando todos los ResourceDictionary que queramos en la propiedad
MergedDictionaries.
Una ltima cosa antes de terminar. Es posible tambin cargar diccionarios
desde archivos en tiempo de ejecucin. De hecho es posible cargar cualquier
XAML. Para ello lo nico que hay que hacer es utilizar la clase XAMLReader.
Esta clase posee un mtodo Load que carga un fichero XAML y devuelve un
objeto. Leer por tanto un diccionario de recursos externo sera tan sencillo
como:
C#
XmlReader xml = XmlReader.Create("Estilo.xaml");
Application.Current.Resources =
(ResourceDictionary)XamlReader.Load(xml);
Visual Basic.NET
Dim xml As XmlReader = XmlReader.Create("Estilo.xaml")
Application.Current.Resources =
CType(XamlReader.Load(xml), ResourceDictionary)

Gua prctica de desarrollo de aplicaciones Windows en .NET

368 | Windows Presentation Foundation

Conclusin
Los estilos son una caracterstica bsica en HTML que se muestra muy til al
hora de especificar el aspecto visual de un sitio. En WPF tras la adaptacin de
esta tecnologa se va ms all y se integran tambin las plantillas que nos
permiten variabilizar completamente el aspecto visual de una aplicacin,
permitiendo de este modo precisar, a posteriori y sin necesidad de tocar ni
una sola coma del cdigo cualquier aspecto grfico de la aplicacin.

A Continuacin
Si algo podemos considerar una ventaja indiscutible en WPF es el apartado
grfico. Podemos crear grficos 2D y 3D, crear y controlar animaciones, aplicar
transformaciones y mucho ms. El nmero de recursos es sumamente amplio
y nos aporta una gran capacidad de personalizacin de aplicaciones. En el
siguiente captulo veremos cmo.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 369

Grficos y
Animaciones
WPF es un sistema de presentacin que a diferencia de Windows Forms
persigue la creacin de interfaces impactantes, con mucha interactividad y
adems incluyendo contenido audiovisual con tanto ahnco como persigue la
creacin de aplicaciones de formularios.
Es por esto que se incluye en la API junto con clases como TextBox o Button,
clases como Rectangle, FloatAnimation o MediaPlayer. Y es por esto que las
aplicaciones adems de servicios de datos y aplicaciones para disearlos y
tratarlos tienen tambin, servicios y aplicaciones para crear novedosos
interfaces destinados a mejorar la usabilidad, la imagen de marca y la
percepcin de nuestras aplicaciones.
Todo el soporte grfico se basa en la clase Visual. Esta clase es la abstraccin
de la cual desciende todos los elementos en WPF.
Esta clase nos aporta soporte para renderizado, gestin de lmites, deteccin
de entradas y transformaciones, sin embargo no tiene soporte para eventos,
layout, estilos, Data Binding o globalizacin.

Gua prctica de desarrollo de aplicaciones Windows en .NET

370 | Windows Presentation Foundation

Graficos y renderizado
El nmero de elementos a cubrir en este punto valdra en si mismo para
escribir un libro, con lo cual el lector no ha de esperar un tratamiento
exhaustivo de lo que aqu exponemos, tan solo se pretende esbozar un ejemplo
en cada uno de los palos que componen el apartado grfico que bsicamente
seran: efectos, brushes, drawings, geometras, shapes y transformaciones.
Los efectos son algoritmos que aplicados a los diferentes elementos que
componen un interfaz WPF consiguen transformar la manera que tienen de
presentarse acorde con el carcter del efecto. Es decir, un DropShadowEffect
aplicado a un botn dibuja el botn como si este tuviera sombra. Toda esta
parte de la API sufri en el Framework 3.5 una intensa remodelacin que
condujo a la sustitucin de los antiguos BitmapEffect, no funcionales ya en
4.0, por los Effect. Actualmente la API consta de las siguientes clases:
Clase

Descripcin.

BlurEffect

Genera un efecto blur.

DropShadowEffect

Genera un efecto sombra.

Effect

Clase base para crear efectos personalizados.

PixelShader

Es un wrapper de alto nivel en torno al soporte de los efectos


basados en Pixel Shader.

ShaderEffect

Clase base para crear efectos personalizados basados en Pixel


Shader.

La aplicacin de los efectos se hace a travs de la propiedad Effects, tal como


se ve en el ejemplo:
XAML
<Button Width="100" Height="30" Name="Button1"
Content="Pulsame">
<Button.Effect>
<DropShadowEffect />
</Button.Effect>
</Button>

Las Brushes o brochas son bsicamente una serie de clases cuyos objectos
sirven para rellenar de una u otra manera los grficos. Podemos tener brochas
que se encarguen de definir el fondo de un elemento o el trazo de su borde.
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 371

Existen varios tipos de brochas:


Brocha

Tipo ejemplo

Slida, representa un color


simple.

<Rectangle Width="75"
Height="75">

Resultado

<Rectangle.Fill>
<SolidColorBrush
Color="Red" />
</Rectangle.Fill>
</Rectangle>

Gradiente lneal, establece


<Rectangle Width="75"
una brocha entre dos o ms
Height="75">
colores que transita en funcin
<Rectangle.Fill>
de una recta.
<LnearGradientBrush>
<GradientStop
Color="Yellow" Offset="0.0"
/>
<GradientStop
Color="Orange" Offset="0.5"
/>
<GradientStop
Color="Red" Offset="1.0" />
</LnearGradientBrush>
</Rectangle.Fill>
</Rectangle>

Gua prctica de desarrollo de aplicaciones Windows en .NET

372 | Windows Presentation Foundation

Gradiente radial, establece


<Rectangle Width="75"
una brocha entre dos o ms
Height="75">
colores que transita en funcin
<Rectangle.Fill>
del radio de una
<RadialGradientBrush
circunferencia.
GradientOrigin="0.75,0.25">
<GradientStop
Color="Yellow" Offset="0.0"
/>
<GradientStop
Color="Orange" Offset="0.5"
/>
<GradientStop
Color="Red" Offset="1.0" />
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>

Estas brochas se basan en colores, en concreto los gradientes se establecen


entre GradientStop que son clases que establecen un color y un offset, medida
relativa relacionada con el tamao del objeto, y que pueden ser al menos dos o
ms.
Tambin existen brochas no vinculadas con el color:
Brocha

Tipo

Brocha de imagen, permite establecer como


brocha una imagen.

<Rectangle Width="75" Height="75">


<Rectangle.Fill>
<ImageBrush ImageSource="imagen.jpg"
/>
</Rectangle.Fill>
</Rectangle>

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 373

Brocha de tipo Drawing, permite establecer un <Rectangle Width="75" Height="75">


dibujo como imagen.
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry
Rect="0,0,100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
Brocha visual, que permite establecer como
brocha un elemento visual, es decir cualquier
control como un botn o un MediaElement,
que nos permita este ltimo establecer como
brocha un vdeo.

<Rectangle Width="75" Height="75">


<Rectangle.Fill>
<VisualBrush TileMode="Tile">
<VisualBrush.Visual>
<MideaElement Source="video.wmv" />
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>

Drawings son elementos que describen elementos visuales:

GeometryDrawing dibuja una shape.

ImageDrawing dibuja una imagen.

GlyphRunDrawing dibuja texto.

VideoDrawing reproduce ficheros de audio y video.


Gua prctica de desarrollo de aplicaciones Windows en .NET

374 | Windows Presentation Foundation

DrawingGroup dibuja un grupo de dibujos combinados en uno


compuesto.

Los objetos Drawing repiten muchas de las caractersticas que tienen otros
elementos, como por ejemplo determinados controles. Cundo, por tanto,
usar unos y otros? En general los objetos Drawing son elementos que
favorecen el rendimiento a costa de perder caractersticas de control, por
ejemplo control de foco, lgica de layout, etc.
Las shapes son rutinas de dibujo que representan formas simples o complejas.
Todas ellas derivan de la clase abstracta Shape, que define la propiedad Fill,
brocha de fondo y las popiedades stroke, que te permiten definir el patrn y la
brocha de borde.

Rectangle

Dibuja un rectngulo

<Rectangle Width="30"
Height="30" />

Ellipse

Dibuja una elipse

<Ellipse Width="30"
Height="30" />

Line

Dibuja una lnea

<Line X1="0" Y1="0"


X2="1" Y2="2" />

Polyline

Dibuja una lnea multipunto

<Polyline Points="10,10,1,1"
/>

Poligon

Idem a la polyline pero cierra


con el primer y ltimo punto

<Polygon
Points="10,10,1,1,30,15" />

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 375

Path

Shape que se establce como


un conjunto de geometras y o
segmentos combinados o no.

<Path Stroke="Black"
StrokeThickness="1"
Fill="#CCCCFF">
<Path.Data>
<GeometryGroup
FillRule="EvenOdd">
<LineGeometry
StartPoint="10,10"
EndPoint="50,30" />
<EllipseGeometry
Center="40,70"
RadiusX="30" RadiusY="30"
/>
<RectangleGeometry
Rect="30,55 100 30" />
</GeometryGroup>
</Path.Data>
</Path>

Una transformacin es un mecanismo para mapear puntos en un espacio de


coordenadas a otro. Esto se realiza mediante una matriz de transformacin.
Manipulando las matrices se pueden producir efectos como rotaciones,
traslaciones.
Aunque se pueden manipular las matrices a bajo nivel WPF aporta clases que
encapsulan las transformaciones ms comunes:
Clase

Descripcin

RotateTransform

Rota un elemento un ngulo especfico.

ScaleTransform

Sscala un elemento en funcin de los factores


ScaleX y ScaleY .

SkewTransform

Transformacin de sesgado en funcin de dos


ngulos AngleX y AngleY.

TranslateTransform

Mueve un elemento segn dos coordenadas X


e Y.

Gua prctica de desarrollo de aplicaciones Windows en .NET

376 | Windows Presentation Foundation

Para utilizar una transformacin se la asignamos a un FrameworkElement en


una de las dos propiedades de transformacin:

LayoutTransform una transformacin que se aplica antes de la situacin


del control del proceso de layout. Este proceso trabaja sobre el tamao y la
posicin el elemento una vez transformado.

RenderTransform Este modificacin trabaja sobre la apariencia del


elemento pero se aplica antes del proceso de layout. Este sita el control ya
transformado.

XAML
<Border Margin="30"
HorizontalAlignment="Left" VerticalAlignment="Top"
BorderBrush="Black" BorderThickness="1" >
<StackPanel Orientation="Vertical">
<Button Content="A Button" Opacity="1" />
<Button Content="Rotated Button">
<Button.RenderTransform>
<RotateTransform Angle="45" />
</Button.RenderTransform>
</Button>
<Button Content="A Button" Opacity="1" />
</StackPanel>
</Border>

Renderizado 3-D
WPF nos permite crear funcionalidad 3D. Esta funcionalidad est dirigida a
crear entornos ms ricos, complejas representaciones de los datos o mejorar la
experiencia de usuario, no para crear aplicaciones de alto rendimiento, como
por ejemplo juegos.
Los grficos 3D se encapsulan en un elemento llamado Viewport3D. Este
elemento es tratado como un elemento visual 2D que es una ventana al mundo
3D.
En el sistema bidimensional el origen se encuentra en el punto superior
izquierdo del contenedor, sin embargo en el 3D en el centro del rea. La
coordenada X crecer hacia la derecha y decrecer hacia la izquierda, la Y
positiva hacia arriba y negativa hacia abajo y la Z positiva desde el centro hacia
el observador.
Este espacio se define como un marco de referencia para los objetos (espacio
mundo), en el se pueden depositar cmaras, luces u objetos, esto ltimos
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 377

pueden ser visibles desde un determinado punto de vista (cmara) o no. El


punto de vista no cambia la posicin ni modifica los objetos.
Una escena 3D en realidad es una representacin 2D de un espacio 3D, en
funcin de un punto de vista. Este se puede especificar mediante una cmara.
Si asumimos la cmara como el punto de vista de un espectador, tambin
podemos decir que es la manera que tiene ese espectador de percibir una
escena.
Una ProjectionCamera permite especificar proyecciones y las propiedades de
estas para cambiar la perspectiva del observador, mientras que una
PerspectiveCamera nos permite restringir la escena con un punto de
desvanecimiento, posicin, direccin de encuadre. Adems cuenta con dos
planos el NearPlaneDistance y FarPlaneDistance que establecen los lmites de
proyeccin, de forma que los elementos que se encuentren fuera del espacio
delimitado por ellos no son visibles.
La OrthographicCamera especifica una proyeccin ortogonal como otras
cmaras establece posicin, direccin, etc. pero no tiene efecto horizonte, esto
significa que los elementos no parecen empequeecer cuando se alejan.
La clase abstracta Model3D que representa objetos 3D, necesarios para crear
escenas. WPF soporta GeometryModel3D que nos permite establecer un
modelo en funcin de una primitiva, actualmente slo se soporta la clase
MeshGeometry3D que necesita especificar lista de posiciones (vrtices de
tringulos) y lista de vrtices (agrupacin de esto de 3 en 3).
Tambin se especifican coordenadas de texturas para situar sobre la forma y
normales que nos permiten especificar la cara de la faceta a la que se aplica la
textura, as como calcular la incidencia de la luz sobre una cara concreta del
objeto.
XAML
<GeometryModel3D>
<GeometryModel3D.Geometry>
<MeshGeometry3D
Positions="-1 -1 0 1 -1 0 -1 1 0 1 1
0"
Normals="0 0 1 0 0 1 0 0 1 0 0 1"
TextureCoordinates="0 1 1 1 0 0 1 0
"
Trianglendices="0 1 2 1 3 2" />
</GeometryModel3D.Geometry>
<GeometryModel3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush Color="Cyan"
Opacity="0.3"/>
Gua prctica de desarrollo de aplicaciones Windows en .NET

378 | Windows Presentation Foundation


</DiffuseMaterial.Brush>
</DiffuseMaterial>
</GeometryModel3D.Material>
<!-- Translate the plane. -->
<GeometryModel3D.Transform>
<TranslateTransform3D
OffsetX="2" OffsetY="0" OffsetZ="-1"
</TranslateTransform3D>
</GeometryModel3D.Transform>
</GeometryModel3D>

>

Los objetos para ser visibles necesitan materiales adems de estar iluminados.
Los modelos para ello pueden aplicar un descendiente de la clase abstracta
Material, cada una de las cuales provee de un aspecto concreto en funcin del
material adems de proveer una propiedad para especificar una brocha:
DiffuseMaterial especifica que el material se aplica iluminado difusamente, no
refleja la luz.
SpecularMaterial en este caso el material refleja la luz.
EmissiveMaterial, este tipo de material emite luz del coincidente con la
textura.
Las escenas tambin han de ser iluminadas, para ello contamos con diferentes
tipos de luces.
AmbientLight: Luz ambiente que ilumina todos los objetos por igual.
DirectionalLight: Iluminan como una fuente distante, con direccin pero no
localizacin.
PointLight: Iluminan como un origen cercano, tiene posicin pero no
direccin, y un rango fuera del cual ya no ilumina.
SpotLight: Hereda de PointLight disponiendo de posicin y direccin.
XAML
<ModelVisual3D.Content>
<AmbientLight Color="#333333" />
</ModelVisual3D.Content>

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 379

Animacin
Las animaciones son pequeos algoritmos que en un espacio de tiempo
transitan desde un valor a otro cuyo tipo depender del tipo de la animacin.
As una animacin numrica puede transitar entre 1 y 2 en un segundo.
La utilidad de una animacin es que se puede conectar con una propiedad de
un objecto, cuyo tipo sea compatible y de manera automtica esta se ver
modificada transitando entre los valores de la animacin en el tiempo
especificado.
Un StoryBoard es una agrupacin de animaciones que permite crear efectos
complejos por la suma de estas. Adems el StoryBoard crea unas propiedades
attached que nos permiten vincular las animaciones con los diferentes
elementos y sus correspondientes propiedades.
XAML
<Storyboard>
<DoubleAnimation From="0" To="5"
Duration="00:00:00.5" Storyboard.TargetName="effect"
Storyboard.TargetProperty="ShadowDepth" />
</Storyboard>

En el ejemplo podemos ver como una animacin que dura apenas mdio
segundo y que transita entre 0 y 5 se aplica a la propiedad ShadowDepth
perteneciente a un elemento llamado effect, que es un ShadowEffect.
Existen decenas de tipos de animaciones e incluso varias versiones de una
misma animacin. Double, Single, Point, Point3D, String, etc.. son tipos que
soportan animaciones, en algunos casos slo del tipo UsingKeyFrames.
Estas animaciones se diferencian de las normales en que contienen una serie
de KeyFrames, valores intermedios, que nos permiten establecer puntos de
inicio y final intermedios. Con ellos logramos cosas como transiciones no
lneales o incluso y segn el caso mejoras de rendimiento.
La clase StoryBoard tiene una serie de mtodos que desde programa nos
permite ejecutarla, pararla, cancelarla, etc. Pero lo mejor de los StoryBoard es
que existen una serie acciones de trigger que nos permiten hacer lo mismo.
Si recordamos cuando hablbamos de los trigger mencionbamos uno en
especial, EventTrigger que nos permite enlazar con las siguientes acciones:

Gua prctica de desarrollo de aplicaciones Windows en .NET

380 | Windows Presentation Foundation

Accin de Trigger

Efecto

BeginStoryBoard

Arranca un Storyboard

ResumeStoryBoard

Restaura un Storyboard despus de parado

PauseStoryBoard

Para un Storyboard

Esto es sumamente til porque nos permite crear StoryBoards sin necesidad
de incluir cdigo en nuestra aplicacin. Esto produce que los diseadores y
programadores puedan trabajar conjuntamente de una manera simultnea, a
tiempo que se reduce la complejidad del cdigo.
XAML
<Button x:Name="button2" Width="100" Height="30"
Content="Pulsame">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="1" To="0"
Storyboard.TargetName="button2"
Storyboard.TargetProperty="Opacity" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>

Visual State Manager


Adems de los Triggers existe otra manera de lanzar una animacin y esta es
Visual State Manager. Esta forma fue originalmente desarrollada para
Silverlight, ya que el modelo de objetos de este no permite los Triggers, como
mecanismo sencillo para hacer transitar visualmente los objetos desde un
punto a otro. El mecanismo se revel tan sencillo y fue tan bien acogido por la
comunidad de desarrolladores que finalmente ha realizado el camino hacia la
tecnologa padre, a diferencia de lo que normalmente suele pasar que las
novedades se incorporan primero a WPF o son tan especficas que finalmente
permanecen en Silverlight.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 381

En todo caso utilizar el Visual State Manager es tan sencillo como anidar un
nodo VisualStateManager.VisualStateGroup, dentro de este definir un
VisualStateGroup que puede acoger diferentes estados en nodos VisualState, a
los cuales se les otorga un nombre y que bsicamente acogen un StoryBoard
que se ejecutar cuando le comuniquemos al Visual State Manager que
queremos que el objeto transite a un determinado estado.
XAML
<Button Width="100" Height="30" Name="Button1"
Content="Pulsame">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState Name="normal">
<Storyboard>
<DoubleAnimation BeginTime="00:00:00.5" From="1"
To="0" Duration="00:00:00.5"
Storyboard.TargetName="Trans"
Storyboard.TargetProperty="ScaleX" />
</Storyboard>
</VisualState>
<VisualState Name="sobre">
<Storyboard>
<DoubleAnimation BeginTime="00:00:00.5" From="0"
To="1" Duration="00:00:00.5"
Storyboard.TargetName="Trans"
Storyboard.TargetProperty="ScaleX" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Button.RenderTransform>
<ScaleTransform x:Name="Trans" />
</Button.RenderTransform>
</Button>

En el ejemplo anterior se crean dos estados en un botn que acogen sendas


animaciones. La ejecucin de esas animaciones tendr lugar cuando
voluntariamente informemos al Visual State Manager de que queremos que
suceda invocando el mtodo GoToElementState o GoToState si los estados
estn definidos en una plantilla.
C#
VisualStateManager.GoToElementState(Button1, "sobre",
true);
Visual Basic.NET
VisualStateManager.GoToElementState(Button1, "sobre",
true)

Gua prctica de desarrollo de aplicaciones Windows en .NET

382 | Windows Presentation Foundation

Tratamiento de medios
Como ya vimos en captulos anteriores existe un amplio soporte para medios
en WPF. Tenemos controles y otro tipo de elementos que nos permiten
reproducir desde imgenes estticas hasta vdeos o audio.
Las imgenes incluyen iconos, fondos e incluso partes de animaciones. El
trabajo bsicamente se realiza a travs de la clase Image que nos permite
introducir una imagen en marcado o hacer tratamiento no visual de ella.
Ejemplos de las capacidades de esta clase pueden ser:
1.

Cambio de formato de pixel.

XAML
<Image Width="200" >
<Image.Source>
<FormatConvertedBitmap Source="imagen.jpg"
DestinationFormat="Gray4" />
</Image.Source>
</Image>

2. Aplicacin de una mscara de corte.


XAML
<Image Width="200" Source="imagen.jpg">
<Image.Clip>
<EllipseGeometry Center="75,50" RadiusX="50"
RadiusY="25" />
</Image.Clip>
</Image>

3. Diferentes formas de adaptacin de la imgen al espacio disponible.


XAML
<Image
Source="imagen.jpg"
Stretch="Fill" />

En cuanto al vdeo y al audio disponemos de una clase, MediaElement, que nos


permite de manera sencilla reproducir vdeos, archivos de audio e incluso
streaming.
XAML
<MediaElement Source="Clock.avi" Width="450"
Height="250" />

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 383

Conclusin
Casi todo en WPF est orientado a potenciar las capacidades grficas. Es este
sin duda el principal objetivo de esta tecnologa y el factor diferenciador. En el
captulo hemos intentado dar una idea general de lo que esta API permite
hacer en este campo.

A continuacin
El tratamiento documental es algo que habitualmente tiene mucha
importancia en las aplicaciones pero que solemos pasar desapercibido a la
hora de evaluar un API de programacin. Comnmente es debido a que suelen
ser servicios externos, generadores de informes y dems los que asumen esta
responsabilidad.
Sin embargo WPF incorpora un soporte documental que nos permite
ciertamente mucha flexibilidad, a continuacin veremos cmo.

Gua prctica de desarrollo de aplicaciones Windows en .NET

384 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 385

Documentos
A diferencia de las versiones de Windows, WPF contiene un soporte para la
creacin, lectura y gestin de la seguridad de documentos de alta calidad, as
como las clases necesarias para su tratamiento.

Documentos en WPF
WPF soporta dos tipos de documentos, "flow documents" y "fixed documents".
Los primeros estn indicados para su uso en aquellas aplicaciones que
pretenden mostrar documentos agradables y adaptables para su lectura, los
segundos en cambio estn ms orientados para la creacin de aplicaciones que
busca precisin en la reproduccin de documentos, WYSIWYG o impresin.
WPF nos aporta una serie de controles que facilitan el uso y la muestra de
ambos tipos de documentos. En el caso de los documentos fijos disponemos
del control DocumentViewer y en el caso de los de flujo FlowDocumentReader,
FlowDocumentPageViewer y FlowDocumentScrollViewer.
El control DocumentViewer nos permite operaciones como impresin, copia,
zoom y bsqueda adems de soportar, como muchos otros controles WPF, la
aplicacin de un nuevo estilo completo o parcial que adapte el control al estilo

Gua prctica de desarrollo de aplicaciones Windows en .NET

386 | Windows Presentation Foundation

visual de nuestra aplicacin. La restriccin principal de este control es que es


de slo lectura, la edicin no est soportada.
En el caso de los documentos no fijos disponemos de ms tipos de controles
segn necesitemos ms o menos caractersticas y queramos balancear el peso
del control.
El control FlowDocumentReader permite que el usuario cambie
dinmicamente el modo de visualizacin, ms modestos
FlowDocumentPageViewer y FlowDocumentScrollViewer nos aportan
visualizaciones fijas, como pgina o una simple cinta sin fin, que se pueden
adaptar a otras necesidades y son ms baratos en trmino de recursos.
XAML
<FlowDocumentReader>
<FlowDocument>
<Paragraph>
<Bold>Algo de texto en un prrafo</Bold>
y algo de texto que no est en negrita.
</Paragraph>
<List>
<ListItem>
<Paragraph>Elemento 1</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Elemento 2</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Elemento 3</Paragraph>
</ListItem>
</List>
</FlowDocument>
</FlowDocumentReader>

Como se puede ver en el ejemplo el documento de flujo se est especificando


tambin como sintaxis de marcado. A continuacin veremos un poco ms en
detalle este tipo de documentos.

Documentos de flujo
Un documento de flujo esta diseado esencialmente para mejorar la
experiencia de lectura, para ello se ha de adaptar al espacio disponible, la
resolucin o preferencias del usuario.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 387

Estos documentos pueden ser consumidos por los controles especficos


adems de por RichTextBox, que nos aporta tambin la capacidad de editar
estos documentos.
XAML
<RichTextBox>
<FlowDocument>
<Paragraph>
Esto es un contenido editable.
</Paragraph>
</FlowDocument>
</RichTextBox>

Los elementos ms commente usados son los siguientes:


Elemento

Uso

Paragraph

Delimitador de prrafo.

Section

Agrupacin de varios prrafos.

BlockUIContainer

Contenedor de controles de UI dentro de un documento.

List

Elemento lista que contiene ListItems.

Tabla

Elemento tabla que contiene TableRow.

TableRow

Fila de una tabla que contiene TableCell.

TableCell

Celda de una tabla.

ListItem

Elemento unitario de una lista.

Run

Elemento para contener texto sin formato.

HyperLink

Hiperenlace contenido en el documento.

Bold

Estilo negrita.

Italic

Estilo cursiva.

Underline

Estilo subrayado.

InlineUIContainer

Contenedor de controles de UI dentro de un documento, dentro


de una lnea de texto.

Gua prctica de desarrollo de aplicaciones Windows en .NET

388 | Windows Presentation Foundation

Floater

Elemento destinado embeber contenido como imgenes o


anuncios, puede paginar pero no se puede posicionar ni
redimimensionar ms all de la columna de texto que ocupa.

Figure

Elemento destinado embeber contenido como imgenes o


anuncios, es posicionable, dimensionable pero no puede paginar.

LineBreak

Salto de lnea.

Serializacin y almacenaje de
documentos
WPF es capaz de manejar un documento en memoria, pero una de las
caractersticas claves del manejo de documentos es tambin guardarlos y
cargarlos desde un soporte de almacenamiento. Esto es lo que llamamos
serializacin.
El proceso de cargar o guardar documentos ha de ser transparente a la
aplicacin, en general esta debe llamar a mtodos Read o Write de un
serializador, sin tener que pensar en el formato.
Adems las aplicaciones proveen habitualmente de mltiples formatos para
leer y escribir documentos. Esa es la razn principal por la cual la arquitectura
de serializadores documentales de WPF es modular.
Las caractersticas principales que los serializadores tienen o han de tener son:

Acceso directo a los objetos del documentos a travs de un interfaz de alto


nivel.

Operatividad sncrona y asncrona.

Soporte para plug-ins y mejoras de las capacidades:

Amplio acceso para su uso desde cualquier aplicacin NET.

Mecanismo de descubrimiento de plug-ins.

Despliegue e instalacin sencillas.

Soporte de interfaz para opciones personalizadas.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 389

Por defecto el serializador instalado es XPS, que es un mecanismo nativo para


crear documentos en WPF y en Windows a partir de Vista.
Adems de este serializador tambin tenemos la oportunidad de desarrollar los
nuestros propios o adquirirlos a un fabricante.
Cuando esto sucede el sistema dispone de varios formatos y necesitamos poder
conocer cuales estn disponibles.
C#
SerializerProvider serializerProvider = new
SerializerProvider();
foreach (SerializerDescriptor serializerDescriptor in
serializerProvider.InstalledSerializers)
{
if (serializerDescriptor.IsLoadable)
{
}
}
Visual Basic.NET
Dim serializerProvider As New SerializerProvider()
For Each serializerDescriptor As SerializerDescriptor
In serializerProvider.InstalledSerializers
If serializerDescriptor.IsLoadable Then
End If
Next

Para localizar los plug-ins simplemente creamos una clase SerializerProvider


recorriendo la coleccin InstalledSerializers y asegurndonos de que se puede
usar a travs del mtodo IsLoadable. Tras lo cual no resta sino guardar el
archivo:
C#
Stream package = File.Create(fileName);
SerializerWriter serializerWriter =
serializerProvider.CreateSerializerWriter(
selectedPlugIn, package);
IDocumentPaginatorSource idoc = flowDocument as
IDocumentPaginatorSource;
serializerWriter.Write(idoc.DocumentPaginator, null);
package.Close();
Visual Basic.NET
Dim package As Stream = File.Create(fileName)
Dim serializerWriter As SerializerWriter =
serializerProvider.CreateSerializerWriter(selectedPlug
In, package)
Dim idoc As IDocumentPaginatorSource =
Gua prctica de desarrollo de aplicaciones Windows en .NET

390 | Windows Presentation Foundation


TryCast(flowDocument, IDocumentPaginatorSource)
serializerWriter.Write(idoc.DocumentPaginator,
Nothing)
package.Close()

Para ello y debido a la curiosa estructura de los archivos XPS hemos de crear
un paquete que junto con el plug-in nos permite crear el serializador. Por
ltimo serializamos el documento.

Anotaciones
Las anotaciones son notas o comentarios que se aaden a los documentos y
que nos permiten marcar informacin o resaltar puntos de inters.
Existe dos tipos de notas Sticky Notes y Highlights.
Las primeras contienen informacin en un papel que se "pega" al documento,
adems de cumplir con su funcin nos permiten mejorar la experiencia de
usuario en dispositivos como Tablet o Tablet PC.
C#
AnnotationService _annotService = new
AnnotationService(docViewer);
FileStream _annotStream = new FileStream(
_annotStorePath, FileMode.OpenOrCreate,
FileAccess.ReadWrite);
XmlStreamStore _annotStore = new
XmlStreamStore(_annotStream);
_annotService.Enable(_annotStore);
Visual Basic.NET
Dim _annotService As New AnnotationService(docViewer)
Dim _annotStream As New FileStream(_annotStorePath,
FileMode.OpenOrCreate, FileAccess.ReadWrite)
Dim _annotStore As New XmlStreamStore(_annotStream)
_annotService.Enable(_annotStore)

Para utilizar estas anotaciones se ha de crear un servicio asociado a un


documento y un almacn de notas (XmlStreamStore), para luego habilitar este
servicio vinculado al almacn.
Los Highlights son dibujos que utilizamos para resaltar partes del texto,
similar a pintar con un rotulador de marcado.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 391

La creacin y borrado de anotaciones, sticky notes y highlights se realiza a


travs de comandos de la clase AnnotationService, conveniente porque
adems de invocar por cdigo se puede vincular a mens y botones.

Conclusin
El tratamiento de documentos es tambin una de las caractersticas de WPF.
Se nos permite crear documentos adaptados a lectura o impresin, con
servicios que nos permiten partiendo de los primeros crear los segundos. Por
ltimo tenemos la capacidad de crear notas para comentar documentos ya
existentes.
Esto incrementa considerablemente las capacidades de los dispositivos
programados con WPF, ya que nos permite integrar un buen conjunto de
tecnologas que van desde los e-Books al tratamiento documental avanzado.

A continuacin
Otra de las caractersticas de cualquier plataforma de desarrollo es la
extensibilidad. En WPF podemos extender la plataforma de muchas maneras
pero la ms comn es la de crear nuevos controles. En el siguiente captulo
veremos cmo.

Gua prctica de desarrollo de aplicaciones Windows en .NET

392 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 393

Controles
Siguiendo un modelo que no es nuevo, en WPF, podemos optar por dos
caminos diferentes a la hora de crear controles. De un lado se encuentran los
controles de usuario, fciles de desarrollar pero con un nivel de
encapsulamiento pequeo o los controles personalizados, ms complicados
pero mejor resueltos a nivel de interfaz de programacin.
Sin embargo a diferencia de otros mecanismos de programacin no es tan
frecuente el desarrollo de nuevos controles, ya que WPF proporciona mltiples
mecanismos para personalizar controles.

Controles de usuario
Los controles de usuario son una seria opcin antes de introducirse en el
farragoso mundo de la creacin de controles personalizados.
Y lo son porque la complejidad de desarrollo es relativamente baja, pudiendo
por otro lado insertarlos en una librera sin mayores problemas e insertarlos
en aquellas aplicaciones que necesitemos.

Gua prctica de desarrollo de aplicaciones Windows en .NET

394 | Window
ws Presentattion Found
dation

Paraa crear un co
ontrol de usu
uario lo nicco que debem
mos hacer es agregarlo a
nuesstro proyecto, y obtendrremos un disseador muy similar a una
u ventanaa,
slo que en estee disearemo
os un controol en vez de toda
t
una ven
ntana.

XAML
L
ontrol x:C
Class="Use
erControl1
1"
<UserCo
xmlns="
"http://sc
chemas.mic
crosoft.co
om/winfx/2
2006/xaml/
/pr
esentat
tion"
xmlns:x
x="http://
/schemas.m
microsoft.
.com/winfx
x/2006/xam
ml"
xmlns:m
mc="http:/
//schemas.
.openxmlfo
ormats.org
g/markupcompatibility/20
006"
xmlns:d
d="http://
/schemas.m
microsoft.
.com/expre
ession/ble
end
/2008"
m
mc:Ignorab
ble="d"
d
d:DesignHe
eight="300
0" d:Desig
gnWidth="3
300">
<Grid>
</Grid>
>
</UserC
Control>

Tras la compilaciin el contro


ol, como con
ntrol
perso
onalizado, ap
parecer insstalado en nu
uesta ToolB
Box y
ya s
lo nos restara arrastrarrlo como si d
de un contro
ol
coven
ncional se trrastase.

La
a jerarqua
a de
ob
bjetos
s en WPF
W
Bien,, si a pesar de
d todas las opciones
o
paara
no haacerlo seguim
mos pensan
ndo que
desarrrollar un nu
uevo controll es el camin
no a
tomaar, entonces debemos co
onocer la
jerarq
qua de objeetos bsica de
d WPF ya q
que
afinaaremos ms a la hora de desarrollar el
nuevvo control, evvitando funccionalidad
inneccesaria o inccluyendo fun
ncionalidad
requeerida que, de otra forma
a, deberamoos
impleementar.
Todo
os los objetoss descienden
n de una missma
clasee que implem
menta las fun
ncionalidadees
Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windows Presentation Foundation | 395

bsicas llamada FrameworkElement, del que descienden tres clases que


dividen las intenciones del desarrollador, Panel, en el caso de que queramos
distribuir otros componentes mediante un lgica predeterminada, Decorator
si lo que queremos es un elemento que ample funcionalidades a elementos ya
existentes y control si queremos crear una clase que sea capaz de interactuar
con el usuario.
Si nos decidimos por el Control, cosa ms habitual, entonces deberamos
establecer si queremos un ContentControl, que sera la base para la mayora de
los controles habituales, un control capaz de tener contenido o un ItemControl
que es un control que slo puede existir dentro de otro. Una vez decidido
deberamos estudiar la rama en cuestin a fin de descender de la clase ms
apropiada.

Pasos para desarrollar un nuevo


control
Como ya dijimos el primer paso para crear un nuevo control es seleccionar la
clase base de la que vamos a descender el control. Despus debemos acometer
los siguientes pasos:
Definir la API, hemos de pensar cuidadosamente que funcionalidad y de que
manera se va a exponer.
Crear el interfaz, crearemos este interfaz creando la clase con los miembros
apropiados.
Template, crearemos la plantilla, necesaria como ya explicamos en el capitulo
de plantillas.
Funcionalidad, completaremos la funcionalidad, que no es posible abordar
hasta ahora ya que est ntimamente ligada a la plantilla.
El interfaz del control estar definido en funcin de:

Propiedades, dependientes o attached, tambin normales.

Eventos, eventos enrutados que nos permiten relacionarnos con los dems
elementos del interfaz.

Comandos, con las funcionalidades preestablecidas e importantes


preparadas o al menos previstas.

Gua prctica de desarrollo de aplicaciones Windows en .NET

396 | Windows Presentation Foundation

Sin embargo los mtodos son parte importante en todas las clases, en los
controles WPF slo sirven como apoyo, ya que estos como hemos podido
comprobar a lo largo del libro no se usan salvo a la manera tradicional, desde
cdigo.
C#
public class Comentario : ContentControl
{
static Comentario()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Coment
ario), new
FrameworkPropertyMetadata(typeof(Comentario)));
CommandManager.RegisterClassCommandBinding(typeof(Come
ntario), new CommandBinding(_ocultar, ocultando));
CommandManager.RegisterClassInputBinding(typeof(Coment
ario), new InputBinding(_ocultar, new
MouseGesture(MouseAction.LeftClick)));
}
public Brush ComentarioBackground
{
get { return
(Brush)GetValue(ComentarioBackgroundProperty); }
set {
SetValue(ComentarioBackgroundProperty, value); }
}
public static readonly DependencyProperty
ComentarioBackgroundProperty =
DependencyProperty.Register("ComentarioBackground",
typeof(Brush), typeof(Comentario), new
UIPropertyMetadata(Brushes.Aqua));
static RoutedCommand _ocultar = new
RoutedCommand();
static private void ocultando(object sender,
ExecutedRoutedEventArgs e)
{
Comentario obj = (Comentario)sender;
object sb =
(obj.Template.FindName("panel", obj) as
Grid).Resources["Ocultar"];
(sb as Storyboard).Begin();
}
}
Visual Basic.NET
Public Class Comentario
Inherits ContentControl
Shared Sub New()
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 397


DefaultStyleKeyProperty.OverrideMetadata(GetType(Comen
tario), New
FrameworkPropertyMetadata(GetType(Comentario)))
CommandManager.RegisterClassCommandBinding(GetTy
pe(Comentario), New CommandBinding(_ocultar, AddressOf
ocultando))
CommandManager.RegisterClassInputBinding(GetType
(Comentario), New InputBinding(_ocultar, New
MouseGesture(MouseAction.LeftClick)))
End Sub
Public Property ComentarioBackground() As Brush
Get
Return
DirectCast(GetValue(ComentarioBackgroundProperty),
Brush)
End Get
Set
SetValue(ComentarioBackgroundProperty, value)
End Set
End Property
Public Shared ReadOnly
ComentarioBackgroundProperty As DependencyProperty =
DependencyProperty.Register("ComentarioBackground",
GetType(Brush), GetType(Comentario), New
UIPropertyMetadata(Brushes.Aqua))
Shared _ocultar As New RoutedCommand()
Private Shared Sub ocultando(sender As Object, e
As ExecutedRoutedEventArgs)
Dim obj As Comentario = DirectCast(sender,
Comentario)
Dim sb As Object =
TryCast(obj.Template.FindName("panel", obj),
Grid).Resources("Ocultar")
TryCast(sb, Storyboard).Begin()
End Sub
End Class

En el ejemplo anterior vemos como hemos creado una clase que deriva de
Content control con una propiedad dependiente que nos servir para
establecer la brocha a aplicar al control.
Tambin tenemos un comando que lanza una StoryBoard. Pero dnde est
definida esta StoryBoard?
La respuesta es sencilla cuando creamos un control personalizado
automticamente Visual Studio crea una carpeta dentro del proyecto llamada
Themes, en ella se introduce un archivo Generic.xaml.
Gua prctica de desarrollo de aplicaciones Windows en .NET

398 | Windows Presentation Foundation

Este archivo almacena la plantilla y el estilo del control y en ella como se puede
ver hemos definido la StoryBoard:
XAML
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/pr
esentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ComentarioLib">
<Style TargetType="{x:Type local:Comentario}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type
local:Comentario}">
<Grid x:Name="panel">
<Grid.Resources>
<Storyboard
x:Key="Ocultar">
<DoubleAnimation
From="1" To="0" Duration="00:00:02"
Storyboard.TargetName="panel"
Storyboard.TargetProperty="Opacity" />
</Storyboard>
</Grid.Resources>
<Border
Background="{TemplateBinding ComentarioBackground}"
CornerRadius="24"
BorderBrush="Black"
Margin="0,0,0,30" Padding="24"
BorderThickness="2">
<ContentPresenter />
</Border>
<Grid
VerticalAlignment="Bottom" HorizontalAlignment="Right"
Margin="0,0,30,0">
<Polygon
Points="10,0,40,0,0,30" Fill="{TemplateBinding
ComentarioBackground}"
VerticalAlignment="Bottom" HorizontalAlignment="Right"
/>
<Line X1="10" Y1="0"
X2="0" Y2="30" Stroke="Black" StrokeThickness="2"/>
<Line X1="10" Y1="0"
X2="40" Y2="0" Stroke="{TemplateBinding
ComentarioBackground}" StrokeThickness="3"/>
<Line X1="40" Y1="0"
X2="0" Y2="30" Stroke="Black" StrokeThickness="2"/>
</Grid>
</Grid>
Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 399


</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Importante el hecho de que en el ResourceDictionary importamos el espacio


de nombres de la aplicacin, para que as el TargetType pueda hacer un
binding al tipo de la clase que definimos.

Conclusin
Aunque la extensibilidad es uno de los captulos ms importantes en cualquier
API de desarrollo. En WPF, sin embargo, esta extensibilidad pasa a un
segundo nivel ya que tenemos mecanismos para crear nuevos controles ms
sencillos de lo habitual. An as existen mecanismos para crear controles con
los que encapsular funcionalidades que de manera reiterada, queremos usar en
nuestros proyectos.

A continuacin
En el mundo tan globalizado en que vivimos las aplicaciones necesitan
competir en un mercado cada vez ms abierto y para ello que una aplicacin
funcione con independencia del pas, el idioma o las configuraciones
regionales de dramtica importancia.
De esto se encarga la globalizacin y la internacionalizacin, en el siguiente
captulo veremos como llevar a cabo estas actividades en WPF.

Gua prctica de desarrollo de aplicaciones Windows en .NET

400 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 401

Localizacin e
InterOperabilidad
En este captulo trataremos dos temas que si bien no son parte del ncleo
principal de servicios de aplicacin en WPF, si que pueden tener una
importancia capital en segn que aplicaciones. La internacionalizacin de
aplicaciones y la interoperabilidad con Windows Forms.
Cuando limitamos nuestra aplicacin a un slo idioma estamos limitando su
mercado a una pequea porcin de los consumidores potenciales, al tiempo
que competimos en inferioridad de condiciones con nuestros competidores.
Este proceso no slo involucra el soporte de ms de un idioma, sino en
ocasiones tambin el diseo de la aplicacin, los formatos y hasta los alfabetos
se ven afectados.
De la traduccin se ocupa la localizacin y del resto la globalizacin.

Gua prctica de desarrollo de aplicaciones Windows en .NET

402 | Windows Presentation Foundation

La interoperabilidad con Windows Forms es un aspecto ciertamente muy


colateral, pero que puede permitirnos la adopcin de WPF de una manera ms
rpida.
Esto es as debido a que un buen mecanismo de interoperabilidad evita la
necesidad de una traduccin completa de toda una aplicacin.

Localizacin y Globalizacin
Existen una serie de prcticas, que son comunes a todas las aplicaciones en
.NET para globalizar y que por lo tanto no vamos a tratar aqu. Sin embargo
existen algunas recomendaciones que en forma de buenas prcticas s
trataremos.
Trate de no crear en cdigo los interfaces, de esta manera quedarn expuestos
a las API de internacionalizacin.
Evite las posiciones absolutas y los tamaos fijos.
Utilice el panel Grid y su posicionamiento y dimensionamiento en vez del
Canvas.
Aprovisione de espacio extra en los textos, porque el texto localizado suele ser
de diferente tamao.
Utilice el TextWrapping.
Establezca el atributo xml:lang all donde pueda, ya que es el atributo que
establece el lenguaje.
Cuando se creen aplicaciones de navegacin establecer la propiedad
FlowDirection en el texto, a fin de que esta no se herede del navegador y pueda
funcionar mal en un entorno idiomtico diferente al esperado.

Localizando una aplicacin


Para localizar una aplicacin WPF hemos de tener en cuenta en primer lugar,
que los interfaces se especifican usando XAML, lo cual implica que WPF toma
una serie de caractersticas de XML en cuanto a la localizacin y globalizacin.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 403

La primera de ellas es la referencia de caracteres. En ocasiones nosotros


podemos necesitar insertar caracteres como una referencia numrica, bien en
decimal o en hexadecimal, basada en el cdigo de posicin en el conjunto de
caracteres actual.
En el caso de especificarlo con nmero decimal, este ha de ir precedido por
&# y finalizar con ;. En caso de que el nmero se especifique con
hexadecimal la combinacin de inicio sera &#x
XAML
&#1000;
&#x3E8;

XAML tambin con diversas codificaciones, en concreto ASCII, UTF-16 y UTF8, la especificacin de cada una de ellas se realiza conforme al procedimiento
XML, o sea;
XAML
<?xml encoding="UTF-8"?>

Otra caracterstica relacionada con XML es el atributo xml:lang. Este


atributo especifica el lenguaje de un elemento. Este atributo puede especificar
cualquiera de los valores de CultureInfo.
Tambin se incluye soporte para todos los sistemas de escritura de
Framework, incluido el soporte para OpenFonts. El soporte de renderizacin
est basado en la tecnologa Microsoft ClearType sub-pixel lo que aumenta la
legibilidad significativamente.
Por ltimo destacar que el soporte de flujo en el idioma se encuentra
soportado por el atributo FlowDirectionque admite los valores LeftToRight
para los derivados del latn, este asitico y similares y RightToLeft para rabe,
hebreo y similares.
Tras esta introduccin de las caractersticas de globalizacin genricas
pasemos a completar un ejemplo concreto.
Si pretendemos localizar una aplicacin lo primero que debemos tener en
cuenta es cul es el idioma neutral. Este idioma es el que la aplicacin
entender como suyo, como idioma que ser usado tanto en los ambientes que
coincidan con l como en aquellos ambientes que no coincidan con ninguno de
los presentes en la aplicacin. Para establecer el idioma neutral debemos ir a
las propiedades de la aplicacin, a la pestaa Aplicacin y a la informacin del
ensamblado, donde podremos establecerlo. Una vez hecho esto el proceso
podr comenzar.

Gua prctica de desarrollo de aplicaciones Windows en .NET

404 | Window
ws Presenta
ation Found
dation

Al igu
ual que el reesto de las ap
plicaciones ..NET, las ap
plicaciones WPF
W son
capacces de soporrtar ensamblados localizzados. Estoss ensamblad
dos son
bsiccamente de recursos
r
que
e se compilaan a partir dee un ensamb
blado normaal.
Esto quiere decirr que cuando
o tenemos u
un ensambla
ado y lo compilamos con
n un
idiom
ma distinto al
a neutral un
n ensamblad
do de recurso
os se genera
a en un
subd
directorio con
n el nombre
e de la culturra selecciona
ada. Para conseguir estoo
hemo
os de incluirr en el archiv
vo de proyeccto .csproj o .vbproj la siiguiente lneea
dentrro del grupo
o de propiedades corresp
pondiente a la plataform
ma y
confiiguracin selleccionadas para la com
mpilacin:
XML
<UICult
ture>en-US
S</UICultu
ure>

Qued
dando el pro
oyecto de la siguiente
s
maanera:
XML
<Prop
pertyGroup
p Conditio
on="
'$(Conf
figuration
n)|$(Platf
form)' == 'Debug|x8
86' ">
<PlatformTar
rget>x86</
/PlatformT
Target>
<De
ebugSymbol
ls>true</D
DebugSymbo
ols>
<De
ebugType>f
full</Debu
ugType>
<Op
ptimize>fa
alse</Opti
imize>
<Ou
utputPath>
>bin\Debug
g\</Output
tPath>
<De
efineConst
tants>DEBU
UG;TRACE</
/DefineCon
nstants>
<Er
rrorReport
t>prompt</
/ErrorRepo
ort>
<Wa
arningLeve
el>4</Warn
ningLevel>
>
<UI
ICulture>e
en-US</UIC
Culture>
</Pro
opertyGrou
up>

Al ejeecutar la com
mpilacin ell siguiente di
directorio se crear:

o se puede ver
v en la ima
agen un nuevvo ensambla
ado con el mismo
m
nombbre
Como
que la aplicacin
n pero con la
a extensin R
Resources.dlll se crea.
Bsicamentee contiene lo
os recursos d
de la
Pero,, qu contieene este ensamblado?. B
propiia aplicacin
n etiquetado
os como paraa ser cargad
dos cuando la
a aplicacin
n se
encueentre en un entorno coincidente con
n el de la cu
ultura.
Gua
a prctica de
d desarrolllo de aplica
aciones Wiindows en .NET
.

Windo
ows Presenttation Foun
ndation | 405

El prroceso de intternacionalizzacin por ttanto consistte en incluir textos,


imggenes y dem
s activos en
n los recursoos de nuestra
a aplicacin y referirnoss a
ellos a la hora dee introducir los
l textos en
n los diferen
ntes elementos. Por ejem
mplo
si queeremos intro
oducir un te
exto, simplem
mente iremo
os a las prop
piedades de
nuesttra aplicaci
n, a la pesta
aa recursoss y aadirem
mos un nuevo recurso:

ar accesible
e a travs dee la clase Ressources denttro del espaccio
Este recurso esta
de no
ombre Propeerties. En ell evento Loaad podemos asignar los diferentes
d
texto
os utilizando
o un cdigo similar
s
a estee:
C#
label1.Content =
WpfApplication2.
.Propertie
es.Resourc
ces.String
g1;
ual Basic.NET
Visu
label1.Content =
WpfApplication2.
.Propertie
es.Resourc
ces.String
g1

De essa manera ell sistema se encarga de detectar el idioma


i
autom
mticamentte y
cargaar el ensamb
blado adecua
ado.
Y sii queremos asignar
a
el id
dioma nosotrros? Entoncces no tenem
mos ms quee
especcificar el idio
oma deseado
o en la prop
piedad CurreentUICultur
re del hilo
actuaal. Algo simiilar a lo siguiente:
C#
Thread.CurrentTh
hread.Curr
rentUICult
ture = new
w
Culture
eInfo(es-ES);
Visu
ual Basic.NET
hread.Curr
rentUICult
ture = new
w
Thread.CurrentTh
Culture
eInfo(es-ES)

Gua prctica de
e desarrolllo de aplica
aciones Win
ndows en .N
NET

406 | Windows Presentation Foundation

Interoperabilidad
Bajo el nombre de interoperabilidad se esconde el camino para hacer
trabajar una o ms tecnologas en principio exclusivas, como podra ser el
caso de WPF y Windows Forms.
No slo Windows Forms sino Directx o la API Win32, pueden ser objeto de
interoperabilidad con WPF, si bien al ser este un libro escrito sobre la
tecnologa .NET poco sentido tendra abordar semejantes interoperabilidades.
Una vez centrado el objeto de nuestro inters diremos que abordar la
interoperabilidad entre WPF y WinForms es tanto como abordar como
integrar WPF en aplicaciones WinForms y viceversa.
El control WindowsFormsHost nos permite la interoperabilidad con Windows
Forms desde WPF. Los siguientes escenarios de interoperacin se soportan
cuando una aplicacin WPF ha de alojar un control Windows Forms:

El control WPF ha de acoger uno o ms controles usando XAML o cdigo.

El control Windows Forms container puede contener controles Windows


Forms que a su vez acojan otros.

Puede acoger formularios maestro/detalle, sea el formulario maestro bien


WPF bien Windows Forms.

Puede acoger uno o mas controles ActiveX o controles compuestos.

Puede contener controles hbridos usando XAML o cdigo.

En cuanto al sistema de "Layout" o distribucin de los controles de la


aplicacin, existen las siguientes limitaciones:

En ocasiones los controles Windows Forms slo pueden ser


redimensionados hasta un punto. Ej.: Combobox.

Los controles Windows Forms no se pueden rotar o desplazar.

En la mayora de los casos los controles Windows Forms no soportan


escalado.

Los controles Windows Forms al tener HWND siempre se dibujan por


encima de los controles WPF.

Los controles Windows Forms soportan autoescalado basado en el tamao


de fuente mientras que en WPF no es as.

Gua prctica de desarrollo de aplicaciones Windows en .NET

Windows Presentation Foundation | 407

En algunas propiedades WPF tienen su equivalente en Windows Forms, estas


son tratadas como propiedades del control.
En el caso de Windows Forms existe tambin un control llamado ElementHost
que nos permite alojar contenido WPF en aplicaciones Windows Forms. Se
soportan, por contra, los siguientes escenarios cuando una aplicacin
Windows Forms acoge un control WPF:

Usar uno o ms controles WPF usando cdigo.

Asociar una hoja de propiedades con uno o ms controles WPF.

Alojar una o ms pginas WPF en un formulario.

Arrancar una aplicacin WPF.

Alojar un formulario maestro detalle con el maestro Windows Forms o


WPF.

Alojar controles WPF personalizados.

Alojar controles hbridos.

Conclusin
Con WPF podemos crear fcilmente aplicaciones internacionales que nos
permitan llegar a, cuantos ms mercados mejor. Este soporte es plenamente
compatible con el soporte general de .NET.
Adems prevee mecanismos para que la integracin con las tecnologas
circundantes, lase Windows Forms, API Win32 o DirectX puedan utilizarse
de la manera ms efectiva posible.

Gua prctica de desarrollo de aplicaciones Windows en .NET

408 | Windows Presentation Foundation

Gua prctica de desarrollo de aplicaciones Windows en .NET

También podría gustarte