Vous êtes sur la page 1sur 445

Manual de Windows Presentation Foundation

INDICE GENERAL
1. Introduccin a WPF
1.1. Introduccin a Windows Presentation Foundation
1.2. Informacin General sobre Windows Presentation Foundation
1.3. Lo Nuevo en Windows Presentation Foundation Versin 3.5
2. Desarrollo de Aplicaciones
2.1. Informacin General sobre el Desarrollo de Aplicaciones
2.2. Administracin de Aplicaciones
2.2.1. Informacin General sobre la Administracin de Aplicaciones
2.2.2. Archivos c Windows Presentation Foundation
2.2.3. URIs de Paquete en Windows Presentation Foundation
2.2.4. Temas Cmo del Modelo de Aplicaciones
2.2.4.1. Cmo: Obtener y Establecer Propiedades en el Ambito de Aplicacin
2.2.4.2. Cmo: Obtener y Establecer Recursos en el Ambito de Aplicacin
2.2.4.3. Cmo: Obtener y Establecer el Cdigo de Salida de Aplicaciones
2.2.4.4. Cmo: Obtener los Argumentos de Lnea de Comandos
2.2.4.5. Cmo: Obtener el Objeto de Aplicacin Actual
2.2.4.6. Cmo: Conservar y Restaurar Propiedades en el Ambito de
Aplicacin a travs de Sesiones de Aplicacin
2.2.4.7. Cmo: Cerrar una Aplicacin
2.2.4.8. Cmo: Iniciar una Aplicacin
2.2.4.9. Cmo: Usar un Diccionario de Recursos en el Ambito de Aplicacin
2.3. Ventanas en Aplicaciones de Windows Presentation Foundation
2.3.1. Informacin General sobre Ventanas de WPF
2.3.2. Informacin General sobre Cuadros de Dilogo
2.3.3. Temas Cmo de la Administracin de Ventanas
2.3.3.1. Cmo: Cambiar Automticamente el Tamao de una Ventana para
que se Ajuste a su Contenido
2.3.3.2. Cmo: Obtener Todas las Ventanas de una Aplicacin
2.3.3.3. Cmo: Obtener y Establecer la Ventana Principal de una Aplicacin
2.3.3.4. Cmo: Abrir un Cuadro de Dilogo
2.3.3.5. Cmo: Abrir un Cuadro de Mensaje
2.3.3.6. Cmo: Abrir una Ventana
2.3.3.7. Cmo: Devolver el Resultado de un Cuadro de Dilogo
2.4. Navegacin en Aplicaciones de Windows Presentation Foundation
2.4.1. Informacin General sobre Navegacin
2.4.2. Informacin General sobre la Navegacin Estructurada
2.4.3. Informacin General sobre Topologas de Navegacin
2.4.4. Temas Cmo de Navegacin
2.4.4.1. Cmo: Llamar a una Funcin de Pgina
2.4.4.2. Cmo: Determinar si una Pgina est Hospedada en un Explorador
2.4.4.3. Cmo: Obtener el Valor Devuelto por una Funcin de Pgina
2.4.4.4. Cmo: Navegar hacia Delante por el Historial de Navegacin
2.4.4.5. Cmo: Navegar hacia Atrs por el Historial de Navegacin
2.4.4.6. Cmo: Navegar hasta una Pgina
2.4.4.7. Cmo: Actualizar una Pgina
2.4.4.8. Cmo: Devolver Resultados de una Funcin de Pgina
2.4.4.9. Cmo: Establecer el Alto de una Ventana desde una Pgina
2.4.4.10. Cmo: Establecer el Ancho de una Ventana desde una Pgina
2.4.4.11. Cmo: Establecer el Ttulo de una Ventana desde una Pgina
2.4.4.12. Cmo: Detener la Carga de una Pgina
2.4.4.13. Cmo: Usar Mailto: para Enviar Correo desde una Pgina
2.5. Extensibilidad de Aplicaciones
2.5.1. Informacin General sobre Complementos de WPF
2.5.2. Temas Cmo de Complementos de WPF
2.5.2.1. Cmo: Crear un Complemento que Devuelva una Interfaz de Usuario
2.5.2.2. Cmo: Crear un Complemento que sea una Interfaz de Usuario
2.6. Hospedar Aplicaciones de Windows Presentation Foundation
2.6.1. Informacin General sobre Aplicaciones de Explorador XAML de WPF

MCT: Luis Dueas

Pag 1 de 445

Manual de Windows Presentation Foundation


2.6.2. Informacin General sobre Aplicaciones Hospedadas en Windows Media
Center para WPF
2.6.3. Host de Windows Presentation Foundation (PresentationHost.exe)
2.6.4. API No Administrada de WpfHostSupport
2.6.4.1. IEnumRAWINPUTDEVICE
2.6.4.2. IWpfHostSupport
2.7. Generar e Implementar Aplicaciones de WPF
2.7.1. Generar una Aplicacin de WPF
2.7.2. Implementar una Aplicacin de WPF
2.7.3. Temas Cmo de Generar e Implementar
2.7.3.1. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin
Independiente de WPF
2.7.3.2. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin
de Navegacin Independiente de WPF
2.7.3.3. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin
de Explorador XAML de WPF
2.7.3.4. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Biblioteca
de Controles Personalizados de WPF
2.7.3.5. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin
Independiente de WPF que slo contiene Cdigo
2.7.3.6. Cmo: Configurar IIS 5.0 e IIS 6.0 para Implementar Aplicaciones de
WPF
2.7.3.7. Configurar Visual Studio 2005 para Depurar una Aplicacin de
Explorador XAML
2.7.3.8. Configurar Visual Studio para Depurar una Aplicacin de Explorador
XAML y Llamar a un Servicio Web
2.7.3.9. Cmo: Determinar la Versin Instalada de Windows Presentation
Foundation
2.7.3.10. Cmo: Detectar si .NET Framework 3.0 est Instalado
2.7.3.11. Cmo: Detectar si .NET Framework 3.5 est Instalado
2.7.3.12. Cmo: Detectar si est Instalado el Complemento XBAP para
Firefox
2.8. Rendimiento
2.8.1. Niveles de Representacin de Grficos
2.8.2. Optimizar WPF: Rendimiento de Aplicaciones
2.8.2.1. Planear para Mejorar el Rendimiento de Aplicaciones
2.8.2.2. Aprovechar el Hardware
2.8.2.3. Presentacin y Diseo
2.8.2.4. Imgenes y Grficos 2D
2.8.2.5. Comportamiento de Objetos
2.8.2.6. Recursos de Aplicacin
2.8.2.7. Texto
2.8.2.8. Enlace de Datos
2.8.2.9. Otras Recomendaciones
2.8.2.10. Herramientas y Recursos de Rendimiento de WPF
3. Elementos Fundamentales de WPF
3.1. Arquitectura de WPF
3.2. XAML
3.2.1. Informacin General sobre XAML
3.2.2. Terminologa de la Sintaxis de XAML
3.2.3. Cdigo Subyacente y XAML
3.2.4. XAML y Clases Personalizadas
3.2.5. Extensiones de Marcado y XAML
3.2.6. Espacios de Nombres y Asignacin de Espacios de Nombres de XAML
3.2.7. Ambitos de Nombres de WPF
3.2.8. Estilos y Plantillas Insertados
3.2.9. Procesamiento de Espacios en Blanco en XAML
3.2.10. Clases TypeConverter y XAML
3.2.11. Entidades de Caracteres XML y XAML
3.2.12. Caractersticas de lenguaje (x:) de espacios de nombres XAML

MCT: Luis Dueas

Pag 2 de 445

Manual de Windows Presentation Foundation


3.2.12.1. Extensin de Marcado x:Array
3.2.12.2. Atributo x:Class
3.2.12.3. Atributo x:ClassModifier
3.2.12.4. Elemento de Directiva x:Code de XAML
3.2.12.5. Atributo x:FieldModifier
3.2.12.6. Atributo x:Key
3.2.12.7. Atributo x:Name
3.2.12.8. Extensin de Marcado x:Null
3.2.12.9. Atributo x:Shared
3.2.12.10. Extensiones de Marcado x:Static
3.2.12.11. Atributo x:Subclase
3.2.12.12. Extensin de Marcado x:Type
3.2.12.13. Atributo x:TypeArguments
3.2.12.14. Atributo x:Uid
3.2.12.15. Elemento de Directiva x:XData de XAML
3.2.12.16. Gramtica de XamlName
3.2.12.17. Secuencia de Escape / Extensin de Marcado {}
3.2.12.18. Control de xml:lang en XAML
3.2.12.19. Control de xml:space en XAML
3.2.13. Extensiones de XAML de Espacio de Nombres de WPF
3.2.13.1. Enlazar Extensin de Marcado
3.2.13.2. Extensin de Marcado ColorConvertedBitmap
3.2.13.3. Extensin de Marcado ComponentResourceKey
3.2.13.4. Extensin de Marcado DynamicResource
3.2.13.5. Extensin de Marcado RelativeSource
3.2.13.6. Extensin de Marcado StaticResource
3.2.13.7. Extensin de Marcado TemplateBinding
3.2.13.8. Extensin de Marcado ThemeDictionary
3.2.13.9. Sintaxis de PropertyPath de XAML
3.2.13.10. Atributo PresentationOptions:Freeze
3.2.14. Caractersticas del Lenguaje de Compatibilidad de Marcado (mc:)
3.2.14.1. Atributo mc:Ignorable
3.2.14.2. Atributo mc:ProcessContent
3.3. Elementos Base
3.3.1. Informacin General sobre Elementos Base
3.3.2. Informacin General sobre Objetos Freezable
3.3.3. Informacin General sobre Alineacin, Mrgenes y Relleno
3.3.4. Temas Cmo sobre Elementos Base
3.3.4.1. Cmo: Hacer que un Elemento UIElement sea Transparente o
Semitransparente
3.3.4.2. Cmo: Animar el Tamao de un Elemento FrameworkElement
3.3.4.3. Cmo: Determinar si un Elemento Freezable est Inmovilizado
3.3.4.4. Cmo: Controlar un Evento Cargado
3.3.4.5. Cmo: Definir Mrgenes de Elementos y Controles
3.3.4.6. Cmo: Hacer que un Elemento Freezable sea de Slo Lectura
3.3.4.7. Cmo: Obtener una Copia Modificable de un Elemento Freezable de
Slo Lectura
3.3.4.8. Cmo: Voltear un Control UIElement Horizontal o Verticalmente
3.3.4.9. Cmo: Utilizar un Objeto ThicknessConverter
3.3.4.10. Cmo: Usar un Objeto LengthConverter
3.3.4.11. Cmo: Controlar el Evento ContextMenuOpening
3.4. Arbol de Elementos y Serializacin
3.4.1. Arboles en WPF
3.4.2. Limitaciones en la Serializacin de XamlWriter.Save
3.4.3. Inicializacin de Elementos de Objeto No Incluidos en un Arbol de Elementos
3.4.4. Temas Cmo sobre el Arbol de Elementos y la Serializacin
3.4.4.1. Cmo: Buscar un Elemento por su Nombre
3.4.4.2. Cmo: Invalidar el Arbol Lgico
3.5. Propiedades
3.5.1. Informacin General sobre las Propiedades de Dependencia

MCT: Luis Dueas

Pag 3 de 445

Manual de Windows Presentation Foundation


3.5.2. Informacin General sobre Propiedades Asociadas
3.5.3. Devoluciones de Llamada y Validacin de las Propiedades de Dependencia
3.5.4. Propiedades de Dependencia Personalizadas
3.5.5. Metadatos de las Propiedades de Dependencia
3.5.6. Metadatos de las Propiedades de Marco de Trabajo
3.5.7. Prioridad de los Valores de Propiedades de Dependencia
3.5.8. Propiedades de Dependencia de Slo Lectura
3.5.9. Herencia de Valores de Propiedad
3.5.10. Seguridad de las Propiedades de Dependencia
3.5.11. Modelos de Constructores Seguros para Objetos DependencyObject
3.5.12. Propiedades de Dependencia de Tipo de Coleccin
3.5.13. Carga de XAML y Propiedades de Dependencia
3.5.14. Temas Cmo sobre Propiedades
3.5.14.1. Cmo: Implementar una Propiedad de Dependencia
3.5.14.2. Cmo: Restaurar el Valor Predeterminado de una Propiedad de
Dependencia
3.5.14.3. Cmo: Agregar un Tipo de Propietario para una Propiedad de
Dependencia
3.5.14.4. Cmo: Registrar una Propiedad Asociada
3.5.14.5. Cmo: Invalidar Metadatos en una Propiedad de Dependencia
3.6. Eventos
3.6.1. Informacin General sobre Eventos Enrutados
3.6.2. Informacin General sobre Eventos Asociados
3.6.3. Eventos de Duracin de Objetos
3.6.4. Marcar Eventos Enrutados como Controlados y Control de Clases
3.6.5. Eventos de Vista Previa
3.6.6. Eventos de Cambio de Propiedades
3.6.7. Control de Eventos en Visual Basic y WPF
3.6.8. Modelos WeakEvent
3.6.9. Temas Cmo sobre Eventos
3.6.9.1. Cmo: Agregar un Controlador de Eventos mediante Cdigo
3.6.9.2. Cmo: Controlar un Evento Enrutado
3.6.9.3. Cmo: Crear un Evento Enrutado Personalizado
3.6.9.4. Cmo: Buscar el Elemento de Origen en un Controlador de Eventos
3.6.9.5. Cmo: Agregar Control de Clases a un Evento Enrutado
3.7. Acciones del Usuario y Comandos
3.7.1. Informacin General sobre Acciones del Usuario
3.7.2. Informacin General sobre Comandos
3.7.3. Informacin General sobre el Foco
3.7.4. Aplicar Estilo a los Controles al Recibir el Foco y FocusVisualStyle
3.7.5. Temas Cmo sobre Acciones del Usuario y Comandos
3.7.5.1. Cmo: Habilitar un Comando
3.7.5.2. Cmo: Cambiar el Tipo de Cursor
3.7.5.3. Cmo: Detectar el Estado de un Botn del Mouse
3.7.5.4. Cmo: Cambiar el Color de un Elemento mediante Eventos de Foco
3.7.5.5. Cmo: Aplicar FocusVisualStyle a un Control
3.7.5.6. Cmo: Detectar cuando se Presiona la Tecla Enter
3.7.5.7. Cmo: Crear un Efecto de Activacin mediante Eventos
3.7.5.8. Cmo: Crear un Objeto que Siga el Puntero del Mouse
3.7.5.9. Cmo: Agregar un Comando a un Elemento de Men
3.7.5.10. Cmo: Crear un Comando RoutedCommand
3.7.5.11. Cmo: Implementar ICommandSource
3.7.5.12. Cmo: Enlazar un Comando a un Control sin la Compatibilidad de
Comandos
3.7.5.13. Cmo: Enlazar un Comando a un Control con la Compatibilidad de
Comandos
3.8. Recursos WPF
3.8.1. Informacin General sobre Recursos
3.8.2. Recursos y Cdigo
3.8.3. Diccionarios de Recursos Combinados

MCT: Luis Dueas

Pag 4 de 445

Manual de Windows Presentation Foundation


3.8.4. Temas Cmo de Recursos
3.8.4.1. Cmo: Definir y Hacer Referencia a un Recurso
3.8.4.2. Cmo: Usar Recursos de Aplicaciones
3.8.4.3. Cmo: Utilizar SystemFonts
3.8.4.4. Cmo: Usar Claves de Fuentes del Sistema
3.8.4.5. Cmo: Utilizar SystemParameters
3.8.4.6. Cmo: Utilizar Claves de Parmetros del Sistema
3.9. Estilos y Plantillas: Conceptual
3.9.1. Aplicar Estilos y Plantillas
3.9.2. Cmo: Buscar Elementos Generados por un Objeto ControlTemplate
3.10. Sistema de Diseo
3.11. Ajuste de Pxeles en Aplicaciones de WPF
3.12. Modelo de Subprocesos

MCT: Luis Dueas

Pag 5 de 445

Manual de Windows Presentation Foundation

Windows Presentation Foundation


Windows Presentation Foundation (WPF) proporciona a los programadores un modelo de programacin
unificado con el que generar experiencias de cliente inteligentes de Windows, en las que se incorpora la interfaz
de usuario, multimedia y documentos.

1. Introduccin a WPF
Este portal proporciona vnculos a informacin destinada a programadores que son nuevos en Windows
Presentation Foundation (WPF).
La plataforma de desarrollo WPF se ha generado sobre un sistema de programacin bsico, que se extiende
para admitir un amplio conjunto de caractersticas de desarrollo de aplicaciones que incluyen el propio modelo
de aplicacin, recursos, controles, grficos, diseo, enlace de datos, documentos y seguridad.

1.1. Introduccin a Windows Presentation Foundation


Windows Presentation Foundation (WPF) es un sistema de presentacin de la prxima generacin, para crear
aplicaciones cliente de Windows que proporcionen una experiencia impactante para el usuario desde el punto de
vista visual. Con WPF, puede crear una amplia gama de aplicaciones independientes y hospedadas en
explorador. Algunos ejemplos de ello son Yahoo! Messenger y New York Times Reader, as como la aplicacin
de ejemplo para atencin sanitaria, Contoso Healthcare Sample Application que se muestra en la ilustracin
siguiente.

El ncleo de WPF es un motor de representacin independiente de la resolucin y basado en vectores


construido para aprovechar al mximo el hardware de grficos moderno. WPF ampla el ncleo con un completo
conjunto de caractersticas de programacin de aplicaciones, entre las que se incluyen Lenguaje de marcado de
aplicaciones extensible (XAML), controles, enlace de datos, diseo, grficos 2D y 3D, animacin, estilos,
plantillas, documentos, multimedia, texto y tipografa. WPF se incluye en Microsoft .NET Framework, lo que
permite crear aplicaciones que incorporen otros elementos de la biblioteca de clases de .NET Framework.
Esta introduccin est dirigida a personas que no conocen an WPF, y en ella se abordan sus conceptos y
capacidades principales. Los programadores de WPF experimentados que deseen revisar este marco de trabajo
tambin la encontrarn de utilidad.
Programar con WPF
WPF constituye un subconjunto de tipos de .NET Framework, en su mayora ubicados en el espacio de nombres
de System.Windows. Si ha creado previamente aplicaciones con .NET Framework mediante tecnologas
administradas como ASP.NET y formularios Windows Forms, los conceptos fundamentales de la programacin
en WPF deben resultarle familiares; crear instancias de clases, definir propiedades, llamar a mtodos y
controlar eventos con el lenguaje de programacin de .NET Framework que prefiera, como C# o Visual Basic.

MCT: Luis Dueas

Pag 6 de 445

Manual de Windows Presentation Foundation


Para admitir algunas de las funciones de WPF ms eficaces y simplificar la experiencia de programacin, WPF
incluye construcciones de programacin adicionales que mejoran las propiedades y los eventos: las propiedades
de dependencia y los eventos enrutados.
Cdigo de lenguaje marcado y cdigo subyacente
WPF proporciona mejoras de programacin adicionales para el desarrollo de aplicaciones cliente de Windows.
Una mejora evidente es la capacidad para programar una aplicacin mediante cdigo de lenguaje marcado y
subyacente, una experiencia con la que resultar familiar a los programadores de ASP.NET. En general, se
utiliza el lenguaje marcado Lenguaje de marcado de aplicaciones extensible (XAML) para implementar la
apariencia de una aplicacin, y los lenguajes de programacin administrados (subyacentes) para implementar
su comportamiento. Esta separacin entre la apariencia y el comportamiento aporta las ventajas siguientes:

Se reducen los costos de programacin y mantenimiento, al no estar el marcado especfico de la


apariencia estrechamente relacionado con el cdigo especfico del comportamiento.

La programacin es ms eficaz porque los diseadores pueden implementar la apariencia de una


aplicacin al mismo tiempo que los programadores implementan su comportamiento.

Se pueden utilizar varias herramientas de diseo para implementar y compartir el lenguaje marcado
XAML, a fin de responder a los requisitos de los colaboradores de programacin de aplicaciones;
Microsoft Expression Blend proporciona una experiencia apropiada para los diseadores, mientras que
Visual Studio 2005 est dirigido a los programadores.

La globalizacin y localizacin de las aplicaciones WPF se ha simplificado en gran medida.

A continuacin, se muestra una introduccin breve al cdigo de lenguaje marcado y subyacente de WPF.
Marcado
XAML es un lenguaje de marcado basado en XML que se utiliza para implementar la apariencia de una
aplicacin mediante declaracin. Se suele utilizar para crear ventanas, cuadros de dilogo, pginas y controles
de usuario, as como para rellenarlos con controles, formas y grficos.
En el ejemplo siguiente se utiliza XAML para implementar la apariencia de una ventana que contiene un solo
botn.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="Window with Button"
Width="250" Height="100">
<!-- Add button to window -->
<Button Name="button">Click Me!</Button>
</Window>
En concreto, este cdigo XAML define una ventana y un botn mediante los elementos Window y Button,
respectivamente. Cada elemento se configura con atributos, como el atributo Title del elemento Window, para
especificar el texto de la barra de ttulo de la ventana. En tiempo de ejecucin, WPF convierte los elementos y
los atributos definidos en el marcado en instancias de clases de WPF. Por ejemplo, el elemento Window se
convierte en una instancia de la clase Window cuya propiedad Title es el valor del atributo Title.
En la ilustracin siguiente se muestra la interfaz de usuario (UI) definida mediante el cdigo XAML del ejemplo
anterior.

Puesto que XAML se basa en XML, la interfaz de usuario que se crea con este lenguaje se ensambla en una
jerarqua de elementos anidados que se denomina rbol de elementos. El rbol de elementos proporciona una
manera lgica e intuitiva de crear y administrar las UIs.

MCT: Luis Dueas

Pag 7 de 445

Manual de Windows Presentation Foundation


Cdigo subyacente
El comportamiento principal de una aplicacin es implementar la funcionalidad que responde a las interacciones
con el usuario, lo que incluye controlar los eventos (por ejemplo, hacer clic en un men, una barra de
herramientas o un botn) y llamar, en respuesta, a la lgica empresarial y de acceso a los datos. En WPF, este
comportamiento se suele implementar en cdigo asociado al marcado. Este tipo de cdigo se denomina
subyacente. En el ejemplo siguiente se muestran el cdigo subyacente y el marcado actualizado del ejemplo
anterior.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.AWindow"
Title="Window with Button"
Width="250" Height="100">
<!-- Add button to window -->
<Button Name="button" Click="button_Click">Click Me!</Button>
</Window>
Namespace SDKSample
Partial Public Class AWindow
Inherits System.Windows.Window
Public Sub New()
' InitializeComponent call is required to merge the UI
' that is defined in markup with this class, including
' setting properties and registering event handlers
InitializeComponent()
End Sub
Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Show message box when button is clicked
MessageBox.Show("Hello, Windows Presentation Foundation!")
End Sub
End Class
End Namespace
En este ejemplo, el cdigo subyacente implementa una clase que se deriva de la clase Window. El atributo
x:Class se utiliza para asociar el marcado a la clase de cdigo subyacente. Se llama a InitializeComponent
desde el constructor de la clase de cdigo subyacente para combinar la interfaz de usuario definida en el
marcado con la clase de cdigo subyacente. ((InitializeComponent se genera automticamente al generar la
aplicacin, por lo que no se requiere su implementacin manual.) La combinacin de x:Class e
InitializeComponent garantiza que la implementacin se inicializa correctamente cada vez que se crea. La clase
de cdigo subyacente tambin implementa un controlador de eventos para el evento Click del botn. Cuando se
hace clic en el botn, el controlador de eventos muestra un cuadro de mensaje llamando al mtodo
MessageBox.Show.
En la ilustracin siguiente se muestra el resultado de hacer clic en el botn.

Aplicaciones
.NET Framework, System.Windows, as como el cdigo de lenguaje marcado y subyacente, constituyen la base
de la experiencia de programacin de aplicaciones en WPF. Adems, WPF cuenta con caractersticas completas
para crear experiencias de usuario con contenido enriquecido. Para empaquetar este contenido y distribuirlo a
los usuarios en forma de "aplicaciones", WPF proporciona tipos y servicios denominados colectivamente el
modelo de aplicacin. El modelo de aplicacin admite la programacin de aplicaciones independientes y
hospedadas en explorador.
Aplicaciones independientes

MCT: Luis Dueas

Pag 8 de 445

Manual de Windows Presentation Foundation


Para las aplicaciones independientes, puede utilizar la clase Window para crear las ventanas y cuadros de
dilogo a los que se tiene acceso desde las barras de mens y las barras de herramientas. En la ilustracin
siguiente se muestra una aplicacin independiente con una ventana principal y un cuadro de dilogo.

Adems, puede utilizar los cuadros de dilogo siguientes de WPF: MessageBox, OpenFileDialog, SaveFileDialog
y PrintDialog.
Aplicaciones hospedadas en explorador
Para las aplicaciones hospedadas en explorador, denominadas Aplicaciones del explorador XAML (XBAPs),
puede crear pginas (Page) y funciones de pgina (PageFunction<(Of <(T>)>)) entre las que se puede navegar
mediante hipervnculos (clases Hyperlink). En la ilustracin siguiente se muestra una pgina de XBAP
hospedada en Internet Explorer 7.

Las aplicaciones WPF se pueden hospedar en Microsoft Internet Explorer 6 y Internet Explorer 7. WPF
proporciona las dos opciones siguientes de hosts de navegacin alternativos:

Frame, para hospedar islas de contenido navegable en pginas o ventanas.


NavigationWindow, para hospedar contenido navegable en una ventana completa.

Clase Application
Tanto las XBAPs como las aplicaciones independientes suelen ser bastante complejas y necesitan servicios
adicionales de mbito de la aplicacin, lo que incluye administracin del inicio y de la duracin, as como
propiedades y recursos compartidos. La clase Application encapsula todos estos servicios y algunos ms, y slo
se puede implementar mediante XAML, como se muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="MainWindow.xaml" />

MCT: Luis Dueas

Pag 9 de 445

Manual de Windows Presentation Foundation


Este cdigo de lenguaje marcado es la definicin de aplicacin de una aplicacin independiente, e indica a WPF
que cree un objeto Application que abre MainWindow automticamente cuando se inicia la aplicacin.
Un concepto que es fundamental entender acerca de Application es que proporciona una plataforma comn de
compatibilidad para las aplicaciones independientes y hospedadas en explorador. Por ejemplo, el cdigo XAML
anterior podra utilizarlo una aplicacin hospedada en explorador para navegar automticamente a una pgina
al iniciar una XBAP, como se muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="HomePage.xaml" />
Seguridad
Dado que las XBAPs se hospedan en un explorador, la seguridad es importante. En particular, las XBAPs utilizan
un recinto de seguridad de confianza parcial para aplicar restricciones menores o iguales a las que se imponen
a las aplicaciones basadas en HTML. Adems, todas las caractersticas de HTML que es seguro ejecutar desde
las XBAPs con confianza parcial se han probado mediante un proceso de seguridad completo.
An as, la mayora de las caractersticas de WPF se pueden ejecutar con seguridad desde las XBAPs.
Controles
Las experiencias para el usuario proporcionadas por el modelo de aplicacin son controles construidos. En WPF,
un "control" es un trmino general que se aplica a una categora de clases de WPF hospedadas en una ventana
o una pgina, tienen una interfaz de usuario (UI) e implementa un comportamiento determinado.
Lista controles de WPF
A continuacin se muestra la lista de controles de WPF integrados.

Botones: Button y RepeatButton.


Cuadros de dilogo: OpenFileDialog, PrintDialog y SaveFileDialog.
Entradas manuscritas digitales: InkCanvas y InkPresenter.
Documentos: DocumentViewer, FlowDocumentPageViewer, FlowDocumentReader,
FlowDocumentScrollViewer y StickyNoteControl.

Entrada: TextBox, RichTextBox y PasswordBox.


Diseo: Border, BulletDecorator, Canvas, DockPanel, Expander, Grid, GridView, GridSplitter,
GroupBox, Panel, ResizeGrip, Separator, ScrollBar, ScrollViewer, StackPanel, Thumb, Viewbox,
VirtualizingStackPanel, Window y WrapPanel.

Multimedia: Image, MediaElement y SoundPlayerAction.


Mens: ContextMenu, Menu y ToolBar.
Navegacin: Frame, Hyperlink, Page, NavigationWindow y TabControl.
Seleccin: CheckBox, ComboBox, ListBox, TreeView y RadioButton, Slider.
Informacin para el usuario: AccessText, Label, Popup, ProgressBar, StatusBar, TextBlock y ToolTip.

Acciones del usuario y comandos


Los controles casi siempre detectan las acciones del usuario y responden a ellas. El sistema de entrada de WPF
utiliza eventos directos y enrutados para admitir entradas de texto, la administracin del enfoque y la posicin
del mouse.
Las aplicaciones suelen tener requisitos de entrada complejos. WPF proporciona un sistema de comandos que
separa las acciones de entrada del usuario del cdigo que responde a esas acciones.
Diseo
Al crear una interfaz de usuario, se organizan los controles segn su ubicacin y tamao para crear un diseo.
Un requisito fundamental de cualquier diseo es adaptarse a los cambios de tamao de la ventana y de
configuracin de pantalla. En lugar de obligarle a escribir cdigo que adapte el diseo en estas circunstancias,
WPF le proporciona un sistema de diseo extensible de primera clase.

MCT: Luis Dueas

Pag 10 de 445

Manual de Windows Presentation Foundation


La piedra angular del sistema de diseo es la situacin relativa, que aumenta la capacidad de adaptacin a los
cambios en la configuracin de las ventanas y de la pantalla. Adems, el sistema de diseo administra la
negociacin entre los controles para determinar el diseo. La negociacin es un proceso de dos pasos: en
primer lugar, el control indica a su elemento primario qu ubicacin y tamao necesita; en segundo lugar, el
elemento primario indica al control de qu espacio dispone.
El sistema de diseo se expone a los controles secundarios mediante las clases base de WPF. Para los diseos
comunes, como son las cuadrculas, el apilamiento y el acoplamiento, WPF incluye varios controles de diseo:

Canvas: los controles secundarios proporcionan su propio diseo.


DockPanel: los controles secundarios se alinean con los bordes del panel.
Grid: los controles secundarios se sitan por filas y columnas.
StackPanel: los controles secundarios se apilan vertical u horizontalmente.
VirtualizingStackPanel: los controles secundarios se organizan en una vista "virtual" de una sola lnea
en sentido horizontal o vertical.

WrapPanel: los controles secundarios se sitan por orden de izquierda a derecha y se ajustan a la lnea
siguiente cuando hay ms controles de los que caben en la lnea actual.

En el ejemplo siguiente se utiliza un control DockPanel para situar varios controles TextBox.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.LayoutWindow"
Title="Layout with the DockPanel" Height="143" Width="319">
<!--DockPanel to layout four text boxes-->
<DockPanel>
<TextBox DockPanel.Dock="Top">Dock = "Top"</TextBox>
<TextBox DockPanel.Dock="Bottom">Dock = "Bottom"</TextBox>
<TextBox DockPanel.Dock="Left">Dock = "Left"</TextBox>
<TextBox Background="White">This TextBox "fills" the remaining
space.</TextBox>
</DockPanel>
</Window>
DockPanel permite que los controles secundarios TextBox le indiquen cmo se deben organizar. Para ello,
DockPanel implementa una propiedad Dock que se expone a los controles secundarios, a fin de para permitir
que cada uno de ellos especifique un estilo de acoplamiento.
Nota:
Una propiedad implementada por un control principal para que la utilicen los controles secundarios es una
construccin de WPF denominada propiedad asociada.
En la ilustracin siguiente se muestra el resultado del marcado XAML del ejemplo anterior.

Enlace de datos
La mayora de las aplicaciones se crean para proporcionar recursos a los usuarios que les permitan ver y editar
los datos. Para aplicaciones WPF, el trabajo de almacenar los datos y tener acceso a ellos se proporciona
mediante tecnologas existentes, como Microsoft SQL Server y ADO.NET. Despus de obtener acceso a los
datos y de cargarlos a los objetos administrados de una aplicacin, comienza la tarea ardua de las aplicaciones
WPF. En esencia, esto implica dos cosas:
1.

Copiar los datos desde los objetos administrados en los controles, donde los datos se pueden mostrar
y editar.

2.

Asegurarse de que los cambios realizados en los datos mediante los controles se vuelvan a copiar en
los objetos administrados.

MCT: Luis Dueas

Pag 11 de 445

Manual de Windows Presentation Foundation


Para simplificar la programacin de aplicaciones, WPF proporciona un motor de enlace de datos que realiza
estos pasos automticamente. La unidad que constituye el ncleo del motor de enlace de datos es la clase
Binding, encargada de enlazar un control (el destino del enlace) a un objeto de datos (el origen del enlace).
Esta relacin se muestra en la ilustracin siguiente.

En el ejemplo siguiente se muestra cmo enlazar un control TextBox a una instancia de un objeto Person
personalizado. La implementacin de Person se muestra en el cdigo siguiente.
Namespace SDKSample
Class Person
Private _name As String = "No Name"
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
End Namespace
El marcado siguiente enlaza el control TextBox a una instancia de un objeto Person personalizado.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.DataBindingWindow">
...
<!-- Bind the TextBox to the data source (TextBox.Text to Person.Name) -->
<TextBox Name="personNameTextBox" Text="{Binding Path=Name}" />
...
</Window>
Imports System.Windows ' Window
Namespace SDKSample
Partial Public Class DataBindingWindow
Inherits Window
Public Sub New()
InitializeComponent()
' Create Person data source
Dim person As Person = New Person()
' Make data source available for binding
Me.DataContext = person
End Sub
End Class
End Namespace
En este ejemplo, se crea una instancia de la clase Person en el cdigo subyacente y se establece como el
contexto de datos de DataBindingWindow. En el marcado, la propiedad Text de TextBox se enlaza a la
propiedad Person.Name (mediante la sintaxis "{Binding ... }" de XAML). Este cdigo XAML indica a WPF que
enlace el control TextBox al objeto Person almacenado en la propiedad DataContext de la ventana.
El motor de enlace de datos de WPF proporciona compatibilidad adicional que incluye validacin, ordenacin,
filtrado y agrupacin. Adems, el enlace de datos admite el uso de plantillas de datos, a fin de crear una
interfaz de usuario personalizada para los datos enlazados cuando la interfaz de usuario mostrada por los
controles estndar de WPF no es adecuada.
Grficos
WPF presenta un conjunto extenso, escalable y flexible de caractersticas de grficos que aportan las ventajas
siguientes:

Grficos independientes de la resolucin e independientes del dispositivo. La unidad de medida bsica


del sistema de grficos de WPF es el pxel independiente del dispositivo, que es 1/96 de pulgada,
independientemente de la resolucin de pantalla real, y que proporciona la base para la representacin
independiente de la resolucin y del dispositivo. Cada pxel independiente del dispositivo se escala

MCT: Luis Dueas

Pag 12 de 445

Manual de Windows Presentation Foundation


automticamente para coincidir con el valor de puntos por pulgada (ppp) del sistema en que se
representa.

Precisin mejorada. El sistema de coordenadas de WPF se mide con nmeros de punto flotante de
precisin doble, en lugar de precisin simple. Las transformaciones y los valores de opacidad tambin
se expresan como doble precisin. WPF admite tambin una amplia gama de colores (scRGB) y
proporciona compatibilidad integrada para administrar las entradas desde espacios de color diferentes.

Compatibilidad con grficos avanzados y animacin. WPF simplifica la programacin de grficos


administrando automticamente las escenas de animacin; no tendr que preocuparse por el
procesamiento de escenas, los bucles de representacin ni la interpolacin bilineal. Adems, WPF
admite la comprobacin de clics y proporciona compatibilidad plena con la composicin alfa.

Aceleracin de hardware. El sistema de grficos de WPF saca partido del hardware de grficos para
minimizar el uso de la CPU.

Formas 2D
WPF proporciona una biblioteca de formas 2D comunes dibujadas mediante vectores, como los rectngulos y
las elipses que se muestran en la ilustracin siguiente.

Una funcin interesante de las formas es que no sirven nicamente para su presentacin; las formas
implementan muchas de las caractersticas que cabe esperar de los controles, incluida la entrada de datos
desde el teclado y el mouse. En el ejemplo siguiente se muestra el control del evento MouseUp de una forma
Ellipse.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.EllipseEventHandlingWindow"
Title="Click the Ellipse">
<Ellipse Name="clickableEllipse" Fill="Blue"
MouseUp="clickableEllipse_MouseUp" />
</Window>
Imports System.Windows ' Window, MessageBox
Imports System.Windows.Input ' MouseButtonEventArgs
Namespace SDKSample
Public Class EllipseEventHandlingWindow
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
Private Sub clickableEllipse_MouseUp(ByVal sender As Object,
ByVal e As MouseButtonEventArgs)
MessageBox.Show("You clicked the ellipse!")
End Sub
End Class
End Namespace
En la ilustracin siguiente se muestra lo que el cdigo anterior genera.

MCT: Luis Dueas

Pag 13 de 445

Manual de Windows Presentation Foundation

Geometras 2D
Las formas 2D proporcionadas por WPF abarcan el conjunto estndar de formas bsicas. Sin embargo, puede
que sea preciso crear formas personalizadas para facilitar el diseo de una interfaz de usuario personalizada.
Para este fin, WPF proporciona las geometras. En la ilustracin siguiente se muestra el uso de geometras para
crear una forma personalizada que se puede dibujar directamente, utilizar como un pincel o utilizar para
recortar otras formas y controles.
Los objetos Path se pueden utilizar para dibujar formas cerradas o abiertas, varias formas o incluso formas
curvas.
Los objetos Geometry se pueden utilizar para el recorte, la comprobacin de visitas y la representacin de
datos de grficos 2D.

Efectos 2D
Un subconjunto de las funciones 2D de WPF son los efectos visuales, tales como degradados, mapas de bits,
dibujos, pintar con vdeos, rotacin, ajuste de escala y sesgo. Todas ellas se aplican mediante pinceles; en la
siguiente ilustracin se muestran algunos ejemplos.

Representacin 3D
WPF tambin incluye funciones de representacin 3D que se integran con los grficos 2D para permitir la
creacin de UIs ms interesantes y apasionantes. Por ejemplo, en la ilustracin siguiente se muestran
imgenes 2D representadas en formas 3D.

Animacin

MCT: Luis Dueas

Pag 14 de 445

Manual de Windows Presentation Foundation


La compatibilidad de WPF con la animacin permite hacer que los controles crezcan, tiemblen, giren o se
desvanezcan, crear transiciones de pgina interesantes, y mucho ms. Puede animar la mayora de las clases
de WPF, incluso las personalizadas. En la ilustracin siguiente se muestra una animacin simple en accin.

Multimedia
Una manera de mostrar un contenido enriquecido es utilizar medios audiovisuales (multimedia). WPF
proporciona compatibilidad especial con imgenes, vdeo y audio.
Imgenes
Las imgenes estn presentes en la mayora de las aplicaciones y WPF proporciona varias maneras de
utilizarlas. En la ilustracin siguiente se muestra una interfaz de usuario con un cuadro de lista que contiene
imgenes en miniatura. Cuando se selecciona una miniatura, aparece la imagen a tamao completo.

Vdeo y audio
El control MediaElement es capaz de reproducir vdeo y audio y presenta la flexibilidad suficiente para constituir
la base de un reproductor multimedia personalizado. El marcado XAML siguiente implementa un reproductor
multimedia.
<MediaElement
Name="myMediaElement"
Source="media/wpf.wmv"
LoadedBehavior="Manual"
Width="350" Height="250" />
En la ventana de la ilustracin siguiente se muestra el control MediaElement en accin.

Texto y tipografa
Para facilitar una representacin de texto de gran calidad, WPF ofrece las caractersticas siguientes:

Compatibilidad con fuentes OpenType.


Mejoras de ClearType.
Alto rendimiento que saca partido de la aceleracin de hardware.
Integracin de texto con multimedia, grficos y animacin.
Compatibilidad con fuentes internacionales y mecanismos de reserva.

MCT: Luis Dueas

Pag 15 de 445

Manual de Windows Presentation Foundation


A modo de demostracin de la integracin del texto con grficos, en la ilustracin siguiente se muestra la
aplicacin de decoraciones al texto.

Documentos
WPF permite trabajar de forma nativa con tres tipos de documentos: documentos de flujo, documentos fijos y
documentos de XML Paper Specification (XPS). WPF proporciona tambin servicios para crear, ver, administrar,
anotar, empaquetar e imprimir documentos.
Documentos dinmicos
Los documentos dinmicos se han diseado para optimizar su presentacin y legibilidad ajustando
dinmicamente su contenido y modificando su flujo cuando se producen cambios en el tamao de la ventana y
la configuracin de pantalla. En el marcado XAML siguiente se muestra la definicin de FlowDocument.
<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Paragraph FontSize="18" FontWeight="Bold">Flow Document</Paragraph>
<Paragraph>
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam
nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat
volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation
ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo
consequat. Duis autem vel eum iriure.
</Paragraph>
...
</FlowDocument>
En el ejemplo siguiente se muestra cmo cargar un documento dinmico en FlowDocumentReader para leerlo,
realizar bsquedas e imprimirlo.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.FlowDocumentReaderWindow"
Title="Flow Document Reader">
<FlowDocumentReader Name="flowDocumentReader" />
</Window>
Imports System.Windows 'Window
Imports System.Windows.Documents 'FlowDocument
Imports System.IO 'FileStream, FileMode
Imports System.Windows.Markup 'XamlReader
Namespace SDKSample
Public Class FlowDocumentReaderWindow
Inherits Window
Public Sub New()
Me.InitializeComponent()
Using stream1 As FileStream = _
New FileStream("AFlowDocument.xaml", _
FileMode.Open, FileAccess.Read)
Dim document1 As FlowDocument = _
TryCast(XamlReader.Load(stream1), FlowDocument)
Me.flowDocumentReader.Document = document1
End Using
End Sub
End Class
End Namespace
En el ejemplo siguiente se muestra el resultado.

Documentos fijos

MCT: Luis Dueas

Pag 16 de 445

Manual de Windows Presentation Foundation


Los documentos fijos estn destinados a aplicaciones que requieren una presentacin con representacin fiel (lo
que se ve es lo que se obtiene, o WYSIWYG, en sus siglas en ingls) precisa, especialmente por lo que respecta
a su impresin. Los usos tpicos para los documentos fijos incluyen la creacin de publicaciones, el
procesamiento de textos y el diseo de formularios, donde es vital que se respete el diseo de pgina original.
Los documentos fijos conservan la organizacin precisa de su contenido de una manera independiente del
dispositivo. Por ejemplo, un documento fijo mostrado en una pantalla de 96 puntos por pulgada (ppp) aparece
exactamente igual que cuando se imprime en una impresora lser de 600 ppp o una mquina tipogrfica
fotogrfica de 4800 ppp. El diseo permanece inalterado en todos los casos, aunque la calidad del documento
vara segn las funciones de cada dispositivo.
Documentos XPS
Los documentos de XML Paper Specification (XPS) se basan en documentos fijos de WPF. Los documentos de
XPS se describen con un esquema basado en XML que bsicamente es una representacin en forma de pgina
de documentos electrnicos. XPS es un formato de documento abierto habilitado para varios exploradores y
diseado para facilitar la creacin, el uso compartido, la impresin y el almacenamiento de documentos
paginados. Entre las caractersticas importantes de la tecnologa XPS se incluyen:

Empaquetado de documentos XPS como archivos ZipPackage conformes con la especificacin Open
Packaging Conventions (OPC).

Hospedaje en aplicaciones independientes y basadas en explorador.


Generacin y manipulacin manuales de documentos XPS desde las aplicaciones WPF.
Representacin de gran fidelidad gracias al establecimiento como destino de la mxima calidad del
dispositivo de salida.

Puesta en cola para impresin de Windows Vista.


Enrutamiento directo de documentos a impresoras compatibles con XPS.
Integracin de la interfaz de usuario con DocumentViewer.

En la ilustracin siguiente se muestra un documento XPS mostrado en un control DocumentViewer.

DocumentViewer tambin permite a los usuarios cambiar la vista de los documentos XPS, realizar bsquedas en
ellos e imprimirlos.
Anotaciones
Las anotaciones son notas o comentarios que se agregan a los documentos para marcar la informacin o
resaltar elementos de inters, a fin de consultarlos ms adelante. Aunque escribir notas en documentos
impresos es fcil, la posibilidad de "escribir" notas en los documentos electrnicos con frecuencia es limitada o
no est disponible en absoluto. Sin embargo, en WPF se proporciona un sistema de anotaciones que admite la
insercin de notas rpidas y el resaltado. Adems, estas anotaciones se pueden aplicar a documentos
hospedados en el control DocumentViewer, como se muestra en la ilustracin siguiente.

MCT: Luis Dueas

Pag 17 de 445

Manual de Windows Presentation Foundation

Empaquetado
Las API System.IO.Packaging de WPF permiten que las aplicaciones organicen los datos, el contenido y los
recursos en un nico documento ZIP porttil, sencillo de distribuir y de fcil acceso. Es posible incluir firmas
digitales para autenticar los elementos contenidos en un paquete y comprobar que el elemento firmado no se
haya manipulado ni modificado. Tambin puede cifrar los paquetes mediante la administracin de derechos
para restringir el acceso a la informacin protegida.
Impresin
.NET Framework incluye un subsistema de impresin al que WPF aporta, adems, compatibilidad con el control
de sistemas de impresin mejorados. Las mejoras de impresin incluyen las siguientes:

Instalacin en tiempo real de servidores de impresin y colas remotos.


Deteccin dinmica de funciones de impresora.
Configuracin dinmica de opciones de impresin.
Modificacin del enrutamiento y las prioridades de los trabajos de impresin.

Los documentos XPS presenta, adems, una mejora fundamental del rendimiento. La ruta de acceso de Interfaz
de dispositivo grfico de Microsoft Windows (GDI) de impresin suele requerir dos conversiones:

La primera conversin del documento a un formato de procesador de impresin, como Metarchivo


mejorado (EMF).

Una segunda conversin al lenguaje de descripcin de pginas de la impresora, como PCL o PostScript.

Sin embargo, los documentos XPS evitan estas conversiones porque un componente del formato de archivo XPS
es un lenguaje de procesador de impresin y un lenguaje de descripcin de pginas. Esta compatibilidad ayuda
a reducir tamao del archivo de cola y las cargas de las impresoras integradas en red.
Personalizar las aplicaciones WPF
Hasta este punto, hemos estudiado las unidades de creacin de WPF fundamentales para la programacin de
aplicaciones. El modelo de aplicacin se utiliza para hospedar y distribuir el contenido de las aplicaciones, que
est compuesto principalmente de controles. Para simplificar la organizacin de los controles en una interfaz de
usuario y asegurarse de que la organizacin se conserve aunque se modifiquen el tamao de la ventana y la
configuracin de pantalla, se utiliza el sistema de diseo de WPF. Dado que la mayora de las aplicaciones
permiten a los usuarios interactuar con los datos, los enlaces de datos se utilizan para reducir el trabajo de
integracin de la interfaz de usuario con esos datos. A fin de mejorar la apariencia visual de la aplicacin, se
utiliza toda la gama de grficos, animacin y multimedia que WPF proporciona. Por ltimo, si la aplicacin
funciona a travs de texto y documentos, puede utilizar las funciones de tipografa, documentos, anotacin,
empaquetado e impresin de WPF.
Sin embargo, con frecuencia estos elementos fundamentales no bastan para crear y administrar una
experiencia del usuario realmente diferenciada y visualmente impactante. Puede que los controles de WPF no se
integren con la apariencia deseada de la aplicacin. Es posible que los datos no se muestren del modo ms
eficaz. La apariencia y el funcionamiento predeterminados de los temas de Windows pueden no ser adecuados
para proporcionar la experiencia global del usuario con respecto a la aplicacin. En muchos aspectos, una
tecnologa de presentacin requiere la extensibilidad visual tanto como cualquier otro tipo de extensibilidad.

MCT: Luis Dueas

Pag 18 de 445

Manual de Windows Presentation Foundation


Por esta razn, WPF proporciona gran variedad de mecanismos para la creacin de experiencias de usuario
nicas, incluido un modelo de contenido enriquecido para los controles, desencadenadores, plantillas de
controles y datos, estilos, recursos de la interfaz de usuario, temas y mscaras.
Modelo de contenido
El propsito principal de la mayora de los controles de WPF es mostrar contenido. En WPF, el tipo y nmero de
elementos que pueden constituir el contenido de un control se denomina el modelo de contenido del control.
Algunos controles pueden contener un solo elemento y tipo de contenido; por ejemplo, el contenido de un
control TextBox es un valor de tipo String que est asignado a la propiedad Text. En el ejemplo siguiente se
establece el contenido de TextBox.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.TextBoxContentWindow"
Title="TextBox Content">
...
<TextBox Text="This is the content of a TextBox." />
...
</Window>
En la ilustracin siguiente se muestra el resultado.

Otros controles, sin embargo, pueden contener varios elementos con tipos diferentes de contenido; el contenido
de un control Button, especificado por la propiedad Content, puede contener gran variedad de elementos, entre
los que se incluyen controles de diseo, texto, imgenes y formas. En el ejemplo siguiente se muestra un
control Button con contenido que incluye DockPanel, Label, Border y MediaElement.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.ButtonContentWindow"
Title="Button Content">
...
<Button Margin="20">
<!-- Button Content -->
<DockPanel Width="200" Height="180">
<Label DockPanel.Dock="Top" HorizontalAlignment="Center">
Click Me!</Label>
<Border Background="Black" BorderBrush="Yellow" BorderThickness="2"
CornerRadius="2" Margin="5">
<MediaElement Source="media/wpf.wmv" Stretch="Fill" />
</Border>
</DockPanel>
</Button>
...
</Window>
En la ilustracin siguiente se muestra el contenido de este botn.

Desencadenadores
Aunque el propsito principal del marcado XAML es implementar la apariencia de una aplicacin, tambin puede
utilizar XAML para implementar algunos aspectos del comportamiento de una aplicacin. Un ejemplo de ello es
el uso de desencadenadores para cambiar la apariencia de una aplicacin de acuerdo con las interacciones con
el usuario.
Plantillas de control

MCT: Luis Dueas

Pag 19 de 445

Manual de Windows Presentation Foundation


Las UIs predeterminadas para los controles de WPF suelen construirse a partir de otros controles y formas. Por
ejemplo, un control Button est compuesto de los controles ButtonChrome y ContentPresenter. ButtonChrome
proporciona la apariencia del botn estndar, mientras que ContentPresenter muestra el contenido del botn,
especificado por la propiedad Content.
A veces, la apariencia predeterminada de un control puede ser incongruente con la apariencia global de una
aplicacin. En este caso, puede utilizar una plantilla de control ControlTemplate para cambiar la apariencia de la
interfaz de usuario del control sin modificar su contenido ni su comportamiento.
En el ejemplo siguiente se muestra cmo cambiar la apariencia de un control Button mediante ControlTemplate.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.ControlTemplateButtonWindow"
Title="Button with Control Template" Height="158" Width="290">
<!-- Button using an ellipse -->
<Button Content="Click Me!" Click="button_Click">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Margin="5">
<Ellipse Stroke="DarkBlue" StrokeThickness="2">
<Ellipse.Fill>
<RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
<GradientStop Color="Azure" Offset="0.1" />
<GradientStop Color="CornflowerBlue" Offset="1.1" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<ContentPresenter Name="content" HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
</Window>
Imports System.Windows ' Window, RoutedEventArgs, MessageBox
Namespace SDKSample
Public Class ControlTemplateButtonWindow
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
Private Sub button_Click(ByVal sender As Object, ByVal e As
RoutedEventArgs)
MessageBox.Show("Hello, Windows Presentation Foundation!")
End Sub
End Class
End Namespace
En este ejemplo, la interfaz de usuario del botn predeterminado se ha reemplazado por una forma Ellipse que
tiene un borde azul marino y se rellena mediante RadialGradientBrush. El control ContentPresenter muestra el
contenido del control Button, "Click Me!" (Haga clic aqu!). Al hacer clic en Button, se provoca como siempre el
evento Click, que forma parte del comportamiento predeterminado del control Button. El resultado se muestra
en la ilustracin siguiente.

Plantillas de datos
Mientras que una plantilla de control permite especificar la apariencia de un control, una plantilla de datos
permite especificar la apariencia del contenido del control. Las plantillas de datos se utilizan con frecuencia para
mejorar la manera de mostrar los datos enlazados. En la ilustracin siguiente se muestra la apariencia
predeterminada de un control ListBox enlazado a una coleccin de objetos Task, donde cada tarea tiene un
nombre, descripcin y prioridad.

MCT: Luis Dueas

Pag 20 de 445

Manual de Windows Presentation Foundation

La apariencia predeterminada es la que cabra esperar de un control ListBox. Sin embargo, la apariencia
predeterminada de cada tarea contiene nicamente el nombre de tarea. Para mostrar el nombre de tarea, la
descripcin y la prioridad, la apariencia predeterminada de los elementos de lista enlazados al control ListBox
se debe modificar, mediante DataTemplate. En el cdigo XAML siguiente se define una plantilla de datos
DataTemplate, que se aplica a cada tarea mediante el atributo ItemTemplate.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.DataTemplateWindow"
Title="With a Data Template">
...
<!-- Data Template (applied to each bound task item in the task collection) -->
<DataTemplate x:Key="myTaskTemplate">
<Border Name="border" BorderBrush="DarkSlateBlue" BorderThickness="2"
CornerRadius="2" Padding="5" Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Padding="0,0,5,0"
Text="Task Name:"/>
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding
Path=TaskName}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Padding="0,0,5,0"
Text="Description:"/>
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding
Path=Description}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Padding="0,0,5,0"
Text="Priority:"/>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding
Path=Priority}"/>
</Grid>
</Border>
</DataTemplate>
...
<!-- Data template is specified by the ItemTemplate attribute -->
<ListBox
ItemsSource="{Binding}"
ItemTemplate="{StaticResource myTaskTemplate}"
HorizontalContentAlignment="Stretch"
IsSynchronizedWithCurrentItem="True"
Margin="5,0,5,5" />
...
</Window>
En la ilustracin siguiente se muestra el efecto de este cdigo.

Observe que ListBox ha conservado su comportamiento y su apariencia global; nicamente ha cambiado la


apariencia del contenido mostrado por el cuadro de lista.
Estilos

MCT: Luis Dueas

Pag 21 de 445

Manual de Windows Presentation Foundation


Los estilos permiten a los programadores y diseadores normalizar un aspecto determinado de sus productos.
WPF proporciona un modelo de estilo slido, que es la base del elemento Style. En el ejemplo siguiente se crea
un estilo que establece el color de fondo de todos los controles Button de una ventana en Orange.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.StyleWindow"
Title="Styles">
...
<!-- Style that will be applied to all buttons -->
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Orange" />
<Setter Property="BorderBrush" Value="Crimson" />
<Setter Property="FontSize" Value="20" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="5" />
</Style>
...
<!-- This button will have the style applied to it -->
<Button>Click Me!</Button>
<!-- This labe will not have the style applied to it -->
<Label>Don't Click Me!</Label>
<!-- This button will have the style applied to it -->
<Button>Click Me!</Button>
...
</Window>
Dado que este estilo tiene como destino todos los controles Button, se aplica automticamente a todos los
botones de la ventana, como se muestra en la ilustracin siguiente.

Recursos
Los controles de una aplicacin deben tener la misma apariencia, que puede incluir todo tipo de recursos, desde
fuentes y colores de fondo hasta plantillas de control, pasando por las plantillas de datos y los estilos. Puede
utilizar la compatibilidad de WPF con los recursos de interfaz de usuario (UI) para encapsular estos recursos en
una ubicacin nica y poder reutilizarlos.
En el ejemplo siguiente se define un color de fondo comn que es compartido por los controles Button y Label.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.ResourcesWindow"
Title="Resources Window">
<!-- Define window-scoped background color resource -->
<Window.Resources>
<SolidColorBrush x:Key="defaultBackground" Color="Red" />
</Window.Resources>
...
<!-- Button background is defined by window-scoped resource -->
<Button Background="{StaticResource defaultBackground}">One Button</Button>
<!-- Label background is defined by window-scoped resource -->
<Label Background="{StaticResource defaultBackground}">One Label</Label>
...
</Window>
En este ejemplo se implementa un recurso de color de fondo mediante el elemento de propiedad
Window.Resources. Este recurso est disponible para todos los elementos secundarios de Window. Existe gran
variedad de mbitos de recursos, incluidos los siguiente, que se muestran en el orden en que se resuelven:
1.

Un control individual (que utiliza la propiedad FrameworkElement..::.Resources heredada).

2.

Window o Page (que tambin utiliza la propiedad FrameworkElement..::.Resources heredada).

3.

Application (que utiliza la propiedad Application..::.Resources).

La variedad de mbitos aporta flexibilidad al programador con respecto a la manera de definir y compartir los
recursos.
Como alternativa a la asociacin directa de los recursos a un mbito determinado, puede empaquetar uno o
varios recursos mediante un ResourceDictionary independiente al que puede hacer referencia en otras partes de

MCT: Luis Dueas

Pag 22 de 445

Manual de Windows Presentation Foundation


una aplicacin. En el ejemplo siguiente se define un color de fondo predeterminado en un diccionario de
recursos.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Define background color resource -->
<SolidColorBrush x:Key="defaultBackground" Color="Red" />
<!-- Define other resources -->
...
</ResourceDictionary>
En el ejemplo siguiente se hace referencia al diccionario de recursos definido en el ejemplo anterior para
compartirlo en toda la aplicacin.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="BackgroundColorResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
...
</Application>
Los recursos y diccionarios de recursos constituyen el fundamento de la compatibilidad de WPF con los temas y
las mscaras.
Temas y mscaras
Desde una perspectiva visual, un tema define la apariencia global de Windows y de las aplicaciones que se
ejecutan en su seno. Windows incluye varios temas. Por ejemplo, Microsoft Windows XP se distribuye con los
temas clsicos de Windows XP y Windows, mientras que Windows Vista se distribuye con los temas clsicos de
Windows Vista y Windows. La apariencia definida por un tema establece la apariencia predeterminada de una
aplicacin WPF. Sin embargo, WPF no se integra directamente con los temas de Windows. Como la apariencia
de WPF se define mediante plantillas, WPF incluye una plantilla para cada uno de los temas conocidos de
Windows, como Aero (Windows Vista), Clsico (Microsoft Windows 2000), Luna (Microsoft Windows XP) y
Royale (Microsoft Windows XP Media Center Edition 2005). Estos temas estn empaquetados en diccionarios de
recursos que se resuelven cuando no se encuentran los recursos correspondientes en una aplicacin. Muchas
aplicaciones se basan en estos temas para definir su apariencia visual; mantener la coherencia con la
apariencia de Windows ayuda a los usuarios a familiarizarse con las aplicaciones ms fcilmente.
Por otro lado, la experiencia del usuario para algunas aplicaciones no procede necesariamente de los temas
estndar. Por ejemplo, Microsoft Windows Media Player funciona a travs de datos de audio y vdeo y saca
partido de un estilo diferente de experiencia del usuario. Tales UIs tienden a proporcionar temas
personalizados, especficos de cada aplicacin. Se denominan mscaras, y las aplicaciones con mscaras suelen
proporcionar enlaces que permiten a los usuarios personalizar diversos aspectos de la mscara. Microsoft
Windows Media Player tiene varias mscaras prefabricadas, as como una serie de mscaras de otros
fabricantes.
Tanto los temas como las mscaras de WPF se definen con toda facilidad mediante los diccionarios de recursos.
En el ejemplo siguiente se muestran ejemplos de definiciones de mscaras.
<!-- Blue Skin -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SDKSample">
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue" />
</Style>
...
<!-- Blue Skin -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SDKSample">
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Blue" />

MCT: Luis Dueas

Pag 23 de 445

Manual de Windows Presentation Foundation


</Style>
...
</ResourceDictionary>
</ResourceDictionary>
<!-- Yellow Skin -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SDKSample">
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Yellow" />
</Style>
...
<!-- Yellow Skin -->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SDKSample">
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Yellow" />
</Style>
...
</ResourceDictionary>
</ResourceDictionary>
Controles personalizados
Aunque WPF proporciona una amplsima compatibilidad con funciones de personalizacin, puede encontrar
situaciones en que los controles existentes de WPF no satisfagan las necesidades de la aplicacin o de los
usuarios. Esto puede suceder cuando:

La interfaz de usuario que necesita no se puede crear personalizando la apariencia y el funcionamiento


de las implementaciones de WPF existentes.

Las implementaciones de WPF existentes no admiten el comportamiento que se necesita (o lo admiten,


pero no fcilmente).

Sin embargo, en este punto puede sacar partido de uno de los tres modelos de WPF para crear un nuevo
control. Cada modelo est destinado a un escenario concreto y exige que el control personalizado se derive de
una clase base de WPF determinada. A continuacin se muestran los tres modelos:

Modelo de control de usuario. El control personalizado se deriva de UserControl y se crea a partir de


uno o varios controles.

Modelo de control. El control personalizado se deriva de Control y se utiliza para generar


implementaciones que separan su comportamiento de su apariencia mediante plantillas, de un modo
muy similar a la mayora de los controles de WPF. Al derivarse de Control, aporta mayor libertad para
la creacin de una interfaz de usuario personalizada que los controles de usuario, pero puede requerir
ms esfuerzo.

Modelo de elemento de marco de trabajo. Un control personalizado se deriva de FrameworkElement


cuando su apariencia se define mediante la lgica de representacin personalizada (no mediante
plantillas).

En el ejemplo siguiente se muestra un control numrico personalizado de arriba/abajo derivado de UserControl.


<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.NumericUpDown">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- Value text box -->
<Border BorderThickness="1" BorderBrush="Gray" Margin="2"
Grid.RowSpan="2"
VerticalAlignment="Center" HorizontalAlignment="Stretch">
<TextBlock Name="valueText" Width="60" TextAlignment="Right"
Padding="5"/>
</Border>
<!-- Up/Down buttons -->
<RepeatButton Name="upButton" Click="upButton_Click"
Grid.Column="1" Grid.Row="0">Up</RepeatButton>

MCT: Luis Dueas

Pag 24 de 445

Manual de Windows Presentation Foundation


<RepeatButton Name="downButton" Click="downButton_Click"
Grid.Column="1" Grid.Row="1">Down</RepeatButton>
</Grid>
</UserControl>
imports System 'EventArgs
imports System.Windows
'DependencyObject, DependencyPropertyChangedEventArgs,
' FrameworkPropertyMetadata, PropertyChangedCallback,
' RoutedPropertyChangedEventArgs
imports System.Windows.Controls 'UserControl
Namespace SDKSample
' Interaction logic for NumericUpDown.xaml
Partial Public Class NumericUpDown
Inherits System.Windows.Controls.UserControl
'NumericUpDown user control implementation
...
End Class
End Namespace
En el ejemplo siguiente se muestra el cdigo XAML necesario para incorporar el control de usuario a una
ventana (Window).
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.UserControlWindow"
xmlns:local="clr-namespace:SDKSample"
Title="User Control Window">
...
<!-- Numeric Up/Down user control -->
<local:NumericUpDown />
...
</Window>
En la ilustracin siguiente se muestra el control NumericUpDown hospedado en una ventana Window.

Procedimientos recomendados en WPF

Como sucede con cualquier plataforma de programacin, WPF se puede utilizar de diversas maneras
para lograr el resultado deseado. A fin de asegurarse de que sus aplicaciones WPF proporcionen la
experiencia de usuario necesaria y cumplan las exigencias del pblico en general, existen
procedimientos recomendados de accesibilidad, globalizacin y localizacin, y rendimiento.

Resumen
WPF es una completa tecnologa de presentacin para generar gran variedad aplicaciones cliente impactantes
desde el punto de vista visual. En esta introduccin se ha proporcionado una introduccin general a las
principales caractersticas de WPF.
El paso siguiente consiste en generar aplicaciones WPF.
Durante el proceso de creacin, puede consultar de nuevo esta introduccin para repasar las caractersticas
clave y encontrar referencias a artculos donde se abordan en mayor profundidad todas las caractersticas
tratadas en esta introduccin.

1.2. Informacin General sobre Windows Presentation Foundation


Este tutorial proporciona una introduccin bsica al desarrollo de una aplicacin de Windows Presentation
Foundation (WPF), que incluye los elementos comunes a la mayora de las aplicaciones de WPF: marcado
Lenguaje de marcado de aplicaciones extensible (XAML), cdigo subyacente, definiciones de aplicacin,
controles, diseo, enlace de datos y estilos.
Resumen
Este tutorial le guiar a lo largo del desarrollo de una aplicacin bsica de WPF mediante los pasos siguientes.

Definir el marcado XAML para disear la apariencia de la interfaz de usuario (UI) de la aplicacin.

MCT: Luis Dueas

Pag 25 de 445

Manual de Windows Presentation Foundation

Escribir cdigo que determine el comportamiento de la aplicacin.


Crear una definicin de aplicacin para administrar la aplicacin.
Agregar controles y diseo para crear la interfaz de usuario de la aplicacin.
Crear estilos que aporten una apariencia coherente a toda la interfaz de usuario de una aplicacin.
Enlazar la interfaz de usuario a datos para rellenar la interfaz de usuario a partir de datos y mantener
los datos sincronizados con la interfaz de usuario.

Cuando termine el tutorial, habr generado una aplicacin independiente de Windows que permitir a los
usuarios ver los informes de gastos de las personas seleccionadas. La aplicacin constar de varias pginas de
WPF hospedadas en una ventana del estilo del explorador.
Crear los archivos de cdigo de la aplicacin
En este paso, crear la infraestructura de la aplicacin, que incluye una definicin de aplicacin, dos pginas y
una imagen.
1.

Cree un nuevo archivo de marcado XAML denominado App.xaml. Este archivo define una aplicacin de
WPF y tambin se utiliza para especificar la interfaz de usuario que debe mostrarse automticamente
cuando se inicia la aplicacin; en este caso, HomePage.xaml (que se crear en el paso siguiente). El

2.

marcado XAML debe ser similar al que se muestra a continuacin:


<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="HomePage.xaml">
</Application>
Cree un nuevo archivo de marcado XAML denominado HomePage.xaml, que ser la primera pgina
que se muestre cuando se inicie la aplicacin. HomePage.xaml mostrar una lista de personas y el
usuario podr seleccionar en esa lista la persona cuyo informe de gastos desee mostrar. Agregue un
elemento Page a HomePage.xaml, con la configuracin siguiente:

3.

La barra de ttulo del explorador es "ExpenseIt".


El ancho de la ventana del explorador es de 550 pxeles independientes del dispositivo.
El alto de la ventana del explorador es de 350 pxeles independientes del dispositivo.
El ttulo de la pgina es "ExpenseIt - Home".

El marcado XAML debe ser similar al que se muestra a continuacin:


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.HomePage"
WindowTitle="ExpenseIt"
Title="ExpenseIt - Home"
WindowWidth="550" WindowHeight="380">
</Page>
Cree un nuevo archivo de cdigo denominado HomePage.xaml.cs. Este archivo ser el archivo de
cdigo subyacente que contiene el cdigo para controlar los eventos declarados en HomePage.xaml. El

4.

cdigo debe ser similar al que se muestra a continuacin:


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace ExpenseIt
{
public partial class HomePage : Page
{
public HomePage()
{
InitializeComponent();
}
}
}
Cree un nuevo archivo de marcado XAML denominado ExpenseReportPage.xaml. Agregue un elemento
Page y establezca "ExpenseIt - View Expense Report" como ttulo de pgina. Esta pgina mostrar el
informe de gastos de la persona que est seleccionada en HomePage.xaml. El marcado XAML debe ser
similar al que se muestra a continuacin:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

MCT: Luis Dueas

Pag 26 de 445

Manual de Windows Presentation Foundation

5.

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.ExpenseReportPage"
Title="ExpenseIt - View Expense Report">
</Page>
Cree un nuevo archivo denominado ExpenseReportPage.xaml.cs. Este archivo ser un archivo de
cdigo subyacente que enlace los datos del informe de gastos a la interfaz de usuario definida en

6.

ExpenseReportPage.xaml. El cdigo debe ser similar al que se muestra a continuacin:


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace ExpenseIt
{
public partial class ExpenseReportPage : Page
{
public ExpenseReportPage()
{
InitializeComponent();
}
}
}
Agregue una imagen denominada watermark.png a la misma carpeta que los cinco archivos de cdigo
que cre en los pasos anteriores. Puede crear su propia imagen o copiar el archivo del mismo nombre del
cdigo de ejemplo.
Generar y ejecutar la aplicacin

En este paso, utilizar MSBuild para generar la aplicacin que defini en la seccin anterior.
1.

Cree un nuevo archivo denominado ExpenseIt.csproj. Este archivo ser el archivo de MSBuild, que es
un archivo XML especial que contiene la configuracin de compilacin de su aplicacin e incluye los
siguientes elementos:

Las variables de compilacin globales para el proyecto compilado, como el nombre del
ensamblado generado, el tipo de ensamblado que debe generarse y la carpeta en la que debe
agregarse el ensamblado generado.

Referencias a los archivos de cdigo.


Referencias a los ensamblados de Microsoft .NET Framework que contienen los tipos utilizados
por la aplicacin.

2.

El contenido del archivo de compilacin debe ser similar al que se muestra a continuacin:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AssemblyName>ExpenseIt</AssemblyName>
<TargetType>winexe</TargetType>
<OutputPath>bin\$(Configuration)\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System"/>
<Reference Include="System.Xml"/>
<Reference Include="System.Data"/>
<Reference Include="WindowsBase"/>
<Reference Include="PresentationCore"/>
<Reference Include="PresentationFramework"/>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml"/>
<Page Include="HomePage.xaml"/>
<Compile Include="HomePage.xaml.cs" />
<Page Include="ExpenseReportPage.xaml"/>
<Compile Include="ExpenseReportPage.xaml.cs" />
<Resource Include="watermark.png"/>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets"/>
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets"/>
</Project>
Abra una ventana de comandos en la misma carpeta donde se encuentra el archivo de proyecto y los
archivos de cdigo de la aplicacin.

3.

Desde el smbolo del sistema, ejecute el siguiente comando:


MSBuild ExpenseIt.csproj
En el caso de Microsoft Visual Basic .NET, ejecute el siguiente comando en su lugar:

MCT: Luis Dueas

Pag 27 de 445

Manual de Windows Presentation Foundation


MSBuild ExpenseIt.vbproj
Para compilar y ejecutar la aplicacin mediante Visual Studio, abra el archivo de proyecto en Visual
Studio y presione F5.
Nota:
Visual Studio 2005 genera automticamente un archivo de proyecto. Dado que en este tutorial no se da por
hecho que se haya instalado Visual Studio, se detalla el proceso de creacin de un archivo de proyecto. Si
est utilizando Visual Studio para completar este tutorial, sobrescriba el contenido del archivo .csproj
generado por el texto de MSBuild anterior.
1.

Abra la carpeta que contiene el archivo ejecutable de la aplicacin generado, es decir, expenseit.exe.
En caso de que haya generado el archivo desde el smbolo del sistema, expenseit.exe se encontrar en la
carpeta siguiente:
Carpeta que contiene los archivos de cdigo de la aplicacin \bin\
Si ha generado el archivo utilizando Visual Studio, expenseit.exe se encontrar en la carpeta siguiente:
Carpeta que contiene los archivos de cdigo de la aplicacin \bin\debug\

2.

Desde el smbolo del sistema, ejecute expenseit.exe. En la siguiente ilustracin se muestra la


aplicacin en ejecucin.

Agregar el diseo
El diseo proporciona un modo ordenado de colocar los elementos de la interfaz de usuario, y tambin controla
el tamao y la posicin de los mismos cuando la interfaz de usuario cambia de tamao. Normalmente, para
agregar el diseo a la interfaz de usuario se utiliza uno de los controles de diseo siguientes:

Canvas
DockPanel
Grid
StackPanel
VirtualizingStackPanel
WrapPanel

Cada uno de ellos admite un tipo de diseo especial para sus elementos secundarios. Es posible cambiar de
tamao las pginas de ExpenseIt, y cada pgina tiene elementos organizados horizontal y verticalmente junto
con otros elementos. Por lo tanto, Grid es el elemento de diseo ideal para la aplicacin.
El marcado XAML siguiente crea una tabla de una columna y tres filas, con un margen de 10 pxeles, agregando
un control Grid a HomePage.xaml:
1.

Abra HomePage.xaml.

2.

Agregue el cdigo XAML siguiente entre las etiquetas Page.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.HomePage"
WindowTitle="ExpenseIt"
Title="ExpenseIt - Home"
WindowWidth="550" WindowHeight="380">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>

MCT: Luis Dueas

Pag 28 de 445

Manual de Windows Presentation Foundation


<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
</Grid>
</Page>
Agregar controles
En este paso, se actualiza la interfaz de usuario de la pgina principal para mostrar una lista de personas y los
usuarios pueden seleccionar el nombre de la persona cuyo informe de gastos desean ver. Para crear esta
interfaz de usuario, se han agregado los elementos siguientes a HomePage.xaml:

Un control ListBox (para la lista de personas).


Un control Label (para el encabezado de la lista).
Un control Button (para hacer clic con objeto de ver el informe de gastos de la persona que est
seleccionada en la lista).

Siga estos pasos para actualizar HomePage.xaml:


1.

Sobrescriba el contenido del archivo HomePage.xaml por el siguiente cdigo XAML.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.HomePage"
WindowTitle="ExpenseIt"
Title="ExpenseIt - Home"
WindowWidth="550" WindowHeight="380">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- People list -->
<Border Grid.Column="0" Grid.Row="0" Height="35" Padding="5"
Background="#4E87D4">
<Label VerticalAlignment="Center" Foreground="White">Names
</Label>
</Border>
<ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
<ListBoxItem>Mike</ListBoxItem>
<ListBoxItem>Lisa</ListBoxItem>
<ListBoxItem>John</ListBoxItem>
<ListBoxItem>Mary</ListBoxItem>
</ListBox>
<!-- View report button -->
<Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,0" Width="125"
Height="25" HorizontalAlignment="Right">View</Button>
</Grid>
</Page>
Compile y ejecute la aplicacin.

2.

La imagen siguiente muestra los controles creados por el cdigo de este paso.

Agregar una imagen y un ttulo


En este paso, la interfaz de usuario de la pgina principal se actualiza con una imagen adecuada y un ttulo de
pgina:
1.

Abra HomePage.xaml.

2.

Sobrescriba el contenido del archivo HomePage.xaml por el siguiente cdigo XAML.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

MCT: Luis Dueas

Pag 29 de 445

Manual de Windows Presentation Foundation

3.

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.HomePage"
WindowTitle="ExpenseIt"
Title="ExpenseIt - Home"
WindowWidth="550" WindowHeight="380">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="230" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
<Canvas DockPanel.Dock="Left" Width="230" Height="100">
<Image Source="watermark.png" />
</Canvas>
<Label VerticalAlignment="Center" FontFamily="Trebuchet MS"
FontWeight="Bold" FontSize="18" Foreground="#0066cc">
View Expense Report
</Label>
</DockPanel>
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- People list -->
<Border Grid.Column="0" Grid.Row="0" Height="35" Padding="5"
Background="#4E87D4">
<Label VerticalAlignment="Center" Foreground="White">Names
</Label>
</Border>
<ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
<ListBoxItem>Mike</ListBoxItem>
<ListBoxItem>Lisa</ListBoxItem>
<ListBoxItem>John</ListBoxItem>
<ListBoxItem>Mary</ListBoxItem>
</ListBox>
<!-- View report button -->
<Button Grid.Column="0" Grid.Row="2" Margin="0,10,0,0"
Width="125" Height="25" HorizontalAlignment="Right">View</Button>
</Grid>
</Grid>
</Page>
Este cdigo XAML actualiza el control Grid de las formas siguientes:

Crea una nueva cuadrcula con dos filas.


Agrega un control DockPanel con los elementos Canvas, Image y Label a la primera fila. El
control DockPanel incluye las dos columnas de la primera fila que, junto con el elemento Canvas
acoplado a la izquierda, permite que Label se superponga a Image.

Utiliza el atributo Source del elemento Image para especificar la imagen de origen, es decir,
watermark.png.

Agrega el texto de ttulo "View Expense Report" a Label.


Utiliza los atributos de los elementos Canvas y Label para configurar su apariencia y su
tamao.

Mueve la cuadrcula que originalmente contena HomePage.xaml a la segunda columna de la


segunda fila de la nueva cuadrcula.

4.

Compile y ejecute la aplicacin.

En la ilustracin siguiente se muestra el resultado de este paso.

MCT: Luis Dueas

Pag 30 de 445

Manual de Windows Presentation Foundation

Agregar cdigo para controlar los eventos


1.

Abra HomePage.xaml.

2.

Sobrescriba el elemento Button definido en el paso anterior por el cdigo siguiente.


...
<!-- View report button -->
<Button Grid.Column="0" Grid.Row="2" Width="125" Height="25"
Margin="0,10,0,0" HorizontalAlignment="Right"
Click="viewButton_Click">View</Button>
...
Nota:
El nombre del evento de Button que se va a controlar es Click. El nombre del controlador de eventos
definido por el programador es viewButton_Click. El controlador de eventos se registra con el evento
Click para el control Button.

3.

Abra el archivo HomePage.xaml.cs que cre en el paso Crear los archivos de cdigo de la aplicacin del
tutorial.

4.

Sobrescriba el contenido del archivo por el siguiente cdigo. De esta forma, se agrega cdigo para
controlar el evento Click, que permite navegar hasta el archivo ExpenseReportPage.xaml.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace ExpenseIt
{
public partial class HomePage : Page
{
public HomePage()
{
InitializeComponent();
}
private void viewButton_Click(object sender, RoutedEventArgs args)
{
// View Expense Report
ExpenseReportPage expenseReportPage = new ExpenseReportPage();
this.NavigationService.Navigate(expenseReportPage);
}
}
}
Crear la interfaz de usuario para ExpenseReportPage

ExpenseReportPage.xaml muestra el informe de gastos de la persona que se seleccion en HomePage.xaml. Las


actualizaciones siguientes agregan los controles y el diseo que sirven para crear la interfaz de usuario bsica
de ExpenseReportPage.xaml. Tambin agregan un fondo y colores de relleno a los distintos elementos de la
interfaz de usuario.
1.

Abra el archivo ExpenseReportPage.xaml y agregue el cdigo siguiente.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.ExpenseReportPage"
Title="ExpenseIt - View Expense Report">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="230" />
<ColumnDefinition />

MCT: Luis Dueas

Pag 31 de 445

Manual de Windows Presentation Foundation

2.

</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
<Canvas DockPanel.Dock="Left" Width="230" Height="100">
<Image Source="watermark.png" />
</Canvas>
<Label VerticalAlignment="Center" FontFamily="Trebuchet MS"
FontWeight="Bold" FontSize="18" Foreground="#0066cc">
Expense Report For:
</Label>
</DockPanel>
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Name -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
Orientation="Horizontal">
<Label Margin="0,0,0,5" FontWeight="Bold">Name:</Label>
<Label Margin="0,0,0,5" FontWeight="Bold"></Label>
</StackPanel>
<!-- Department -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1"
Orientation="Horizontal">
<Label Margin="0,0,0,5" FontWeight="Bold">Department:</Label>
<Label Margin="0,0,0,5" FontWeight="Bold"></Label>
</StackPanel>
<Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="10" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Expense type list -->
<Border Grid.Column="0" Grid.Row="0" Height="35" Padding="5"
Background="#4E87D4">
<Label VerticalAlignment="Center" Foreground="White">Expense
Type</Label>
</Border>
<ListBox Grid.Column="0" Grid.Row="1" />
<!-- Amount list -->
<Border Grid.Column="2" Grid.Row="0" Height="35" Padding="5"
Background="#4E87D4">
<Label VerticalAlignment="Center" Foreground="White">Amount
</Label>
</Border>
<ListBox Grid.Column="2" Grid.Row="1" />
</Grid>
</Grid>
</Grid>
</Page>
Compile y ejecute la aplicacin.

La imagen siguiente muestra los elementos de la interfaz de usuario agregados a ExpenseReportPage.xaml.

MCT: Luis Dueas

Pag 32 de 445

Manual de Windows Presentation Foundation


Agregar cdigo para aplicar estilo a un control
Es habitual que todos los elementos del mismo tipo de una interfaz de usuario presenten la misma apariencia.
La interfaz de usuario utiliza estilos para permitir la reutilizacin de las distintas apariencias en diversos
elementos. Esta posibilidad de reutilizar los estilos ayuda a simplificar la creacin y la administracin del
marcado XAML. En este paso se reemplazan por estilos los atributos que se definieron en pasos anteriores para
los distintos elementos:
1.

Abra el archivo App.xaml creado en el paso Crear los archivos de cdigo de la aplicacin de este
tutorial.

2.

3.

Sobrescriba el contenido del archivo por el siguiente marcado XAML:


<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="HomePage.xaml">
<Application.Resources>
<!-- Background image style -->
<Style x:Key="backgroundImageStyle">
<Setter Property="Image.Source" Value="watermark.png"/>
</Style>
<!-- Header text style -->
<Style x:Key="headerTextStyle">
<Setter Property="Label.VerticalAlignment" Value="Center">
</Setter>
<Setter Property="Label.FontFamily" Value="Trebuchet MS">
</Setter>
<Setter Property="Label.FontWeight" Value="Bold"></Setter>
<Setter Property="Label.FontSize" Value="18"></Setter>
<Setter Property="Label.Foreground" Value="#0066cc"></Setter>
</Style>
<!-- Label style -->
<Style x:Key="labelStyle" TargetType="{x:Type Label}">
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
<!-- List header style -->
<Style x:Key="listHeaderStyle" TargetType="{x:Type Border}">
<Setter Property="Height" Value="35" />
<Setter Property="Padding" Value="5" />
<Setter Property="Background" Value="#4E87D4" />
</Style>
<!-- List header text style -->
<Style x:Key="listHeaderTextStyle" TargetType="{x:Type Label}">
<Setter Property="Foreground" Value="White" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<!-- Button style -->
<Style x:Key="buttonStyle" TargetType="{x:Type Button}">
<Setter Property="Width" Value="125" />
<Setter Property="Height" Value="25" />
<Setter Property="Margin" Value="0,10,0,0" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</Application.Resources>
</Application>
Este marcado XAML agrega los estilos siguientes:

headerTextStyle: para dar formato al control Label de ttulo de pgina.


labelStyle: para dar formato a las etiquetas Label.
listHeaderStyle: para dar formato a los controles Border de encabezado de lista.
listHeaderTextStyle: para dar formato a los controles Label de encabezado de lista.
buttonStyle: para dar formato al botn de HomePage.xaml.

Observe que los estilos son los recursos secundarios del elemento de propiedad Application.Resources. En
esta ubicacin, los estilos se aplican a todos los elementos de una aplicacin.
4.
5.

Abra HomePage.xaml.
Sobrescriba el contenido del archivo por el siguiente cdigo. En este paso se reemplazan atributos
especficos de la apariencia de cada elemento por un estilo apropiado.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

MCT: Luis Dueas

Pag 33 de 445

Manual de Windows Presentation Foundation

6.
7.

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.HomePage"
WindowTitle="ExpenseIt"
Title="ExpenseIt - Home"
WindowWidth="550" WindowHeight="380">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="230" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
<Canvas DockPanel.Dock="Left" Width="230" Height="100">
<Image Style="{StaticResource backgroundImageStyle}" />
</Canvas>
<Label Style="{StaticResource headerTextStyle}">View Expense
Report</Label>
</DockPanel>
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- People list -->
<Border Grid.Column="0" Grid.Row="0" Style="{StaticResource
listHeaderStyle}">
<Label Style="{StaticResource listHeaderTextStyle}">Names
</Label>
</Border>
<ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1">
<ListBoxItem>Mike</ListBoxItem>
<ListBoxItem>Lisa</ListBoxItem>
<ListBoxItem>John</ListBoxItem>
<ListBoxItem>Mary</ListBoxItem>
</ListBox>
<!-- View report button -->
<Button Grid.Column="0" Grid.Row="2" Style="{StaticResource
buttonStyle}" Click="viewButton_Click">View</Button>
</Grid>
</Grid>
</Page>
Abra ExpenseReportPage.xaml.
Sobrescriba el contenido del archivo por el siguiente cdigo.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.ExpenseReportPage"
Title="ExpenseIt - View Expense Report">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="230" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
<Canvas DockPanel.Dock="Left" Width="230" Height="100">
<Image Style="{StaticResource backgroundImageStyle}" />
</Canvas>
<Label Style="{StaticResource headerTextStyle}">Expense Report
For:</Label>
</DockPanel>
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Name -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
Orientation="Horizontal">

MCT: Luis Dueas

Pag 34 de 445

Manual de Windows Presentation Foundation

8.

<Label Style="{StaticResource labelStyle}">Name:</Label>


<Label Style="{StaticResource labelStyle}"></Label>
</StackPanel>
<!-- Department -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1"
Orientation="Horizontal">
<Label Style="{StaticResource labelStyle}">Department:</Label>
<Label Style="{StaticResource labelStyle}"></Label>
</StackPanel>
<Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="10" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Expense type list -->
<Border Grid.Column="0" Grid.Row="0" Style="{StaticResource
listHeaderStyle}">
<Label Style="{StaticResource listHeaderTextStyle}">Expense
Type</Label>
</Border>
<ListBox Grid.Column="0" Grid.Row="1" />
<!-- Amount list -->
<Border Grid.Column="2" Grid.Row="0" Style="{StaticResource
listHeaderStyle}">
<Label Style="{StaticResource listHeaderTextStyle}">Amount
</Label>
</Border>
<ListBox Grid.Column="2" Grid.Row="1" />
</Grid>
</Grid>
</Grid>
</Page>
Compile y ejecute la aplicacin. Despus de agregar el marcado XAML de este paso, la aplicacin
presenta la misma apariencia que tena antes de actualizarla con los estilos.
Enlazar datos a un control.

En este paso se crean datos XML que se enlazan a varios controles:


1.

Abra HomePage.xaml.

2.

Sobrescriba el contenido del archivo por el siguiente marcado XAML.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.HomePage"
WindowTitle="ExpenseIt"
Title="ExpenseIt - Home"
WindowWidth="550" WindowHeight="380">
<Grid>
<Grid.Resources>
<!-- Expense Report Data -->
<XmlDataProvider x:Key="ExpenseDataSource" XPath="Expenses">
<x:XData>
<Expenses xmlns="">
<Person Name="Mike" Department="Legal">
<Expense ExpenseType="Lunch" ExpenseAmount="50" />
<Expense ExpenseType="Transportation" ExpenseAmount="50" />
</Person>
<Person Name="Lisa" Department="Marketing">
<Expense ExpenseType="Document printing"
ExpenseAmount="50"/>
<Expense ExpenseType="Gift" ExpenseAmount="125" />
</Person>
<Person Name="John" Department="Engineering">
<Expense ExpenseType="Magazine subscription"
ExpenseAmount="50"/>
<Expense ExpenseType="New machine" ExpenseAmount="600" />
<Expense ExpenseType="Software" ExpenseAmount="500" />
</Person>
<Person Name="Mary" Department="Finance">
<Expense ExpenseType="Dinner" ExpenseAmount="100" />
</Person>
</Expenses>
</x:XData>
</XmlDataProvider>
<!-- Name item template -->
<DataTemplate x:Key="nameItemTemplate">
<Label Content="{Binding XPath=@Name}"/>

MCT: Luis Dueas

Pag 35 de 445

Manual de Windows Presentation Foundation

3.

</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="230" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
<Canvas DockPanel.Dock="Left" Width="230" Height="100">
<Image Style="{StaticResource backgroundImageStyle}" />
</Canvas>
<Label Style="{StaticResource headerTextStyle}">View Expense
Report</Label>
</DockPanel>
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- People list -->
<Border Grid.Column="0" Grid.Row="0" Style="{StaticResource
listHeaderStyle}">
<Label Style="{StaticResource listHeaderTextStyle}">Names
</Label>
</Border>
<ListBox Name="peopleListBox" Grid.Column="0" Grid.Row="1"
ItemsSource="{Binding Source={StaticResource
ExpenseDataSource}, XPath=Person}"
ItemTemplate="{StaticResource nameItemTemplate}" />
<!-- View report button -->
<Button Grid.Column="0" Grid.Row="2" Style="{StaticResource
buttonStyle}" Click="viewButton_Click">View</Button>
</Grid>
</Grid>
</Page>
Observe que los datos se crean como un recurso Grid.
Conectar los datos a los controles

En este paso, escribir el cdigo que recupera el elemento actual que est seleccionado en la lista de personas
de HomePage y pasa su referencia al constructor de ExpenseReportPage durante la creacin de instancias.
ExpenseReportPage establece su contexto de datos con el elemento que se pasa, que es el elemento con el que
se enlazarn los controles definidos en ExpenseReportPage.xaml.
1.

Abra HomePage.xaml.cs.

2.

Sobrescriba el contenido del archivo por el siguiente cdigo.


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace ExpenseIt
{
public partial class HomePage : Page
{
public HomePage()
{
InitializeComponent();
}
private void viewButton_Click(object sender, RoutedEventArgs args)
{
// Create a new expense report page and pass it the
// selected person by using the non-default constructor.
ExpenseReportPage expenseReportPage =
new ExpenseReportPage(this.peopleListBox.SelectedItem);
// Navigate to the expense report page,
this.NavigationService.Navigate(expenseReportPage);
}
}
}
Abra ExpenseReportPage.xaml.cs.

3.
4.

Sobrescriba el contenido del archivo por el siguiente cdigo.


using System;

MCT: Luis Dueas

Pag 36 de 445

Manual de Windows Presentation Foundation


using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
namespace ExpenseIt
{
public partial class ExpenseReportPage : Page
{
public ExpenseReportPage(object data)
{
InitializeComponent();
// Bind to expense report data.
this.DataContext = data;
}

}
Agregar estilo a los datos con plantillas de datos
En este paso, actualizar la interfaz de usuario para cada elemento de las listas enlazadas a datos utilizando las
plantillas de datos:
1.

Abra ExpenseReportPage.xaml.

2.

Sobrescriba el contenido del archivo por el siguiente cdigo.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ExpenseIt.ExpenseReportPage"
Title="ExpenseIt - View Expense Report">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="230" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0">
<Canvas DockPanel.Dock="Left" Width="230" Height="100">
<Image Style="{StaticResource backgroundImageStyle}" />
</Canvas>
<Label Style="{StaticResource headerTextStyle}">Expense Report
For:</Label>
</DockPanel>
<Grid Margin="10" Grid.Column="1" Grid.Row="1">
<Grid.Resources>
<!-- Reason item template -->
<DataTemplate x:Key="typeItemTemplate">
<Label Content="{Binding XPath=@ExpenseType}"/>
</DataTemplate>
<!-- Amount item template -->
<DataTemplate x:Key="amountItemTemplate">
<Label Content="{Binding XPath=@ExpenseAmount}"/>
</DataTemplate>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Name -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
Orientation="Horizontal">
<Label Style="{StaticResource labelStyle}">Name:</Label>
<Label Content="{Binding XPath=@Name}" Style="{StaticResource
labelStyle}"/>
</StackPanel>
<!-- Department -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1"
Orientation="Horizontal">
<Label Style="{StaticResource labelStyle}">Department:</Label>
<Label Content="{Binding XPath=@Department}"
Style="{StaticResource labelStyle}"/>
</StackPanel>
<Grid Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="10" />
<ColumnDefinition />
</Grid.ColumnDefinitions>

MCT: Luis Dueas

Pag 37 de 445

Manual de Windows Presentation Foundation

3.

<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Expense type list -->
<Border Grid.Column="0" Grid.Row="0" Style="{StaticResource
listHeaderStyle}">
<Label Style="{StaticResource listHeaderTextStyle}">Expense
Type</Label>
</Border>
<ListBox Grid.Column="0" Grid.Row="1" ItemsSource="{Binding
XPath=Expense}"
ItemTemplate="{StaticResource typeItemTemplate}" />
<!-- Amount list -->
<Border Grid.Column="2" Grid.Row="0" Style="{StaticResource
listHeaderStyle}">
<Label Style="{StaticResource listHeaderTextStyle}">Amount
</Label>
</Border>
<ListBox Grid.Column="2" Grid.Row="1" ItemsSource="{Binding
XPath=Expense}"
ItemTemplate="{StaticResource amountItemTemplate}" />
</Grid>
</Grid>
</Grid>
</Page>
Compile y ejecute la aplicacin.

Observe que las plantillas de datos estn definidas como recursos Grid.
En las dos ilustraciones siguientes se muestran las dos pginas de la aplicacin ExpenseIt con los controles, el
diseo, los estilos, el enlace de datos y las plantillas de datos aplicadas:

1.3. Lo Nuevo en Windows Presentation Foundation Versin 3.5


En este tema se explican brevemente las principales diferencias entre las versiones 3.0 y 3.5 de Windows
Presentation Foundation (WPF).
Compatibilidad con la versin 3.0
Compatibilidad con versiones anteriores y posteriores
Una aplicacin generada con WPF 3.0 se ejecutar en el motor de tiempo de ejecucin de WPF 3.5.
Una aplicacin generada con WPF 3.5 se ejecutar en el motor de tiempo de ejecucin de la versin 3.0 si la
aplicacin utiliza nicamente las caractersticas disponibles en WPF 3.0.
WPF 3.5 define un nuevo espacio de nombres XML, http://schemas.microsoft.com/netfx/2007/xaml/presentation. Al
generar una aplicacin mediante WPF 3.5, puede utilizar este espacio de nombres o el espacio de nombres
definido en WPF 3.0.

MCT: Luis Dueas

Pag 38 de 445

Manual de Windows Presentation Foundation


Usar como destino un motor de tiempo de ejecucin concreto
Las aplicaciones generadas con WPF 3.0 pueden destinarse a cualquier versin del marco de trabajo igual o
posterior a la versin en la que se generaron originalmente.
Aplicaciones
Se han realizado las mejoras siguientes en el modelo de aplicacin:

Compatibilidad completa con complementos para admitir los complementos visuales y no visuales de
aplicaciones independientes y Aplicaciones del explorador XAML (XBAPs).

Las XBAPs se pueden ejecutar ahora en Firefox.


Las cookies se pueden compartir entre las XBAPs y aplicaciones web del mismo sitio de origen.
Mejora de la experiencia de XAML IntelliSense para una mayor productividad.
Compatibilidad de localizacin expandida.

Complementos visuales y no visuales en WPF


Una aplicacin extensible expone la funcionalidad de modo que permite a otras aplicaciones integrarse con su
funcionalidad y extenderla. Los complementos son una manera comn para que las aplicaciones expongan su
extensibilidad. En .NET Framework, un complemento suele ser un ensamblado empaquetado como una
biblioteca de vnculos dinmicos (.dll). La aplicacin host carga dinmicamente el complemento en tiempo de
ejecucin para usar y extender los servicios que expone el host. El host y el complemento interactan entre s
mediante un contrato conocido, que normalmente es una interfaz comn publicada por la aplicacin host.
Cuando una aplicacin admite complementos, los desarrolladores propios y los de otros fabricantes pueden
crear complementos para ella. Hay muchos ejemplos de estos tipos de aplicacin, entre ellos Office, Visual
Studio y Microsoft Windows Media Player. Por ejemplo, la compatibilidad con complementos de Microsoft
Windows Media Player permite que otros fabricantes creen descodificadores de DVD y codificadores de MP3.
.NET Framework implementa los bloques de construccin que permiten que las aplicaciones admitan
complementos. Sin embargo, el tiempo y la complejidad necesarios para generar esa compatibilidad pueden ser
costosos, teniendo en cuenta que un diseo de complemento robusto debe ocuparse de lo siguiente:

Deteccin: bsqueda de complementos que se adhieran a los contratos admitidos por las aplicaciones
host.

Activacin: carga, ejecucin y establecimiento de la comunicacin con los complementos.


Aislamiento: uso de dominios de aplicacin o procesos para establecer lmites de aislamiento que
protejan las aplicaciones frente a posibles problemas de seguridad y ejecucin con los complementos.

Comunicacin: los complementos y las aplicaciones host deben poder comunicarse entre s ms all de
los lmites de aislamiento llamando a mtodos y pasando datos.

Administracin de la duracin: carga y descarga de los dominios de aplicacin y procesos de una


manera limpia y predecible.

Control de versiones: garanta de que las aplicaciones host y los complementos puedan continuar
comunicndose cuando se creen nuevas versiones de cualquiera de ellos.

En lugar de exigirle que resuelva estos problemas, .NET Framework incluye ahora un conjunto de tipos,
ubicados en el espacio de nombres System.AddIn, que se conocen como el "modelo de complementos". El
modelo de complementos de .NET Framework proporciona funcionalidad para cada uno de los comportamientos
de complemento comunes que se han mencionado anteriormente.
En algunos escenarios, sin embargo, tambin puede ser conveniente permitir que los complementos se integren
con las UIs de la aplicacin host y las extiendan. WPF extiende el modelo de complementos de .NET Framework
para permitir esta compatibilidad, que se genera en torno a un objeto FrameworkElement propiedad de un
complemento en las UIs de una aplicacin host. Esto permite a los desarrolladores de WPF crear aplicaciones
compatibles con los siguientes escenarios comunes:

Aplicaciones de estilo Messenger que proporcionen servicios adicionales con complementos afines de
otros fabricantes.

MCT: Luis Dueas

Pag 39 de 445

Manual de Windows Presentation Foundation

Aplicaciones de juegos diseadas para hospedar juegos de otros fabricantes.


Aplicaciones lectoras de contenido que hospeden anuncios.
Aplicaciones mashup que hospeden mdulos arbitrarios; por ejemplo, Windows Sidebar.

Por ltimo, los complementos de WPF pueden ser hospedados tanto por aplicaciones independientes como por
XBAPs.
Compatibilidad con Firefox para aplicaciones XBAP
Un complemento para WPF 3.5 permite ejecutar XBAPs desde Firefox 2.0. Esta caracterstica no est disponible
en WPF 3.0. Entre las caractersticas principales se incluyen las siguientes:

Si Firefox 2.0 es su explorador predeterminado, las XBAPsrespetan la configuracin. Es decir, no se


utiliza Internet Explorer para las XBAPs si Firefox 2.0 es la opcin predeterminada.

Las caractersticas de seguridad disponibles para las XBAPs que se ejecutan en Internet Explorer
tambin estn disponibles para las XBAPs que se ejecutan en Firefox 2.0, incluido el recinto de
seguridad de confianza parcial. Las caractersticas de seguridad adicionales proporcionadas por el
explorador son especficas del explorador.

Cookies
Las aplicaciones WPF independientes y las XBAPs pueden crear, obtener y eliminar cookies tanto de sesin
como persistentes. En WPF 3.5, las cookies persistentes se pueden compartir entre las XBAPs, los servidores
web y los archivos HTML que tienen el mismo sitio de origen.
Mejoras de Visual Studio IntelliSense
Ahora es posible agregar un nuevo elemento XAML mediante el editor XAML de Visual Studio, asignarle un
nombre (mediante el atributo Name), hacer referencia a l desde cdigo subyacente y ver sus miembros desde
el explorador de IntelliSense.
Localizacin
WPF 3.5 agrega compatibilidad para los siguientes sistemas de escritura:

Bengal
Devanagari
Gujarati
Gurmukhi
Kannada
Malayalam
Oriya
Tamil
Telugu

Compatibilidad con el Editor de mtodos de entrada (IME) para el control TextBox


La clase FrameworkTextComposition tiene ahora las siguientes propiedades:

CompositionOffset
CompositionLength
ResultOffset
ResultLength

Se utiliza un objeto FrameworkTextComposition como propiedad TextCompositionEventArgs..TextComposition


cuando el usuario escribe texto en un control TextBox mediante un IME y se produce el evento TextInput,
TextInputUpdate o TextInputStart.
Grficos

MCT: Luis Dueas

Pag 40 de 445

Manual de Windows Presentation Foundation


Ahora se pueden almacenar en memoria cach las imgenes que se descargan a travs de http en la memoria
cach local de archivos temporales de Microsoft Internet Explorer, de modo que las subsiguientes solicitudes de
la imagen procedan del disco local en lugar de Internet. En funcin del tamao de las imgenes, sta puede ser
una importante mejora de rendimiento de la red. Se han agregado los siguientes miembros para permitir esta
caracterstica:

BitmapImage.UriCachePolicy
BitmapDecoder.Create(Uri, BitmapCreateOptions, BitmapCacheOption, RequestCachePolicy)
BitmapFrame.Create(Uri, RequestCachePolicy)
BitmapFrame.Create(Uri, BitmapCreateOptions, BitmapCacheOption, RequestCachePolicy)

Se ha agregado el evento BitmapSource..::.DecodeFailed para notificar al usuario cuando no se carga una


imagen debido a un encabezado daado.
Grficos 3D
Se han agregado las siguientes caractersticas nuevas al modelo de objetos 3D.
Compatibilidad con la entrada, el foco y los eventos en 3D
El modelo de objetos 3D admite ahora conceptos de UIElement como la entrada, el foco y los eventos. Las
nuevas clases que proporcionan estos servicios son UIElement3D y sus clases derivadas ContainerUIElement3D
y ModelUIElement3D.
Contenido 2D interactivo en 3D
La nueva clase Viewport2DVisual3D proporciona la compatibilidad necesaria para colocar contenido 2D
interactivo en un objeto 3D.
Nuevos servicios de transformacin
Las nuevas clases GeneralTransform3D, GeneralTransform2DTo3D y GeneralTransform3DTo2D permiten las
transformaciones entre objetos Visual3D, as como de objetos 2D a objetos 3D y viceversa.
Enlace de datos
Se han realizado las mejoras siguientes en el enlace de datos:

Un nuevo mecanismo de depuracin facilita la depuracin de los enlaces de datos.


El modelo de datos permite la validacin en la capa de negocios proporcionando compatibilidad para la
interfaz IDataErrorInfo. Adems, el modelo de validacin admite ahora el uso de la sintaxis de
propiedad para establecer las reglas de validacin.

El modelo de enlaces de datos admite ahora LINQ y XLINQ.

Nuevo mecanismo de depuracin


Ahora, los enlaces de datos son ms fciles de depurar. Se puede establecer la nueva propiedad adjunta
PresentationTraceSources..::.TraceLevel en un objeto relacionado con el enlace para recibir informacin sobre
el estado de un enlace concreto. PresentationTraceSources es una clase esttica en el espacio de nombres
System.Diagnostics.
Compatibilidad con IDataErrorInfo
El modelo de validacin de datos admite ahora la interfaz IDataErrorInfo para que un objeto de negocios pueda
determinar la validez de la entrada. La interfaz define un indizador que toma un nombre de propiedad y
devuelve una cadena. Se ha agregado la regla de validacin DataErrorValidationRule, que comprueba las
excepciones devueltas por el indizador.
Sintaxis alternativa para la validacin de datos
Las clases Binding y MultiBinding tienen 2 propiedades nuevas ValidatesOnExceptions y ValidatesOnDataErrors
Estas

dos

propiedades

proporcionan

una

alternativa

establecer

ExceptionValidationRule

DataErrorValidationRule en la sintaxis de elementos.

MCT: Luis Dueas

Pag 41 de 445

Manual de Windows Presentation Foundation


Compatibilidad con LINQ y XLINQ
Se han realizado mejoras en BindingListCollectionView para proporcionar una mejor compatibilidad con el
enlace a una coleccin de tipo BindingList<(Of <(T>)>) y con LINQ. El comportamiento de los enlaces de datos
con un objeto CollectionView sobre una interfaz IEnumerable tambin se ha mejorado para proporcionar un
mayor rendimiento y una mejor compatibilidad con el enlace a los resultados generados por LINQ.
Adems, el modelo de enlaces de datos tambin proporciona compatibilidad con XLINQ.
Controles
RichTextBox
El control RichTextBox conserva ahora los objetos TextElement personalizados cuando guarda los objetos
TextElement y cuando los objetos TextElement participan en operaciones del portapapeles. Las siguientes
nuevas API permiten este comportamiento:

La clase TextRange tiene una nueva sobrecarga Save(Stream, String, Boolean) que acepta un valor
booleano que especifica si se deben conservar los objetos TextElement personalizados.

La clase TextElementEditingBehaviorAttribute permite especificar el comportamiento del objeto


TextElement personalizado. Cuando se establecen las propiedades IsMergeable y IsTypographicOnly en
false, un control RichTextBox conserva los lmites y el contenido del objeto TextElement personalizado
cuando el usuario modifica el contenido del control RichTextBox.

El control RichTextBox tiene una nueva propiedad denominada IsDocumentEnabled. Cuando el valor de
IsDocumentEnabled es true, los elementos de la interfaz de usuario, como botones e hipervnculos, aceptan los
datos proporcionados por el usuario.
TextBoxBase
TextBoxBase tiene una nueva propiedad denominada UndoLimit, que especifica el nmero mximo de acciones
a las que el control hace referencia.
SoundPlayerAction
SoundPlayerAction puede ahora cargar archivos de audio que pueden ser identificados mediante pack
identificadores de recursos uniformes (URIs) relativos y absolutos:

Archivos de recursos: archivos de audio con la accin de compilacin Resource.


Archivos de contenido: archivos de audio con la accin de compilacin Content.
Archivos de sitio de origen: archivos de audio con la accin de compilacin None.

Descriptores de acceso set protegidos


Los descriptores de acceso set de las siguientes propiedades estn ahora protegidos, en lugar de ser internos:

Thumb.IsDragging
ButtonBase.IsPressed
MenuItem.IsPressed
MenuItem.IsHighlighted
ComboBoxItem.IsHighlighted

Documentos
FlowDocumentPageViewer, FlowDocumentScrollViewer y FlowDocumentReader tienen una nueva propiedad
pblica denominada Selection. La propiedad obtiene el objeto TextSelection que representa el contenido
seleccionado en el documento.
Anotaciones
El marco de trabajo de anotaciones expone ahora las capacidades necesarias para hacer coincidir las
anotaciones con los correspondientes objetos anotados. Se ha agregado una nueva interfaz denominada
IAnchorInfo. Adems, se ha agregado un nuevo mtodo denominado GetAnchorInfo, que devuelve un objeto
IAnchorInfo, a la clase AnnotationHelper.

MCT: Luis Dueas

Pag 42 de 445

Manual de Windows Presentation Foundation


Estas nuevas adiciones permiten la existencia de escenarios en los que se necesite obtener acceso al objeto
respecto al que est delimitado el objeto de anotacin.

2. Desarrollo de Aplicaciones
El modelo de aplicacin est en el ncleo de todas las aplicaciones de Windows Presentation Foundation (WPF).
Esta pgina contiene vnculos a informacin general del modelo de aplicacin de WPF.

2.1. Informacin General sobre el Desarrollo de Aplicaciones


Windows Presentation Foundation (WPF) admite la creacin de los tipos de aplicaciones siguientes:

Aplicaciones independientes (aplicaciones en el estilo tradicional de Windows generadas como


ensamblados ejecutables que se instalan en el equipo cliente y se ejecutan desde l).

Aplicaciones del explorador XAML (XBAPs) (aplicaciones compuestas de pginas navegables que se
generan como ensamblados ejecutables que se exploran y hospedan por Windows Internet Explorer).

Bibliotecas

de

control

personalizadas

(ensamblados

no

ejecutables

que

contienen

controles

reutilizables).

Bibliotecas de clases (ensamblados no ejecutables que contienen clases reutilizables).

Nota:
No se admite el uso de WPF para generar servicios de Windows. Dado que WPF es una tecnologa de
presentacin, el servicio de Windows requiere los permisos adecuados para realizar operaciones visuales
que requieren la interaccin con el usuario. Si el servicio de Windows no tiene los permisos adecuados,
pueden producirse resultados inesperados.
Para generar este conjunto de aplicaciones, WPF implementa un host de servicios. En este tema se proporciona
informacin general sobre estos servicios y se indica dnde buscar ms informacin.
Administracin de aplicaciones
Las aplicaciones ejecutables de WPF suelen requerir un conjunto bsico de funcionalidades, que incluye:

Crear y administrar la infraestructura de aplicaciones comn (lo que incluye crear un mtodo de punto
de entrada y un bucle de mensajes de Windows para recibir los mensajes del sistema y de entrada).

Realizar el seguimiento de la duracin de una aplicacin e interactuar con l.


Recuperar y procesar parmetros de la lnea de comandos.
Compartir propiedades del mbito de la aplicacin y recursos de la interfaz de usuario.
Detectar y procesar las excepciones no administradas.
Devolver cdigos de salida.
Administrar las ventanas en las aplicaciones independientes.
Realizar el seguimiento de la navegacin en las Aplicaciones del explorador XAML (XBAPs), y en las
aplicaciones independientes con ventanas y marcos de navegacin.

Estas funciones se implementan mediante la clase Application, que se agrega a las aplicaciones utilizando una
definicin de aplicacin. Application tiene las caractersticas siguientes.
Archivos de recursos, contenido y datos de aplicaciones de WPF
WPF aprovecha y extiende la compatibilidad bsica de Microsoft .NET Framework para los recursos incrustados
con compatibilidad para tres tipos de archivos de datos no ejecutables: de recursos, de contenido y de datos.
Un componente clave de la compatibilidad con archivos de datos no ejecutables de WPF es la capacidad de
identificarlos y cargarlos utilizando un URI nico.
Ventanas y cuadros de dilogo
Los usuarios interactan con las aplicaciones independientes de WPF por medio de ventanas. El propsito de
una ventana es hospedar contenido de la aplicacin y exponer la funcionalidad de la aplicacin que suele

MCT: Luis Dueas

Pag 43 de 445

Manual de Windows Presentation Foundation


permitir a los usuarios interactuar con el contenido. En WPF, las ventanas estn encapsuladas en la clase
Window, que permite:

Crear y mostrar las ventanas.


Establecer relaciones entre ventanas propietarias y pertenecientes.
Configurar el aspecto de la ventana (por ejemplo, tamao, ubicacin, iconos, texto de la barra de
ttulo, borde).

Realizar el seguimiento de la duracin de una ventana e interactuar con ella.

Window admite la capacidad de crear un tipo especial de ventana denominado cuadro de dilogo. Se pueden
crear los tipos modales y no modales de cuadros de dilogo.
Para mayor comodidad y para ofrecer las ventajas de reusabilidad, as como una experiencia del usuario
uniforme en todas las aplicaciones, WPF expone tres de los cuadros de dilogo comunes de Windows, que son:
OpenFileDialog, SaveFileDialog y PrintDialog.
Un cuadro de mensaje es un tipo especial de cuadro de dilogo utilizado para mostrar informacin de texto
importante a los usuarios y plantear preguntas sencillas de S/No/Aceptar/Cancelar. Para crear y mostrar
cuadros de mensaje se utiliza la clase MessageBox.
Navegacin
WPF admite la navegacin de tipo web con pginas (Page) e hipervnculos (Hyperlink). La navegacin se puede
implementar de diversas maneras; entre otras:

Pginas independientes hospedadas en Internet Explorer.


Pginas compiladas en una XBAP hospedada en Internet Explorer.
Pginas compiladas en una aplicacin independiente y hospedadas por una ventana de navegacin
(NavigationWindow).

Pginas hospedadas por un marco (Frame), hospedadas en una pgina que puede ser independiente o
bien compilada en una XBAP o en una aplicacin independiente.

Para facilitar la navegacin, WPF implementa lo siguiente:

NavigationService, el motor de navegacin compartido para procesar las solicitudes de navegacin


utilizado Frame, NavigationWindow y XBAPs para admitir la navegacin dentro de la aplicacin.

Mtodos de navegacin para iniciar la navegacin.


Eventos de navegacin para realizar el seguimiento de la duracin de la navegacin e interactuar con
ella.

Uso del "diario" (que se puede inspeccionar y manipular) para memorizar la navegacin hacia delante
y hacia atrs.

WPF tambin admite un tipo especial de navegacin denominado navegacin estructurada. La navegacin
estructurada se puede utilizar para llamar a una o ms pginas que devuelven datos de una manera
estructurada y previsible coherente con las funciones que realizaron las llamadas. Esta capacidad depende de la
clase PageFunction<(Of <(T>)>). PageFunction<(Of <(T>)>) tambin permite simplificar la creacin de
topologas de navegacin complejas.
Hospedaje
Las XBAPs se pueden hospedar en Microsoft Internet Explorer 6, Windows Internet Explorer 7 o Microsoft
Windows Media Center (WMC). Cada modelo de hospedaje tiene su propio conjunto de consideraciones y
restricciones.
Compilacin e implementacin
Aunque las aplicaciones de WPF simples se pueden generar desde un smbolo del sistema mediante
compiladores de lnea de comandos, WPF se integra con Microsoft build engine (MSBuild) y lo extiende a fin de
proporcionar compatibilidad adicional para simplificar el proceso de programacin y compilacin.

MCT: Luis Dueas

Pag 44 de 445

Manual de Windows Presentation Foundation


Segn el tipo de aplicacin que se genere, puede elegir entre una o ms opciones de implementacin.

2.2. Administracin de Aplicaciones


Todas las aplicaciones que utilizan Windows Presentation Foundation (WPF) estn asociadas a un objeto
Application. Este objeto representa la aplicacin en el sistema operativo y permite que el sistema se comunique
con ella. El objeto Application admite propiedades, mtodos y eventos que permiten convertir una coleccin de
pginas XAML (Lenguaje de marcado de aplicaciones extensible) en una aplicacin coherente.

2.2.1. Informacin General sobre la Administracin de Aplicaciones


Este tema proporciona informacin general sobre los servicios de Windows Presentation Foundation (WPF) para
crear y administrar aplicaciones. El kernel de una aplicacin WPF es la clase Application, que admite diversos
servicios bsicos de la aplicacin. En este tema se proporciona una introduccin a los servicios ms
importantes.
Clase Application
Una aplicacin se compone de muchos elementos especficos de la aplicacin, entre ellos la interfaz de usuario
(UI), la lgica de negocios, la lgica de acceso a datos, los controles y los datos. Estos elementos difieren
habitualmente de una aplicacin a otra. Sin embargo, todas las aplicaciones tienden a compartir un conjunto
comn de funcionalidades que facilita la implementacin y la administracin de la aplicacin. En WPF, esta
funcionalidad comn para el mbito de la aplicacin se encapsula en la clase Application, que proporciona los
siguientes servicios:

Crear y administrar la infraestructura comn de las aplicaciones.


Realizar el seguimiento e interactuar con la duracin de la aplicacin.
Recuperar y procesar los parmetros de la lnea de comandos.
Compartir propiedades y recursos del mbito de la aplicacin.
Detectar y responder a las excepciones no controladas.
Devolver cdigos de salida.
Administrar las ventanas en las aplicaciones independientes.
Realizar el seguimiento y administrar la navegacin.

Para utilizar estos servicios en la aplicacin, necesita utilizar la clase Application para implementar una
definicin de aplicacin.
Definicin de aplicacin
Una definicin de aplicacin WPF es una clase que deriva de Application y se configura con un valor de Microsoft
build engine (MSBuild) especial.
Implementar una definicin de aplicacin
Una definicin de aplicacin WPF tpica se implementa utilizando tanto marcado como cdigo subyacente. Esto
permite utilizar marcado para establecer mediante declaracin propiedades, recursos y eventos de registro de
la aplicacin, mientras que el control de eventos y la implementacin del comportamiento especfico de la
aplicacin se realizan en el cdigo subyacente.
En el ejemplo siguiente se muestra cmo implementar una definicin de aplicacin utilizando tanto marcado
como cdigo subyacente:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App" />
using System.Windows; // Application
namespace SDKSample
{
public partial class App : Application { }
}

MCT: Luis Dueas

Pag 45 de 445

Manual de Windows Presentation Foundation


Para que un archivo de marcado y un archivo de cdigo subyacente funcionen conjuntamente, debe ocurrir lo
siguiente:

En el marcado, el elemento Application debe incluir el atributo x:Class. Al generarse la aplicacin, la


existencia de x:Class en el archivo de marcado permite que MSBuild cree una clase partial que se
derive de Page y tenga el nombre especificado por el atributo x:Class. Para ello, es necesario agregar
una

declaracin

de

espacio

de

nombres

XML

para

el

esquema

XAML

(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml").

En el archivo de cdigo subyacente, la clase debe ser una clase partial con el mismo nombre que el
especificado por el atributo x:Class en el marcado, y debe derivarse de Application. Esto permite que
el archivo de cdigo subyacente se asocie a la clase partial que se genera para el archivo de marcado
cuando se genera la aplicacin.

Nota:
Al crearse un nuevo proyecto de Aplicacin WPF o Aplicacin de explorador WPF mediante Microsoft Visual
Studio, se incluye de forma predeterminada una definicin de aplicacin, que se define utilizando tanto
marcado como cdigo subyacente.
Este cdigo es el mnimo necesario para implementar una definicin de aplicacin. Sin embargo, es necesario
realizar una configuracin adicional de MSBuild en la definicin de aplicacin antes de generar y ejecutar la
aplicacin.
Configurar la definicin de aplicacin para MSBuild
Las aplicaciones independientes y Aplicaciones del explorador XAML (XBAPs) requieren la implementacin de un
cierto nivel de infraestructura para poderse ejecutar. La parte ms importante de esta infraestructura es el
punto de entrada. Cuando un usuario inicia una aplicacin, el sistema operativo llama al punto de entrada, que
es una funcin conocida para iniciar las aplicaciones.
Tradicionalmente, los desarrolladores necesitaban escribir todo o parte de este cdigo, segn la tecnologa. Sin
embargo, WPF se encarga de generar este cdigo cuando el archivo de marcado de la definicin de aplicacin
est configurado como un elemento MSBuildApplicationDefinition, tal como se muestra en el siguiente archivo
de proyecto de MSBuild:
<Project
DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ApplicationDefinition Include="App.xaml" />
<Compile Include="App.xaml.cs" />
...
</Project>
Dado que el archivo de cdigo subyacente contiene cdigo, se marca como un elemento MSBuildCompile, lo
cual es normal.
La aplicacin de estas configuraciones de MSBuild a los archivos de cdigo subyacente y marcado de una
definicin de aplicacin hace que MSBuild genere cdigo como el siguiente:
using System; // STAThread
using System.Windows; // Application
namespace SDKSample
{
public class App : Application
{
public App() { }
[STAThread]
public static void Main()
{
// Create new instance of application subclass
App app = new App();
// Code to register events and set properties that were
// defined in XAML in the application definition
app.InitializeComponent();
// Start running the application
app.Run();
}
public void InitializeComponent()
{
...
}

MCT: Luis Dueas

Pag 46 de 445

Manual de Windows Presentation Foundation


}
}
El cdigo resultante ampla la definicin de aplicacin con cdigo de infraestructura adicional, que incluye el
mtodo de punto de entrada Main. Se aplica el atributo STAThreadAttribute al mtodo Main para indicar que el
principal subproceso de la interfaz de usuario para la aplicacin WPF es un subproceso STA, requerido para las
aplicaciones

WPF. Cuando

se

invoca,

Main crea

una

nueva

instancia

de

App

antes

de

llamar

al

mtodo InitializeComponent para registrar los eventos y establecer las propiedades que se implementan en el
marcado. Dado que se genera InitializeComponent, no es necesario llamar explcitamente a InitializeComponent
desde una definicin de aplicacin tal y como se hace para las implementaciones de Page y Window.
Finalmente, se llama al mtodo Run para iniciar la aplicacin.
Obtener la aplicacin actual
Dado que los servicios de la clase Application se comparten en una aplicacin, puede haber solamente una
instancia de la clase Application por AppDomain. Para exigir esto, la clase Application se implementa como una
clase singleton, que crea una nica instancia de s misma y proporciona acceso compartido a ella con la
propiedad static Current.
En el cdigo siguiente se muestra cmo adquirir una referencia al objeto Application para el objeto AppDomain
actual.
// Get current application
Application current = App.Current;
Current devuelve una referencia a una instancia de la clase Application. Si desea obtener una referencia a la
clase derivada de Application, debe convertir el valor de la propiedad Current, como se muestra en el ejemplo
siguiente.
// Get strongly-typed current application
App app = (App)App.Current;
Puede inspeccionar el valor de Current en cualquier punto de la duracin de un objeto Application. Sin
embargo, se recomienda tener cuidado. Tras crearse una instancia de la clase Application, el estado del objeto
Application es incoherente durante un perodo de tiempo. Durante este perodo, Application realiza las diversas
tareas de inicializacin necesarias para que se ejecute el cdigo, incluido el establecimiento de la
infraestructura de la aplicacin, la configuracin de las propiedades y el registro de los eventos. Si intenta
utilizar el objeto Application durante este perodo, el cdigo puede generar resultados inesperados, en particular
si depende de las diversas propiedades de Application que se estn estableciendo.
Cuando Application completa sus tareas de inicializacin, se inicia realmente su duracin.
Duracin de la aplicacin
La duracin de una aplicacin WPF est marcada por varios eventos que Application provoca para indicar
cundo se inicia la aplicacin, cundo se activa y se desactiva, y cundo se cierra.
Iniciar una aplicacin
Despus de llamarse a Run e inicializarse la aplicacin, esta est lista para ejecutarse. El evento Startup indica
este momento:
using System.Windows; // Application, StartupEventArgs, WindowState
namespace SDKSample
{
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
// Application is running
...
}
}
}
En este punto de la duracin de una aplicacin, se suele mostrar una interfaz de usuario.
Mostrar una interfaz de usuario

MCT: Luis Dueas

Pag 47 de 445

Manual de Windows Presentation Foundation


La mayora de las aplicaciones independientes para Windows abren un objeto Window cuando comienzan a
ejecutarse. El controlador de eventos Startup es una de las ubicaciones donde se puede hacer esto, tal como se
muestra en el cdigo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
Startup="App_Startup" />
using System.Windows; // Application, StartupEventArgs
namespace SDKSample
{
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
// Open a window
MainWindow window = new MainWindow();
window.Show();
}
}
}
Nota:
El primer objeto Window del que se va a crear una instancia en una aplicacin independiente se convierte
de forma predeterminada en la ventana principal de la aplicacin. A este objeto Window se hace referencia
mediante la propiedad Application..::.MainWindow. El valor de la propiedad MainWindow se puede cambiar
mediante programacin si una ventana diferente del primer objeto Window del que se cre una instancia
debe ser la ventana principal.
Cuando se inicia por primera vez una aplicacin XBAP, lo ms probable es que navegue a un objeto Page. Esto
se muestra en el cdigo siguiente.
<Application
x:Class="SDKSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_Startup" />
using System; // Uri, UriKind, EventArgs, Console
using System.Windows; // Application, StartupEventArgs
using System.Windows.Navigation; // NavigationWindow
namespace SDKSample
{
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
((NavigationWindow)this.MainWindow).Navigate(new
Uri("HomePage.xaml", UriKind.Relative));
}
}
}
Si controla Startup para que abra solamente un objeto Window o navegue a un objeto Page, podr establecer el
atributo StartupUri en el marcado.
En el ejemplo siguiente se muestra cmo utilizar StartupUri desde una aplicacin independiente para abrir un
objeto Window.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="MainWindow.xaml" />
En el ejemplo siguiente se muestra cmo utilizar la propiedad StartupUri de una aplicacin XBAP para navegar a
un objeto Page.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="HomePage.xaml" />
Este marcado tiene el mismo efecto que el cdigo anterior para abrir una ventana.
Debe controlar el evento Startup para que se abra un objeto Window si necesita crear instancias del mismo
mediante un constructor no predeterminado, o bien, si necesita establecer sus propiedades o suscribirse a sus
eventos antes de que se muestre, o bien, si necesita procesar los argumentos de lnea de comandos
proporcionados al iniciarse la aplicacin.

MCT: Luis Dueas

Pag 48 de 445

Manual de Windows Presentation Foundation


Procesar argumentos de la lnea de comandos
En Windows, las aplicaciones independientes pueden iniciarse desde el smbolo del sistema o desde el
escritorio. En ambos casos, es posible pasar argumentos de la lnea de comandos a la aplicacin. En el ejemplo
siguiente, se muestra una aplicacin que se inicia con un solo argumento de la lnea de comandos,
"/StartMinimized":
wpfapplication.exe /StartMinimized
Durante la inicializacin de la aplicacin, WPF recupera los argumentos de la lnea de comandos del sistema
operativo y los pasa al controlador de eventos Startup a travs de la propiedad Args del parmetro
StartupEventArgs. Puede recuperar y almacenar los argumentos de la lnea de comandos utilizando cdigo
como el siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
Startup="App_Startup" />
using System.Windows; // Application, StartupEventArgs, WindowState
namespace SDKSample
{
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
// Application is running
// Process command line args
bool startMinimized = false;
for (int i = 0; i != e.Args.Length; ++i)
{
if (e.Args[i] == "/StartMinimized")
{
startMinimized = true;
}
}
// Create main application window, starting minimized if specified
MainWindow mainWindow = new MainWindow();
if (startMinimized)
{
mainWindow.WindowState = WindowState.Minimized;
}
mainWindow.Show();
}
}
}
El cdigo controla el evento Startup para comprobar si se proporcion el argumento de la lnea de comandos
/StartMinimized; en caso afirmativo, abre la ventana principal con el valor de WindowState Minimized.
Observe que, dado que la propiedad WindowState debe establecerse mediante programacin, el objeto Window
principal se debe abrir explcitamente en el cdigo.
Las XBAPs no pueden recuperar ni procesar los argumentos de la lnea de comandos porque se inician usando
la implementacin de ClickOnce. Sin embargo, pueden recuperar y procesar los parmetros de cadenas de
consulta de las direcciones URL usadas para iniciarlas.
Activacin y desactivacin de aplicaciones
Windows permite a los usuarios cambiar de una aplicacin a otra. El mtodo ms comn es la combinacin de
teclas ALT+TAB. Solamente se puede cambiar a una aplicacin si tiene un objeto Window visible que el usuario
pueda seleccionar. El objeto Window actualmente seleccionado es la ventana activa (tambin conocida como
ventana de primer plano) y es el objeto Window que recibe los datos proporcionados por el usuario. La
aplicacin con la ventana activa es la aplicacin activa (o aplicacin de primer plano). Una aplicacin se
convierte en la aplicacin activa en las siguientes circunstancias:

Se inicia y muestra un objeto Window.


Un usuario cambia desde otra aplicacin seleccionando un objeto Window de la aplicacin.

Para detectar cundo una aplicacin se convierte en la aplicacin activa, controle el evento Activated.
De manera similar, una aplicacin puede volverse inactiva en las circunstancias siguientes:

MCT: Luis Dueas

Pag 49 de 445

Manual de Windows Presentation Foundation

Un usuario cambia a otra aplicacin desde la actual.


Cuando se cierra la aplicacin.

Para detectar cundo una aplicacin se vuelve inactiva, controle el evento Application.Deactivated.
En el cdigo siguiente se muestra cmo controlar los eventos Activated y Deactivated para determinar si una
aplicacin est activa.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
StartupUri="MainWindow.xaml"
Activated="App_Activated"
Deactivated="App_Deactivated" />
using System; // EventArgs
using System.Windows; // Application
namespace SDKSample
{
public partial class App : Application
{
bool isApplicationActive;
void App_Activated(object sender, EventArgs e)
{
// Application activated
this.isApplicationActive = true;
}
void App_Deactivated(object sender, EventArgs e)
{
// Application deactivated
this.isApplicationActive = false;
}
}
}
Un objeto Window tambin se puede activar y desactivar.
Nota:
En el caso de las XBAPs, no se provoca el evento Application.Activated ni el evento Application.Deactivated.
Cierre de la aplicacin
La duracin de una aplicacin finaliza cuando se cierra, lo cual puede ocurrir por las razones siguientes:

El usuario cierra todos los objetos Window.


El usuario cierra el objeto Window principal.
El usuario finaliza la sesin de Windows cerrando sesin o apagando.
Se ha cumplido una condicin especfica de la aplicacin.

Para facilitar la administracin del cierre de la aplicacin, Application proporciona el mtodo Shutdown, la
propiedad ShutdownMode y los eventos SessionEnding y Exit.
Nota:
Solamente se puede llamar a Shutdown desde aplicaciones que tengan UIPermission. Las aplicaciones WPF
independientes siempre tienen este permiso. Sin embargo, las XBAPs que se ejecutan en el recinto de
seguridad de confianza parcial de la zona de Internet no lo tienen.
Modo de apagado
La mayora de las aplicaciones se apagan cuando se cierran todas las ventanas o cuando se cierra la ventana
principal. En ocasiones, sin embargo, puede haber otras condiciones especficas de la aplicacin que determinen
cundo se cierra la aplicacin. Puede especificar las condiciones en las que se cerrar la aplicacin
estableciendo la propiedad ShutdownMode en uno de los valores siguientes de la enumeracin ShutdownMode:

OnLastWindowClose
OnMainWindowClose
OnExplicitShutdown

El valor predeterminado de ShutdownMode es OnLastWindowClose, lo que significa que una aplicacin se cierra
automticamente cuando el usuario cierra la ltima ventana de la aplicacin. Sin embargo, si la aplicacin debe

MCT: Luis Dueas

Pag 50 de 445

Manual de Windows Presentation Foundation


cerrarse cuando se cierre la ventana principal, WPF lo har automticamente si establece ShutdownMode en
OnMainWindowClose. Esto se muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
ShutdownMode="OnMainWindowClose" />
En el caso de condiciones de cierre especficas de la aplicacin, establezca

ShutdownMode

en

OnExplicitShutdown. En este caso, es su responsabilidad cerrar la aplicacin llamando al mtodo Shutdown; de


lo contrario, la aplicacin seguir ejecutndose aunque se cierren todas las ventanas. Observe que se llama
implcitamente a Shutdown cuando el valor de ShutdownMode es OnLastWindowClose u OnMainWindowClose.
Nota:
ShutdownMode se puede establecer desde una aplicacin XBAP, pero se omite; una aplicacin XBAP
siempre se cierra cuando se navega fuera de ella en un explorador o cuando se cierra el explorador que
hospeda la aplicacin XBAP.
Fin de la sesin
Las condiciones de apagado que describe la propiedad ShutdownMode son especficas de la aplicacin. En
algunos casos, sin embargo, es posible que una aplicacin se cierre como resultado de una condicin externa.
La condicin externa ms comn se produce cuando el usuario finaliza la sesin de Windows mediante las
acciones siguientes:

Cerrar sesin
Apagar
Reiniciar
Hibernar

Para detectar cundo finaliza una sesin de Windows, puede controlar el evento SessionEnding, tal como se
muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
StartupUri="MainWindow.xaml"
SessionEnding="App_SessionEnding" />
using System.Windows; // Application, SessionEndingCancelEventArgs, MessageBox,
MessageBoxResult, MessageBoxButton
namespace SDKSample
{
public partial class App : Application
{
void App_SessionEnding(object sender, SessionEndingCancelEventArgs e)
{
// Ask the user if they want to allow the session to end
string msg = string.Format("{0}. End session?",
e.ReasonSessionEnding);
MessageBoxResult result = MessageBox.Show(msg, "Session
Ending", MessageBoxButton.YesNo);
// End session, if specified
if (result == MessageBoxResult.No)
{
e.Cancel = true;
}
}
}
}
En este ejemplo, el cdigo inspecciona la propiedad ReasonSessionEnding para determinar cmo finaliza la
sesin de Windows. Utiliza este valor para mostrar un mensaje de confirmacin al usuario. Si el usuario no
desea que la sesin finalice, el cdigo establece Cancel en true para evitar que finalice la sesin de Windows.
Nota:
No se provoca el evento SessionEnding para las XBAPs.
Salir
Cuando una aplicacin se apaga, es posible que necesite realizar algunos ltimos procesos, como conservar el
estado de la aplicacin. Para estas situaciones, puede controlar el evento Exit.
<Application

MCT: Luis Dueas

Pag 51 de 445

Manual de Windows Presentation Foundation


xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App" StartupUri="MainWindow.xaml"
Startup="App_Startup" Exit="App_Exit">
...
</Application>
using System.Windows; // Application, StartupEventArgs
using System.IO; // StreamReader, FileMode
using System.IO.IsolatedStorage; // IsolatedStorageFile, IsolatedStorageFileStream
namespace SDKSample
{
public partial class App : Application
{
string filename = "App.txt";
El evento Exit puede ser controlado tanto por las aplicaciones independientes como por las XBAPs. En el caso
de las XBAPs, se provoca el evento Exit en las circunstancias siguientes:

Cuando se navega fuera de una aplicacin XBAP.


En Internet Explorer 7, cuando se cierra la ficha en la que se hospeda la aplicacin XBAP.
Cuando se cierra el explorador.

Cdigo de salida
La mayora de las aplicaciones las inicia el sistema operativo en respuesta a una solicitud del usuario. Sin
embargo, una aplicacin puede ser iniciada por otra aplicacin para realizar alguna tarea concreta. Cuando la
aplicacin iniciada se cierra, es posible que la aplicacin que la inici desee conocer la condicin en la que se
cerr la aplicacin iniciada. En estas situaciones, Windows permite que las aplicaciones devuelvan un cdigo de
salida al cerrarse. De forma predeterminada, las aplicaciones WPF devuelven 0 como valor de cdigo de salida.
Nota:
Cuando se depura desde Visual Studio, el cdigo de salida de la aplicacin se muestra en la ventana
Resultados cuando se cierra la aplicacin, en un mensaje similar al siguiente:

The program '[5340] AWPFApp.vshost.exe: Managed' has exited with code 0 (0x0).
Para abrir la ventana Resultados, haga clic en Resultados en el men Ver.
Para cambiar el cdigo de salida, puede llamar a la sobrecarga Shutdown(Int32), que acepta un argumento de
tipo entero como cdigo de salida:
// Shutdown and return a non-default exit code
Application.Current.Shutdown(-1);
Para detectar el valor del cdigo de salida y cambiarlo, controle el evento Exit. Al controlador de eventos Exit se
le

pasa

un

objeto

ExitEventArgs

que

proporciona

acceso

al

cdigo

de

salida

con

la

propiedad

ApplicationExitCode.
Nota:
El cdigo de salida puede establecerse tanto en las aplicaciones independientes como en las XBAPs. Sin
embargo, el valor del cdigo de salida se omite para las XBAPs.
Excepciones no controladas
A veces, puede que una aplicacin se cierre en condiciones irregulares, como cuando se produce una excepcin
imprevista. En este caso, es posible que la aplicacin no tenga el cdigo necesario para detectar y procesar la
excepcin. Este tipo de excepcin es una excepcin no controlada; se muestra una notificacin similar a la que
aparece en la figura siguiente antes de que se cierre la aplicacin.

MCT: Luis Dueas

Pag 52 de 445

Manual de Windows Presentation Foundation


Desde la perspectiva del usuario, es mejor que una aplicacin evite este comportamiento predeterminado
realizando todas o alguna de las siguientes acciones:

Mostrar informacin fcil de usar.


Intentar mantener la aplicacin en funcionamiento.
Registrar en el registro de eventos de Windows informacin detallada sobre la excepcin que sea fcil
de usar para el desarrollador.

La implementacin de esta compatibilidad depende de la capacidad para detectar las excepciones no


controladas; el evento DispatcherUnhandledException se provoca con esta finalidad.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
StartupUri="MainWindow.xaml"
DispatcherUnhandledException="App_DispatcherUnhandledException" />

Al

using System.Windows; // Application


using System.Windows.Threading; // DispatcherUnhandledExceptionEventArgs
namespace SDKSample
{
public partial class App : Application
{
void App_DispatcherUnhandledException(object sender,
DispatcherUnhandledExceptionEventArgs e)
{
// Process unhandled exception
...
// Prevent default unhandled exception processing
e.Handled = true;
}
}
}
controlador
de
eventos
DispatcherUnhandledException
se
le
pasa

un

parmetro

DispatcherUnhandledExceptionEventArgs que contiene informacin contextual referente a la excepcin no


controlada, incluida la propia excepcin. Puede utilizar esta informacin para determinar cmo debe controlar la
excepcin.
Cuando controle DispatcherUnhandledException, establezca la propiedad Handled en true; de lo contrario, WPF
seguir considerando la excepcin como no controlada y volver al comportamiento predeterminado que se ha
descrito

anteriormente.

Si

se

produce

una

excepcin

no

controlada

no

se

controla

el

evento

DispatcherUnhandledException, o bien, se controla el evento y se establece Handled en false, la aplicacin se


cerrar inmediatamente. Adems, no se provocar ningn otro evento de Application. Por consiguiente, deber
controlar DispatcherUnhandledException si la aplicacin tiene cdigo que deba ejecutarse antes de que se cierre
la aplicacin.
Aunque es posible que una aplicacin se cierre como resultado de una excepcin no controlada, las aplicaciones
suelen cerrarse en respuesta a una solicitud del usuario, tal como se explica en la seccin siguiente.
Eventos de duracin de la aplicacin
Las aplicaciones independientes y las XBAPs no tienen exactamente la misma duracin. En la figura siguiente,
se muestran los eventos clave en la duracin de una aplicacin independiente y la secuencia en la que se
provocan.

MCT: Luis Dueas

Pag 53 de 445

Manual de Windows Presentation Foundation

Igualmente, en la figura siguiente se muestran los eventos clave a lo largo de la duracin de una aplicacin
XBAP y la secuencia en la que se provocan.

Otros servicios de aplicacin


Adems de administrar la duracin de una aplicacin, Application proporciona servicios entre los cuales figuran
los siguientes:

Propiedades compartidas en el mbito de la aplicacin.


Recursos compartidos en el mbito de la aplicacin.
Archivos de recursos, de contenido y de sitio de origen de la aplicacin.
Administracin de ventanas.
Administracin de la navegacin.

Propiedades compartidas en el mbito de la aplicacin


La aplicacin proporciona la propiedad Properties para exponer el estado que se puede compartir en toda la
aplicacin. A continuacin se muestra un ejemplo de cmo usar Properties:
// Set an application-scope property with a custom type
CustomType customType = new CustomType();
Application.Current.Properties["CustomType"] = customType;
...
// Get an application-scope property
// NOTE: Need to convert since Application.Properties is a dictionary of System.Object
CustomType customType = (CustomType)Application.Current.Properties["CustomType"];
Recursos compartidos en el mbito de la aplicacin
La aplicacin proporciona la propiedad Resources, que permite a los desarrolladores compartir los recursos de
la interfaz de usuario en una aplicacin. A continuacin se muestra un ejemplo de cmo usar Properties:
// Set an application-scope resource
Application.Current.Resources["ApplicationScopeResource"] = Brushes.White;
...
// Get an application-scope resource
Brush whiteBrush = (Brush)Application.Current.Resources["ApplicationScopeResource"];
Archivos de recursos, de contenido y de sitio de origen de la aplicacin
Las aplicaciones WPF pueden administrar varios tipos de archivos de datos que no son de cdigo, como los
archivos de recursos, los archivos de contenido y los archivos de sitio de origen. Se pueden utilizar los
siguientes mtodos auxiliares para cargar estos tipos de archivos de datos:

GetResourceStream

MCT: Luis Dueas

Pag 54 de 445

Manual de Windows Presentation Foundation

GetContentStream
GetRemoteStream

Administracin de ventanas
Application y Window tienen una relacin estrecha. Como se ha mencionado anteriormente, la duracin de una
aplicacin puede depender de la duracin de sus ventanas, segn lo especificado por la propiedad
ShutdownMode. Application registra qu ventana se designa como ventana principal de la aplicacin
(MainWindow) y mantiene una lista de las ventanas de las que se han creado instancias (Windows).
Administracin de la navegacin
Para las aplicaciones independientes con navegacin (que utilizan NavigationWindow y Frame) o XBAPs,
Application detecta cualquier navegacin dentro de una aplicacin y provoca los siguientes eventos segn
corresponda:

Navigating
Navigated
NavigationProgress
NavigationFailed
NavigationStopped
LoadCompleted
FragmentNavigation

Adems, Application permite a las aplicaciones de cualquier tipo crear, conservar y recuperar cookies, mediante
los mtodos GetCookie y SetCookie.

2.2.2. Archivos c Windows Presentation Foundation


Las aplicaciones para Microsoft Windows suelen depender de archivos que contienen datos no ejecutables,
como Lenguaje de marcado de aplicaciones extensible (XAML), imgenes, vdeo y audio. Windows Presentation
Foundation (WPF) proporciona una compatibilidad especial para configurar, identificar y utilizar estos tipos de
archivos de datos, que se denominan archivos de datos de aplicacin. Esta compatibilidad gira en torno a un
conjunto especfico de tipos de archivos de datos de aplicacin, como:

Archivos de recursos: archivos de datos que se generan en un ejecutable o en un ensamblado de


biblioteca de WPF.

Archivos de contenido: archivos de datos independientes que tienen una asociacin explcita con un
ensamblado ejecutable de WPF.

Archivos de sitio de origen: archivos de datos independientes que no tienen ninguna asociacin con un
ensamblado ejecutable de WPF.

Hay una diferencia importante entre estos tres tipos de archivos: los archivos de recursos y los archivos de
contenido se conocen en tiempo de compilacin; un ensamblado tiene conocimiento explcito de ellos. En el
caso de los archivos de sitio de origen, sin embargo, es posible que el ensamblado no tenga conocimiento de
ellos o tenga un conocimiento implcito a travs de una referencia de pack identificador de recursos uniforme
(URI); en este ltimo caso, no hay ninguna garanta de que exista realmente el archivo de sitio de origen al que
se hace referencia.
Para hacer referencia a los archivos de datos de aplicacin, Windows Presentation Foundation (WPF) utiliza el
esquema de pack identificador de recursos uniforme (URI).
En este tema se describe cmo configurar y utilizar los archivos de datos de aplicacin.
Archivos de recursos
Si un archivo de datos de aplicacin debe estar siempre disponible para una aplicacin, la nica manera de
garantizar la disponibilidad es generarlo en el ensamblado ejecutable principal de una aplicacin o en uno de los

MCT: Luis Dueas

Pag 55 de 445

Manual de Windows Presentation Foundation


ensamblados a los que hace referencia. Este tipo de archivo de datos de aplicacin se conoce como archivo de
recursos.
Los archivos de recursos deben usarse cuando:

No es necesario actualizar el contenido del archivo de recursos una vez generado en un ensamblado.
Se desea simplificar la distribucin de la aplicacin reduciendo el nmero de dependencias de archivo.
El archivo de datos de aplicacin debe ser localizable.

Nota:
Los diccionarios de recursos (archivos XAML con ResourceDictionary como su elemento de nivel superior)
no son archivos de recursos de WPF; aunque los archivos de recursos de WPF pueden ser diccionarios de
recursos, un diccionario de recursos no tiene que ser necesariamente un archivo de recursos.
Adems, los archivos de recursos de WPF no son los mismos que el tipo de recursos incrustados o
vinculados que se pueden configurar usando la compatibilidad bsica de .NET Framework con los recursos
de ensamblado (vea). Si bien los archivos de recursos de WPF aprovechan la compatibilidad bsica con los
recursos incrustados de .NET Framework, el acceso a los archivos de recursos de WPF mediante pack URIs
resulta ms fcil que el uso de espacios de nombres.
Configurar archivos de recursos
En WPF, un archivo de recursos es un archivo que est incluido en un proyecto de Microsoft build engine
(MSBuild) como un elemento Resource.
<Project "xmlns=http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>
Nota:
En Microsoft Visual Studio, se crea un archivo de recursos agregando un archivo a un proyecto y
estableciendo el valor de Build Action en Resource.
Una vez generado el proyecto, MSBuild genera el recurso en el ensamblado.
Usar archivos de recursos
Para cargar un archivo de recursos, puede llamar al mtodo GetResourceStream de la clase Application,
pasando un pack URI que identifique el archivo de recursos deseado. GetResourceStream devuelve un objeto
StreamResourceInfo, que expone el archivo de recursos como un objeto Stream y describe su tipo de
contenido.
Como ejemplo, en el cdigo siguiente se muestra cmo utilizar GetResourceStream para cargar un archivo de
recursos Page y establecerlo como contenido de un control Frame (pageFrame):
// Navigate to xaml page
Uri uri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetResourceStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;
Aunque al llamar a GetResourceStream se obtiene acceso a Stream, debe realizar el trabajo adicional de
convertirlo en el tipo de la propiedad con la que lo establecer. Como alternativa, puede dejar que WPF se
ocupe de abrir y convertir el objeto Stream cargando un archivo de recursos directamente en la propiedad de
un tipo mediante cdigo.
En el ejemplo siguiente, se muestra cmo se carga un control Page directamente en un control Frame
(pageFrame) mediante cdigo.
Uri pageUri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
El ejemplo siguiente es el equivalente en marcado del ejemplo anterior.
<Frame Name="pageFrame" Source="PageResourceFile.xaml" />
Archivos de cdigo de aplicacin como archivos de recursos
Se puede hacer referencia a un conjunto especial de archivos de cdigo de aplicacin de WPF utilizando pack
URIs, incluidos documentos dinmicos, ventanas, pginas y diccionarios de recursos. Por ejemplo, puede

MCT: Luis Dueas

Pag 56 de 445

Manual de Windows Presentation Foundation


establecer la propiedad Application..::.StartupUri con un pack URI que hace referencia a la ventana o pgina
que desee cargar cuando se inicie una aplicacin.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="MainWindow.xaml" />
Puede hacer esto cuando se incluye un archivo XAML en un proyecto de Microsoft build engine (MSBuild) como
un elemento Page.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
Nota:
En Visual Studio, agregue un nuevo objeto Window, NavigationWindow, Page, FlowDocument o
ResourceDictionary a un proyecto; el valor predeterminado de Build Action para el archivo de marcado
ser Page.
Cuando se genera un proyecto con elementos Page, los elementos XAML se convierten al formato binario y se
generan en el ensamblado asociado. Por consiguiente, estos archivos se pueden utilizar de la misma manera
que los archivos de recursos tpicos.
Nota:
Si un archivo XAML se configura como un elemento Resource y no tiene un archivo de cdigo subyacente, el
cdigo XAML sin formato se generar en un ensamblado en lugar de una versin binaria del cdigo XAML
sin formato.
Archivos de contenido
Un archivo de contenido se distribuye como un archivo separado junto a un ensamblado ejecutable. Aunque no
estn generados en un ensamblado, los ensamblados se generan con metadatos que establecen una asociacin
con cada archivo de contenido.
Se recomienda utilizar archivos de contenido cuando la aplicacin requiere un conjunto concreto de archivos de
datos de aplicacin que se desee poder actualizar sin tener que volver a generar el ensamblado que los
consume.
Configurar archivos de contenido
Para agregar un archivo de contenido a un proyecto, un archivo de datos de aplicacin debe incluir un elemento
Content. Adems, dado que un archivo de contenido no se genera directamente en el ensamblado, es necesario
establecer el elemento de metadatos CopyToOutputDirectory de MSBuild para especificar que el archivo de
contenido se copie en una ubicacin relativa al ensamblado generado. Si desea que el recurso se copie en la
carpeta de resultados de la compilacin cada vez que se genere un proyecto, establezca el elemento de
metadatos CopyToOutputDirectory en el valor Always. De lo contrario, para asegurarse de que slo se copie la
versin ms reciente del recurso en la carpeta de resultados de la compilacin, use el valor PreserveNewest.
A continuacin se muestra un archivo configurado como archivo de contenido que slo se copia en la carpeta de
resultados de la compilacin cuando se agrega al proyecto una nueva versin del recurso.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Content Include="ContentFile.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...
</Project>
Nota:
En Visual Studio, puede crear un archivo de contenido agregando un archivo a un proyecto y
estableciendo el valor de Build Action en Content; establezca el valor de Copy to Output Directory en

MCT: Luis Dueas

Pag 57 de 445

Manual de Windows Presentation Foundation

Copy always (es lo mismo que Always) y Copy if newer (es lo mismo que PreserveNewest).
Cuando se genera el proyecto, se compila un atributo AssemblyAssociatedContentFileAttribute en los metadatos
del ensamblado para cada archivo de contenido.
[assembly: AssemblyAssociatedContentFile("ContentFile.xaml")]
El valor de AssemblyAssociatedContentFileAttribute implica la ruta de acceso al archivo de contenido con
respecto a su posicin en el proyecto. Por ejemplo, si un archivo de contenido se encontrara en una subcarpeta
del

proyecto,

la

informacin

adicional

de

ruta

de

acceso

se

incorporara

en

el

valor

de

AssemblyAssociatedContentFileAttribute.
[assembly: AssemblyAssociatedContentFile("Resources/ContentFile.xaml")]
El valor de AssemblyAssociatedContentFileAttribute es tambin el valor de la ruta de acceso al archivo de
contenido en la carpeta de resultados de la compilacin.
Utilizar archivos de contenido
Para cargar un archivo de contenido, puede llamar al mtodo GetContentStream de la clase Application,
pasando un pack URI que identifique el archivo de recursos deseado. GetContentStream devuelve un objeto
StreamResourceInfo, que expone el archivo de contenido como un objeto Stream y describe su tipo de
contenido.
Como ejemplo, en el cdigo siguiente se muestra cmo utilizar GetContentStream para cargar un archivo de
contenido Page y establecerlo como contenido de un control Frame (pageFrame).
// Navigate to xaml page
Uri uri = new Uri("/PageContentFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetContentStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;
Aunque al llamar a GetContentStream se obtiene acceso a Stream, debe realizar el trabajo adicional de
convertirlo en el tipo de la propiedad con la que lo establecer. Como alternativa, puede dejar que WPF se
ocupe de abrir y convertir el objeto Stream cargando un archivo de recursos directamente en la propiedad de
un tipo mediante cdigo.
En el ejemplo siguiente, se muestra cmo se carga un control Page directamente en un control Frame
(pageFrame) mediante cdigo.
Uri pageUri = new Uri("/PageContentFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
El ejemplo siguiente es el equivalente en marcado del ejemplo anterior.
<Frame Name="pageFrame" Source="PageContentFile.xaml" />
Archivos de sitio de origen
Los archivos de recursos tienen una relacin explcita con los ensamblados junto a los que se distribuyen, segn
lo definido en AssemblyAssociatedContentFileAttribute. No obstante, habr ocasiones en las que quiz desee
establecer una relacin implcita o inexistente entre un ensamblado y un archivo de datos de aplicacin, por
ejemplo cuando:

Un archivo no exista en tiempo de compilacin.


No sepa qu archivos necesitar el ensamblado hasta el tiempo de ejecucin.
Desee poder actualizar los archivos sin tener que volver a generar el ensamblado al que estn
asociados.

La aplicacin utilice archivos de datos grandes, como los de audio y vdeo, y desee que los usuarios los
descarguen slo si as lo eligen.

Es posible cargar estos tipos de archivo utilizando esquemas de URI tradicionales, como los esquemas file:/// y
http://.
<Image Source="file:///C:/DataFile.bmp" />
<Image Source="http://www.datafilewebsite.com/DataFile.bmp" />
Sin embargo, los esquemas file:/// y http:// requieren que la aplicacin sea de plena confianza. Si la aplicacin
es una aplicacin Aplicacin del explorador XAML (XBAP) iniciada desde Internet o desde una intranet y solicita
solamente el conjunto de permisos que se permiten para las aplicaciones iniciadas desde esas ubicaciones, los

MCT: Luis Dueas

Pag 58 de 445

Manual de Windows Presentation Foundation


archivos separados solamente se podrn cargar desde el sitio de origen de la aplicacin (ubicacin de inicio).
Esos archivos se conocen como archivos de sitio de origen.
Los archivos de sitio de origen son la nica opcin para las aplicaciones de confianza parcial, aunque no se
limitan a ellas. Puede que las aplicaciones de plena confianza necesiten cargar archivos de datos de aplicacin
que desconocen en tiempo de compilacin; aunque las aplicaciones de plena confianza podran utilizar file:///,
es probable que los archivos de datos de aplicacin se instalen en la misma carpeta o en una subcarpeta del
ensamblado de la aplicacin. En este caso, el uso de referencias al sitio de origen es ms fcil que el uso de
file:/// porque en este ltimo caso es necesario especificar la ruta de acceso completa al archivo.
Nota:
A diferencia de los archivos de contenido, los archivos de sitio de origen no se almacenan en la memoria
cach con una aplicacin Aplicacin del explorador XAML (XBAP) en un equipo cliente. Por consiguiente, se
descargan slo cuando se solicita especficamente su descarga. Si una aplicacin Aplicacin del explorador
XAML (XBAP) tiene archivos multimedia grandes, configurarlos como archivos de sitio de origen significa
que el inicio de la aplicacin ser mucho ms rpido y que los archivos solamente se descargarn a
peticin.
Configurar archivos de sitio de origen
Si los archivos de sitio de origen son inexistentes o se desconocen en tiempo de compilacin, necesitar utilizar
los mecanismos de distribucin tradicionales para asegurarse de que los archivos necesarios estn disponibles
en tiempo de ejecucin, como el programa de lnea de comandos XCopy o Microsoft Windows Installer.
Si desconoce en tiempo de compilacin los archivos que deben encontrarse en el sitio de origen, pero an
desea evitar dependencias explcitas, puede agregar esos archivos a un proyecto de Microsoft build engine
(MSBuild) como elemento None. Al igual que en el caso de los archivos de contenido, es necesario establecer el
atributo MSBuild CopyToOutputDirectory para especificar que el archivo de sitio de origen se copie en una
ubicacin relativa al ensamblado generado, especificando el valor Always o el valor PreserveNewest.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
Nota:
En Visual Studio, se crea un archivo de sitio de origen agregando un archivo a un proyecto y
estableciendo el valor de Build Action en None.
Al generar el proyecto, MSBuild copia los archivos especificados en la carpeta de resultados de la compilacin.
Utilizar archivos de sitio de origen
Para cargar un archivo de sitio de origen, puede llamar al mtodo GetRemoteStream de la clase Application,
pasando un pack URI que identifique el archivo de sitio de origen deseado. GetRemoteStream devuelve un
objeto StreamResourceInfo, que expone el archivo de sitio de origen como Stream y describe su tipo de
contenido.
Como ejemplo, en el cdigo siguiente se muestra cmo utilizar GetRemoteStream para cargar un archivo de
sitio de origen Page y establecerlo como contenido de un control Frame (pageFrame).
// Navigate to xaml page
Uri uri = new Uri("/SiteOfOriginFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetRemoteStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;
Aunque al llamar a GetRemoteStream se obtiene acceso a Stream, debe realizar el trabajo adicional de
convertirlo en el tipo de la propiedad con la que lo establecer. Como alternativa, puede dejar que WPF se
ocupe de abrir y convertir el objeto Stream cargando un archivo de recursos directamente en la propiedad de
un tipo mediante cdigo.

MCT: Luis Dueas

Pag 59 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente, se muestra cmo se carga un control Page directamente en un control Frame
(pageFrame) mediante cdigo.
Uri pageUri = new Uri("pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml",
UriKind.Absolute);
this.pageFrame.Source = pageUri;
El ejemplo siguiente es el equivalente en marcado del ejemplo anterior.
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
Volver a generar despus de cambiar el tipo de compilacin
Despus de cambiar el tipo de compilacin de un archivo de datos de aplicacin, debe volver a generar la
aplicacin completa para asegurarse de que se apliquen esos cambios. Si solamente genera la aplicacin, no se
aplicarn los cambios.

2.2.3. URIs de Paquete en Windows Presentation Foundation


En Windows Presentation Foundation (WPF), se utilizan identificadores de recursos uniformes (URIs) para
identificar y cargar archivos de muchas maneras, incluidas las que figuran a continuacin:

Especificando la interfaz de usuario (UI) que se va a mostrar cuando se inicie una aplicacin por
primera vez.

Cargando imgenes.
Navegando a pginas.
Cargando archivos de datos no ejecutables.

Adems, se pueden usar URIs para identificar y cargar archivos desde diversas ubicaciones, como las que
figuran a continuacin:

El ensamblado actual.
Un ensamblado al que se hace referencia.
Una ubicacin relativa a un ensamblado.
El sitio de origen de la aplicacin.

Para proporcionar un mecanismo coherente para identificar y cargar estos tipos de archivo desde estas
ubicaciones, WPF aprovecha la extensibilidad del esquema de pack URI. En este tema se proporciona
informacin general sobre el esquema, se describe cmo construir pack URIs para diversos escenarios, se
explican los URIs absolutos y relativos y la resolucin de URI antes de mostrar cmo utilizar los pack URIs tanto
desde el marcado como desde el cdigo.
Esquema de pack URI
El esquema de pack URI se utiliza en la especificacin de Open Packaging Conventions (OPC), que describe un
modelo para organizar e identificar contenido. Los elementos clave de este modelo son los paquetes y las
partes, donde un paquete es un contenedor lgico para una o varias partes lgicas. La figura siguiente ilustra
este concepto.

Para identificar las partes, la especificacin de OPC aprovecha la extensibilidad de RFC 2396 (Identificadores
uniformes de recursos (URI): sintaxis genrica) para definir el esquema de pack URI.
El esquema especificado por un URI se define por su prefijo; http, ftp y file son ejemplos conocidos. El esquema
de pack URI utiliza "pack" como esquema y tiene dos componentes: la autoridad y la ruta de acceso. A
continuacin figura el formato de un pack URI.
pack://autoridad/ruta de acceso

MCT: Luis Dueas

Pag 60 de 445

Manual de Windows Presentation Foundation


La autoridad especifica el tipo de paquete que contiene una parte, mientras que la ruta de acceso especifica la
ubicacin de una parte dentro de un paquete.
Este concepto se ilustra en la siguiente figura:

Los paquetes y las partes son anlogos a las aplicaciones y los archivos, puesto que una aplicacin (paquete)
puede incluir uno o varios archivos (partes), como los siguientes:

Archivos de recursos que se compilan en el ensamblado local.


Archivos de recursos que se compilan en un ensamblado al que se hace referencia.
Archivos de recursos que se compilan en un ensamblado que hace referencia.
Archivos de contenido.
Archivos de sitio de origen.

Para obtener acceso a estos tipos de archivo, WPF admite dos autoridades: application:/// y siteoforigin:///. La
autoridad application:/// identifica los archivos de datos de aplicacin que se conocen en tiempo de
compilacin, incluidos los archivos de recursos y de contenido. La autoridad siteoforigin:/// identifica los
archivos de sitio de origen. El mbito de cada autoridad se muestra en la figura siguiente.

Nota:
El componente de autoridad de un pack URI es un URI incrustado que apunta a un paquete y debe
ajustarse a RFC 2396. Adems, el carcter "/" debe sustituirse por el carcter "," y los caracteres
reservados tales como "%" y "?" deben incluirse en secuencias de escape. Vea la especificacin de OPC
para obtener informacin detallada.
En las secciones siguientes se explica cmo construir pack URIs utilizando estas dos autoridades junto con las
rutas de acceso adecuadas para identificar los archivos de recursos, de contenido y de sitio de origen.
Pack URI de archivos de recursos
Los archivos de recursos se configuran como elementos Resource de MSBuild y se compilan en ensamblados.
WPF admite la construccin de pack URIs que se pueden utilizar para identificar los archivos de recursos
compilados en el ensamblado local o compilados en un ensamblado al que se hace referencia desde el
ensamblado local.
Archivo de recursos del ensamblado local
El pack URI para un archivo de recursos compilado en el ensamblado local utiliza la siguiente autoridad y ruta
de acceso:

Autoridad: application:///.
Ruta de acceso: nombre del archivo de recursos, incluida su ruta de acceso relativa a la carpeta raz
del proyecto de ensamblado local.

MCT: Luis Dueas

Pag 61 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente se muestra el pack URI para un archivo de recursos XAML que se encuentra en la
carpeta raz del proyecto de ensamblado local.
pack://application:,,,/ResourceFile.xaml
En el ejemplo siguiente se muestra el pack URI para un archivo de recursos XAML que se encuentra en una
subcarpeta de la carpeta del proyecto de ensamblado local.
pack://application:,,,/Subfolder/ResourceFile.xaml
Archivo de recursos del ensamblado al que se hace referencia
El pack URI para un archivo de recursos compilado en un ensamblado al que se hace referencia utiliza la
siguiente autoridad y ruta de acceso:

Autoridad: application:///.
Ruta de acceso: nombre de un archivo de recursos compilado en un ensamblado al que se hace
referencia. La ruta de acceso debe tener el formato siguiente:
nombreCortoDeEnsamblado[;Versin][;clavePblica];component/rutaDeAcceso

nombreCortoDeEnsamblado: nombre corto del ensamblado al que se hace referencia.


;Versin [opcional]: versin del ensamblado al que se hace referencia y que contiene el
archivo de recursos. Se utiliza cuando hay cargados dos o ms ensamblados a los que se hace
referencia con el mismo nombre corto.

;clavePblica [opcional]: clave pblica utilizada para firmar el ensamblado al que se hace
referencia. Se utiliza cuando hay cargados dos o ms ensamblados a los que se hace referencia
con el mismo nombre corto.

;component: especifica que la referencia al ensamblado se hace desde el ensamblado local.


/rutaDeAcceso: nombre del archivo de recursos, incluida su ruta de acceso relativa a la
carpeta raz del proyecto del ensamblado al que se hace referencia.

En el ejemplo siguiente se muestra el pack URI para un archivo de recursos XAML que se encuentra en la
carpeta raz del proyecto de ensamblado al que se hace referencia.

pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml
En el ejemplo siguiente se muestra el pack URI para un archivo de recursos XAML que se encuentra en una
subcarpeta de la carpeta del proyecto de ensamblado al que se hace referencia.

pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml
En el ejemplo siguiente se muestra el pack URI para un archivo de recursos XAML que se encuentra en la
carpeta raz de un proyecto de ensamblado especfico de la versin al que se hace referencia.

pack://application:,,,/ReferencedAssembly;v1.0.0.1;component/ResourceFile.xaml
Observe que la sintaxis del pack URI para los archivos de recursos de ensamblado a los que se hace referencia
solamente se puede utilizar con la autoridad application:///. Por ejemplo, no se admite lo siguiente en WPF.
pack://siteoforigin:,,,/SomeAssembly;component/ResourceFile.xaml
Pack URI de archivo de contenido
El pack URI para un archivo de contenido utiliza la siguiente autoridad y ruta de acceso:

Autoridad: application:///.
Ruta de acceso: nombre del archivo de contenido, incluida su ruta de acceso relativa a la ubicacin del
sistema de archivos del ensamblado ejecutable principal de la aplicacin.

En el ejemplo siguiente se muestra el pack URI para un archivo de contenido XAML, ubicado en la misma
carpeta que el ensamblado ejecutable.
pack://application:,,,/ContentFile.xaml

MCT: Luis Dueas

Pag 62 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente se muestra el pack URI para un archivo de contenido XAML, situado en una subcarpeta
relativa al ensamblado ejecutable de la aplicacin.
pack://application:,,,/Subfolder/ContentFile.xaml
Nota:
No se puede navegar a los archivos de contenido HTML. El esquema de URI solamente admite la
navegacin a archivos HTML ubicados en el sitio de origen.
Pack URI de sitio de origen
El pack URI para un archivo de sitio de origen utiliza la siguiente autoridad y ruta de acceso:

Autoridad: siteoforigin:///.
Ruta de acceso: nombre del archivo de sitio de origen, incluida su ruta de acceso relativa a la
ubicacin desde la que se inici el ensamblado ejecutable.

En el ejemplo siguiente se muestra el pack URI para un archivo de sitio de origen XAML, almacenado en la
ubicacin desde la que se inicia el ensamblado ejecutable.
pack://siteoforigin:,,,/SiteOfOriginFile.xaml
En el ejemplo siguiente se muestra el pack URI para un archivo de sitio de origen XAML, almacenado en una
subcarpeta relativa a la ubicacin desde la que se inicia el ensamblado ejecutable de la aplicacin.
pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml
Archivos de paginacin
Los archivos XAML configurados como elementos Page de MSBuild se compilan en ensamblados del mismo
modo que los archivos de recursos. Por consiguiente, los elementos Page de MSBuild se pueden identificar
mediante los pack URIs para los archivos de recursos.
Los tipos de archivo XAML que se configuran habitualmente como elementos Page de MSBuild tienen uno de los
siguientes elementos como elemento raz:

System.Windows.Window
System.Windows.Controls.Page
System.Windows.Navigation.PageFunction<(Of <(T>)>)
System.Windows.ResourceDictionary
System.Windows.Documents.FlowDocument
System.Windows.Controls.UserControl

Pack URI absolutos y relativos


Un pack URI completo incluye el esquema, la autoridad y la ruta de acceso, y se considera un pack URI
absoluto. Como simplificacin para los desarrolladores, los elementos XAML suelen permitir que se establezcan
los atributos adecuados con un pack URI relativo, que incluye solamente la ruta de acceso.
Por ejemplo, considere el siguiente pack URI absoluto para un archivo de recursos en el ensamblado local.
pack://application:,,,/ResourceFile.xaml
El pack URI relativo que hace referencia a este recurso sera el siguiente.
/ResourceFile.xaml
Nota:
Dado que los archivos de sitio de origen no estn asociados a ensamblados, solamente se puede hacer
referencia a ellos con pack URIs absolutos.
De forma predeterminada, un pack URI relativo se considera relativo a la ubicacin del marcado o del cdigo
que contiene la referencia. Sin embargo, si se utiliza una barra diagonal inversa inicial, el pack URI relativo se
considera relativo a la raz de la aplicacin. Por ejemplo, considere la estructura de proyecto siguiente.
App.xaml

MCT: Luis Dueas

Pag 63 de 445

Manual de Windows Presentation Foundation


Page2.xaml
\SubFolder
+ Page1.xaml
+ Page2.xaml
Si Page1.xaml contiene un URI que hace referencia a Raz\SubFolder\Page2.xaml, la referencia puede utilizar el
siguiente pack URI.
Page2.xaml
Si Page1.xaml contiene un URI que hace referencia a Raz\Page2.xaml, la referencia puede utilizar el siguiente
pack URI relativo.
/Page2.xaml
Resolucin de pack URI
El formato de los pack URIs permite que los pack URIs para diferentes tipos de archivo tengan la misma
apariencia. Por ejemplo, considere el siguiente pack URI absoluto.
pack://application:,,,/ResourceOrContentFile.xaml
Este pack URI absoluto podra hacer referencia a un archivo de recursos del ensamblado local o a un archivo de
contenido. Lo mismo se aplica al siguiente URI relativo.
/ResourceOrContentFile.xaml
Para determinar el tipo de archivo al que hace referencia un pack URI, WPF resuelve los URIs para los archivos
de recursos en ensamblados locales y los archivos de contenido usando la siguiente heurstica:
1.

Sondear

los

metadatos

del

ensamblado

para

buscar

un

atributo

AssemblyAssociatedContentFileAttribute que coincida con el pack URI.


2.

Si se encuentra el atributo AssemblyAssociatedContentFileAttribute, la ruta de acceso del pack URI


hace referencia a un archivo de contenido.

3.

Si no se encuentra el atributo AssemblyAssociatedContentFileAttribute, sondee los archivos de


recursos establecidos que estn compilados en el ensamblado local.

4.

Si se encuentra un archivo de recursos que coincida con el pack URI, la ruta de acceso del pack URI
hace referencia a un archivo de recursos.

5.

Si no se encuentra el recurso, el Uri creado internamente no es vlido.

La resolucin de URI no se aplica a los URIs que hacen referencia a los siguientes archivos:

Archivos de contenido en ensamblados a los que se hace referencia: WPF no admite estos tipos de
archivo.

Archivos incrustados en ensamblados a los que se hace referencia: los URIs que los identifican son
nicos porque incluyen tanto el nombre del ensamblado al que se hace referencia como el sufijo
;component.

Archivos de sitio de origen: los URIs que los identifican son nicos porque son los nicos archivos que
se pueden identificar mediante pack URIs que contienen la autoridad siteoforigin:///.

Una simplificacin que permite la resolucin de pack URI es que el cdigo sea independiente, hasta cierto
punto, de la ubicacin de los archivos de recursos y de contenido. Por ejemplo, si tiene un archivo de recursos
en el ensamblado local que se ha reconfigurado para que sea un archivo de contenido, el pack URI para el
recurso continuar siendo el mismo, al igual que el cdigo que utiliza el pack URI.
Programar con pack URI

MCT: Luis Dueas

Pag 64 de 445

Manual de Windows Presentation Foundation


Muchas clases de WPF implementan propiedades que se pueden establecer con pack URIs, como:

Application.StartupUri
Frame.Source
NavigationWindow.Source
Hyperlink.NavigateUri
Window.Icon
Image.Source

Estas propiedades se pueden establecer tanto desde marcado como desde cdigo. En esta seccin se muestran
las construcciones bsicas para ambos y, a continuacin, se muestra ejemplos de escenarios comunes.
Utilizar pack URI en el marcado
Un pack URI se especifica en el marcado estableciendo el elemento de un atributo con el pack URI. Por
ejemplo:
<element attribute="pack://application:,,,/File.xaml" />
En la tabla 1 se muestran los diversos pack URIs absolutos que se pueden especificar en el marcado.
Tabla 1: pack URI absolutos en el marcado
Archivo

Pack URI absoluto

Archivo de recursos:
ensamblado local

"pack://application:,,,/ResourceFile.xaml"

Archivo de recursos en
subcarpeta: ensamblado local

"pack://application:,,,/Subfolder/ResourceFile.xaml"

Archivo de recursos:
ensamblado al que se hace
referencia

"pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml"

Archivo de recursos en
subcarpeta del ensamblado al
que se hace referencia

"pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml"

Archivo de recursos en el
ensamblado al que se hace
referencia con versin

"pack://application:,,,/ReferencedAssembly;v1.0.0.0;component/ResourceFile.xaml"

Archivo de contenido

"pack://application:,,,/ContentFile.xaml"

Archivo de contenido en
subcarpeta

"pack://application:,,,/Subfolder/ContentFile.xaml"

Archivo de sitio de origen

"pack://siteoforigin:,,,/SOOFile.xaml"

Archivo de sitio de origen en


subcarpeta

"pack://siteoforigin:,,,/Subfolder/SOOFile.xaml"

En la tabla 2 se muestran los diversos pack URIs relativos que se pueden especificar en el marcado.
Tabla 2: pack URI relativos en el marcado
Archivo

Pack URI relativo

Archivo de recursos en ensamblado local

"/ResourceFile.xaml"

Archivo de recursos en subcarpeta del


ensamblado local

"/Subfolder/ResourceFile.xaml"

Archivo de recursos en ensamblado al que se


hace referencia

"/ReferencedAssembly;component/ResourceFile.xaml"

MCT: Luis Dueas

Pag 65 de 445

Manual de Windows Presentation Foundation

Archivo de recursos en subcarpeta del


ensamblado al que se hace referencia

"/ReferencedAssembly;component/Subfolder/ResourceFile.xaml"

Archivo de contenido

"/ContentFile.xaml"

Archivo de contenido en subcarpeta

"/Subfolder/ContentFile.xaml"

Utilizar pack URI en el cdigo


Para especificar un pack URI en el cdigo, puede crear una instancia de la clase Uri y pasar el pack URI como
parmetro al constructor. Esto ltimo se muestra en el ejemplo siguiente.
Uri uri = new Uri("pack://application:,,,/File.xaml");
De forma predeterminada, la clase Uri considera que el pack URIs es absoluto. Por consiguiente, se produce
una excepcin cuando se crea una instancia de la clase Uri con un pack URI relativo.
Uri uri = new Uri("/File.xaml");
Afortunadamente, la sobrecarga Uri(String, UriKind) del constructor de clase Uri acepta un parmetro de tipo
UriKind para permitir que se especifique si un pack URI es absoluto o relativo.
// Absolute URI (default)
Uri absoluteUri = new Uri("pack://application:,,,/File.xaml", UriKind.Absolute);
// Relative URI
Uri relativeUri = new Uri("/File.xaml", UriKind.Relative);
Solamente se debe especificar Absolute o Relative cuando se tiene la seguridad de que el pack URI
proporcionado es uno u otro. Si no conoce el tipo de pack URI que se utiliza, como cuando un usuario escribe
un pack URI en tiempo de ejecucin, utilice RelativeOrAbsolute.
// Relative or Absolute URI provided by user via a text box
TextBox userProvidedUriTextBox = new TextBox();
Uri uri = new Uri(userProvidedUriTextBox.Text, UriKind.RelativeOrAbsolute);
En la tabla 3 se muestran los diversos pack URIs relativos que se pueden especificar en el cdigo utilizando
System.Uri.
Tabla 3: pack URI absolutos en el cdigo
Archivo

Pack URI absoluto

Archivo de recursos:
ensamblado local

Uri uri = new Uri("pack://application:,,,/ResourceFile.xaml", UriKind.Absolute);

Archivo de recursos
en subcarpeta:
ensamblado local

Uri uri = new Uri("pack://application:,,,/Subfolder/ResourceFile.xaml", UriKind.Absolute);

Archivo de recursos:
ensamblado al que se
hace referencia

Uri uri = new Uri("pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml",

Archivo de recursos
en subcarpeta del
ensamblado al que se
hace referencia

Uri uri = new

Archivo de recursos
en el ensamblado al
que se hace
referencia con versin

Uri uri = new

Archivo de contenido

Uri uri = new Uri("pack://application:,,,/ContentFile.xaml", UriKind.Absolute);

Archivo de contenido
en subcarpeta

Uri uri = new Uri("pack://application:,,,/Subfolder/ContentFile.xaml", UriKind.Absolute);

Archivo de sitio de
origen

Uri uri = new Uri("pack://siteoforigin:,,,/SOOFile.xaml", UriKind.Absolute);

Archivo de sitio de
origen en subcarpeta

Uri uri = new Uri("pack://siteoforigin:,,,/Subfolder/SOOFile.xaml", UriKind.Absolute);

MCT: Luis Dueas

UriKind.Absolute);

Uri("pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml",
UriKind.Absolute);

Uri("pack://application:,,,/ReferencedAssembly;v1.0.0.0;component/ResourceFile.xaml",
UriKind.Absolute);

Pag 66 de 445

Manual de Windows Presentation Foundation


En la tabla 4 se muestran los diversos pack URIs relativos que se pueden especificar en el cdigo utilizando
System.Uri.
Tabla 4: pack URI relativos en el cdigo
Archivo

Pack URI relativo

Archivo de recursos: ensamblado


local

Uri uri = new Uri("/ResourceFile.xaml", UriKind.Relative);

Archivo de recursos en
subcarpeta: ensamblado local

Uri uri = new Uri("/Subfolder/ResourceFile.xaml", UriKind.Relative);

Archivo de recursos: ensamblado


al que se hace referencia

Uri uri = new Uri("/ReferencedAssembly;component/ResourceFile.xaml",

Archivo de recursos en
subcarpeta: ensamblado al que se
hace referencia

Uri uri = new

UriKind.Relative);

Uri("/ReferencedAssembly;component/Subfolder/ResourceFile.xaml",
UriKind.Relative);

Archivo de contenido

Uri uri = new Uri("/ContentFile.xaml", UriKind.Relative);

Archivo de contenido en
subcarpeta

Uri uri = new Uri("/Subfolder/ContentFile.xaml", UriKind.Relative);

Escenarios comunes de pack URI


En las secciones anteriores se ha explicado cmo construir pack URIs para identificar archivos de recursos, de
contenido y de sitio de origen. En WPF, estas construcciones se utilizan de diversas maneras. En las secciones
siguientes, se abordan varios usos comunes.
Especificar la interfaz de usuario que se va a mostrar cuando se inicie una aplicacin
StartupUri especifica la primera interfaz de usuario que se va a mostrar cuando se inicie una aplicacin WPF. En
el caso de las aplicaciones independientes, la interfaz de usuario puede ser una ventana, como se muestra en el
ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="MainWindow.xaml" />
Las aplicaciones independientes y las Aplicaciones del explorador XAML (XBAPs) tambin pueden especificar
una pgina como interfaz de usuario inicial, tal como se muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="HomePage.xaml" />
Si la aplicacin es una aplicacin independiente y hay una pgina especificada con StartupUri, WPF abre un
objeto NavigationWindow para hospedar la pgina. En el caso de las XBAPs, la pgina se muestra en el
explorador del host.
Navegar a una pgina
En el ejemplo siguiente se muestra cmo navegar a una pgina.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page With Hyperlink"
WindowWidth="250"
WindowHeight="250">
...
<Hyperlink NavigateUri="UriOfPageToNavigateTo.xaml">
Navigate to Another Page
</Hyperlink>
...
</Page>
Especificar un icono de ventana
En el ejemplo siguiente se muestra cmo utilizar un URI para especificar el icono de una ventana.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MainWindow"
Icon="WPFIcon1.ico">

MCT: Luis Dueas

Pag 67 de 445

Manual de Windows Presentation Foundation


</Window>
Cargar archivos de imagen, audio y vdeo
WPF permite a las aplicaciones utilizar una amplia variedad de tipos multimedia, que se pueden identificar y
cargar todos con pack URIs, tal como se muestra en los ejemplos siguientes.
<MediaElement Stretch="Fill" LoadedBehavior="Play"
Source="pack://siteoforigin:,,,/Media/bee.wmv" />
<MediaElement Stretch="Fill" LoadedBehavior="Play"
Source="pack://siteoforigin:,,,/Media/ringin.wav" />
<Image Source="Images/Watermark.png" />
Cargar un diccionario de recursos desde el sitio de origen
Los diccionarios de recursos (ResourceDictionary) se pueden utilizar para ofrecer compatibilidad con los temas
de aplicacin. Una manera de crear y administrar temas consiste en crear varios temas como diccionarios de
recursos que se encuentran en el sitio de origen de una aplicacin. Esto permite agregar temas y actualizarlos
sin tener que volver a compilar e implementar una aplicacin. Estos diccionarios de recursos se pueden
identificar y cargar mediante pack URIs, tal como se muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="HomePage.xaml">
<Application.Resources>
<ResourceDictionary Source="pack://siteoforigin:,,,/PageTheme.xaml" />
</Application.Resources>
</Application>

2.2.4. Temas Cmo del Modelo de Aplicaciones


En los temas siguientes se muestra cmo utilizar las caractersticas del modelo de aplicacin de Windows
Presentation Foundation (WPF).

2.2.4.1. Cmo: Obtener y Establecer Propiedades en el Ambito de Aplicacin


En este ejemplo se muestra cmo obtener y establecer propiedades del mbito de aplicacin mediante
Properties.
Ejemplo
Application expone un almacn de datos para las propiedades que se pueden compartir en un AppDomain:
Properties.
El almacn de datos de propiedad es un diccionario de pares de clave/valor que se pueden utilizar as:
// Set an application-scope property
Application.Current.Properties["MyApplicationScopeProperty"] =
"myApplicationScopePropertyValue";
// Get an application-scope property
// NOTE: Need to convert since Application.Properties is a dictionary of System.Object
string myApplicationScopeProperty =
(string)Application.Current.Properties["MyApplicationScopeProperty"];
Debe tener en cuenta dos aspectos al utilizar Properties. En primer lugar, la clave de diccionario es un objeto,
por lo que es preciso utilizar exactamente la misma instancia del objeto al establecer y obtener un valor de
propiedad (tenga en cuenta que la clave distingue entre maysculas y minsculas cuando se utiliza una clave
de cadena). En segundo lugar, el valor del diccionario es un objeto, por lo que deber convertir el valor al tipo
que desee cuando obtenga un valor de propiedad.
Dado que el valor de diccionario es un objeto, resulta igual de fcil utilizar tipos personalizados o tipos simples,
as:
// Set an application-scope property with a custom type
CustomType customType = new CustomType();
Application.Current.Properties["CustomType"] = customType;
// Get an application-scope property
// NOTE: Need to convert since Application.Properties is a dictionary of System.Object
CustomType customType = (CustomType)Application.Current.Properties["CustomType"];

2.2.4.2. Cmo: Obtener y Establecer Recursos en el Ambito de Aplicacin

MCT: Luis Dueas

Pag 68 de 445

Manual de Windows Presentation Foundation


En este ejemplo se muestra cmo obtener y establecer recursos del mbito de aplicacin mediante Resources.
Ejemplo
Application expone un almacn de mbito de aplicacin para los recursos compartidos: Resources. Los recursos
almacenados en Resources estn disponibles desde cualquier cdigo que se ejecute dentro del mbito del
objeto Application de una aplicacin (es decir, cdigo que pueda obtener acceso a Current). Adems, Resources
se utiliza en la ruta de acceso de bsqueda de recursos.
Resources es un diccionario de pares de clave/valor que se puede establecer mediante marcado y cdigo, as:
// Set an application-scope resource
Application.Current.Resources["ApplicationScopeResource"] = Brushes.White;
<Application.Resources>
<SolidColorBrush x:Key="ApplicationScopeResource" Color="White"></SolidColorBrush>
</Application.Resources>
Se utiliza el cdigo para obtener un recurso:
// Get an application-scope resource
Brush whiteBrush = (Brush)Application.Current.Resources["ApplicationScopeResource"];
Debe tener en cuenta dos aspectos al utilizar Resources. En primer lugar, la clave de diccionario es un objeto,
por lo que es preciso utilizar exactamente la misma instancia del objeto al establecer y obtener un valor de
propiedad (tenga en cuenta que la clave distingue entre maysculas y minsculas cuando se utiliza una
cadena). En segundo lugar, el valor del diccionario es un objeto, por lo que deber convertir el valor al tipo que
desee cuando obtenga un valor de propiedad.

2.2.4.3. Cmo: Obtener y Establecer el Cdigo de Salida de Aplicaciones


En este ejemplo se muestra cmo obtener y establecer el cdigo de salida de aplicaciones.
Ejemplo
Application devuelve automticamente un valor de cdigo de salida al sistema operativo cuando la aplicacin
deja de ejecutarse. Casi siempre, las aplicaciones utilizan los cdigos de salida para comunicar la razn por la
que han dejado de ejecutarse al sistema operativo o a otras aplicaciones en ejecucin.
El valor del cdigo de salida predeterminado devuelto por Application es 0. Puede obtener el valor del cdigo de
salida controlando el evento Exit e inspeccionando la propiedad ApplicationExitCode:
int exitCode = e.ApplicationExitCode;
Puede cambiar el valor del cdigo de salida predeterminado estableciendo la propiedad ApplicationExitCode o
llamando al mtodo Shutdown:
e.ApplicationExitCode = 11;
Application.Current.Shutdown(11);

2.2.4.4. Cmo: Obtener los Argumentos de Lnea de Comandos


En este ejemplo se muestra cmo obtener los argumentos de la lnea de comandos que se pasaron a una
aplicacin.
Ejemplo
En el siguiente ejemplo de cdigo se muestra cmo usar el objeto Application y el evento Startup para obtener
los argumentos de la lnea de comandos.
<Application
x:Class="CSharp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="app_Startup">
</Application>
using System;
using System.Windows;
namespace CSharp
{
public partial class App : Application
{
void app_Startup(object sender, StartupEventArgs e)
{

MCT: Luis Dueas

Pag 69 de 445

Manual de Windows Presentation Foundation


// If no command line arguments were provided, don't process them
if (e.Args.Length == 0) return;
// Get command line arguments
foreach (string argument in e.Args)
{
switch (argument)
{
case "arg1":
// Process arg 1
break;
case "arg2":
// Process arg 2
break;
case "arg3":
// Process arg 3
break;
}
}
}

2.2.4.5. Cmo: Obtener el Objeto de Aplicacin Actual


En este ejemplo se muestra cmo obtener una referencia a la instancia del objeto Application para el
AppDomain actual.
Ejemplo
En el ejemplo siguiente se muestra cmo recibir una referencia a la instancia del objeto Application actual de la
propiedad Current.
// Get a reference to the current Application object
Application currentApplication = Application.Current;

2.2.4.6. Cmo: Conservar y Restaurar Propiedades en el Ambito de Aplicacin


a travs de Sesiones de Aplicacin
En este ejemplo se muestra cmo conservar las propiedades del mbito de aplicacin cuando una aplicacin se
cierra, y cmo restaurar las propiedades del mbito de aplicacin la prxima vez que se inicia la aplicacin.
Ejemplo
La aplicacin conserva las propiedades del mbito de aplicacin en un almacenamiento aislado, desde el que las
restaura. El almacenamiento aislado es una rea de almacenamiento protegido que puede ser utilizada sin
ningn riesgo por aplicaciones que no tengan permiso de acceso a archivos.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
StartupUri="MainWindow.xaml"
Startup="App_Startup"
Exit="App_Exit">
...
</Application>
using System.Windows; // Application, StartupEventArgs
using System.IO; // StreamReader, FileMode
using System.IO.IsolatedStorage; // IsolatedStorageFile, IsolatedStorageFileStream
namespace SDKSample
{
public partial class App : Application
{
string filename = "App.txt";
...
private void App_Startup(object sender, StartupEventArgs e)
{
// Restore application-scope property from isolated storage
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForDomain();
try
{
using (IsolatedStorageFileStream stream = new _
IsolatedStorageFileStream(filename, FileMode.Open, storage))
using (StreamReader reader = new StreamReader(stream))
{
// Restore each application-scope property individually
while (!reader.EndOfStream)

MCT: Luis Dueas

Pag 70 de 445

Manual de Windows Presentation Foundation


{
string[] keyValue = reader.ReadLine().Split(new char[] {','});
this.Properties[keyValue[0]] = keyValue[1];
}
}

}
catch (FileNotFoundException ex)
{
// Handle when file is not found in isolated storage:
// * When the first application session
// * When file has been deleted
}
}
private void App_Exit(object sender, ExitEventArgs e)
{
// Persist application-scope property to isolated storage
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForDomain();
using (IsolatedStorageFileStream stream = new _
IsolatedStorageFileStream(filename, FileMode.Create, storage))
using (StreamWriter writer = new StreamWriter(stream))
{
// Persist each application-scope property individually
foreach (string key in this.Properties.Keys)
{
writer.WriteLine("{0},{1}", key, this.Properties[key]);
}
}
}
}

2.2.4.7. Cmo: Cerrar una Aplicacin


En este ejemplo se muestra cmo cerrar una aplicacin.
Ejemplo
app.Current.Shutdown()

2.2.4.8. Cmo: Iniciar una Aplicacin


En este ejemplo se muestra cmo iniciar una aplicacin.
Ejemplo
App app = new App();
app.Run();
Slo necesitar llamar a Run cuando defina la aplicacin nicamente mediante cdigo.

2.2.4.9. Cmo: Usar un Diccionario de Recursos en el Ambito de Aplicacin


En este ejemplo se muestra cmo utilizar diccionario de recursos personalizado de mbito de aplicacin.
Ejemplo
Application expone un almacn de mbito de aplicacin para los recursos compartidos: Resources. De manera
predeterminada, Resources se inicializa con una instancia del tipo ResourceDictionary. Esta instancia se utiliza
al obtener y establecer propiedades del mbito de aplicacin mediante la propiedad Resources.
Si tiene varios recursos que se establecen mediante Resources, en su lugar puede utilizar un diccionario de
recursos personalizado para almacenar esos recursos y establecer Resources en dicho diccionario. Un
diccionario de recursos personalizado se declara mediante marcado, as:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<SolidColorBrush x:Key="StandardSolidColorBrush" Color="White" />
<LinearGradientBrush x:Key="StandardLinearGradientBrush" StartPoint="0.0,0.0"
EndPoint="1.0,1.0">
<LinearGradientBrush.GradientStops>
<GradientStop Color="White" Offset="0" />
<GradientStop Color="Black" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</ResourceDictionary>

MCT: Luis Dueas

Pag 71 de 445

Manual de Windows Presentation Foundation


Intercambiar diccionarios de recursos completos mediante Resources permite admitir temas del mbito de
aplicacin, donde cada tema se encapsula en un solo diccionario de recursos. Consulte el ejemplo de aplicacin
con tema.
Para obtener recursos del mbito de aplicacin del diccionario de recursos expuesto por Resources,
independientemente de si lo ha creado usted o Application, se necesita un cdigo como el siguiente:
// Get an application-scope resource
Brush whiteBrush = (Brush)Application.Current.Resources["ApplicationScopeResource"];
Debe tener en cuenta dos aspectos al utilizar Resources. En primer lugar, la clave de diccionario es un objeto,
por lo que es preciso utilizar exactamente la misma instancia del objeto al establecer y obtener un valor de
propiedad (tenga en cuenta que la clave distingue entre maysculas y minsculas cuando se utiliza una
cadena). En segundo lugar, el valor del diccionario es un objeto, por lo que deber convertir el valor al tipo que
desee cuando obtenga un valor de propiedad.

2.3. Ventanas en Aplicaciones de Windows Presentation Foundation


Los usuarios interactan con las aplicaciones a travs de las ventanas. El propsito fundamental de una
ventana es hospedar y mostrar contenido. El tipo de contenido que una ventana hospeda depende del tipo de
datos con que opera que una aplicacin, y puede incluir multimedia, pginas XAML (Lenguaje de marcado de
aplicaciones extensible), pginas web, documentos, tablas y registros de base de datos e informacin del
sistema.

2.3.1. Informacin General sobre Ventanas de WPF


Los usuarios interactan con las aplicaciones independientes de Windows Presentation Foundation (WPF) por
medio de ventanas. El propsito principal de una ventana es hospedar contenido que muestre datos y permita
al usuario interactuar con ellos. Las aplicaciones WPF independientes proporciona ventanas propias usando la
clase Window. En este tema se presenta Window antes de tratar los principios de la creacin y administracin
de ventanas en aplicaciones independientes.
Nota:
Las aplicaciones WPF hospedadas por explorador, incluso las Aplicaciones del explorador XAML (XBAPs) y
las pginas Lenguaje de marcado de aplicaciones extensible (XAML) separadas, no proporcionan ventanas
propias. En su lugar, se hospedan en ventanas proporcionadas por Windows Internet Explorer.
La clase Window
La figura siguiente muestra las partes constituyente de una ventana.

Una ventana est dividida en dos reas: el rea de no cliente y rea cliente.
El rea de no cliente de una ventana se implementa mediante WPF e incluye las partes de una ventana que son
comunes a la mayora de las ventanas, incluidas las siguientes:

Borde.
Barra de ttulo.
Icono.

MCT: Luis Dueas

Pag 72 de 445

Manual de Windows Presentation Foundation

Botones para minimizar, maximizar y restaurar.


Botn Cerrar.
Men Sistema con elementos de men que permiten a los usuarios minimizar, maximice, restaurar,
mover, cambiar de tamao y cerrar una ventana.

El rea cliente de una ventana es el rea dentro del rea de no cliente de una ventana y es utilizada por los
programadores para agregar contenido especfico de la aplicacin, tal como barras de mens, barras de
herramientas y controles.
En WPF, las ventanas se encapsulan en la clase Window, que se utiliza para hacer lo siguiente:

Mostrar una ventana.


Configurar el tamao, posicin y aspecto de una ventana.
Hospedar contenido especfico de la aplicacin.
Administrar la duracin de una ventana.

Implementar una ventana


La implementacin de una ventana tpica abarca tanto su aspecto como su comportamiento, donde el aspecto
define la apariencia de la ventana para los usuarios y el comportamiento define cmo funciona una ventana
cuando los usuarios interactan con ella. En WPF, puede implementar el aspecto y el comportamiento de una
ventana utilizando cdigo o marcado XAML.
En general, sin embargo, el aspecto de una ventana se implementa utilizando el marcado XAML, y su
comportamiento se implementa utilizando cdigo subyacente, como se muestra en el ejemplo siguiente.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MarkupAndCodeBehindWindow">
<!-- Client area (for content) -->
</Window>
using System.Windows; // Window
namespace SDKSample
{
public partial class MarkupAndCodeBehindWindow : Window
{
public MarkupAndCodeBehindWindow()
{
InitializeComponent();
}
}
}
Para permitir que un archivo de marcado XAML y un archivo de cdigo subyacente funcionen juntos, se requiere
lo siguiente:

En el marcado, el elemento Window debe incluir el atributo x:Class. Al generar la aplicacin, la


existencia de x:Class en el archivo de marcado permite que Microsoft build engine (MSBuild) cree una
clase partial que se deriva de Windowy tenga el nombre especificado por el atributo x:Class. Para ello,
es necesario agregar una declaracin de espacio de nombres XML para el esquema XAML
(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"). La clase partial generada implementa el
mtodo InitializeComponent, al que se llama para registrar los eventos y establecer las propiedades
implementadas en el marcado.

En el archivo de cdigo subyacente, la clase debe ser una clase partial con el mismo nombre que el
que especific el atributo x:Class en el marcado, y debe derivarse de Window. Esto permite que el
archivo de cdigo subyacente se asocie a la clase partial que se genera para el archivo de marcado
cuando se crea la aplicacin.

En el archivo de cdigo subyacente, la clase Window debe implementar un constructor que llame al
mtodo InitializeComponent. InitializeComponent se implementa mediante la clase partial generada

MCT: Luis Dueas

Pag 73 de 445

Manual de Windows Presentation Foundation


del archivo de marcado para registrar eventos y establecer las propiedades que se definen en el
marcado.
Nota:
Al agregar un nuevo objeto Window a su proyecto con Microsoft Visual Studio, se implementa Window
utilizando el marcado y el cdigo subyacente; este control incluye la configuracin necesaria para crear la
asociacin entre los archivos de cdigo subyacente y de marcado tal como aqu se describe.
Con esta configuracin activa, puede centrarse en definir el aspecto de la ventana en el marcado XAML y en
implementar su comportamiento en el cdigo subyacente. En el ejemplo siguiente se muestra una ventana con
un botn, implementado en marcado XAML y un controlador de eventos para el evento Click del botn,
implementado en cdigo subyacente.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MarkupAndCodeBehindWindow">
<!-- Client area (for content) -->
<Button Click="button_Click">Click This Button</Button>
</Window>
using System.Windows;
namespace SDKSample
{
public partial class MarkupAndCodeBehindWindow : Window
{
public MarkupAndCodeBehindWindow()
{
InitializeComponent();
}
void button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Button was clicked.");
}
}
}
Configurar una definicin de ventana para MSBuild
La forma de implementar la ventana determina cmo se configura para MSBuild. Para una ventana que se
define utilizando tanto marcado XAML como cdigo subyacente:

Los archivos de marcado XAML se configuran como elementos MSBuild Page.


Los archivos de cdigo subyacente se configuran como elementos MSBuildCompile.

Esto se muestra en el siguiente archivo de proyecto MSBuild.


<Project ... xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<Page Include="MarkupAndCodeBehindWindow.xaml" />
<Compile Include=" MarkupAndCodeBehindWindow.xaml.cs" />
...
</Project>
Duracin de la ventana
Como con cualquier clase, una ventana tiene una duracin que comienza cuando se crea por primera vez la
instancia, despus de lo cual se abre, se activa, se desactiva y, finalmente, se cierra.
Abrir una ventana
Para abrir una ventana, crea primero una instancia de ella, como se muestra en el ejemplo siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
Startup="app_Startup">
</Application>
using System.Windows;
namespace SDKSample
{
public partial class App : Application
{
void app_Startup(object sender, StartupEventArgs e)
{
// Create a window
MarkupAndCodeBehindWindow window = new MarkupAndCodeBehindWindow();
// Open a window
window.Show();

MCT: Luis Dueas

Pag 74 de 445

Manual de Windows Presentation Foundation


}
}

}
En este ejemplo, se crea una instancia de MarkupAndCodeBehindWindow cuando se inicia la aplicacin, lo que
ocurre cuando se produce el evento Startup.
Cuando se crea una instancia de una ventana, automticamente se agrega una referencia a la ventana a la lista
de ventanas administrada por el objeto Application. Adems, Application establece la primera ventana de la que
se crea una instancia, de forma predeterminada, como la ventana principal de la aplicacin.
La ventana se abre finalmente llamando al mtodo Show; el resultado se muestra en la figura siguiente.

Una ventana que se abre llamando a Show es una ventana no modal, lo que significa que la aplicacin funciona
en un modo que permite a los usuarios activar otras ventanas en la misma aplicacin.
Nota:
Para abrir tales ventanas como cuadros de dilogo, modalmente, se llama a ShowDialog.
Cuando se llama a Show, una ventana realiza antes de mostrarse un trabajo de inicializacin que establece la
infraestructura necesaria para recibir la entrada del usuario. Cuando se inicializa la ventana, se provoca el
evento SourceInitialized y se muestra la ventana.
Como mtodo abreviado, se puede establecer StartupUri para especificar la primera ventana que se abre
automticamente cuando se inicia una aplicacin.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
StartupUri="PlainWindow.xaml" />
Cuando se inicia la aplicacin, la ventana especificada por el valor de StartupUri se abre de forma no modal;
internamente, la ventana se abre llamando a su mtodo Show.
Propiedad de la ventana
Una ventana que se abre utilizando el mtodo Show no tiene una relacin implcita con la ventana que la cre;
los usuarios pueden interactuar con cualquier ventana independientemente de las dems, lo que significa que
cualquier ventana puede hacer lo siguiente:

Cubrir las dems (a menos que una de las ventanas tenga su propiedad Topmost establecida en true).
Minimizarse, maximizarse y restaurarse sin afectar a las dems.

Algunas ventanas requieren una relacin con la ventana que las abre. Por ejemplo, una aplicacin Entorno de
desarrollo integrado (IDE) puede abrir ventanas de propiedades y ventanas de herramientas cuyo
comportamiento tpico es cubrir la ventana que las crea. Adems, tales ventanas siempre se deben cerrar,
minimizar, maximizar y restaurar de acuerdo con la ventana que las cre. Este tipo de relacin se puede
establecer haciendo que una ventana posea otra y se logra estableciendo la propiedad Owner de la ventana
poseda con una referencia a la ventana propietaria. Esto se muestra en el ejemplo siguiente.
// Create a window and make this window its owner
Window ownedWindow = new Window();
ownedWindow.Owner = this;
ownedWindow.Show();
Una vez establecida la propiedad:

La ventana poseda puede hacer referencia a su ventana propietaria inspeccionando el valor de su


propiedad Owner.

La ventana propietaria puede detectar todas las ventanas que posee inspeccionando el valor de su
propiedad OwnedWindows.

MCT: Luis Dueas

Pag 75 de 445

Manual de Windows Presentation Foundation


Activacin de la ventana
Cuando se abre una ventana por primera vez, se convierte en la ventana activa. La ventana activa es la
ventana que est capturando los datos proporcionados por el usuario, tales como la presin de las teclas y los
clics del mouse. Cuando una ventana se activa, provoca el evento Activated.
Nota:
Cuando una ventana se abre por primera vez, se producen los eventos Loaded y ContentRendered una vez
que se produce el evento Activated. Con esta perspectiva, una ventana puede considerarse abierta cuando
se produce ContentRendered.
Una vez que una ventana se activa, un usuario puede activar otra ventana de la misma aplicacin o activar otra
aplicacin. Cuando ocurre as, la ventana activa actualmente se desactiva y produce el evento Deactivated.
Igualmente, cuando el usuario selecciona una ventana actualmente desactivada, la ventana se vuelve a activar
y se produce Activated.
Una razn comn para administrar Activated y Deactivated es habilitar y deshabilitar funcionalidad que
solamente se puede ejecutar cuando una ventana est activa. Por ejemplo, algunas ventanas muestran
contenido interactivo que requiere constantemente los datos proporcionados por el usuario o su atencin, por
ejemplo los juegos y los reproductores de vdeo. El ejemplo siguiente es un reproductor de vdeo simplificado
que muestra cmo administrar Activated y Deactivated para implementar este comportamiento.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.CustomMediaPlayerWindow"
Activated="window_Activated"
Deactivated="window_Deactivated">
<!-- Media Player -->
<MediaElement
Name="mediaElement"
Stretch="Fill"
LoadedBehavior="Manual"
Source="numbers.wmv" />
</Window>
using System; // EventArgs
using System.Windows; // Window
namespace SDKSample
{
public partial class CustomMediaPlayerWindow : Window
{
public CustomMediaPlayerWindow()
{
InitializeComponent();
}
void window_Activated(object sender, EventArgs e)
{
// Recommence playing media if window is activated
this.mediaElement.Play();
}
void window_Deactivated(object sender, EventArgs e)
{
// Pause playing if media is being played and window is deactivated
this.mediaElement.Pause();
}
}
}
Otros tipos de aplicacin pueden continuar ejecutando cdigo en segundo plano cuando se desactiva una
ventana. Por ejemplo, un cliente de correo puede continuar sondeando el servidor de correo mientras el usuario
est utilizando otras aplicaciones. Aplicaciones como stas suelen ofrecer un comportamiento diferente o
adicional mientras la ventana principal est desactivada. Con respecto al programa de correo, esto puede
significar tanto agregar el nuevo elemento de correo a la bandeja de entrada como agregar un icono de
notificacin a la bandeja del sistema. Solamente es necesario mostrar un icono de notificacin cuando la
ventana de correo no est activa, lo que se puede determinar inspeccionando la propiedad IsActive.
Si se completa una tarea en segundo plano, puede ser preferible que una ventana avise al usuario ms
urgentemente llamando al mtodo Activate. Si el usuario est interactuando con otra aplicacin activada
cuando se llama a Activate, el botn de la barra de tareas de la ventana parpadea. Si un usuario est
interactuando con la aplicacin actual, al llamar a Activate, se trae la ventana al primero plano.

MCT: Luis Dueas

Pag 76 de 445

Manual de Windows Presentation Foundation

Nota:
Puede administrar la activacin del mbito de la aplicacin mediante los eventos Application.Activated y
Application.Deactivated.
Cerrar una ventana
La duracin de una ventana empieza a acabarse cuando un usuario la cierra. Una ventana se puede cerrar
utilizando los elementos del rea de no cliente, incluidos los siguientes:

El elemento Cerrar del men Sistema.


Presionar ALT + F4.
Presionar el botn Cerrar.

Puede proporcionar mecanismos adicionales al rea cliente para cerrar una ventana; algunos de los ms
comunes son los siguientes:

Un elemento Salir en el men Archivo, normalmente para las ventanas principales de la aplicacin.
Un elemento Cerrar en el men Archivo, normalmente en una ventana secundaria de la aplicacin.
Un botn Cancelar, normalmente en un cuadro de dilogo modal.
Un botn Cerrar, normalmente en un cuadro de dilogo no modal.

Para cerrar una ventana en respuesta a uno de estos mecanismos personalizados, debe llamar al mtodo Close.
En el ejemplo siguiente se implementa la capacidad de cerrar una ventana eligiendo Salir en el men Archivo.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.WindowWithFileExit">
<Menu>
<MenuItem Header="_File">
<MenuItem Header="E_xit" Click="fileExitMenuItem_Click" />
</MenuItem>
</Menu>
</Window>
using System.Windows; // window, RoutedEventArgs
namespace SDKSample
{
public partial class WindowWithFileExit : System.Windows.Window
{
public WindowWithFileExit()
{
InitializeComponent();
}
void fileExitMenuItem_Click(object sender, RoutedEventArgs e)
{
// Close this window
this.Close();
}
}
}
Cuando una ventana se cierra, provoca dos eventos: Closing y Closed.
Closing se provoca antes de que la ventana se cierre y proporciona un mecanismo para evitar el cierre de la
ventana. Una razn comn para evitar el cierre de la ventana es que el contenido de la ventana contenga datos
modificados. En esta situacin, se puede administrar el evento Closing para determinar si los datos se han
modificado y, en ese caso, preguntar al usuario si desea continuar cerrando la ventana sin guardar los datos o
si desea cancelar el cierre de la ventana. En el ejemplo siguiente se muestran los aspectos clave de la
administracin de Closing.
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // window
namespace CSharp
{
public partial class DataWindow : Window
{
// Is data dirty
bool isDataDirty = false;
...
void DataWindow_Closing(object sender, CancelEventArgs e)
{
MessageBox.Show("Closing called");

MCT: Luis Dueas

Pag 77 de 445

Manual de Windows Presentation Foundation


// If data is dirty, notify user and ask for a response
if (this.isDataDirty)
{
string msg = "Data is dirty. Close without saving?";
MessageBoxResult result = MessageBox.Show(msg, "Data App",
MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.No)
{
// If user doesn't want to close, cancel closure
e.Cancel = true;
}
}
}
}

}
Al controlador del evento Closing se le pasa un objeto CancelEventArgs, que implementa la propiedad
BooleanCancel que se establece en true para evitar que una ventana se cierre.
Si no se administra Closing, o se administra pero no se cancela, la ventana se cierra. El evento Closed se
produce inmediatamente antes de que una ventana se cierre realmente. En este punto, no se puede evitar que
la ventana se cierre.
Nota:
Una aplicacin se puede configurar para que se cierre automticamente cuando se cierre la ventana de la
aplicacin principal o cuando se cierre la ltima ventana.
Aunque una ventana se puede cerrar explcitamente a travs de los mecanismos proporcionados en las reas
cliente y no cliente, una ventana tambin se puede cerrar implcitamente como resultado del comportamiento
de otras partes de la aplicacin o de Windows, incluido lo siguiente:

Un usuario cierra la sesin o apaga Windows.


Se cierra la ventana propietaria de una ventana.
La ventana principal de la aplicacin se cierra y ShutdownMode es OnMainWindowClose.
Se llama a Shutdown.

Nota:
Una ventana no se puede volver a abrir una vez cerrada.
Eventos de duracin de ventana
La ilustracin siguiente muestra la secuencia de eventos principales en la duracin de una ventana.

Ubicacin de la ventana
Mientras una ventana est abierta, tiene una ubicacin en las dimensiones xe y respecto al escritorio. Esta
ubicacin se puede determinar inspeccionando las propiedades Left y Top, respectivamente. Puede establecer
estas propiedades para cambiar la ubicacin de la ventana.
Tambin puede especificar la ubicacin inicial de un objeto Window la primera vez que aparece estableciendo la
propiedad WindowStartupLocation en uno de los siguientes valores de la enumeracin WindowStartupLocation:

Manual (predeterminado)
CenterScreen
CenterOwner

MCT: Luis Dueas

Pag 78 de 445

Manual de Windows Presentation Foundation


Si la ubicacin de inicio se especifica como Manual, y no se han establecido las propiedades Left y Top, Window
preguntar a Windows dnde debe aparecer.
Ventanas de nivel superior y orden z
Adems de tener una ubicacin x e y, una ventana tiene tambin una ubicacin en la dimensin z, que
determina su posicin vertical con respecto a otras ventanas. Esto se conoce como el orden z de la ventana y
hay dos tipos: orden z normal y orden z superior. La ubicacin de una ventana en el orden z normal se
determina por si est actualmente activa o no. De forma predeterminada, una ventana se encuentra en el
orden z normal. La ubicacin de una ventana en el orden z superior tambin se determina por si est
actualmente activa o no. Adems, las ventanas del orden z superior siempre se encuentran por encima de las
ventanas del orden z normal. Una ventana se encuentra en orden z superior estableciendo su propiedad
Topmost en true.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Topmost="True">
...
</Window>
Dentro de cada orden z, ventana actualmente activa aparece por encima de todas las dems ventanas del
mismo orden z.
Tamao de la ventana
Adems de tener una ubicacin en el escritorio, una ventana tiene un tamao determinado por varias
propiedades, incluidas las diversas propiedades de alto y ancho, y SizeToContent.
MinWidth, Widthy MaxWidth se utilizan para administrar el intervalo de anchos que una ventana puede tener
durante su duracin y se configuran como se muestra en el ejemplo siguiente.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
MinWidth="300" Width="400" MaxWidth="500">
...
</Window>
El alto de la ventana se administra mediante MinHeight, Height y MaxHeight, y se configura como se muestra
en el ejemplo siguiente.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
MinHeight="300" Height="400" MaxHeight="500">
...
</Window>
Dado que los diversos valores de ancho y alto especifican cada uno un intervalo, es posible que el ancho y alto
de una ventana de tamao variable estn en cualquier punto dentro del intervalo especificado para la
dimensin respectiva. Para detectar su ancho y alto actuales, inspeccione ActualWidth y ActualHeight,
respectivamente.
Si desea que el ancho y el alto de la ventana tengan un tamao que se ajuste al tamao del contenido de la
ventana, puede utilizar la propiedad SizeToContent, que tiene los valores siguientes:

Manual. Ningn efecto (valor predeterminado).


Width. Ajustar al ancho del contenido, que tiene el mismo efecto que establecer tanto MinWidth como
MaxWidth en el ancho del contenido.

Height. Ajustar al alto del contenido, que tiene el mismo efecto que establecer MinHeight y MaxHeight
en el alto del contenido.

WidthAndHeight. Ajustar al ancho y al alto del contenido, que tiene el mismo efecto que establecer
tanto MinHeight como MaxHeight en el alto del contenido, y establecer tanto MinWidth como MaxWidth
en el ancho del contenido.

En el cdigo siguiente se muestra una ventana cuyo tamao se ajusta automticamente a su contenido, tanto
vertical como horizontalmente, cuando se muestra por primera vez.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
SizeToContent="WidthAndHeight">
...

MCT: Luis Dueas

Pag 79 de 445

Manual de Windows Presentation Foundation


</Window>
Orden de prioridad para las propiedades de tamao
Esencialmente, las diversas propiedades de tamao de una ventana se combinan para definir el intervalo de
ancho y alto para una ventana de tamao variable. Para asegurarse de que se mantenga un intervalo vlido,
Window evala los valores de las propiedades de tamao utilizando los rdenes de prioridad siguientes.
Para las propiedades de alto:
1.

FrameworkElement..MinHeight >

2.

FrameworkElement.MaxHeight >

3.

SizeToContent.Height/SizeToContent.WidthAndHeight >

4.

FrameworkElement.Height

Para las propiedades de ancho:


1.

FrameworkElement.MinWidth >

2.

FrameworkElement.MaxWidth >

3.

SizeToContent.Width/SizeToContent.WidthAndHeight >

4.

FrameworkElement.Width

El orden de prioridad tambin puede determinar el tamao de una ventana cuando se maximiza, lo que se
administra con la propiedad WindowState.
Estado de la ventana
Durante la duracin de una ventana de tamao variable, puede tener tres estados: normal, minimizado y
maximizado. Una ventana con un estado normal es el estado predeterminado de una ventana. Una ventana con
este estado permite al usuario moverla y cambiar su tamao utilizando los controladores de tamao o el borde,
si es de tamao variable.
Una ventana con el estado minimizado se contrae a su botn de la barra de tareas si ShowInTaskbar est
establecido en true; de lo contrario, se contrae al mnimo tamao posible y se reubica en la esquina inferior
izquierda del escritorio. Ningn tipo de ventana minimizada puede cambiar su tamao mediante el borde ni
controladores de tamao, aunque una ventana minimizada que no se muestre en la barra de tareas puede
arrastrarse por el escritorio.
Una ventana con un estado maximizado se expande a su tamao mximo, que solamente puede ser tan grande
como dicten sus propiedades MaxWidth, MaxHeight y SizeToContent. Como ocurre con una ventana
minimizada, no se puede cambiar el tamao de una ventana maximizada utilizando un controlador de tamao
ni arrastrando el borde.
El estado de una ventana se puede configurar estableciendo su propiedad WindowState, que puede tener uno
de los siguientes valores de la enumeracin WindowState:

Normal (predeterminado)
Maximized
Minimized

En el ejemplo siguiente se muestra cmo crear una ventana que se muestra como maximizada al abrirse.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowState="Maximized">
...
</Window>
En general, es recomendable establecer WindowState para configurar el estado inicial de una ventana. Una vez
mostrada una ventana de tamao variable, los usuarios pueden presionar los botones de minimizar, maximizar
y restablecer de la barra de ttulo de la ventana para cambiar el estado de la ventana.
Aspecto de la ventana

MCT: Luis Dueas

Pag 80 de 445

Manual de Windows Presentation Foundation


Para cambiar el aspecto del rea cliente de una ventana, agrguele contenido especfico tal como botones,
etiquetas y cuadros de texto. Para configurar el rea no cliente, Window proporciona varias propiedades, entre
las que se incluye Icon para establecer el icono de una ventana y Title para establecer su ttulo.
Tambin puede cambiar el aspecto y comportamiento del borde del rea de no cliente configurando el modo de
cambio de tamao de la ventana, su estilo y si aparece como un botn de la barra de tarea del escritorio.
Modo de cambio de tamao
En funcin de la propiedad WindowStyle, puede controlar cmo (y si) los usuarios pueden cambiar el tamao de
la ventana. La eleccin de estilo de ventana determina si un usuario puede cambiar el tamao de la ventana
arrastrando su borde con el mouse, si los botones Minimizar, Maximizar y Cambiar tamao aparecen en el rea
de no cliente, y, si aparecen, si estn habilitados.
Puede configurar cmo cambia de tamao una ventana estableciendo su propiedad ResizeMode, que puede ser
uno de los siguientes valores de la enumeracin ResizeMode:

NoResize
CanMinimize
CanResize (predeterminado)
CanResizeWithGrip

Como ocurre con WindowStyle, es improbable que el modo de cambio de tamao de una ventana cambie
durante su duracin, los que significa que probablemente se establecer desde el marcado XAML.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
ResizeMode="CanResizeWithGrip">
...
</Window>
Observe que puede detectar si una ventana est maximizada, minimizada o restaurada inspeccionando la
propiedad WindowState.
Estilo de ventana
El borde que se expone desde el rea de no cliente de una ventana es adecuado para la mayora de las
aplicaciones. Sin embargo, hay circunstancias en las que se necesitan diferentes tipos de borde, o no se
necesita ningn borde en absoluto, segn el tipo de ventana.
Para controlar qu tipo de borde obtiene una ventana, establezca su propiedad WindowStyle con uno de los
siguientes valores de la enumeracin WindowStyle:

None
SingleBorderWindow (predeterminado)
ThreeDBorderWindow
ToolWindow

El efecto de estos estilos de ventana se muestra en la figura siguiente.

MCT: Luis Dueas

Pag 81 de 445

Manual de Windows Presentation Foundation

Puede establecer WindowStyle mediante marcado XAML o mediante cdigo; dado que es improbable que
cambie durante la duracin de una ventana, lo ms probable es que lo configure utilizando el marcado XAML.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowStyle="ToolWindow">
...
</Window>
Estilo de ventana no rectangular
Tambin hay situaciones en las que los estilos de borde que permite WindowStyle no sern suficientes. Por
ejemplo, quiz desee crear una aplicacin con un borde no rectangular, como el que utiliza Microsoft Windows
Media Player.
Por ejemplo, considere la ventana de burbuja de voz que se muestra en la figura siguiente.

Este tipo de ventana se puede crear estableciendo la propiedad WindowStyle en None y utilizando la
compatibilidad especial de Window para la transparencia.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent">
...
</Window>
Esta combinacin de valores indica a la ventana que debe representarse completamente transparente. En este
estado, las opciones grficas del rea de no cliente de la ventana (el men Cerrar, los botones Minimizar,
Maximizar y Restaurar, etc.) no se pueden utilizar. Por consiguiente, necesita proporcionar opciones propias.
Presencia de la barra de tareas
El aspecto predeterminado de una ventana incluye un botn de barra de tareas, como el que se muestra en la
figura siguiente.

Algunos tipos de ventana no tienen botn de barra de tareas, como los cuadros de mensaje y los cuadros de
dilogo. Puede controlar si se muestra el botn de barra de tareas para una ventana estableciendo la propiedad
ShowInTaskbar (true de forma predeterminada).
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
ShowInTaskbar="False">
...
</Window>
Consideraciones de seguridad

MCT: Luis Dueas

Pag 82 de 445

Manual de Windows Presentation Foundation


Window requiere permiso de seguridad UnmanagedCode para crear instancias. Para las aplicaciones instaladas
en el equipo local e iniciadas desde l, esto pertenece al conjunto de permisos que se conceden a la aplicacin.
Sin embargo, esto no pertenece al conjunto de permisos concedido a las aplicaciones que se inician desde la
zona de Internet o LocalIntranet utilizando ClickOnce. Por consiguiente, los usuarios recibirn una advertencia
de seguridad ClickOnce y debern elevar permisos establecido para la aplicacin a plena confianza.
Adems, las XBAPs no pueden mostrar ventanas ni cuadros de dilogo de forma predeterminada. Para obtener
una explicacin sobre las consideraciones de seguridad de las aplicaciones independientes.
Otros tipos de ventanas
NavigationWindow es una ventana diseada para hospedar contenido navegable. Para obtener ms
informacin.
Los cuadros de dilogo son ventanas que se suelen utilizar para recopilar informacin de un usuario para
completar una funcin. Por ejemplo, cuando un usuario desea abrir un archivo, una aplicacin muestra
normalmente el cuadro de dilogo Abrir archivo para obtener el nombre de archivo del usuario.

2.3.2. Informacin General sobre Cuadros de Dilogo


Las aplicaciones independientes tienen normalmente una ventana principal, que tanto muestra los datos
principales sobre los que funciona la aplicacin como expone la funcionalidad de procesamiento de datos a
travs de mecanismos de interfaz de usuario (UI) tales como barras de mens, barras de herramientas y barras
de estado. Una aplicacin no trivial tambin puede mostrar ventanas adicionales para hacer lo siguiente:

Mostrar informacin especfica a los usuarios


Recopilar informacin de los usuarios.
Tanto mostrar como recopilar informacin.

Estos tipos de ventanas se conocen como cuadros de dilogo y hay dos tipos: modales y no modales.
Los cuadros de dilogo modales los muestras las funciones cuando necesitan datos adicionales de los usuarios
para continuar. Dado que la funcin depende del cuadro de dilogo modal para recopilar los datos, el cuadro de
dilogo modal tambin impide que un usuario active otras ventanas de la aplicacin mientras permanece
abierto. En la mayora de los casos, los cuadros de dilogo modales permiten a los usuarios sealar que han
terminado con el cuadro de dilogo modal presionando un botn Aceptar o Cancelar. Al presionar el botn
Aceptar se indica que el usuario ha introducido los datos y desea que la funcin contine su proceso con esos
datos. Presionar el botn Cancelar indica que el usuario desea detener la ejecucin de la funcin. Los ejemplos
ms comunes de cuadros de dilogo modales se muestran para abrir, guardar e imprimir datos.
Un cuadro de dilogo no modal, por otra parte, no impide que el usuario active otras ventanas mientras est
abierto. Por ejemplo, si un usuario desea buscar apariciones de una palabra determinada en un documento,
una ventana principal abrir habitualmente un cuadro de dilogo para preguntar al usuario qu palabra est
buscando. Dado que la bsqueda de una palabra no impide que un usuario edite el documento, no obstante, no
es necesario que el cuadro de dilogo sea modal. Un cuadro de dilogo no modal proporciona al menos un
botn Cerrar para cerrar el cuadro de dilogo y puede proporcionar botones adicionales para ejecutar funciones
concretas, como un botn Buscar siguiente para buscar la palabra siguiente que coincida con los criterios de
una bsqueda de palabra.
Windows Presentation Foundation (WPF) permite crear varios tipos de cuadros de dilogo, incluidos cuadros de
mensaje, cuadros de dilogo comunes y cuadros de dilogo personalizados.
Cuadros de mensaje
Un cuadro de mensaje es un cuadro de dilogo que se puede utilizar para mostrar informacin textual y
permitirles que los usuarios tomen decisiones con botones. La figura siguiente muestra un cuadro de mensaje

MCT: Luis Dueas

Pag 83 de 445

Manual de Windows Presentation Foundation


que muestra informacin textual, hace una pregunta y proporciona al usuario tres botones para responder a la
pregunta.

Para crear un cuadro de mensaje, utilice la clase MessageBox. MessageBox permite configurar el texto, el ttulo,
el icono y los botones del cuadro de mensaje, utilizando cdigo como el siguiente.
// Configure the message box to be displayed
string messageBoxText = "Do you want to save changes?";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
Para mostrar un cuadro de mensaje, llame al mtodo static Show, como se muestra en el cdigo siguiente.
Cuando el cdigo que muestra un cuadro de mensaje necesite detectar y procesar la decisin del usuario (qu
botn se presion), el cdigo puede inspeccionar el resultado del cuadro de mensaje, como se muestra en el
cdigo siguiente.
// Display message box
MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (result)
{
case MessageBoxResult.Yes:
// User pressed Yes button
// ...
break;
case MessageBoxResult.No:
// User pressed No button
// ...
break;
case MessageBoxResult.Cancel:
// User pressed Cancel button
// ...
break;
}
Aunque MessageBox puede proporcionar una experiencia simple de usuario de cuadro de dilogo, la ventaja de
utilizar MessageBox es que se trata del nico tipo de ventana que pueden mostrar las aplicaciones que se
ejecutan dentro de un recinto de seguridad confiable parcial, tal como Aplicaciones del explorador XAML
(XBAPs).
La mayora de los cuadros de dilogo muestran y recopilan datos ms complejos que el resultado de un cuadro
de mensaje, incluidos texto, selecciones (casillas), selecciones mutuamente excluyentes (botones de opcin) y
selecciones de lista (cuadros de lista, cuadros combinados, cuadros de lista desplegables). Para stos, Windows
Presentation Foundation (WPF) proporciona varios cuadros de dilogo comunes y permite crear cuadros de
dilogo propios, aunque el uso de cualquiera de ellos se limita a aplicaciones que se ejecuten con plena
confianza.
Cuadros de dilogo comunes
Windows implementa diversos cuadros de dilogo reutilizables que son comunes para todas las aplicaciones,
incluidos cuadros de dilogo para abrir archivos, guardar archivos e imprimir. Puesto que es el sistema
operativo el que implementa estos cuadros de dilogo, se pueden compartir entre todas las aplicaciones que se
ejecutan en el sistema operativo, los que contribuye a la coherencia de la experiencia del usuario; cuando los
usuarios estn familiarizados con el uso de un cuadro de dilogo proporcionado por el sistema operativo en una
aplicacin, no necesitan obtener informacin sobre cmo utilizar ese cuadro de dilogo en otras aplicaciones.
Dado que estos cuadros de dilogo estn disponibles para todas las aplicaciones y que ayudan a proporcionar
una experiencia de usuario coherente, se conocen como cuadros de dilogo comunes.

MCT: Luis Dueas

Pag 84 de 445

Manual de Windows Presentation Foundation


Windows Presentation Foundation (WPF) encapsula el archivo abierto, excepto el archivo, e imprime los cuadros
de dilogo comunes y los expone como clases administradas para que los utilice en aplicaciones
independientes. En este tema se proporciona una breve informacin general sobre:
Abrir archivo (Dilogo)
La funcionalidad de apertura de archivos utiliza el cuadro de dilogo de apertura de archivos, que se muestra
en la figura siguiente, para recuperar el nombre de un archivo a abrir.

El cuadro de dilogo comn de apertura de archivos se implementa como la clase OpenFileDialog y se


encuentra en el espacio de nombres Microsoft.Win32. El cdigo siguiente muestra cmo crear, configurar y
mostrar uno, y cmo procesar el resultado.
// Configure open file dialog box
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
}
Nota:
OpenFileDialog se puede utilizar para recuperar sin ningn riesgo los nombres de archivo por aplicaciones
que se ejecutan con confianza parcial.
Guardar archivo (Cuadro de dilogo)
La funcionalidad de guardado de archivos utiliza el cuadro de dilogo de guardado de archivos, que se muestra
en la figura siguiente, para recuperar el nombre de un archivo a guardar.

MCT: Luis Dueas

Pag 85 de 445

Manual de Windows Presentation Foundation

El cuadro de dilogo comn de guardado de archivos se implementa como la clase SaveFileDialog y se


encuentra en el espacio de nombres Microsoft.Win32. El cdigo siguiente muestra cmo crear, configurar y
mostrar uno, y cmo procesar el resultado.
// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".text"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension
// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog box results
if (result == true)
{
// Save document
string filename = dlg.FileName;
}
Imprimir (Cuadro de dilogo)
La funcionalidad de impresin de archivos utiliza el cuadro de dilogo de impresin de archivos, que se muestra
en la figura siguiente, para elegir y configurar la impresora en la que el usuario desea imprimir datos.

El cuadro de dilogo comn de impresin de archivos se implementa como la clase PrintDialog y se encuentra
en el espacio de nombres System.Windows.Controls. El cdigo siguiente muestra cmo crear, configurar y
mostrar uno.
Cuadros de dilogo personalizados

MCT: Luis Dueas

Pag 86 de 445

Manual de Windows Presentation Foundation


Aunque los cuadros de dilogo comunes son tiles, y se deben utilizar cuando sea posible, no satisfacen las
necesidades de los cuadros de dilogo especficos de dominio. En estos casos, es necesario crear cuadros de
dilogo propios. Cuando veremos, un cuadro de dilogo es una ventana con comportamientos especiales.
Window implementa esos comportamientos y, por consiguiente, utiliza Window para crear cuadros de dilogo
modales y no modales personalizados.
Crear un cuadro de dilogo personalizado modal
En este tema se muestra cmo utilizar Window para crear una implementacin de un cuadro de dilogo modal
tpico, utilizando el cuadro de dilogo Margins como ejemplo. El cuadro de dilogo Margins se muestra en la
figura siguiente.

Configurar un cuadro de dilogo modal


La interfaz de usuario de un cuadro de dilogo tpico incluye lo siguiente:

Los diversos controles necesarios para recopilar los datos deseados.


Mostrar un botn Aceptar en el que los usuarios hacen clic para cerrar el cuadro de dilogo, volver a la
funcin y continuar el proceso.

Mostrar un botn Cancelar en el que los usuarios hagan clic para cerrar el cuadro de dilogo y hacer
que la funcin detenga el proceso.

Mostrar un botn Cerrar en la barra de ttulo.


Mostrar un icono.
Mostrar botones Minimizar, Maximizary Restaurar.
Mostrar un men Sistema para minimizar, maximizar, restaurar y cerrar el cuadro de dilogo.
Apertura encima y en el centro de la ventana que abri el cuadro de dilogo.
Los cuadros de dilogo deben ser de tamao variable cuando sea posible de modo que, para evitar que
resulten ser demasiado pequeos y para proporcionar al usuario un tamao predeterminado til,
deber establecer tanto unas dimensiones predeterminadas como unas dimensiones mnimas.

Es recomendable configurar la accin de presionar la tecla ESC como un mtodo abreviado de teclado
que haga que se presione el botn Cancelar. Esto se logra estableciendo la propiedad IsCancel del
botn Cancelar en true.

Es recomendable configurar la accin de presionar la tecla Entrar (o Retorno) como un mtodo


abreviado de teclado que provoca que se presione el botn Aceptar. Esto se logra estableciendo la
propiedad IsDefault del botn Aceptar en true.

El cdigo siguiente muestra esta configuracin.


<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MarginsDialogBox"
xmlns:local="clr-namespace:SDKSample"
Title="Margins"
Height="190"
Width="300"
MinHeight="10"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">
<Grid>
...
<!-- Accept or Cancel -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
<Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>

MCT: Luis Dueas

Pag 87 de 445

Manual de Windows Presentation Foundation


<Button Name="cancelButton" IsCancel="True">Cancel</Button>
</StackPanel>
</Grid >
</Window>
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
Public Sub New()
Me.InitializeComponent()
End Sub
End Class
End Namespace
La experiencia del usuario en un cuadro de dilogo se extiende tambin a la barra de mens de la ventana que
abre el cuadro de dilogo. Cuando un elemento de men ejecuta una funcin que requiere interaccin con el
usuario a travs de un cuadro de dilogo antes de que la funcin pueda continuar, el elemento de men para la
funcin tendr puntos suspensivos en su encabezado, como se muestra aqu.
<!--Main Window-->
...
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..."
Click="formatMarginsMenuItem_Click" />
Cuando un elemento de men ejecute una funcin que muestre un cuadro de dilogo que no requiera
interaccin con el usuario, como un cuadro de dilogo Acerca de, los puntos suspensivos no son necesarios.
Abrir un cuadro de dilogo modal
Un cuadro de dilogo se muestra normalmente como resultado de la seleccin de un elemento de men, por
parte de un usuario, para realizar una funcin especfica del dominio, tal como establecer los mrgenes de un
documento en un procesador de textos. Mostrar una ventana como un cuadro de dilogo es similar a mostrar
una ventana normal, aunque requiere la configuracin adicional especfica del cuadro de dilogo. El proceso
completo de crear instancias, configurar y abrir un cuadro de dilogo se muestra en el cdigo siguiente.
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As
RoutedEventArgs)
' Instantiate the dialog box
Dim dlg As New MarginsDialogBox
' Configure the dialog box
dlg.Owner = Me
dlg.DocumentMargin = Me.documentTextBox.Margin
' Open the dialog box modally
dlg.ShowDialog()
End Sub
End Class
End Namespace
Aqu, el cdigo est pasando informacin predeterminada (los mrgenes actuales) al cuadro de dilogo.
Tambin est estableciendo la propiedad Window..::.Owner con una referencia a la ventana que est
mostrando el cuadro de dilogo. En general, siempre se debe establecer el propietario de un cuadro de dilogo
para ofrecer comportamientos relacionados con el estado de la ventana que son comunes a todos los cuadros
de dilogo.
Nota:
Para que sea posible la automatizacin interfaz de usuario (UI) para cuadros de dilogo debe proporcionar
un propietario.
Una vez configurado el cuadro de dilogo, se mostrar modalmente llamando al mtodo ShowDialog.
Validar datos proporcionados por el usuario
Cuando se abre un cuadro de dilogo y el usuario proporciona los datos necesarios, el cuadro de dilogo es
responsable de asegurarse que los datos proporcionados sean vlidos por las razones siguientes:

Desde la perspectiva de la seguridad, todas las entradas se deben validar.

MCT: Luis Dueas

Pag 88 de 445

Manual de Windows Presentation Foundation

Desde la perspectiva especfica del dominio, la validacin de datos impide que el cdigo procese datos
errneos, lo que podra iniciar excepciones.

Desde la perspectiva de un usuario, un cuadro de dilogo puede ayudar a los usuarios mostrndoles
qu datos de los introducidos no son vlidos.

Desde la perspectiva del rendimiento, la validacin de datos en una aplicacin de varios niveles puede
reducir el nmero de viajes de ida y vuelta entre los niveles de cliente y de aplicacin, en particular
cuando la aplicacin se compone de servicios web o bases de datos basadas en servidor.

Para validar un control enlazado en WPF, debe definir una regla de validacin y asociarla al enlace. Una regla de
validacin es una clase personalizada derivada de ValidationRule. El ejemplo siguiente muestra una regla de
validacin, MarginValidationRule, que comprueba que un valor enlazado es Double y est dentro de un intervalo
especificado.
Imports System.Globalization
Imports System.Windows.Controls
Namespace SDKSample
Public Class MarginValidationRule
Inherits ValidationRule
Private _maxMargin As Double
Private _minMargin As Double
Public Property MaxMargin() As Double
Get
Return Me._maxMargin
End Get
Set(ByVal value As Double)
Me._maxMargin = value
End Set
End Property
Public Property MinMargin() As Double
Get
Return Me._minMargin
End Get
Set(ByVal value As Double)
Me._minMargin = value
End Set
End Property
Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As
CultureInfo) As ValidationResult
Dim margin As Double
' Is a number?
If Not Double.TryParse(CStr(value), margin) Then
Return New ValidationResult(False, "Not a number.")
End If
' Is in range?
If ((margin < Me.MinMargin) OrElse (margin > Me.MaxMargin)) Then
Dim msg As String = String.Format("Margin must be between {0} and {1}.",
Me.MinMargin, Me.MaxMargin)
Return New ValidationResult(False, msg)
End If
' Number is valid
Return New ValidationResult(True, Nothing)
End Function
End Class
End Namespace
En este cdigo, la lgica de validacin de una regla de validacin se implementa invalidando el mtodo Validate,
que valida los datos y devuelve el objeto ValidationResult correspondiente.
Para asociar la regla de validacin al control enlazado, utilice el marcado siguiente.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MarginsDialogBox"
xmlns:local="clr-namespace:SDKSample"
Title="Margins"
Height="190"
Width="300"
MinHeight="10"
MinWidth="300"
ResizeMode="CanResizeWithGrip"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">
<Grid>
...
<Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
<TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
<TextBox.Text>
<Binding Path="Left" UpdateSourceTrigger="PropertyChanged">

MCT: Luis Dueas

Pag 89 de 445

Manual de Windows Presentation Foundation


<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
...
</Window>
Una vez asociada la regla de validacin, WPF lo aplicar automticamente cuando se introduzcan los datos en el
control enlazado. Cuando un control contenga datos no vlidos, WPF mostrar un borde rojo alrededor del
control no vlido, como se muestra en la figura siguiente.

WPF no restringe a un usuario al control no vlido hasta que haya introducido datos vlidos. sta es una buena
prctica para un cuadro de dilogo; un usuario debe poder navegar libremente por los controles de un cuadro
de dilogo tanto si los datos son vlidos como si no. Sin embargo, esto significa que un usuario puede
introducir datos no vlidos y presionar el Aceptar botn. Por esta razn, el cdigo necesita adems validar
todos los controles del cuadro de dilogo cuando se presione el botn Aceptar, controlando el evento Click.
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Don't accept the dialog box if there is invalid data
If Not Me.IsValid(Me) Then Return
End Sub
' Validate all dependency objects in a window
Private Function IsValid(ByVal node As DependencyObject) As Boolean
' Check if dependency object was passed and if dependency object is valid.
' NOTE: Validation.GetHasError works for controls that have validation rules attached
If ((Not node Is Nothing) AndAlso Validation.GetHasError(node)) Then
' If the dependency object is invalid, and it can receive the focus,
' set the focus
If TypeOf node Is IInputElement Then
Keyboard.Focus(DirectCast(node, IInputElement))
End If
Return False
End If
' If this dependency object is valid, check all child dependency objects
Dim subnode As Object
For Each subnode In LogicalTreeHelper.GetChildren(node)
If (TypeOf subnode Is DependencyObject AndAlso Not
Me.IsValid(DirectCast(subnode, DependencyObject))) Then
' If a child dependency object is invalid, return false immediately,
' otherwise keep checking
Return False
End If
Next
' All dependency objects are valid
Return True
End Function
End Class
End Namespace
Este cdigo enumera todos los objetos de dependencia de una ventana y, si hay alguno que no es vlido (si
devuelve GetHasError, el control no vlido obtiene el foco, el mtodo IsValid devuelve false y la ventana se
considera no vlida.
Cuando un cuadro de dilogo es vlido, se puede cerrar y devolver sin ningn riesgo. Como parte del proceso
de retorno, debe devolver un resultado a la funcin que realiza la llamada.
Establecer el resultado del dilogo modal
Abrir un cuadro de dilogo mediante ShowDialog es fundamentalmente como llamar a un mtodo: el cdigo
que abri el cuadro de dilogo mediante ShowDialog espera hasta que vuelva ShowDialog. Cuando vuelve

MCT: Luis Dueas

Pag 90 de 445

Manual de Windows Presentation Foundation


ShowDialog, el cdigo que lo llam debe decidir si contina o detiene el procesamiento, segn si el usuario
presion el botn Aceptar o el botn Cancelar. Para facilitar esta decisin, el cuadro de dilogo debe devolver la
opcin del usuario como un valor Boolean que se devuelve desde el mtodo ShowDialog.
Cuando se hace clic en el botn Aceptar, ShowDialog debe devolver true. Esto se logra estableciendo la
propiedad DialogResult del cuadro de dilogo al hacer clic en el botn Aceptar.
Tenga en cuenta que establecer la propiedad DialogResult tambin hace que la ventana se cierre
automticamente, los que elimina la necesidad de llamar explcitamente a Close.
Cuando se hace clic en el botn Cancelar, ShowDialog debe devolver false, que tambin requiere que se
establezca la propiedad DialogResult.
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Dialog box canceled
Me.DialogResult = False
End Sub
End Class
End Namespace
Cuando la propiedad IsCancel de un botn se establece en true y el usuario presiona el botn Cancelar o la
tecla ESC, DialogResult se establece automticamente en false. El marcado siguiente tiene el mismo efecto que
el cdigo anterior, sin la necesidad de administrar el evento Click.
<Button Name="cancelButton" IsCancel="True">Cancel</Button>
Un cuadro de dilogo devuelve automticamente true cuando un usuario presiona el botn Cerrar de la barra de
ttulo o elige el elemento de men Cerrar en el men Sistema.
Procesar datos devueltos desde un cuadro de dilogo modal
Cuando un cuadro de dilogo establece DialogResult, la funcin que lo abri puede obtener el resultado del
cuadro de dilogo inspeccionando la propiedad DialogResult cuando vuelve ShowDialog.
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As
RoutedEventArgs)
' Process data entered by user if dialog box is accepted
If (dlg.DialogResult.GetValueOrDefault = True) Then
Me.documentTextBox.Margin = dlg.DocumentMargin
End If
End Sub
End Class
End Namespace
Si el resultado del dilogo es true, la funcin lo utiliza como indicacin para recuperar y procesar los datos
proporcionados por el usuario.
Nota:
Una vez que vuelve ShowDialog, no se puede volver a abrir el cuadro de dilogo. En su lugar, debe crear
una nueva instancia.
Si el resultado del dilogo es false, la funcin debe finalizar el procesamiento correctamente.
Crear un cuadro de dilogo personalizado no modal
Un cuadro de dilogo no modal, tal como el cuadro de dilogo Buscar que se muestra en la figura siguiente,
tiene el mismo aspecto fundamental que un cuadro de dilogo modal.

MCT: Luis Dueas

Pag 91 de 445

Manual de Windows Presentation Foundation

Sin embargo, su comportamiento es ligeramente diferente, como se describe en las secciones siguientes.
Abrir un cuadro de dilogo no modal
Un cuadro de dilogo no modal se abre llamando al mtodo Show.
<!--Main Window-->
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
Private Sub editFindMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim dlg As New FindDialogBox(Me.documentTextBox)
dlg.Owner = Me
AddHandler dlg.TextFound, New TextFoundEventHandler(AddressOf Me.dlg_TextFound)
dlg.Show()
End Sub
A diferencia de ShowDialog, Show vuelve inmediatamente. Por consiguiente, la ventana que realiza la llamada
no puede distinguir cundo se cierra el cuadro de dilogo no modal y, en consecuencia, no sabe cundo
comprobar los resultados del cuadro de dilogo o recibir los datos del cuadro de dilogo para continuar el
procesamiento. En su lugar, el cuadro de dilogo debe crear una manera alternativa de devolver datos a la
ventana que realiza la llamada para el procesamiento.
Procesar datos devueltos desde un cuadro de dilogo no modal
En este ejemplo, FindDialogBox puede devolver uno o ms resultados de bsqueda a la ventana principal, segn
el texto que se est buscando, sin ninguna frecuencia concreta. Como con un cuadro de dilogo modal, un
cuadro de dilogo no modal puede devolver resultados mediante propiedades. Sin embargo, la ventana que
posee el cuadro de dilogo necesita saber cundo debe comprobar esas propiedades. Una manera de habilitar
esto es que el cuadro de dilogo implemente un evento que se produzca siempre que se encuentre el texto.

FindDialogBox implementa TextFoundEvent para este propsito, que requiere primero un delegado.
Namespace SDKSample
Public Delegate Sub TextFoundEventHandler(ByVal sender As Object, ByVal e As EventArgs)
End Namespace
Con el delegado TextFoundEventHandler, FindDialogBox implementa TextFoundEvent.
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
Public Event TextFound As TextFoundEventHandler
Protected Overridable Sub OnTextFound()
RaiseEvent TextFound(Me, EventArgs.Empty)
End Sub
End Class
End Namespace
Por consiguiente, Find puede provocar el evento cuando se encuentra un resultado de bsqueda.
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
Private Sub findNextButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.Index = match.Index
Me.Length = match.Length
RaiseEvent TextFound(Me, EventArgs.Empty)

MCT: Luis Dueas

Pag 92 de 445

Manual de Windows Presentation Foundation


End Sub
End Class
End Namespace
La ventana propietaria necesita entonces registrarse con este evento y administrarlo.
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
Namespace SDKSample
Public Class MainWindow
Inherits Window
Private Sub dlg_TextFound(ByVal sender As Object, ByVal e As EventArgs)
Dim dlg As FindDialogBox = DirectCast(sender, FindDialogBox)
Me.documentTextBox.Select(dlg.Index, dlg.Length)
Me.documentTextBox.Focus()
End Sub
End Class
End Namespace
Cerrar un cuadro de dilogo no modal
Dado que no es necesario establecer DialogResult, un dilogo no modal se puede cerrar utilizando los
mecanismos proporcionados por el sistema, que incluyen los siguientes:

Hacer clic en el botn Cerrar en la barra de ttulo.


Presionar ALT + F4.
Elegir Cerrar en el men Sistema.

Como alternativa, el cdigo puede llamar a Close cuando se haga clic en el botn Cerrar.
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
Private Sub closeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
MyBase.Close()
End Sub
End Class
End Namespace

2.3.3. Temas Cmo de la Administracin de Ventanas


En los temas siguientes se muestra cmo administrar ventanas de Windows Presentation Foundation (WPF).

2.3.3.1. Cmo: Cambiar Automticamente el Tamao de una Ventana para que


se Ajuste a su Contenido
En este ejemplo se muestra cmo establecer la propiedad SizeToContent para especificar cmo cambia de
tamao una ventana para ajustarse a su contenido.
Ejemplo
// Manually alter window height and width
this.SizeToContent = SizeToContent.Manual;
// Automatically resize width relative to content
this.SizeToContent = SizeToContent.Width;
// Automatically resize height relative to content
this.SizeToContent = SizeToContent.Height;
// Automatically resize height and width relative to content
this.SizeToContent = SizeToContent.WidthAndHeight;

2.3.3.2. Cmo: Obtener Todas las Ventanas de una Aplicacin


En este ejemplo se muestra cmo obtener todos los objetos Window de una aplicacin.
Ejemplo
Cada objeto Window del que se crea una instancia, est visible o no, se agrega automticamente a una
coleccin de referencias a ventanas administrada por Application y expuesta en la propiedad Windows.
Puede enumerar Windows para obtener todas las ventanas con instancias mediante el cdigo siguiente:
foreach( Window window in Application.Current.Windows ) {

MCT: Luis Dueas

Pag 93 de 445

Manual de Windows Presentation Foundation


Console.WriteLine(window.Title);
}

2.3.3.3. Cmo: Obtener y Establecer la Ventana Principal de una Aplicacin


En este ejemplo se muestra cmo obtener y establecer la ventana principal de la aplicacin.
Ejemplo
Application establece automticamente el primer objeto Window del que se crea una instancia en una aplicacin
Windows Presentation Foundation (WPF) como la ventana principal de la aplicacin. El primer objeto Window
del que se crea una instancia ser, probablemente, la ventana que se especifica como identificador de recursos
uniforme (URI) de inicio.
Tambin se puede crear una instancia del primer objeto Window mediante cdigo. Un ejemplo de ello es la
apertura de una ventana al iniciar una aplicacin, como se muestra a continuacin:
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
MainWindow window = new MainWindow();
window.Show();
}
}
A veces, el primer objeto Window del que se crea una instancia no es realmente la ventana principal de la
aplicacin; por ejemplo, una pantalla de presentacin. En este caso, puede especificar la ventana principal de la
aplicacin mediante marcado, como se muestra a continuacin:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="StartupWindow.xaml"
>
<Application.MainWindow>
<NavigationWindow Source="MainPage.xaml" Visibility="Visible"></NavigationWindow>
</Application.MainWindow>
</Application>
Independientemente de si se especifica la ventana principal automtica o manualmente, puede obtenerla de
MainWindow utilizando el cdigo siguiente, como se muestra a continuacin:
// Get the main window
Window mainWindow = this.MainWindow;

2.3.3.4. Cmo: Abrir un Cuadro de Dilogo


En este ejemplo se muestra cmo abrir un cuadro de dilogo.
Ejemplo
Un cuadro de dilogo es una ventana que se abre creando una instancia de Window y llamando al mtodo
ShowDialog. ShowDialog abre una ventana y no vuelve hasta que se cierra el nuevo cuadro de dilogo. Este
tipo de ventana tambin se denomina ventana modal, y restringe los datos proporcionados por el usuario.
CustomDialogBox dialogBox = new CustomDialogBox();
dialogBox.ShowDialog(); // Returns when dialog box has closed
Seguridad
Para poder llamar a ShowDialog se necesita permiso para usar todas las ventanas y todos los eventos de datos
proporcionados por el usuario sin restricciones.

2.3.3.5. Cmo: Abrir un Cuadro de Mensaje


En este ejemplo se muestra cmo abrir un cuadro de mensaje.
Ejemplo
Un cuadro de mensaje es un cuadro de dilogo modal prefabricado para mostrar informacin a los usuarios. Un
cuadro de mensaje se abre llamando al mtodo Show esttico de la clase MessageBox. Cuando se llama a
Show, se pasa el mensaje mediante un parmetro de cadena. Varias sobrecargas de Show permiten configurar
cmo aparecer el cuadro de mensaje.

MCT: Luis Dueas

Pag 94 de 445

Manual de Windows Presentation Foundation


void showMessageBoxButton_Click(object sender, RoutedEventArgs e) {
// Configure message box
string message = "Hello, MessageBox!";
// Show message box
MessageBoxResult result = MessageBox.Show(message);
}

2.3.3.6. Cmo: Abrir una Ventana


En este ejemplo se muestra cmo abrir una ventana.
Ejemplo
Una ventana se abre creando una instancia de Window y llamando al mtodo Show. Show abre una ventana y
vuelve inmediatamente, sin esperar a que se cierre la nueva ventana. Este tipo de ventana tambin se
denomina ventana no modal y no restringe los datos proporcionados por el usuario.
CustomWindow window = new CustomWindow();
window.Show(); // Returns immediately

2.3.3.7. Cmo: Devolver el Resultado de un Cuadro de Dilogo


En este ejemplo se muestra cmo recuperar el resultado del cuadro de dilogo de una ventana que se abre
llamando a ShowDialog.
Ejemplo
Antes de que un cuadro de dilogo se cierre, su propiedad DialogResult se debe establecer en un tipo Boolean
Nullable<(Of <(T>)>) que indica cmo lo ha cerrado el usuario. ShowDialog devuelve este valor para permitir
que el cdigo de cliente determine cmo se cerr el cuadro de dilogo y, por consiguiente, cmo procesar el
resultado.
Nota:
DialogResult nicamente se puede establecer si una ventana se abri llamando a ShowDialog.
DialogBoxWithResult dialogBoxWithResult = new DialogBoxWithResult();
// Open dialog box and retrieve dialog result when ShowDialog returns
bool? dialogResult = dialogBoxWithResult.ShowDialog();
switch (dialogResult)
{
case true:
// User accepted dialog box
break;
case false:
// User canceled dialog box
break;
default:
// Indeterminate
break;
}

2.4. Navegacin en Aplicaciones de Windows Presentation Foundation


Las aplicaciones de Windows Presentation Foundation (WPF) suelen estar compuestas de una coleccin de
pginas. Cuando el usuario progresa a travs de la aplicacin, navega de una pgina a otra, de un modo muy
similar a una aplicacin web. La navegacin constituye, en esencia, una manera sencilla de cargar y
representar una "pgina de destino" seleccionada.

2.4.1. Informacin General sobre Navegacin


Windows Presentation Foundation (WPF) permite una navegacin similar a la de los exploradores en dos tipos
de aplicaciones: las aplicaciones independientes y las Aplicaciones del explorador XAML (XBAPs). Para
empaquetar el contenido de la navegacin, WPF proporciona la clase Page. Puede navegar desde un objeto
Page a otro mediante declaracin a travs de un Hyperlink o mediante programacin a travs de
NavigationService. WPF utiliza el diario para recordar las pginas desde y a las que se ha navegado.
Page, Hyperlink, NavigationService y el diario son los componentes esenciales de la compatibilidad de
navegacin proporcionada por WPF. En esta introduccin se describen detalladamente estas caractersticas

MCT: Luis Dueas

Pag 95 de 445

Manual de Windows Presentation Foundation


antes de abordar el tema de la compatibilidad de navegacin avanzada, que incluye la navegacin a archivos
Lenguaje de marcado de aplicaciones extensible (XAML) independientes, a archivos HTML y a objetos.
Nota:
En este tema, el trmino "explorador" hace referencia nicamente a los exploradores que pueden hospedar
aplicaciones WPF, que actualmente son Internet Explorer 7, Microsoft Internet Explorer 6 y Firefox 2.0+.
Cuando slo se admiten determinadas caractersticas de WPF en un explorador concreto, se hace referencia
a la versin del explorador.
Navegacin en aplicaciones de WPF
En este tema se proporciona informacin general sobre las funciones de navegacin principales en WPF. Estas
funciones estn disponibles para las aplicaciones independientes y XBAPs, aunque en este tema se describen en
el contexto de XBAP.
Nota:
En este tema no se explica cmo generar e implementar XBAPs.
Implementar una pgina
En WPF, puede navegar a varios tipos de contenido, como objetos, objetos personalizados, valores de
enumeracin y controles de usuario de .NET Framework, archivos XAML y archivos HTML. Sin embargo,
descubrir que la forma ms comn y til de empaquetar contenido consiste en utilizar Page. Adems, Page
implementa caractersticas especficas de la navegacin para mejorar la apariencia y simplificar el desarrollo.
Con Page, puede implementar mediante declaracin una pgina navegable de contenido XAML utilizando
marcado como el siguiente.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />
Un objeto Page que se implementa en marcado XAML tiene Page como su elemento raz y requiere la
declaracin de espacio de nombres WPFXML. El elemento Page incluye el contenido al que desea navegar y que
desea mostrar. El contenido se agrega estableciendo el elemento de propiedad Page.Content, como se muestra
en el marcado siguiente.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Page.Content>
<!-- Page Content -->
Hello, Page!
</Page.Content>
</Page>
Page.Content slo puede contener un elemento secundario; en el ejemplo anterior, el contenido es una sola
cadena, "Hello, Page!". En la prctica, utilizar normalmente un control de dise;o como elemento secundario
para incluir y crear el contenido.
Se considera que los elementos secundarios de un elemento Page son el contenido de Page y, por tanto, no
necesita utilizar la declaracin Page.Content explcita. El siguiente marcado es el equivalente declarativo del
ejemplo anterior.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<!-- Page Content -->
Hello, Page!
</Page>
En este caso, Page.Content se establece automticamente con los elementos secundarios del elemento Page.
Un objeto Page de slo marcado sirve para mostrar contenido. Sin embargo, un objeto Page puede mostrar
tambin controles que permitan a los usuarios interactuar con la pgina, y puede responder a la interaccin del
usuario controlando eventos y la lgica de la aplicacin de llamada. Un objeto Page interactivo se implementa
mediante una combinacin de marcado y cdigo subyacente, como se muestra en el ejemplo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.HomePage">
Hello, from the XBAP HomePage!
</Page>
using System.Windows.Controls; // Page
namespace SDKSample
{

MCT: Luis Dueas

Pag 96 de 445

Manual de Windows Presentation Foundation


public partial class HomePage : Page
{
public HomePage()
{
InitializeComponent();
}
}
}
Para permitir que un archivo de marcado y un archivo de cdigo subyacente funcionen conjuntamente, se
requiere la siguiente configuracin:

En el marcado, el elemento Page debe incluir el atributo x:Class. Al generar la aplicacin, la existencia
de x:Class en el archivo de marcado permite que Microsoft build engine (MSBuild) cree una clase
partial que se derive de Pagey tenga el nombre especificado por el atributo x:Class. Para ello, es
necesario

agregar

una

declaracin

de

espacio

de

(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml").

nombres
La

clase

XML

para

partial

el

esquema

generada

XAML

implementa

InitializeComponent, al que se llama para registrar los eventos y establecer las propiedades que se
implementan en el marcado.

En el archivo de cdigo subyacente, la clase debe ser una clase partial con el mismo nombre que el
que especific el atributo x:Class en el marcado, y debe derivarse de Page. Esto permite que el archivo
de cdigo subyacente se asocie a la clase partial que se genera para el archivo de marcado cuando se
crea la aplicacin.

En el archivo de cdigo subyacente, la clase Page debe implementar un constructor que llame al
mtodo InitializeComponent. InitializeComponent se implementa mediante la clase partial generada
del archivo de marcado para registrar eventos y establecer las propiedades que se definen en el
marcado.

Nota:
Al agregar un nuevo objeto Page a su proyecto con Microsoft Visual Studio, se implementa Page utilizando
el marcado y el cdigo subyacente; este control incluye la configuracin necesaria para crear la asociacin
entre los archivos de cdigo subyacente y de marcado tal como aqu se describe.
Cuando ya tenga un objeto Page, podr navegar a l. Para especificar el primer objeto Page al que navega una
aplicacin, necesita configurar el objeto Page de inicio.
Configurar una pgina de inicio
Las XBAPs exigen que una determinada cantidad de infraestructura de la aplicacin est hospedada en un
explorador. En WPF, la clase Application forma parte de una definicin de aplicacin que establece la
infraestructura de aplicacin necesaria.
Una definicin de aplicacin se suele implementar mediante marcado y cdigo subyacente, con el archivo de
marcado configurado como un elemento ApplicationDefinition de MSBuild. A continuacin, se incluye una
definicin de aplicacin para XBAP.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App" />
using System.Windows; // Application
namespace SDKSample
{
public partial class App : Application { }
}
XBAP puede utilizar su definicin de aplicacin para especificar un objeto Page de inicio, que es el objeto
Page que se carga automticamente cuando se inicia XBAP. Para ello, se establece la propiedad StartupUri con
el identificador de recursos uniforme (URI) del objeto Page deseado.
Nota:
Normalmente, el objeto Page se compila o se implementa con una aplicacin. En tales casos, el URI que
identifica un objeto Page es un pack URI, que es un URI compatible con el esquema pack. Tambin puede
navegar al contenido mediante el esquema http, que se describe a continuacin.
Puede establecer StartupUri mediante declaracin en el marcado, como se muestra en el ejemplo siguiente.

MCT: Luis Dueas

Pag 97 de 445

Manual de Windows Presentation Foundation


<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.App"
StartupUri="PageWithHyperlink.xaml" />
En este ejemplo, el atributo StartupUri se establece con un pack URI relativo que identifica HomePage.xaml.
Cuando se inicia XBAP, se navega automticamente a HomePage.xaml y se muestra. Esto se muestra en la
ilustracin siguiente, en la que se inicia una XBAP desde un servidor web.

Configurar el ttulo, ancho y alto de la ventana host


Es posible que haya advertido que en la figura anterior el ttulo del explorador y del panel de fichas es el URI de
la XBAP. Adems de largo, el ttulo no tiene un aspecto atractivo ni aporta informacin. Por este motivo, Page
proporciona un modo de cambiar el ttulo estableciendo la propiedad WindowTitle. Asimismo, puede configurar
el ancho y alto de la ventana del explorador estableciendo WindowWidth y WindowHeight, respectivamente.
Puede establecer WindowTitle, WindowWidth y WindowHeight mediante declaracin en el marcado, como se
muestra en el ejemplo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.HomePage"
WindowTitle="Page Title"
WindowWidth="500"
WindowHeight="200">
Hello, from the XBAP HomePage!
</Page>
El resultado se muestra en la ilustracin siguiente.

Navegacin por hipervnculos


Una XBAP tpica comprende varias pginas. La manera ms simple de navegar de una pgina a otra es utilizar
un objeto Hyperlink. Puede agregar mediante declaracin un objeto Hyperlink a Page utilizando el elemento
Hyperlink, que se muestra en el marcado siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page With Hyperlink"
WindowWidth="250"
WindowHeight="250">
...
<Hyperlink NavigateUri="UriOfPageToNavigateTo.xaml">
Navigate to Another Page
</Hyperlink>
...
</Page>
Un elemento Hyperlink requiere lo siguiente:

El pack URI del objeto Page al que se va navegar, especificado por el atributo NavigateUri.

MCT: Luis Dueas

Pag 98 de 445

Manual de Windows Presentation Foundation

El contenido en el que un usuario puede hacer clic para iniciar la navegacin, como texto e imgenes
(para saber qu contenido se puede incluir en el elemento Hyperlink).

En la ilustracin siguiente se muestra una XBAP con Page que tiene un objeto Hyperlink.

Como era de prever, al hacer clic en Hyperlink XBAP se desplaza al control Page, identificado por el atributo
NavigateUri. Adems, la XBAP agrega una entrada para el objeto Page anterior a la lista Pginas recientes de
Internet Explorer 7. Esto se muestra en la ilustracin siguiente.

Adems de permitir la navegacin de un objeto Page a otro, Hyperlink admite la navegacin por fragmentos.
Navegacin por fragmentos
La navegacin por fragmentos es la navegacin a un fragmento de contenido en el objeto Page u otro objeto
Page. En WPF, un fragmento de contenido es el contenido incluido en un elemento con nombre. Un elemento
con nombre es un elemento que tiene establecido su atributo Name. En el marcado siguiente se muestra un
elemento TextBlock con nombre que contiene un fragmento de contenido.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page With Fragments" >
...
<!-- Content Fragment called "Fragment1" -->
<TextBlock Name="Fragment1">
Ea vel dignissim te aliquam facilisis ...
</TextBlock>
...
</Page>
Para que un objeto Hyperlink navegue a un fragmento de contenido, el atributo NavigateUri debe incluir lo
siguiente:

El URI del objeto Page con el fragmento de contenido al que se va a navegar.


Un carcter "#".
El nombre del elemento del objeto Page que contiene el fragmento de contenido.

Un URI de fragmento tiene el siguiente formato.


URIdePgina # NombreDeElemento
A continuacin, se muestra un ejemplo de un objeto Hyperlink configurado para navegar a un fragmento de
contenido.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page That Navigates To Fragment" >
...
<Hyperlink NavigateUri="PageWithFragments.xaml#Fragment1">
Navigate To pack Fragment
</Hyperlink>
...
</Page>
Nota:

MCT: Luis Dueas

Pag 99 de 445

Manual de Windows Presentation Foundation

En esta seccin se describe la implementacin de navegacin por fragmentos predeterminada en WPF. WPF
permite tambin implementar un esquema de navegacin por fragmentos propio, que requiere
parcialmente que se controle el evento NavigationService.FragmentNavigation.
Nota importante:
Slo puede navegar a fragmentos en pginas XAML independientes (archivos de XAML de slo marcado con
Page como elemento raz) si las pginas se pueden examinar mediante HTTP.
Sin embargo, una pgina XAML independiente puede navegar a sus propios fragmentos.
Servicio de navegacin
Aunque Hyperlink permite que un usuario inicie la navegacin en un objeto Page determinado, la clase
NavigationService es la encargada de buscar y descargar la pgina. Bsicamente, NavigationService
proporciona la capacidad de procesar una solicitud de navegacin en nombre de cdigo cliente, como Hyperlink.
Adems, NavigationService implementa la compatibilidad de nivel superior para realizar el seguimiento y dirigir
las solicitudes de navegacin.
Al hacer clic en Hyperlink, WPF llama a NavigationService.Navigate para buscar y descargar el objeto Page en el
pack URI especificado. El objeto Page descargado se convierte en un rbol de objetos cuyo objeto raz es una
instancia del objeto Page descargado. En la propiedad NavigationService.Content se almacena una referencia al
objeto

Page raz.

El

pack

URI

del

contenido

al

que

se

naveg

se

almacena

en

la

propiedad

NavigationService.Source, mientras que NavigationService.CurrentSource almacena el pack URI de la ltima


pgina a la que se naveg.
Nota:
Es posible que una aplicacin de WPF tenga ms de un objeto NavigationService actualmente activo.
Navegacin mediante programacin con el servicio de navegacin
No necesita conocer NavigationService si la navegacin se implementa mediante declaracin en el marcado
utilizando Hyperlink, porque Hyperlink utiliza NavigationService en su nombre. Esto significa que, siempre y
cuando el elemento primario directo o indirecto de Hyperlink sea un host de navegacin, Hyperlink podr
buscar y utilizar el servicio de navegacin del host de desplazamiento para procesar una solicitud de
navegacin.
Sin embargo, hay situaciones en las que tendr que usar NavigationService directamente, como las siguientes:

Cuando tenga que crear una instancia de Page utilizando un constructor no predeterminado.
Cuando tenga que establecer propiedades en el objeto Page antes de navegar a l.
Cuando el objeto Page al que hay que navegar slo pueda determinarse en tiempo de ejecucin.

En estas situaciones, deber escribir cdigo para iniciar la navegacin mediante programacin llamando al
mtodo Navigate del objeto NavigationService. Para ello, es necesario obtener una referencia a un objeto
NavigationService.
Obtener una referencia a NavigationService
Por los motivos explicados en la seccin Hosts de navegacin, una aplicacin de WPF puede tener ms de un
objeto

NavigationService.

Esto

implica

que

el

cdigo

necesita

un

modo

de

encontrar

un

objeto

NavigationService, que normalmente es el objeto NavigationService que ha navegado al objeto Page


actual. Puede

obtener

una

referencia

un

objeto

NavigationService

llamando

al

mtodo

static

GetNavigationService. Para obtener el objeto NavigationService que naveg a un objeto Page determinado,
tendr que pasar una referencia al objeto Page como argumento del mtodo GetNavigationService. En el
ejemplo de cdigo siguiente se muestra cmo obtener el NavigationService para el objeto Page actual.
using System.Windows.Navigation; // NavigationServce
...
// Get a reference to the NavigationService that navigated to this Page
NavigationService ns = NavigationService.GetNavigationService(this);
Para simplificar la bsqueda de un NavigationService para un objeto Page, Page implementa la propiedad
NavigationService. Esto se muestra en el ejemplo siguiente.

MCT: Luis Dueas

Pag 100 de 445

Manual de Windows Presentation Foundation


using System.Windows.Navigation; // NavigationServce
...
// Get a reference to the NavigationService that navigated to this Page
NavigationService ns = this.NavigationService;
Nota:
Un objeto Page slo puede obtener una referencia a su NavigationService cuando Page provoca el evento
Loaded.
Navegacin mediante programacin a un objeto Page
En el ejemplo siguiente se muestra cmo utilizar el objeto NavigationService para navegar a un objeto Page
mediante programacin. Se requiere la navegacin mediante programacin porque slo se puede crear una
instancia del control Page al que se navega mediante un constructor no predeterminado. El objeto Page con el
constructor no predeterminado se muestra en el siguiente marcado y cdigo.
<Page
x:Class="SDKSample.PageWithNonDefaultConstructor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="PageWithNonDefaultConstructor">
<!-- Content goes here -->
</Page>
using System.Windows.Controls; // Page
namespace SDKSample
{
public partial class PageWithNonDefaultConstructor : Page
{
public PageWithNonDefaultConstructor(string message)
{
InitializeComponent();
this.Content = message;
}
}
}
El objeto Page que navega al objeto Page con el constructor no predeterminado se muestra en el siguiente
marcado y cdigo.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.NSNavigationPage">
<Hyperlink Click="hyperlink_Click">
Navigate to Page with Non-Default Constructor
</Hyperlink>
</Page>
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService
namespace SDKSample
{
public partial class NSNavigationPage : Page
{
public NSNavigationPage()
{
InitializeComponent();
}
void hyperlink_Click(object sender, RoutedEventArgs e)
{
// Instantiate the page to navigate to
PageWithNonDefaultConstructor page = new PageWithNonDefaultConstructor("Hello!");
// Navigate to the page, using the NavigationService
this.NavigationService.Navigate(page);
}
}
}
Al hacer clic en el objeto Hyperlink de este Page, se inicia la navegacin mediante la creacin de una instancia
del objeto Page al que se va a navegar con el constructor no predeterminado y llamando al mtodo Navigate.
Navigate acepta una referencia al objeto al que va a navegar el NavigationService, en lugar de un pack URI.
Navegacin mediante programacin con un pack URI
Si necesita crear un Pack URI mediante programacin (por ejemplo, cuando slo pueda determinar el Pack URI
en tiempo de ejecucin), puede utilizar el mtodo Navigate. Esto se muestra en el ejemplo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.NSUriNavigationPage">

MCT: Luis Dueas

Pag 101 de 445

Manual de Windows Presentation Foundation


<Hyperlink Click="hyperlink_Click">Navigate to Page by Pack URI</Hyperlink>
</Page>
using System; // Uri, UriKind
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService
namespace SDKSample
{
public partial class NSUriNavigationPage : Page
{
public NSUriNavigationPage()
{
InitializeComponent();
}
void hyperlink_Click(object sender, RoutedEventArgs e)
{
// Create a pack URI
Uri uri = new Uri("AnotherPage.xaml", UriKind.Relative);
// Get the navigation service that was used to
// navigate to this page, and navigate to
// AnotherPage.xaml
this.NavigationService.Navigate(uri);
}
}
}
Actualiza la pgina actual
Un objeto Page no se descarga si tiene el mismo pack URI que el pack URI almacenado en la propiedad Source.
Para forzar a WPF a que descargue de nuevo la pgina actual, puede llamar al mtodo Refresh, como se
muestra en el ejemplo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.NSRefreshNavigationPage">
<Hyperlink Click="hyperlink_Click">Refresh this page</Hyperlink>
</Page>
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService
namespace SDKSample
{
public partial class NSRefreshNavigationPage : Page
{
void hyperlink_Click(object sender, RoutedEventArgs e)
{
// Force WPF to download this page again
this.NavigationService.Refresh();
}
}
}
Duracin de la navegacin
Como puede ver, hay muchas formas de iniciar la navegacin. Cuando se inicia la navegacin, y mientras la
navegacin est en curso, puede controlar y dirigir la navegacin mediante los eventos siguientes
implementados por NavigationService:

Navigating. Se produce cuando se solicita una nueva navegacin. Se puede utilizar para cancelar la
navegacin.

NavigationProgress. Se produce peridicamente durante una descarga para proporcionar informacin


sobre el progreso de la navegacin.

Navigated. Se produce cuando la pgina se ha encontrado y descargado.


NavigationStopped. Se produce cuando se detiene la navegacin (llamando al mtodo StopLoading), o
cuando se solicita una nueva navegacin mientras la navegacin actual est en curso.

NavigationFailed. Se produce cuando surge un error al navegar al contenido solicitado.


LoadCompleted. Se produce cuando se ha cargado, se ha analizado y se ha empezado a representar el
contenido al que se naveg.

FragmentNavigation. Se produce cuando se inicia la navegacin a un fragmento de contenido, que


tiene lugar:

Inmediatamente, si el fragmento deseado est en el contenido actual.


Una vez cargado el contenido de origen, si el fragmento deseado est en contenido diferente.

Los eventos de navegacin se provocan en el orden que se indica en la siguiente ilustracin.

MCT: Luis Dueas

Pag 102 de 445

Manual de Windows Presentation Foundation

En general, los objetos Page no tienen que ocuparse de estos eventos. Es ms probable que una aplicacin
tenga que ocuparse de ellos, razn por la cual la clase Application provoca tambin estos eventos:

Application.Navigating
Application.NavigationProgress
Application.Navigated
Application.NavigationFailed
Application.NavigationStopped
Application.LoadCompleted
Application.FragmentNavigation

Cada vez que NavigationService provoca un evento, la clase Application provoca el evento correspondiente.
Frame y NavigationWindow ofrecen los mismos eventos para detectar la navegacin dentro de sus mbitos
respectivos.
En algunos casos, un objeto Page podra tener que ocuparse de estos eventos. Por ejemplo, un objeto Page
podra controlar el evento Navigating para determinar si debe cancelar o no la navegacin fuera del propio
objeto. Esto se muestra en el ejemplo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.CancelNavigationPage">
<Button Click="button_Click">Navigate to Another Page</Button>
</Page>
using System; // Uri, UriKind
using System.Windows; // RoutedEventArgs, MessageBox, MessageBoxResult
using System.Windows.Controls; // Page
using System.Windows.Navigation; // NavigationService, NavigatingCancelEventArgs
namespace SDKSample
{
public partial class CancelNavigationPage : Page
{
public CancelNavigationPage()
{
InitializeComponent();
// Can only access the NavigationService when the page has been loaded
this.Loaded += new RoutedEventHandler(CancelNavigationPage_Loaded);
this.Unloaded += new RoutedEventHandler(CancelNavigationPage_Unloaded);
}
void button_Click(object sender, RoutedEventArgs e)
{
// Force WPF to download this page again
this.NavigationService.Navigate(new Uri("AnotherPage.xaml",
UriKind.Relative));
}
void CancelNavigationPage_Loaded(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigating += new
NavigatingCancelEventHandler(NavigationService_Navigating);
}
void CancelNavigationPage_Unloaded(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigating -= new
NavigatingCancelEventHandler(NavigationService_Navigating);
}
void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
// Does the user really want to navigate to another page?

MCT: Luis Dueas

Pag 103 de 445

Manual de Windows Presentation Foundation

MessageBoxResult result;
result = MessageBox.Show("Do you want to leave this page?", "Navigation
Request", MessageBoxButton.YesNo);
// If the user doesn't want to navigate away, cancel the navigation
if (result == MessageBoxResult.No) e.Cancel = true;

}
}
Si registra un controlador con un evento de navegacin desde un objeto Page, como en el ejemplo anterior,
tambin debe cancelar el registro del controlador de eventos. Si no lo hace, se podran producir efectos
secundarios relacionados con el modo en que la navegacin de WPF recuerda la navegacin de Page a travs
del diario.
Recordar la navegacin con el diario
WPF utiliza dos pilas para recordar las pginas desde las que se ha navegado: una pila de retroceso y una pila
de avance. Al navegar desde el objeto Page actual a un nuevo objeto Page o avanzar a un objeto Page
existente, el objeto Page actual se agrega a la pila de retroceso. Al retroceder desde el objeto Page al
objeto Page anterior, el objeto Page se agrega a la pila de avance. La pila de retroceso, la pila de avance y las
funciones para administrar estas pilas reciben en conjunto el nombre de diario. Cada elemento de la pila de
retroceso y de la pila de avance es una instancia de la clase JournalEntry y se hace referencia a l como una
entrada del diario.
Navegar por el diario desde Internet Explorer 7
Conceptualmente, el diario funciona de la misma manera que los botones Atrs y Adelante de Internet Explorer
7. Este comportamiento se muestra en la siguiente ilustracin.

Para las XBAPs hospedadas por Internet Explorer 7, WPF integra el diario en la interfaz de usuario de
navegacin de Internet Explorer 7. Esto permite que los usuarios naveguen a pginas de una aplicacin XBAP
mediante los botones Atrs, Adelante y Pginas recientes de Internet Explorer 7. El diario no se integra en
Microsoft Internet Explorer 6 del mismo modo que en Internet Explorer 7. En lugar de ello, WPF representa una
interfaz de usuario de navegacin alternativa.
Nota importante:
En Internet Explorer 7, cuando un usuario sale y vuelve a una XBAP, slo se conservan en el diario las
entradas de las pginas que no se mantuvieron activas.
De forma predeterminada, el texto de cada Page que aparece en la lista Pginas recientes de Internet Explorer
7 es el URI de Page. En muchos casos, esto no le resulta particularmente significativo al usuario.
Afortunadamente, puede cambiar el texto mediante una las opciones siguientes:
1.

El valor del atributo JournalEntry.Name asociado.

2.

El valor del atributo Page.Title.

3.

El valor del atributo Page.WindowTitle y el URI del objeto Page actual.

4.

El URI del objeto Page actual. (Opcin predeterminada).

El orden en que se indican las opciones es el mismo que el orden de prioridad de la bsqueda de texto. Por
ejemplo, si se establece JournalEntry.Name, se omiten los dems valores.
En el ejemplo siguiente se utiliza el atributo Page.Title para cambiar el texto que aparece para una entrada del
diario.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

MCT: Luis Dueas

Pag 104 de 445

Manual de Windows Presentation Foundation


xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.PageWithTitle"
Title="This is the title of the journal entry for this page.">
...
</Page>
using System.Windows.Controls; // Page
namespace SDKSample
{
public partial class PageWithTitle : Page
{
...
}
}
Navegar por el diario mediante WPF
Aunque un usuario puede navegar por el diario mediante los botones Atrs, Adelante y Pginas recientes de
Internet Explorer 7, tambin puede utilizar para tal fin los mecanismos declarativos y de programacin
proporcionados por WPF. Esto puede ser necesario, por ejemplo, para proporcionar una UIs de navegacin
personalizada en sus pginas.
Puede permitir mediante declaracin la navegacin por el diario utilizando los comandos de navegacin
expuestos por NavigationCommands. En el siguiente ejemplo se muestra cmo utilizar el comando de
navegacin BrowseBack.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.NavigationCommandsPage">
...
<Hyperlink Command="NavigationCommands.BrowseBack">Back</Hyperlink>
...
</Page>
Puede navegar por el diario mediante programacin utilizando alguno de los miembros siguientes de la clase
NavigationService:

GoBack
GoForward
CanGoBack
CanGoForward

El diario se puede manipular tambin mediante programacin.


Duracin y diario de pginas
Considere una XBAP con varias pginas que alojan contenido avanzado, como grficos, animacin y elementos
multimedia. La superficie de memoria durante la duracin de estos elementos podra ser bastante grande,
sobre todo si se utilizan elementos multimedia de audio y vdeo. Como el diario "recuerda" las pginas a las que
se ha navegado, una XBAP podra utilizar una cantidad considerable de memoria rpidamente.
Por esta razn, el comportamiento predeterminado del diario es almacenar los metadatos de Page en cada
entrada del diario en lugar de una referencia a un objeto Page. Cuando se navega a una entrada del diario, se
utilizan sus metadatos de Page para crear una nueva instancia del objeto Page especificado. Por consiguiente,
cada objeto Page visitado tiene la duracin que se muestra en la siguiente ilustracin.

Aunque el uso del comportamiento del diario predeterminado puede ahorrar memoria, podra dar lugar a una
reduccin del rendimiento de la representacin de cada pgina, ya que crear una nueva instancia de un objeto
Page puede ser laborioso, especialmente si tiene mucho contenido. Si necesita conservar una instancia de Page

MCT: Luis Dueas

Pag 105 de 445

Manual de Windows Presentation Foundation


en el diario, puede utilizar dos tcnicas para ello. En primer lugar, puede navegar mediante programacin a un
objeto Page llamando al mtodo Navigate.
En segundo lugar, puede especificar que WPF conserve una instancia de Page en el diario estableciendo la
propiedad KeepAlive en true (el valor predeterminado es false). Como se muestra en el ejemplo siguiente,
puede establecer KeepAlive mediante declaracin en el marcado.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.KeepAlivePage"
KeepAlive="True">
An instance of this page is stored in the journal.
</Page>
La duracin de un objeto Page que se mantiene activo es ligeramente diferente al de uno inactivo. La primera
vez que se navega a un objeto Page que se mantiene activo, se crea una instancia de dicho objeto, como
ocurre con un objeto Page que no se mantiene activo. Sin embargo, como se conserva una instancia de Page en
el diario, no se vuelve a crear nunca ms una nueva instancia mientras sta permanezca en el diario. Por tanto,
si un objeto Page contiene lgica de inicializacin a la que hay que llamar cada vez que se navega a Page,
deber mover esa lgica del constructor a un controlador del evento Loaded. Como se muestra en la ilustracin
siguiente, los eventos Loaded y Unloaded se provocan igualmente cada vez que se navega a y desde un objeto
Page, respectivamente.

Cuando un objeto Page no se mantiene activo, no debe realizar ninguna de las operaciones siguientes:

Almacenar una referencia al objeto o a alguna parte del mismo.


Registrar controladores de eventos con eventos no implementados por el objeto.

Si realiza alguna de estas operaciones, crear referencias que obliguen al objeto Page a conservarse en
memoria, incluso despus de que se quite del diario.
En general, debera optar por el comportamiento Page predeterminado, que no mantiene el objeto Page activo.
Sin embargo, este comportamiento tiene implicaciones que afectan al estado, descritas en la siguiente seccin.
Conservar el estado del contenido con el historial de navegacin
Si un objeto Page no se mantiene activo y tiene controles que recopilan datos del usuario, qu ocurre con los
datos si un usuario avanza y retrocede al objeto Page? Desde la perspectiva de la experiencia del usuario, el
usuario debe esperar ver los datos que especific previamente. Desgraciadamente, como se crea una nueva
instancia de Page con cada navegacin, se crean nuevas instancias de los controles que recopilaron los datos y
los datos se pierden.
Por fortuna, el diario proporciona compatibilidad para recordar los datos durante la navegacin por Page,
incluidos los datos de los controles. En concreto, la entrada del diario de cada Page acta como un contenedor
temporal para el estado de Page asociado. En los pasos siguientes se explica brevemente cmo funciona esta
compatibilidad cuando se navega desde un objeto Page:
1.
2.

Se agrega una entrada del objeto Page actual al diario.


El estado del objeto Page se almacena con la entrada del diario de esa pgina, que se agrega a la pila
de retroceso.

3.

Se navega al nuevo objeto Page.

Cuando se retrocede al objeto Page, gracias al diario, se producen las siguientes operaciones:
1.

Se crea una instancia de Page (la entrada superior del diario en la pila de retroceso).

MCT: Luis Dueas

Pag 106 de 445

Manual de Windows Presentation Foundation


2.

El objeto Page se actualiza con el estado que se almacen con la entrada del diario para el objeto
Page.

3.

Se retrocede al objeto Page.

WPF utiliza automticamente esta compatibilidad cuando se utilizan los controles siguientes en un objeto Page:

CheckBox
ComboBox
Expander
Frame
ListBox
ListBoxItem
MenuItem
ProgressBar
RadioButton
Slider
TabControl
TabItem
TextBox

Si un objeto Page utiliza estos controles, los datos registrados en ellos se recuerdan durante la navegacin por
Page, como se muestra en Favorite colorListBox en la ilustracin siguiente.

Cuando un objeto Page tiene controles distintos de los de la lista anterior, o cuando el estado se almacena en
objetos personalizados, debe escribir cdigo que permita al diario recordar el estado durante la navegacin por
Page.
Si necesita recordar peque;os segmentos de estado durante la navegacin por Page, puede utilizar
propiedades

de

dependencia

que

se

configuran

con

el

marcador

de

metadatos

de

FrameworkPropertyMetadata.Journal.
Si el estado que el objeto Page necesita recordar durante la navegacin consta de varios segmentos de datos,
puede resultarle ms sencillo encapsular el estado en una clase nica e implementar la interfaz
IProvideCustomContentState.
Si necesita desplazarse por varios estados de un mismo objeto Page, sin navegar desde el propio objeto Page,
puede utilizar IProvideCustomContentState y NavigationService.AddBackEntry.
Cookies

MCT: Luis Dueas

Pag 107 de 445

Manual de Windows Presentation Foundation


Otro modo en que las aplicaciones de WPF pueden almacenar datos es mediante cookies, que se crean,
actualizan y eliminan con los mtodos SetCookie y GetCookie. Las cookies que puede crear en WPF son las
mismas cookies que utilizan otros tipos de aplicaciones web; las cookies son segmentos arbitrarios de datos
que almacena una aplicacin en un equipo cliente durante una o varias sesiones. Los datos de las cookies
normalmente son pares de nombre y valor con el formato siguiente.
Nombre = Valor
Cuando se pasan los datos a SetCookie, junto con el Uri de la ubicacin para la que se debe establecer la
cookie, se crea una cookie en memoria, y slo est disponible durante la sesin de la aplicacin actual. Este
tipo de cookie se denomina cookie de sesin.
Para almacenar una cookie en varias sesiones de la aplicacin, debe agregarse una fecha de expiracin a la
cookie, con el formato siguiente.
NAME = VALOR ; expires=DAY, DD-MMM-YYYY HH:MM:SS GMT
Una cookie con fecha de expiracin se almacena en la carpeta Archivos temporales de Internet de la instalacin
de Windows hasta que la cookie expira. Este tipo de cookie se denomina cookie persistente porque se conserva
durante las sesiones de la aplicacin.
Puede recuperar las cookies de sesin y persistentes llamando al mtodo GetCookie, pasando el Uri de la
ubicacin donde se estableci la cookie con el mtodo SetCookie.
A continuacin, se indican algunas de las formas en que se admiten cookies en WPF:

Las aplicaciones de WPF independientes y las XBAPs pueden crear y administrar cookies.
Se puede tener acceso a las cookies creadas por una XBAP desde el explorador.
Las XBAPs del mismo dominio pueden crear y compartir cookies.
Las XBAPs y las pginas HTML del mismo dominio pueden crear y compartir cookies.
Las cookies se envan cuando las XBAPs y las pginas XAML independientes crean solicitudes web.
Las XBAPs de alto nivel y las XBAPs hospedadas en IFRAMES pueden tener acceso a las cookies.
La compatibilidad de las cookies en WPF es la misma para todos los exploradores compatibles
(Internet Explorer 7, Microsoft Internet Explorer 6 y Firefox 2.0+).

En Microsoft Internet Explorer 6 e Internet Explorer 7, WPF aplica la directiva P3P relacionada con las
cookies, especialmente en relacin con las XBAPs propias y de otros fabricantes.

Navegacin estructurada
Si necesita pasar datos de un objeto Page a otro, puede pasarlos como argumentos a un constructor no
predeterminado de Page. Tenga en cuenta que si utiliza esta tcnica, debe mantener el objeto Page activo ya
que, de lo contrario, la prxima vez que navegue al objeto Page, WPF crear una nueva instancia del objeto
Page mediante el constructor predeterminado.
Page puede implementar tambin propiedades que se establezcan con los datos que debe pasar. Sin embargo,
las cosas se complican cuando un objeto Page tiene que volver a pasar datos al objeto Page que naveg a l. El
problema reside en que la navegacin no permite de forma nativa mecanismos que garanticen que se vuelva a
un

objeto

Page

una

vez

abandonado.

Esencialmente,

la

navegacin

no

admite

la

semntica

de

llamada/devolucin. Para resolver este problema, WPF proporciona la clase PageFunction<(Of <(T>)>), que se
puede utilizar para garantizar que se vuelva a un objeto Page de un modo previsible y estructurado.
La clase NavigationWindow
Llegados a este punto, ya se han abordado los servicios de navegacin que probablemente utilizar con ms
frecuencia para crear aplicaciones con contenido navegable. Estos servicios se describen en el contexto de
XBAPs, pero no se limitan a XBAPs. Los sistemas operativos modernos y las aplicaciones de Windows

MCT: Luis Dueas

Pag 108 de 445

Manual de Windows Presentation Foundation


aprovechan la experiencia de los usuarios con el uso de los exploradores para incorporar una navegacin
similar a la de un explorador en las aplicaciones independientes. Algunos ejemplos comunes son los siguientes:

Diccionario de sinnimos de Word: navegacin por opciones de palabras.


Explorador de archivos: navegacin por archivos y carpetas.
Asistentes: descomposicin de una tarea compleja en varias pginas por las que se puede navegar. Un
ejemplo es el Asistente para componentes de Windows que controla la incorporacin y eliminacin de
caractersticas de Windows.

Para incorporar una navegacin similar a la de los exploradores en sus aplicaciones independientes, puede usar
la clase NavigationWindow. NavigationWindow se deriva de Window y se extiende con la misma compatibilidad
de navegacin proporcionada por las XBAPs. Puede utilizar NavigationWindow como la ventana principal de su
aplicacin independiente o como una ventana secundaria (por ejemplo, un cuadro de dilogo).
Para implementar NavigationWindow, al igual que con la mayora de las clases de nivel superior de WPF
(Window, Page, etc.), se utiliza una combinacin de marcado y cdigo subyacente. Esta implementacin se
muestra en el ejemplo siguiente.
<NavigationWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.MainWindow"
Source="HomePage.xaml"/>
using System.Windows.Navigation; // NavigationWindow
namespace SDKSample
{
public partial class MainWindow : NavigationWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}
Este cdigo crea un objeto NavigationWindow que navega automticamente a un objeto Page (HomePage.xaml)
cuando se abre NavigationWindow. Si NavigationWindow es la ventana principal de la aplicacin, puede utilizar
el atributo StartupUri para iniciarla. Esto queda reflejado en el marcado siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="MainWindow.xaml" />
En la ilustracin siguiente se muestra el objeto NavigationWindow como la ventana principal de una aplicacin
independiente.

En la ilustracin, puede ver que NavigationWindow tiene un ttulo, aunque no se estableci en el cdigo de
implementacin de NavigationWindow del ejemplo anterior. El ttulo se establece mediante la propiedad
WindowTitle, que se muestra en el cdigo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="Home Page"
WindowTitle="NavigationWindow">
...
</Page>
El establecimiento de propiedades WindowWidth y WindowHeight afecta tambin al objeto NavigationWindos.
Normalmente, implementar su propio NavigationWindow cuando necesite personalizar su comportamiento o su
apariencia. Si no es el caso, hay una alternativa ms simple. Si especifica el pack URI de un objeto Page como
StartupUri en una aplicacin independiente, Application crea automticamente un objeto NavigationWindow
para hospedar el objeto Page. Esta operacin se muestra en el marcado siguiente.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

MCT: Luis Dueas

Pag 109 de 445

Manual de Windows Presentation Foundation


StartupUri="HomePage.xaml" />
Si desea que una ventana de la aplicacin secundaria como un cuadro de dilogo sea un objeto
NavigationWindow, puede utilizar el cdigo del ejemplo siguiente para abrirla.
// Open a navigation window as a dialog box
NavigationWindowDialogBox dlg = new NavigationWindowDialogBox();
dlg.Source = new Uri("HomePage.xaml", UriKind.Relative);
dlg.Owner = this;
dlg.ShowDialog();
En la ilustracin siguiente se muestra el resultado.

Como puede ver, NavigationWindow muestra los botones Atrs y Adelante con el formato de Internet Explorer
7, que permiten a los usuarios navegar por el diario. Estos botones proporcionan la misma experiencia del
usuario, como se muestra en la ilustracin siguiente.

Si sus pginas proporcionan su propia compatibilidad e interfaz de usuario de navegacin por el diario, puede
ocultar los botones Atrs y Adelante mostrados por NavigationWindow estableciendo el valor de la propiedad
ShowsNavigationUI en false. Tambin puede utilizar la compatibilidad de personalizacin de WPF para
reemplazar la interfaz de usuario del propio NavigationWindow.
La clase Frame
Tanto el explorador como NavigationWindow son ventanas que hospedan contenido navegable. En algunos
casos, las aplicaciones tienen contenido que no necesita hospedarse en una ventana completa. Este contenido
se puede hospedar dentro de otro contenido. Puede insertar contenido navegable en otro contenido utilizando la
clase Frame. Frame proporciona la misma compatibilidad que NavigationWindow y XBAPs.
En el ejemplo siguiente se muestra cmo agregar mediante declaracin un objeto Frame a Page con el
elemento Frame.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page that Hosts a Frame"
WindowWidth="250"
WindowHeight="250">
...
<Frame Source="FramePage1.xaml" />
...
</Page>
Este marcado establece el atributo Source del elemento Frame con un pack URI para el Page al que Frame debe
navegar inicialmente. En la ilustracin siguiente se muestra una XBAP con un objeto Page que tiene un Frame
que ha navegado por varias pginas.

MCT: Luis Dueas

Pag 110 de 445

Manual de Windows Presentation Foundation

No slo tiene que utilizar Frame dentro del contenido de un objeto Page. Tambin es habitual hospedar un
Frame dentro del contenido de un objeto Window.
De forma predeterminada, Frame slo utiliza su propio diario si no existe ningn otro. Si un Frame forma parte
del contenido que se hospeda dentro de un objeto NavigationWindow o de una XBAP, Frame utiliza el diario que
pertenece a NavigationWindow o XBAP. Sin embargo, en algunas ocasiones, es posible que un objeto Frame
tenga que ocuparse de su propio diario. Esto se muestra en la ilustracin siguiente.

En este caso, puede configurar el objeto Frame para que utilice su propio diario estableciendo la propiedad
JournalOwnership de Frame en OwnsJournal. Esto queda reflejado en el marcado siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page that Hosts a Frame"
WindowWidth="250"
WindowHeight="250">
...
<Frame Source="FramePage1.xaml" JournalOwnership="OwnsJournal" />
...
</Page>
En la ilustracin siguiente se muestra el efecto de navegar dentro de un objeto Frame que utiliza su propio
diario.

Observe que es la interfaz de usuario de navegacin de Frame y no Internet Explorer 7 la que muestra las
entradas del diario.
Nota:
Si un objeto Frame forma parte del contenido hospedado en Window, Frame utiliza su propio diario y, por
tanto, presenta su propia interfaz de usuario de navegacin.
Si la experiencia de usuario requiere que un objeto Frame proporcione su propio diario sin mostrar la interfaz
de

usuario

de

navegacin,

puede

ocultar

la

interfaz

de

usuario

de

navegacin

estableciendo

NavigationUIVisibility en Hidden. Esto queda reflejado en el marcado siguiente.


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page that Hosts a Frame"
WindowWidth="250"

MCT: Luis Dueas

Pag 111 de 445

Manual de Windows Presentation Foundation


WindowHeight="250">
...
<Frame
Source="FramePage1.xaml"
JournalOwnership="OwnsJournal"
NavigationUIVisibility="Hidden" />
...
</Page>
Hosts de navegacin
Frame y NavigationWindow son clases que se denominan hosts de navegacin. Un host de navegacin es una
clase que puede navegar a contenido y mostrarlo. Para tal fin, cada host de navegacin utiliza su propio
NavigationService y diario. La creacin bsica de un host de navegacin se muestra en la ilustracin siguiente.

Bsicamente, este host permite que NavigationWindow y Frame proporcionen la misma compatibilidad de
navegacin que la que proporciona una XBAP cuando se hospeda en el explorador.
Adems de utilizar NavigationService y un diario, los hosts de navegacin implementan los mismos miembros
que implementa NavigationService. Esto se muestra en la ilustracin siguiente.

Esto permite programar directamente en ellos la compatibilidad de navegacin. Puede considerar esta opcin si
necesita proporcionar una interfaz de usuario de navegacin personalizada para un objeto Frame hospedado en
Window. Adems, ambos tipos implementan miembros adicionales relacionados con la navegacin, entre los
que

se

incluyen

BackStack

(NavigationWindow.BackStack,

Frame.BackStack)

ForwardStack

(NavigationWindow.ForwardStack, Frame.ForwardStack), que permiten enumerar las entradas del diario en la


pila de retroceso y en la pila de avance, respectivamente.
Como se indic anteriormente, puede haber varios diarios en una aplicacin. En la ilustracin siguiente se
proporciona un ejemplo de esta circunstancia.

Navegar a contenido distinto de pginas


A lo largo de este tema, se han utilizado Page y XBAPs de paquete para mostrar las distintas opciones de
navegacin de WPF. Sin embargo, un objeto Page compilado en una aplicacin no es el nico tipo de contenido
al que se puede navegar, y las XBAPs de paquete no constituyen el nico modo de identificar contenido.

MCT: Luis Dueas

Pag 112 de 445

Manual de Windows Presentation Foundation


Como se muestra en esta seccin, puede navegar tambin a archivos XAML independientes, a archivos HTML y
a objetos.
Navegar a archivos XAML independientes
Un archivo XAML independiente es un archivo con las caractersticas siguientes:

Slo contiene XAML (es decir, no contiene cdigo).


Tiene una declaracin de espacio de nombres adecuada.
Tiene la extensin de nombre de archivo .xaml.

Considere, por ejemplo, el contenido siguiente que est almacenado como un archivo XAML independiente,
Person.xaml.
<!-- Person.xaml -->
<TextBlock xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<TextBlock FontWeight="Bold">Name:</TextBlock>
<TextBlock>Nancy Davolio</TextBlock>
<LineBreak />
<TextBlock FontWeight="Bold">Favorite Color:</TextBlock>
<TextBlock>Yellow</TextBlock>
</TextBlock>
Al hacer doble clic en el archivo, el explorador se abre, se desplaza al contenido y lo muestra. Este
comportamiento se muestra en la ilustracin siguiente.

Puede mostrar un archivo XAML independiente desde los siguientes elementos:

Un sitio web en el equipo local, la intranet o Internet.


Un recurso compartido de archivos Convencin de nomenclatura universal (UNC).
El disco local.

Un archivo XAML independiente se puede agregar a los favoritos del explorador o convertirse en la pgina
principal del explorador.
Una limitacin de los archivos XAML independientes es que slo permiten hospedar contenido que se pueda
ejecutar de forma segura en una relacin de confianza parcial. Por ejemplo, Window no puede ser el elemento
raz de un archivo XAML independiente.
Navegar a archivos HTML
Como cabe esperar, tambin es posible navegar a HTML. Slo tiene que proporcionar un URI que utilice el
esquema http. Por ejemplo, el XAML siguiente muestra un objeto Frame que navega a una pgina HTML.
<Frame Source="http://www.microsoft.com/default.aspx" />
Para navegar a HTML se requieren permisos especiales. Por ejemplo, no puede navegar desde una XBAP que se
ejecute en el recinto de seguridad de confianza parcial de la zona de Internet.
Navegar a objetos personalizados
Si tiene datos que estn almacenados como objetos personalizados, una manera de mostrar esos datos es
crear un objeto Page con contenido enlazado a esos objetos. Si puede prescindir del trabajo adicional que
supone crear una pgina completa para mostrar simplemente los objetos, puede navegar directamente a ellos.
Considere la clase Person que se implementa en el cdigo siguiente.
using System.Windows.Media; // Color
namespace SDKSample
{
public class Person
{
string name;
Color favoriteColor;

MCT: Luis Dueas

Pag 113 de 445

Manual de Windows Presentation Foundation


public Person() { }
public Person(string name, Color favoriteColor)
{
this.name = name;
this.favoriteColor = favoriteColor;
}
public string Name
{
get { return this.name; }
set { this.name = value; }
}
public Color FavoriteColor
{
get { return this.favoriteColor; }
set { this.favoriteColor = value; }
}
}
}
Para navegar a ella, llama al mtodo NavigationWindow.Navigate, como se muestra en el cdigo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.HomePage"
WindowTitle="Page that Navigates to an Object">
...
<Hyperlink Name="hyperlink" Click="hyperlink_Click">
Navigate to Nancy Davolio
</Hyperlink>
...
</Page>
using System.Windows; // RoutedEventArgs
using System.Windows.Controls; // Page
using System.Windows.Media; // Colors
namespace SDKSample
{
public partial class HomePage : Page
{
public HomePage()
{
InitializeComponent();
}
void hyperlink_Click(object sender, RoutedEventArgs e)
{
Person person = new Person("Nancy Davolio", Colors.Yellow);
this.NavigationService.Navigate(person);
}
}
}
En la ilustracin siguiente se muestra el resultado.

En esta ilustracin, puede ver que no se muestra ninguna informacin til. De hecho, el valor que se muestra
es el valor devuelto por el mtodo ToString para el objeto Person; de forma predeterminada, ste es el nico
valor que WPF puede utilizar para representar el objeto. Podra invalidar el mtodo ToString para devolver
informacin ms til, pero seguira siendo simplemente un valor de cadena. Una tcnica posible que aprovecha
las funciones de presentacin WPF es usar una plantilla de datos. Puede implementar una plantilla de datos que
WPF pueda asociar a un objeto de un tipo determinado. En el cdigo siguiente se muestra una plantilla de datos
para el objeto Person.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SDKSample"
x:Class="SDKSample.App"
StartupUri="HomePage.xaml">
<Application.Resources>
<!-- Data Template for the Person Class -->
<DataTemplate DataType="{x:Type local:Person}">
<TextBlock xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<TextBlock FontWeight="Bold">Name:</TextBlock>
<TextBlock Text="{Binding Path=Name}" />

MCT: Luis Dueas

Pag 114 de 445

Manual de Windows Presentation Foundation


<LineBreak />
<TextBlock FontWeight="Bold">Favorite Color:</TextBlock>
<TextBlock Text="{Binding Path=FavoriteColor}" />
</TextBlock>
</DataTemplate>
</Application.Resources>
</Application>
Aqu, la plantilla de datos est asociada al tipo Person mediante la extensin de marcado x:Type del atributo
DataType. La plantilla de datos enlaza los elementos TextBlock a las propiedades de la clase Person. En la
ilustracin siguiente se muestra el aspecto actualizado del objeto Person.

Una ventaja de esta tcnica es la coherencia conseguida al ser capaz de reutilizar la plantilla de datos para
mostrar los objetos con un aspecto similar en cualquier lugar de la aplicacin.
Seguridad
La compatibilidad de navegacin de WPF permite utilizar las XBAPs para toda la navegacin por Internet, y
permite que las aplicaciones hospeden contenido de otros fabricantes. Para proteger las aplicaciones y a los
usuarios de un comportamiento malintencionado, WPF proporciona un conjunto de caractersticas de seguridad

2.4.2. Informacin General sobre la Navegacin Estructurada


El contenido que puede ser hospedado por Aplicacin del explorador XAML (XBAP), un objeto Frame o un objeto
NavigationWindow se compone de pginas que pueden ser identificadas por identificadores de recursos
uniformes (URIs) paquete y a las que se puede navegar mediante hipervnculos. La estructura de las pginas y
las maneras en las que se pueden navegar, tal como las definen los hipervnculos, se conocen como la topologa
de navegacin. Este tipo de topologa satisface diversos tipos de aplicacin, particularmente aqullas que
navegan por documentos. Para tales aplicaciones, el usuario puede navegar de una pgina a otra sin que
ninguna de ellas necesite saber nada sobre la otra.
Sin embargo, otros tipos de aplicaciones tienen pginas que necesitan saber cundo se ha navegado entre
ellas. Por ejemplo, considere una aplicacin de recursos humanos que tenga una pgina con la lista de todos los
empleados de la organizacin, la pgina "Lista de empleados". Esta pgina tambin podra permitir a los
usuarios agregar un nuevo empleado haciendo clic en un hipervnculo. Cuando se hace clic, la pgina navega a
una pgina "Agregar un empleado", para recopilar los detalles del nuevo empleado y devolverlos a la pgina
"Lista de empleados", para crear el nuevo empleado y actualizar la lista. Este estilo de navegacin es similar a
llamar a un mtodo para realizar algn procesamiento y devolver un valor, lo que se considera programacin
estructurada. Como tal, este estilo de navegacin se conoce como navegacin estructurada.
La clase Page no implementa compatibilidad con la navegacin estructurada. En su lugar, la clase
PageFunction<(Of <(T>)>) deriva de Page y la ampla extiende con las estructuras bsicas requeridas para la
navegacin estructurada. En este tema se muestra cmo establecer navegacin estructurada mediante
PageFunction<(Of <(T>)>).
Navegacin estructurada
Cuando una pgina llama a otra pgina en una navegacin estructurada, se requieren algunos o todos los
comportamientos siguientes:

La pgina que llama navega a la pgina llamada, con la opcin de pasar parmetros requeridos por la
pgina llamada.

La pgina llamada, cuando un usuario ha terminado de usar la pgina que llama, puede devolver
especficamente a la pgina de llamada lo siguiente:

MCT: Luis Dueas

Pag 115 de 445

Manual de Windows Presentation Foundation

Devolucin de informacin de estado, que describe cmo se complet la pgina que llama
(por ejemplo, si un usuario presion un botn Aceptar o un botn Cancelar).

Devolucin de los datos recopilados del usuario (por ejemplo, los detalles del nuevo
empleado).

Cuando la pgina que llama vuelve a la pgina llamada, la pgina llamada se quita del historial de
navegacin, para aislar cada instancia de la pgina llamada.

En la figura siguiente se muestran estos comportamientos.

Puede implementar estos comportamientos utilizando un objeto PageFunction<(Of <(T>)>) como pgina
llamada.
Navegacin estructurada con PageFunction
En este tema se muestra cmo implementar los mecanismos bsicos de navegacin estructurada que implica
un

objeto

PageFunction<(Of

<(T>)>)nico.

En

este

ejemplo,

un

objeto

Page

llama

un

objeto

PageFunction<(Of <(T>)>) para recibir un valor String del usuario y devolverlo.


Crear una pgina que llama
La pgina que llama a PageFunction<(Of <(T>)>) puede ser un objeto Page o un objeto PageFunction<(Of
<(T>)>). En este ejemplo, es un objeto Page, como se muestra en el cdigo siguiente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="StructuredNavigationSample.CallingPage"
WindowTitle="Calling Page"
WindowWidth="250" WindowHeight="150">
...
</Page>
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler, Visibility
Imports System.Windows.Controls ' Page
Imports System.Windows.Navigation ' ReturnEventArgs
Namespace StructuredNavigationSample
Public Class CallingPage
Inherits Page
Public Sub New()
Me.InitializeComponent()
...
End Sub
...
End Class
End Namespace
Crear una funcin de la pgina para la llamada
Dado que la pgina que llama puede utilizar la pgina llamada para recopilar y devolver datos del usuario,
PageFunction<(Of <(T>)>) se implementa como una clase genrica cuyo argumento de tipo especifica el tipo
del valor que devolver la pgina llamada. En el cdigo siguiente se muestra la implementacin inicial de la
pgina llamada, utilizando un objeto PageFunction<(Of <(T>)>), que devuelve un objeto String.
<PageFunction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="StructuredNavigationSample.CalledPageFunction"
x:TypeArguments="sys:String"
Title="Page Function"
WindowWidth="250" WindowHeight="150">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Data -->
<Label Grid.Column="0" Grid.Row="0">DataItem1:</Label>
<TextBox Grid.Column="1" Grid.Row="0" Name="dataItem1TextBox"></TextBox>

MCT: Luis Dueas

Pag 116 de 445

Manual de Windows Presentation Foundation


<!-- Accept/Cancel buttons -->
<TextBlock Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right">
<Button Name="okButton" IsDefault="True" MinWidth="50">OK</Button>
<Button Name="cancelButton" IsCancel="True" MinWidth="50">Cancel</Button>
</TextBlock>
</Grid>
</PageFunction>
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
Public Sub New()
Me.InitializeComponent()
End Sub
...
End Class
End Namespace
La declaracin de un objeto PageFunction<(Of <(T>)>) es similar a la declaracin de un objeto Page con la
adicin de los argumentos de tipo. Como puede ver en cdigo de ejemplo, los argumentos de tipo se
especifican tanto en el marcado XAML, utilizando el atributo x:TypeArguments, como en el cdigo subyacente,
utilizando la sintaxis de argumento de tipo genrico estndar.
No tiene que utilizar solamente clases .NET Framework como argumentos de tipo. Se podra llamar a un objeto
PageFunction<(Of <(T>)>) para recopilar datos especficos de dominio que se resuman como un tipo
personalizado. El cdigo siguiente muestra cmo utilizar un tipo personalizado como argumento de tipo para un
objeto PageFunction<(Of <(T>)>).
Public Class CustomType
...
End Class
<PageFunction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SDKSample"
x:Class="SDKSample.CustomTypePageFunction"
x:TypeArguments="local:CustomType">
...
</PageFunction>
Partial Public Class CustomTypePageFunction
Inherits System.Windows.Navigation.PageFunction(Of CustomType)
Los argumentos de tipo para el objeto PageFunction<(Of <(T>)>) proporcionan la base para la comunicacin
entre una pgina que llama y la pgina llamada, que se explican en las secciones siguientes.
Como ver, el tipo que se identifica con la declaracin de un objeto PageFunction<(Of <(T>)>) desempea un
papel importante en la devolucin de datos de un objeto PageFunction<(Of <(T>)>) a la pgina que llama.
Llamar a PageFunction y pasar parmetros
Para llamar a una pgina, la pgina que llama debe crear instancias de la pgina llamada y navegar a ellas
utilizando el mtodo Navigate. Esto permite que la pgina que llama pase datos iniciales a la pgina llamada,
tales como valores predeterminados para los datos recopilados por la pgina llamada.
El cdigo siguiente muestra la pgina que llama con un constructor no predeterminado para aceptar parmetros
de la pgina que llama.
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
...
Public Sub New(ByVal initialDataItem1Value As String)
Me.InitializeComponent()
...
' Set initial value
Me.dataItem1TextBox.Text = initialDataItem1Value
End Sub
...
End Class
End Namespace

MCT: Luis Dueas

Pag 117 de 445

Manual de Windows Presentation Foundation


En el cdigo siguiente e muestra la pgina que llama administrando el evento Click del objeto Hyperlink
declarado anteriormente para crear instancias de la pgina llamada y pasarle un valor de cadena inicial.
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
...
Public Sub New(ByVal initialDataItem1Value As String)
Me.InitializeComponent()
...
' Set initial value
Me.dataItem1TextBox.Text = initialDataItem1Value
End Sub
...
End Class
End Namespace
No es obligatorio pasar parmetros a la pgina llamada. En su lugar, podra hacer lo siguiente:

En la pgina que llama:


1.

Cree una instancia de la clase PageFunction<(Of <(T>)>) llamada utilizando el constructor


predeterminado.

2.

Almacene los parmetros en Properties.

3.

Navegue al objeto PageFunction<(Of <(T>)>) llamado.

En el objeto PageFunction<(Of <(T>)>) llamado:

Recupere y utilice los parmetros almacenados en Properties.

Sin embargo, como ver pronto, todava necesitar utilizar cdigo para crear instancias y navegar a la pgina
llamada para recopilar los datos devueltos por la pgina llamada. Por esta razn, PageFunction<(Of <(T>)>)
necesita mantenerse vivo; de lo contrario, la prxima vez que navegue al objeto PageFunction<(Of <(T>)>),
WPF crear una instancia de PageFunction<(Of <(T>)>) utilizando el constructor predeterminado.
Para que la pgina llamada puede volver, sin embargo, necesita devolver datos que puedan ser recuperados
por la pgina que llama.
Devolver el resultado y los datos de una tarea a una pgina que llama
Cuando el usuario ha terminado de utilizar la pgina llamada, lo que sucede en este ejemplo al presionar los
botones Aceptar o Cancelar, la pgina llamada debe volver. Puesto que la pgina que llama utiliz la pgina
llamada para recopilar los datos del usuario, la pgina que llama requiere dos tipos de informacin:
1.

Si el usuario cancel la pgina llamada (presionando el botn Aceptar o el botn Cancelar en este
ejemplo). Esto permite decidir a la pgina que llama si debe procesar los datos que la pgina de llamada
recopil del usuario.

2.

Los datos que proporcion el usuario.

Para devolver informacin, PageFunction<(Of <(T>)>) implementa el mtodo OnReturn. En el cdigo siguiente
se muestra cmo llamarlo.
Imports System ' String
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler
Imports System.Windows.Navigation ' PageFunction
Namespace StructuredNavigationSample
Public Class CalledPageFunction
Inherits PageFunction(Of String)
...
Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Accept when Ok button is clicked
Me.OnReturn(New ReturnEventArgs(Of String)(Me.dataItem1TextBox.Text))
End Sub
Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Cancel
Me.OnReturn(Nothing)
End Sub
End Class
End Namespace

MCT: Luis Dueas

Pag 118 de 445

Manual de Windows Presentation Foundation


En este ejemplo, si un usuario presiona el botn Cancelar, se devuelve un valor de null a la pgina de llamada.
Si en su lugar se presiona el botn Aceptar, se devuelve el valor de cadena proporcionado por el usuario.
OnReturn es un mtodo protectedvirtual al que llama para devolver los datos a la pgina que llama. Los datos
deben empaquetarse en una instancia del tipo ReturnEventArgs<(Of <(T>)>) genrico, cuyo argumento de tipo
especifica el tipo de valor que devuelve Result. De esta manera, al declarar PageFunction<(Of <(T>)>) con un
argumento de tipo determinado, se est indicando que PageFunction<(Of <(T>)>) devolver una instancia del
tipo que especificado por el argumento de tipo. En este ejemplo, el argumento de tipo y, por consiguiente, el
valor devuelto son del tipo String.
Cuando se llama a OnReturn, la pgina que llama necesita alguna manera de recibir el valor devuelto de l
objeto PageFunction<(Of <(T>)>). Por esta razn, PageFunction<(Of <(T>)>) implementa el evento Return
para llamar pginas para administrar. Cuando se llama a OnReturn, de produce Return, de modo que la pgina
que llama se puede registrar en Return para recibir la notificacin.
Imports System.Windows ' RoutedEventArgs, RoutedEventHandler, Visibility
Imports System.Windows.Controls ' Page
Imports System.Windows.Navigation ' ReturnEventArgs
Namespace StructuredNavigationSample
Public Class CallingPage
Inherits Page
...
Private Sub pageFunctionHyperlink_Click(ByVal sender As Object, ByVal e As
RoutedEventArgs)
' Instantiate and navigate to page function
Dim calledPageFunction As New CalledPageFunction("Initial Data Item Value")
AddHandler calledPageFunction.Return, New ReturnEventHandler(Of String)
(AddressOf Me.calledPageFunction_Return)
MyBase.NavigationService.Navigate(calledPageFunction)
End Sub
Private Sub calledPageFunction_Return(ByVal sender As Object, ByVal e As
ReturnEventArgs(Of String))
Me.pageFunctionResultsTextBlock.Visibility = Windows.Visibility.Visible
' Display result
Me.pageFunctionResultsTextBlock.Text = IIf((Not e Is Nothing), "Accepted",
"Canceled")
' If page function returned, display result and data
If (Not e Is Nothing) Then
Me.pageFunctionResultsTextBlock.Text = (Me.pageFunctionResultsTextBlock.Text
& ChrW(10) & e.Result)
End If
End Sub
End Class
End Namespace
Quitar pginas de tarea cuando se completa una tarea
Cuando vuelve una pgina llamada y el usuario no la cancel, la pgina de llamada procesa los datos
proporcionados por el usuario y tambin los devueltos desde la pgina llamada. La adquisicin de datos de esta
manera suele ser una actividad aislada; cuando vuelve la pgina llamada, la pgina que llama debe crear y
navegar a una nueva pgina que llama para capturar ms datos.
Sin embargo, a menos que la pgina llamada se quite del diario, el usuario podr volver a una instancia
anterior de la pgina que llama. Si un objeto PageFunction<(Of <(T>)>) se retiene en el diario est
determinado por la propiedad RemoveFromJournal. De forma predeterminada, una funcin de pgina se quita
automticamente cuando se llama a OnReturn, porque RemoveFromJournal se establece en true. Para
mantener una funcin de pgina en el historial de navegacin despus de llamar a OnReturn, establezca
RemoveFromJournal en false.
Otros tipos de navegacin estructurada
En este tema se muestra el uso ms bsico de un objeto PageFunction<(Of <(T>)>) para permitir la
navegacin estructurada de llamada/retorno. Esta base proporciona la capacidad de crear ms tipos complejos
de navegacin estructurada.
Por ejemplo, hay ocasiones en las que una pgina que llama necesita varias pginas para recopilar suficientes
datos de un usuario o para realizar una tarea. El uso de varias pginas se conoce como un "asistente".

MCT: Luis Dueas

Pag 119 de 445

Manual de Windows Presentation Foundation


En otros casos, las aplicaciones pueden tener topologas de navegacin complejas que dependen de la
navegacin estructurada para funcionar eficazmente.

2.4.3. Informacin General sobre Topologas de Navegacin


En esta informacin general se proporciona una introduccin a las topologas de navegacin en WPF. A
continuacin, se abordan tres topologas de navegacin comunes, con ejemplos.
Topologas de navegacin
En WPF, la navegacin suele estar compuesta de pginas (Page) con hipervnculos (Hyperlink) que navegan a
otras pginas cuando se hace clic en ellos. Las pginas a las que se navega se identifican mediante
identificadores de recursos uniformes (URIs). Estudie el ejemplo siguiente sencillo, en el que se muestran
pginas, hipervnculos y identificadores de recursos uniformes (URIs):
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page1">
<Hyperlink NavigateUri="Page2.xaml">Navigate to Page2</Hyperlink>
</Page>
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Page2">
<Hyperlink NavigateUri="Page1.xaml">Navigate to Page1</Hyperlink>
</Page>
Estas pginas estn organizadas en una topologa de navegacin cuya estructura se determina en virtud de
cmo se puede navegar entre ellas. Esta topologa de navegacin concreta es adecuada en escenarios simples,
aunque la navegacin puede exigir topologas ms complejas, algunas de las cuales slo se pueden definir
cuando una aplicacin se est ejecutando.
En este tema se abarcan tres topologas de navegacin comunes: fija lineal, fija jerrquica y generada
dinmicamente. Cada topologa de navegacin se muestra con un ejemplo que tiene una interfaz de usuario
como la mostrada en la ilustracin siguiente:

Topologas de navegacin estructuradas


Hay dos tipos generales de topologas de navegacin:

Topologa fija: se define en tiempo de compilacin y no cambia en tiempo de ejecucin. Las topologas
fijas son tiles para la navegacin a travs de una secuencia fija de pginas en orden lineal o
jerrquico.

Topologa dinmica: se define en tiempo de ejecucin basndose en los datos proporcionados por el
usuario, la aplicacin o el sistema. Las topologas dinmicas son tiles cuando se puede navegar por
las pginas en secuencias diferentes.

Aunque es posible crear topologas de navegacin mediante pginas, en los ejemplos se utilizan funciones de
pgina, porque proporcionan compatibilidad adicional que simplifica la compatibilidad con el paso y la
devolucin de datos a travs de las pginas de una topologa.
Navegacin por una topologa fija lineal

MCT: Luis Dueas

Pag 120 de 445

Manual de Windows Presentation Foundation


Una topologa fija lineal es parecida a la estructura de un asistente, que tiene una o ms pginas por las que se
navega siguiendo una secuencia fija. En la ilustracin siguiente se muestra la estructura de nivel superior y el
flujo de un asistente con una topologa fija lineal.

Los comportamientos tpicos para navegar por una topologa fija lineal son:

Navegar desde la pgina de llamada a una pgina de inicio que inicializa el asistente y navega a la
primera pgina de este ltimo. No se requiere una pgina de inicio (PageFunction<(Of <(T>)>) sin
interfaz de usuario), ya que una pgina de llamada puede llamar directamente a la primera pgina del
asistente. Sin embargo, el uso de una pgina de inicio puede simplificar la inicializacin del asistente,
especialmente si es compleja.

El usuario puede navegar de una pgina a otra mediante los botones (o hipervnculos) de retroceso y
avance (Atrs y Siguiente).

El usuario puede navegar de una pgina a otra mediante el diario.


El usuario puede cancelar el asistente desde cualquier pgina del mismo presionando el botn de
cancelacin (Cancelar).

El usuario puede aceptar el asistente en la ltima pgina del mismo presionando un botn de
finalizacin (Finalizar).

Si se cancela un asistente, ste devuelve el resultado correspondiente y no devuelve ningn dato.


Si el usuario acepta un asistente, ste devuelve el resultado correspondiente y los datos que ha
recolectado.

Cuando se completa el asistente (se acepta o se cancela), las pginas que componen el asistente se
quitan del diario. De este modo, cada instancia del asistente se mantiene aislada, lo que evita posibles
anomalas en los datos o en el estado.

Navegacin dinmica por una topologa fija jerrquica


En algunas aplicaciones, las pginas permiten la navegacin a dos o ms otras pginas, como se muestra en la
ilustracin siguiente.

Esta estructura se denomina topologa fija jerrquica y la aplicacin o el usuario suelen determinar en tiempo
de ejecucin la secuencia en la que se recorre la jerarqua. En tiempo de ejecucin, cada pgina de la jerarqua
que permite la navegacin a dos o ms otras pginas recolecta los datos necesarios para determinar a qu
pgina se va a navegar. En la ilustracin siguiente se muestra una de las distintas secuencias de navegacin
posibles basndose en la ilustracin anterior.

MCT: Luis Dueas

Pag 121 de 445

Manual de Windows Presentation Foundation

Aunque la secuencia en la que se navega por las pginas en una estructura fija jerrquica se determina en
tiempo de ejecucin, la experiencia del usuario es igual que en una topologa fija lineal:

Navegar desde la pgina de llamada a una pgina de inicio que inicializa el asistente y navega a la
primera pgina de este ltimo. No se requiere una pgina de inicio (PageFunction<(Of <(T>)>) sin
interfaz de usuario), ya que una pgina de llamada puede llamar directamente a la primera pgina del
asistente. Sin embargo, el uso de una pgina de inicio puede simplificar la inicializacin del asistente,
especialmente si es compleja.

El usuario puede navegar de una pgina a otra mediante los botones (o hipervnculos) de retroceso y
avance (Atrs y Siguiente).

El usuario puede navegar de una pgina a otra mediante el diario.


El usuario puede cambiar la secuencia de navegacin si navega hacia atrs en el diario.
El usuario puede cancelar el asistente desde cualquier pgina del mismo presionando el botn de
cancelacin (Cancelar).

El usuario puede aceptar el asistente en la ltima pgina del mismo presionando un botn de
finalizacin (Finalizar).

Si se cancela un asistente, ste devuelve el resultado correspondiente y no devuelve ningn dato.


Si el usuario acepta un asistente, ste devuelve el resultado correspondiente y los datos que ha
recolectado.

Cuando se completa el asistente (se acepta o se cancela), las pginas que componen el asistente se
quitan del diario. De este modo, cada instancia del asistente se mantiene aislada, lo que evita posibles
anomalas en los datos o en el estado.

Ejemplo de navegacin por una topologa generada dinmicamente


En algunas aplicaciones, la secuencia en la que se navega por dos o ms pginas se puede determinar
nicamente en tiempo de ejecucin, ya sea por el usuario, por la aplicacin o por los datos externos. En la
ilustracin siguiente se muestra un conjunto de pginas con una secuencia de navegacin indeterminada.

En la figura siguiente se muestra una secuencia de navegacin elegida por el usuario en tiempo de ejecucin.

MCT: Luis Dueas

Pag 122 de 445

Manual de Windows Presentation Foundation

La secuencia de navegacin se denomina topologa generada dinmicamente. Para el usuario, al igual que en
las otras topologas de navegacin, la experiencia es igual que en las topologas anteriores:

Navegar desde la pgina de llamada a una pgina de inicio que inicializa el asistente y navega a la
primera pgina de este ltimo. No se requiere una pgina de inicio (PageFunction<(Of <(T>)>) sin
interfaz de usuario), ya que una pgina de llamada puede llamar directamente a la primera pgina del
asistente. Sin embargo, el uso de una pgina de inicio puede simplificar la inicializacin del asistente,
especialmente si es compleja.

El usuario puede navegar de una pgina a otra mediante los botones (o hipervnculos) de retroceso y
avance (Atrs y Siguiente).

El usuario puede navegar de una pgina a otra mediante el diario.


El usuario puede cancelar el asistente desde cualquier pgina del mismo presionando el botn de
cancelacin (Cancelar).

El usuario puede aceptar el asistente en la ltima pgina del mismo presionando un botn de
finalizacin (Finalizar).

Si se cancela un asistente, ste devuelve el resultado correspondiente y no devuelve ningn dato.


Si el usuario acepta un asistente, ste devuelve el resultado correspondiente y los datos que ha
recolectado.

Cuando se completa el asistente (se acepta o se cancela), las pginas que componen el asistente se
quitan del diario. De este modo, cada instancia del asistente se mantiene aislada, lo que evita posibles
anomalas en los datos o en el estado.

2.4.4. Temas Cmo de Navegacin


En los temas siguientes se muestra cmo utilizar la navegacin en Windows Presentation Foundation (WPF).

2.4.4.1. Cmo: Llamar a una Funcin de Pgina


En este ejemplo se muestra cmo llamar a una funcin de pgina desde una pgina Lenguaje de marcado de
aplicaciones extensible (XAML).
Ejemplo
Puede navegar a una funcin de pgina utilizando un identificador de recursos uniforme (URI), exactamente
igual que cuando navega a una pgina. El ejemplo siguiente muestra esta opcin.
// Navigate to a page function like a page
Uri pageFunctionUri = new Uri("GetStringPageFunction.xaml", UriKind.Relative);
this.NavigationService.Navigate(pageFunctionUri);
Si necesita pasar datos a la funcin de pgina, puede crear una instancia de ella y pasar los datos estableciendo
una propiedad. O bien, como se muestra en el ejemplo siguiente, puede pasar los datos mediante un
constructor no predeterminado.
<Page x:Class="UsingPageFunctionsSample.CallingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CallingPage" >
<Hyperlink Name="callPageFunctionHyperlink"
Click="callPageFunctionHyperlink_Click">Call Page Function</Hyperlink>
</Page>
void callPageFunctionHyperlink_Click(object sender, RoutedEventArgs e)
{
// Call a page function
GetStringPageFunction pageFunction = new GetStringPageFunction("initialValue");

MCT: Luis Dueas

Pag 123 de 445

Manual de Windows Presentation Foundation


this.NavigationService.Navigate(pageFunction);
}

2.4.4.2. Cmo: Determinar si una Pgina est Hospedada en un Explorador


En este ejemplo se muestra cmo determinar si un objeto Page se hospeda en un explorador.
Ejemplo
Page puede ser vlido para hosts y, por consiguiente, se puede cargar en varios tipos diferentes de hosts,
incluso un objeto Frame, un objeto NavigationWindow o un explorador. Esto puede suceder cuando existe un
ensamblado de biblioteca que contiene una o ms pginas, y al que se hace referencia en varias aplicaciones
host autnomas que se pueden examinar (Aplicacin del explorador XAML (XBAP)).
En el ejemplo siguiente se muestra cmo utilizar BrowserInteropHelper.IsBrowserHosted para determinar si
Page se hospeda en un explorador.
// Detect if browser hosted
if (BrowserInteropHelper.IsBrowserHosted)
{
// Note: can only inspect BrowserInteropHelper.Source property if page is browserhosted.
this.dataTextBlock.Text = "Is Browser Hosted: " +
BrowserInteropHelper.Source.ToString();
}
else
{
this.dataTextBlock.Text = "Is not browser hosted";
}

2.4.4.3. Cmo: Obtener el Valor Devuelto por una Funcin de Pgina


En este ejemplo se muestra cmo obtener el resultado devuelto por una funcin de pgina.
Ejemplo
Para obtener el resultado devuelto por una funcin de pgina, es preciso controlar el evento Return de la
funcin de pgina a la que llama.
<Page x:Class="UsingPageFunctionsSample.CallingPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CallingPage" >
<Hyperlink Name="callPageFunctionHyperlink" Click="callPageFunctionHyperlink_Click">
Call Page Function</Hyperlink>
</Page>
void callPageFunctionAndReturnHyperlink_Click(object sender, RoutedEventArgs e)
{
// Call a page function and hook up page function's return event to get result
GetStringPageFunction pageFunction = new GetStringPageFunction();
pageFunction.Return+=new ReturnEventHandler<String>(GetStringPageFunction_Returned);
this.NavigationService.Navigate(pageFunction);
}
void GetStringPageFunction_Returned(object sender, ReturnEventArgs<String> e)
{
// Get the result, if a result was passed.
if (e.Result != null)
{
Console.WriteLine(e.Result);
}
}

2.4.4.4. Cmo: Navegar hacia Delante por el Historial de Navegacin


En este ejemplo se muestra cmo navegar hacia delante en las entradas del historial de navegacin.
Ejemplo
Puede navegar hacia delante mediante el historial de navegacin (de entrada en entrada) por el cdigo que se
est ejecutando desde el contenido que se hospeda en NavigationWindow, Frame, NavigationService o Windows
Internet Explorer.

MCT: Luis Dueas

Pag 124 de 445

Manual de Windows Presentation Foundation


Para navegar hacia delante a la siguiente entrada es preciso comprobar primero que haya entradas
subsiguientes en el historial de navegacin inspeccionando la propiedad CanGoForward, antes de navegar a la
entrada siguiente llamando al mtodo GoForward. Esto se muestra en el siguiente ejemplo:
void navigateForwardButton_Click(object sender, RoutedEventArgs e)
{
// Navigate forward one page from this page, if there is an entry
// in forward navigation history
if (this.NavigationService.CanGoForward)
{
this.NavigationService.GoForward();
}
else
{
MessageBox.Show("No entries in forward navigation history.");
}
}
CanGoForward y GoForward se implementan mediante NavigationWindow, Frame y NavigationService.
Nota:
Si llama a GoForward y no hay ninguna entrada hacia delante en el historial de navegacin, se inicia una
excepcin InvalidOperationException.

2.4.4.5. Cmo: Navegar hacia Atrs por el Historial de Navegacin


En este ejemplo se muestra cmo navegar hacia atrs en las entradas del historial de navegacin.
Ejemplo
Puede navegar hacia atrs mediante el historial de navegacin (de entrada en entrada) por el cdigo que se
est ejecutando desde el contenido que se hospeda en NavigationWindow, Frame, NavigationService o Windows
Internet Explorer.
Para navegar hacia atrs a la entrada anterior es preciso comprobar primero que haya entradas anteriores en el
historial de navegacin inspeccionando la propiedad CanGoBack, antes de navegar a la entrada anterior
llamando al mtodo GoBack. Esto se muestra en el siguiente ejemplo:
void navigateBackButton_Click(object sender, RoutedEventArgs e)
{
// Navigate back one page from this page, if there is an entry
// in back navigation history
if (this.NavigationService.CanGoBack)
{
this.NavigationService.GoBack();
}
else
{
MessageBox.Show("No entries in back navigation history.");
}
}
CanGoBack y GoBack se implementan mediante NavigationWindow, Frame y NavigationService.
Nota:
Si llama a GoBack y no hay ninguna entrada hacia atrs en el historial de navegacin, se inicia una
excepcin InvalidOperationException.

2.4.4.6. Cmo: Navegar hasta una Pgina


En este ejemplo se muestran varias maneras de navegar hasta una pgina desde un objeto NavigationWindow.
Ejemplo
Es posible navegar desde NavigationWindow a una pgina mediante uno de los elementos siguientes:

La propiedad Source

El mtodo Navigate.
// Navigate to URI using the Source property
this.Source = new Uri("HomePage.xaml", UriKind.Relative);
// Navigate to URI using the Navigate method
this.Navigate(new Uri("HomePage.xaml", UriKind.Relative));
// Navigate to object using the Navigate method

MCT: Luis Dueas

Pag 125 de 445

Manual de Windows Presentation Foundation


this.Navigate(new HomePage());
Nota:
Los Identificadores de recursos uniformes (URIs) pueden ser relativos o absolutos.

2.4.4.7. Cmo: Actualizar una Pgina


En este ejemplo se muestra cmo llamar al mtodo Refresh para actualizar el contenido actual de un objeto
NavigationWindow.
Ejemplo
Refresh actualiza el contenido actual de un objeto NavigationWindow recargndolo desde su origen.
void navigateRefreshButton_Click(object sender, RoutedEventArgs e)
{
this.Refresh();
}

2.4.4.8. Cmo: Devolver Resultados de una Funcin de Pgina


En este ejemplo se muestra cmo devolver un resultado de una funcin de pgina.
Ejemplo
Para realizar una devolucin desde una funcin de pgina, es preciso llamar a OnReturn y pasar una instancia
de ReturnEventArgs<(Of <(T>)>).
<PageFunction
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="UsingPageFunctionsSample.GetStringPageFunction"
x:TypeArguments="sys:String"
Title="GetStringPageFunction">
...
</PageFunction>
public partial class GetStringPageFunction : PageFunction<String>
{
public GetStringPageFunction()
{
InitializeComponent();
}
public GetStringPageFunction(string initialValue) : this()
{
this.stringTextBox.Text = initialValue;
}
void okButton_Click(object sender, RoutedEventArgs e)
{
// Page function is accepted, so return a result
OnReturn(new ReturnEventArgs<string>(this.stringTextBox.Text));
}
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Page function is cancelled, so don't return a result
OnReturn(new ReturnEventArgs<string>(null));
}
}

2.4.4.9. Cmo: Establecer el Alto de una Ventana desde una Pgina


En este ejemplo se muestra cmo establecer el alto de la ventana desde una Page.
Ejemplo
Page puede establecer el alto de su ventana host estableciendo WindowHeight. Esta propiedad permite que
Page no tenga conocimiento explcito del tipo de ventana que la hospeda.
Nota:
Para establecer el alto de una ventana mediante WindowHeight, la Page debe ser el elemento secundario de
una ventana.

MCT: Luis Dueas

Pag 126 de 445

Manual de Windows Presentation Foundation


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SetWindowHeightPage"
WindowHeight="500" >
</Page>

2.4.4.10. Cmo: Establecer el Ancho de una Ventana desde una Pgina


En este ejemplo se muestra cmo establecer el ancho de la ventana desde una Page.
Ejemplo
Page puede establecer el ancho de su ventana host estableciendo WindowWidth. Esta propiedad permite que
Page no tenga conocimiento explcito del tipo de ventana que la hospeda.
Nota:
Para establecer el ancho de una ventana mediante WindowWidth, la Pagina debe ser el elemento
secundario de una ventana.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SetWindowWidthPage"
WindowWidth="500" >
</Page>

2.4.4.11. Cmo: Establecer el Ttulo de una Ventana desde una Pgina


En este ejemplo se muestra cmo establecer el ttulo de la ventana en la que se hospeda un control Page.
Ejemplo
Una pgina puede cambiar el ttulo de la ventana en la que se hospeda estableciendo la propiedad WindowTitle,
como sigue:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page Title"
WindowTitle="Window Title" >
</Page>
Nota:
Al establecer la propiedad Title de una pgina, no se cambia el valor del ttulo de la ventana. En lugar de
ello, Title especifica el nombre de una entrada de pgina en el historial de navegacin.

2.4.4.12. Cmo: Detener la Carga de una Pgina


En este ejemplo se muestra cmo llamar al mtodo StopLoading para detener la navegacin al contenido antes
de que finalice su carga.
Ejemplo
StopLoading detiene la descarga del contenido solicitado y hace que se produzca el evento NavigationStopped.
void navigateStopButton_Click(object sender, RoutedEventArgs e)
{
this.StopLoading();
}

2.4.4.13. Cmo: Usar Mailto: para Enviar Correo desde una Pgina
En este ejemplo se muestra cmo utilizar Hyperlink junto con un identificador de recursos uniforme (URI) de
mailto:.
Ejemplo
En el cdigo siguiente se muestra cmo utilizar un identificador de recursos uniforme (URI) de mailto: para
abrir una nueva ventana de correo que contiene una direccin de correo electrnico, una direccin de correo
electrnico y un asunto, y una direccin de correo electrnico, un asunto y un cuerpo de mensaje.

MCT: Luis Dueas

Pag 127 de 445

Manual de Windows Presentation Foundation


<Hyperlink NavigateUri="mailto:username@domainname">mailto: With Email Address</Hyperlink>
<Hyperlink NavigateUri="mailto:username@domainname?subject=SubjectText">mailto: With Email
Address and Subject</Hyperlink>
<Hyperlink
NavigateUri="mailto:username@domainname?subject=SubjectText&amp;body=BodyText">mailto: With
Email Address, Subject, and Body</Hyperlink>

2.5. Extensibilidad de Aplicaciones


.NET Framework 3.5 incluye un modelo de complementos que Windows Presentation Foundation (WPF)
extiende para que las aplicaciones host puedan mostrar las interfaces de usuario (UIs) proporcionadas por los
complementos.

2.5.1. Informacin General sobre Complementos de WPF


.NET Framework incluye un modelo de complementos que los desarrolladores pueden utilizar para crear
aplicaciones que admitan la extensibilidad de los complementos. Este modelo de complementos permite la
creacin de complementos que se integran con la funcionalidad de la aplicacin y la extienden. En algunos
escenarios, las aplicaciones tambin necesitan mostrar las UIs proporcionadas por los complementos. En este
tema se muestra cmo WPF aumenta el modelo de complementos de .NET Framework para permitir estos
escenarios, la arquitectura subyacente, sus ventajas y sus limitaciones.
Informacin general sobre los complementos
Para evitar las complejidades que implican las acciones de compilar e implementar de nuevo una aplicacin
para que incorpore nuevas funcionalidades, las aplicaciones implementan mecanismos de extensibilidad que
permiten a los desarrolladores (tanto propios como de otros fabricantes) crear otras aplicaciones que se
integren con ellas. La manera ms comn de admitir este tipo de extensibilidad es mediante el uso de
complementos. Algunos ejemplos de aplicaciones reales que exponen la extensibilidad con complementos son
los siguientes:

Complementos de Internet Explorer.


Complementos del Reproductor de Windows Media.
Complementos de Visual Studio.

Por ejemplo, el modelo de complementos del Reproductor de Windows Media permite a los desarrolladores de
otros fabricantes implementar complementos que extienden el Reproductor de Windows Media de diversas
maneras, entre las que estn la creacin de descodificadores y codificadores para los formatos multimedia que
el Reproductor de Windows Media no admite de forma nativa (por ejemplo, DVD y MP3), efectos de audio y
mscaras. Cada modelo de complementos se ha generado de modo que exponga la funcionalidad que es nica
de una aplicacin, aunque hay varias entidades y comportamientos que son comunes a todos los modelos de
complementos.
Las tres entidades principales de las tpicas soluciones de extensibilidad mediante complementos son los
contratos, los complementos y las aplicaciones host. Los contratos definen cmo se integran los complementos
con las aplicaciones host de dos maneras:

Los complementos se integran con la funcionalidad que implementan las aplicaciones host.
Las aplicaciones host exponen la funcionalidad para los complementos con los que se integran.

Para poder utilizar complementos, las aplicaciones host deben encontrarlos y cargarlos en tiempo de ejecucin.
Por consiguiente, las aplicaciones que admiten complementos tienen las siguientes responsabilidades
adicionales:

Deteccin: bsqueda de complementos que se adhieran a los contratos admitidos por las aplicaciones
host.

Activacin: carga, ejecucin y establecimiento de la comunicacin con los complementos.


Aislamiento: uso de dominios de aplicacin o procesos para establecer lmites de aislamiento que
protejan las aplicaciones frente a posibles problemas de seguridad y ejecucin con los complementos.

MCT: Luis Dueas

Pag 128 de 445

Manual de Windows Presentation Foundation

Comunicacin: los complementos y las aplicaciones host deben poder comunicarse entre s ms all de
los lmites de aislamiento llamando a mtodos y pasando datos.

Administracin de la duracin: carga y descarga de los dominios de aplicacin y procesos de una


manera limpia y predecible.

Control de versiones: garanta de que las aplicaciones host y los complementos puedan continuar
comunicndose cuando se creen nuevas versiones de cualquiera de ellos.

En ltima instancia, el desarrollo de un modelo de complementos robusto no es una tarea trivial. Por esta
razn, .NET Framework proporciona una infraestructura para generar modelos de complementos.
.Informacin general sobre el modelo de complementos de .NET Framework
El modelo de complementos de .NET Framework, que se encuentra en el espacio de nombres System.AddIn,
contiene un conjunto de tipos que permiten simplificar el desarrollo de la extensibilidad mediante
complementos. La unidad fundamental del modelo de complementos de .NET Framework es el contrato, que
define cmo se comunican entre s una aplicacin host y un complemento. Un contrato se expone a una
aplicacin host utilizando una vista del contrato que es especfica de la aplicacin host. De manera similar, se
expone al complemento una vista del contrato que es especfica del complemento. Se utiliza un adaptador para
que una aplicacin host y un complemento puedan comunicarse entre sus respectivas vistas del contrato. Los
contratos, las vistas y los adaptadores se conocen como segmentos y un conjunto de segmentos relacionados
constituye una canalizacin. Las canalizaciones son la base para que el modelo de complementos de .NET
Framework admita la deteccin, la activacin, el aislamiento de seguridad, el aislamiento de ejecucin
(utilizando tanto dominios de aplicacin como procesos), la comunicacin, la administracin de la duracin y el
control de versiones.
La suma de estas compatibilidades permite a los desarrolladores generar complementos que se integran con la
funcionalidad de una aplicacin host. Sin embargo, algunos escenarios requieren que las aplicaciones host
muestren las UIs proporcionadas por los complementos. Dado que cada tecnologa de presentacin de .NET
Framework tiene su propio modelo para implementar las UIs, el modelo de complementos de .NET Framework
no es compatible con ninguna tecnologa de presentacin en particular. En su lugar, WPF extiende el modelo de
complementos de .NET Framework con la compatibilidad de interfaz de usuario para los complementos.
Complementos de WPF
WPF, junto con el modelo de complementos de .NET Framework, permite manejar una amplia variedad de
escenarios que requieren que las aplicaciones host muestren las UIs de los complementos. En concreto, WPF
maneja estos escenarios con estos dos modelos de programacin:
1.

El complemento devuelve una interfaz de usuario. Un complemento devuelve una interfaz de usuario a
la aplicacin host mediante una llamada de mtodo, que se define en el contrato. Este escenario se utiliza
en los casos siguientes:

La apariencia de una interfaz de usuario devuelta por un complemento depende de los datos o
condiciones que solamente existen en tiempo de ejecucin, como informes generados
dinmicamente.

La interfaz de usuario para los servicios proporcionados por un complemento difiere de la


interfaz de usuario de las aplicaciones host que pueden usar el complemento.

El complemento realiza principalmente un servicio para la aplicacin host e informa de su


estado a la aplicacin host mediante una interfaz de usuario.

2.

El complemento es una interfaz de usuario. Un complemento es una interfaz de usuario, tal como lo
define el contrato. Este escenario se utiliza en los casos siguientes:

Un complemento no proporciona ms servicios que el de mostrarse, como un anuncio.

MCT: Luis Dueas

Pag 129 de 445

Manual de Windows Presentation Foundation

La interfaz de usuario para los servicios proporcionados por un complemento es comn a


todas las aplicaciones host que pueden utilizar ese complemento, como una calculadora o un
selector de color.

Estos escenarios requieren que se puedan pasar los objetos de la interfaz de usuario entre la aplicacin host y
los dominios de aplicacin del complemento. Puesto que el modelo de complementos de .NET Framework se
basa en la comunicacin remota para establecer la comunicacin entre los dominios de aplicacin, los objetos
que se pasen entre ellos debern poder usarse de forma remota.
Un objeto utilizable de forma remota es una instancia de una clase que cumple una o varias de las siguientes
condiciones:

Deriva de la clase MarshalByRefObject.


Implementa la interfaz ISerializable.
Tiene aplicado el atributo SerializableAttribute.

Los tipos de interfaz de usuario de WPF no se pueden usar de forma remota. Para resolver el problema, WPF
extiende el modelo de complementos de .NET Framework para permitir que la interfaz de usuario de WPF
creada por complementos se muestre desde las aplicaciones host. Esta compatibilidad la proporciona WPF
mediante dos tipos: la interfaz INativeHandleContract y dos mtodos estticos que se implementan mediante la
clase FrameworkElementAdapters: ContractToViewAdapter y ViewToContractAdapter. A alto nivel, estos tipos y
mtodos se utilizan de la manera siguiente:
1.

WPF requiere que las UIs proporcionadas por complementos sean clases que deriven, directa o
indirectamente, de FrameworkElement, como formas, controles, controles de usuario, paneles de diseo y
pginas.

2.

Siempre que el contrato declare que se pasar una interfaz de usuario entre el complemento y la
aplicacin host, sta debe declararse como una interfaz INativeHandleContract (en lugar de un objeto
FrameworkElement);INativeHandleContract es una representacin utilizable de forma remota de la
interfaz de usuario del complemento que se puede pasar ms all de los lmites de aislamiento.

3.

Antes de que pase desde el dominio de aplicacin del complemento, un objeto FrameworkElement se
empaqueta como una interfaz INativeHandleContract llamando a ViewToContractAdapter.

4.

Despus de pasar al dominio de aplicacin de la aplicacin host, la interfaz INativeHandleContract


debe volver a empaquetarse como un objeto FrameworkElement llamando a ContractToViewAdapter.

Cmo se utilicen INativeHandleContract, ContractToViewAdapter y ViewToContractAdapter depende del


escenario en cuestin. En las secciones siguientes se proporciona informacin detallada para cada modelo de
programacin.
El complemento devuelve una interfaz de usuario
Para que un complemento devuelva una interfaz de usuario a una aplicacin host, se requiere lo siguiente:
1.

La aplicacin host, el complemento y la canalizacin deben crearse de acuerdo con la documentacin


de .NET Framework Complementos y extensibilidad.

2.

El contrato debe implementar IContract y, para devolver una interfaz de usuario, el contrato debe
declarar un mtodo que devuelva un valor de tipo INativeHandleContract.

3.

La interfaz de usuario que se pasa entre el complemento y la aplicacin host debe derivarse, directa o
indirectamente, de FrameworkElement.

4.

La interfaz de usuario que el complemento devuelve debe convertirse de un objeto FrameworkElement


en una interfaz INativeHandleContract antes de cruzar el lmite de aislamiento.

MCT: Luis Dueas

Pag 130 de 445

Manual de Windows Presentation Foundation


5.

La interfaz de usuario que se devuelve debe convertirse de una interfaz INativeHandleContract en un


objeto FrameworkElement despus de cruzar el lmite de aislamiento.

6.

La aplicacin host muestra el objeto FrameworkElement devuelto.


El complemento es una interfaz de usuario

Cuando un complemento es una interfaz de usuario, se requiere lo siguiente:


1.

La aplicacin host, el complemento y la canalizacin deben crearse de acuerdo con la documentacin


de .NET Framework Complementos y extensibilidad.

2.

La interfaz de contrato para el complemento debe implementar INativeHandleContract.

3.

El complemento que se pasa a la aplicacin host debe derivar, directa o indirectamente, de


FrameworkElement.

4.

El

complemento

se

debe

convertir

de

un

objeto

FrameworkElement

en

una

interfaz

INativeHandleContract antes de cruzar el lmite de aislamiento.


5.

El

complemento

se

debe

convertir

de

una

interfaz

INativeHandleContract

en

un

objeto

FrameworkElement despus de cruzar el lmite de aislamiento.


6.

La aplicacin host muestra el objeto FrameworkElement devuelto.


Devolver varias interfaces de usuario de un complemento

Los complementos proporcionan a menudo varias UIs para mostrar aplicaciones host. Por ejemplo, considere
un complemento que sea una interfaz de usuario que adems proporciona informacin de estado a la aplicacin
host, tambin como una interfaz de usuario. Un complemento de este tipo se puede implementar mediante una
combinacin de tcnicas de los modelos El complemento devuelve una interfaz de usuario y El complemento es
una interfaz de usuario.
Complementos y aplicaciones de explorador XAML
Hasta ahora, en los ejemplos, la aplicacin host era una aplicacin independiente instalada. Sin embargo, las
Aplicaciones del explorador XAML (XBAPs) tambin pueden hospedar complementos, aunque con los siguientes
requisitos adicionales de compilacin e implementacin:

El manifiesto de aplicacin XBAP se debe configurar especialmente para descargar la canalizacin


(carpetas y ensamblados) y el ensamblado de complemento en la memoria cach de aplicacin de
ClickOnce del equipo cliente, en la misma carpeta que la aplicacin XBAP.

El cdigo de la aplicacin XBAP para detectar y cargar los complementos debe usar la memoria cach
de aplicacin de ClickOnce para la aplicacin XBAP como ubicacin de la canalizacin y del
complemento.

La aplicacin XBAP debe cargar el complemento en un contexto de seguridad especial si el


complemento hace referencia a archivos separados que estn ubicados en el sitio de origen; cuando se
hospedan en XBAPs, los complementos solamente pueden hacer referencia a archivos separados que
se encuentran en el sitio de origen de la aplicacin host.

Estas tareas se describen detalladamente en las siguientes subsecciones.


Configurar la canalizacin y el complemento para la implementacin de ClickOnce
Las XBAPs se descargan y se ejecutan en una carpeta segura en la memoria cach de implementacin de
ClickOnce. Para que una aplicacin XBAP pueda hospedar un complemento, la canalizacin y el ensamblado de
complemento tambin se deben descargar en la carpeta segura. Para ello, se debe configurar el manifiesto de
aplicacin de modo que incluya tanto la canalizacin como el ensamblado de complemento para la descarga.
Esto se hace fcilmente en Visual Studio, aunque la canalizacin y el ensamblado de complemento deben estar

MCT: Luis Dueas

Pag 131 de 445

Manual de Windows Presentation Foundation


en la carpeta raz del proyecto de la aplicacin XBAP host para que Visual Studio detecte los ensamblados de
canalizacin.
Por consiguiente, el primer paso es generar la canalizacin y el ensamblado de complemento en la raz del
proyecto de la aplicacin XBAP estableciendo el resultado de la compilacin de cada ensamblado de canalizacin
y proyecto de ensamblado de complemento. En la tabla siguiente, se muestran las rutas de acceso de los
resultados de la compilacin para los proyectos de ensamblado de canalizacin y el proyecto de ensamblado de
complemento que estn en la misma solucin y en la misma carpeta raz que el proyecto de la aplicacin XBAP
host
Tabla 1: rutas de acceso de los resultados de compilacin para los ensamblados de canalizacin hospedados por
una XBAP
Proyecto de ensamblado de canalizacin

Ruta de acceso de los resultados de la compilacin

Contrato

..\HostXBAP\Contracts\

Vista de complemento

..\HostXBAP\AddInViews\

Adaptador del complemento

..\HostXBAP\AddInSideAdapters\

Adaptador del host

..\HostXBAP\HostSideAdapters\

Complemento

..\HostXBAP\AddIns\WPFAddIn1

El paso siguiente es especificar los ensamblados de canalizacin y el ensamblado de complemento como


archivos de contenido de las XBAPs en Visual Studio; para ello, siga este procedimiento:
1.

Incluya el ensamblado de canalizacin y el ensamblado de complemento en el proyecto haciendo clic


con el botn secundario del mouse en cada carpeta de canalizacin del Explorador de soluciones y, a
continuacin, elija Incluir en el proyecto.

2.

Establezca el valor de Accin de compilacin de cada ensamblado de canalizacin y ensamblado de


complemento en Contenido en la ventana Propiedades.

El paso final es configurar el manifiesto de aplicacin de modo que incluya los archivos de ensamblado de
canalizacin y el archivo de ensamblado de complemento para la descarga. Los archivos deben ubicarse en
carpetas en la raz de la carpeta de la memoria cach de ClickOnce que la aplicacin XBAP ocupa. La
configuracin se puede realizar en Visual Studio siguiendo este procedimiento:
1.

Haga clic con el botn secundario del mouse en el proyecto XBAP, haga clic en Propiedades, haga clic
en Publicar y, a continuacin, haga clic en el botn Archivos de aplicacin.

2.

En el cuadro de dilogo Archivos de aplicacin, establezca el valor de Estado de la publicacin de cada


DLL de canalizacin y de complemento en Incluir (automtico) y establezca el valor de Grupo de descarga
para cada DLL de canalizacin y de complemento en (Requerido).

Utilizar la canalizacin y el complemento de la base de la aplicacin


Cuando la canalizacin y el complemento se configuran para la implementacin de ClickOnce, se descargan en
la misma carpeta de la memoria cach de ClickOnce que la aplicacin XBAP. Para utilizar la canalizacin y el
complemento de la aplicacin XBAP, el cdigo de la aplicacin XBAP debe obtenerlos de la base de la aplicacin.
Los diversos tipos y miembros del modelo de complementos de .NET Framework para el uso de canalizaciones y
complementos proporcionan una compatibilidad especial para este escenario. En primer lugar, se identifica la
ruta de acceso mediante el valor de enumeracin ApplicationBase. Este valor se utiliza con sobrecargas de los
miembros pertinentes del complemento para el uso de canalizaciones que incluyan lo siguiente:

MCT: Luis Dueas

Pag 132 de 445

Manual de Windows Presentation Foundation

AddInStore.FindAddIns(Type, PipelineStoreLocation)
AddInStore.FindAddIns(Type, PipelineStoreLocation, array<String>[]()[])
AddInStore.Rebuild(PipelineStoreLocation)
AddInStore.Update(PipelineStoreLocation)

Obtener acceso al sitio de origen del host


Para asegurarse de que un complemento pueda hacer referencia a los archivos del sitio de origen, el
complemento debe cargarse con aislamiento de seguridad equivalente a la aplicacin host. Este nivel de
seguridad se identifica mediante el valor de enumeracin AddInSecurityLevel.Host y se pasa al mtodo Activate
cuando se activa un complemento.
Arquitectura de complementos de WPF
En el nivel ms alto, tal y como hemos visto, WPF permite a los complementos de .NET Framework
implementar UIs (que derivan, directa o indirectamente, de FrameworkElement) mediante los mtodos
INativeHandleContract, ViewToContractAdapter y ContractToViewAdapter. El resultado es que a la aplicacin
host se le devuelve un objeto FrameworkElement que se muestra en la interfaz de usuario de la aplicacin host.
Para los escenarios simples de complementos de interfaz de usuario, esta es toda la informacin que necesita el
desarrollador. Para los escenarios ms complejos, en particular aqullos en los que se intenten utilizar servicios
adicionales de WPF como el diseo, los recursos y el enlace de datos, se requieren conocimientos ms
detallados de cmo WPF extiende el modelo de complementos de .NET Framework con compatibilidad de
interfaz de usuario para entender sus ventajas y limitaciones.
Fundamentalmente, WPF no pasa una interfaz de usuario de un complemento a una aplicacin host; WPF pasa
el identificador de ventana Win32 para la interfaz de usuario utilizando la interoperabilidad de WPF. Como tal,
cuando se pasa una interfaz de usuario de un complemento a una aplicacin host, ocurre lo siguiente:

En el lado del complemento, WPF adquiere un identificador de ventana para la interfaz de usuario que
la aplicacin host mostrar. El identificador de ventana est encapsulado por una clase interna de
WPF que

deriva

de

HwndSource

implementa

INativeHandleContract.

ViewToContractAdapter devuelve una instancia de esta clase y se calculan sus referencias desde el
dominio de aplicacin del complemento al dominio de aplicacin de la aplicacin host.

En el lado de la aplicacin host, WPF reempaqueta HwndSource como una clase interna de WPF que
deriva de HwndHost y consume INativeHandleContract. ContractToViewAdapter devuelve una instancia
de esta clase a la aplicacin host.

HwndHost existe para mostrar las UIs, identificadas por identificadores de ventana, desde las UIs de WPF.
En resumen, INativeHandleContract, ViewToContractAdapter y ContractToViewAdapter existen para permitir
que el identificador de ventana de una interfaz de usuario de WPF pase de un complemento a una aplicacin
host, donde es encapsulado por HwndHost y muestra la interfaz de usuario de la aplicacin.
Nota:
Dado que la aplicacin host obtiene una clase HwndHost, no puede convertir el objeto devuelto por
ContractToViewAdapter en el tipo implementado por el complemento (por ejemplo, un control UserControl).
Debido a su naturaleza, la clase HwndHost tiene ciertas limitaciones que afectan al modo en que las
aplicaciones host la usan. Sin embargo, WPF extiende HwndHost con varias funciones para los escenarios de
complementos. Estas ventajas y limitaciones se describen a continuacin.
Ventajas de los complementos de WPF
Dado que las UIs de los complementos de WPF se muestran en las aplicaciones host utilizando una clase interna
que deriva de HwndHost, esas UIs estn restringidas por las funciones de HwndHost respecto a los servicios de
la interfaz de usuario de WPF, como el diseo, la representacin, el enlace de datos, los estilos, las plantillas y

MCT: Luis Dueas

Pag 133 de 445

Manual de Windows Presentation Foundation


los recursos. Sin embargo, WPF aumenta su subclase HwndHost interna con funciones adicionales que incluyen
las siguientes:

Tabulacin entre la interfaz de usuario de una aplicacin host y la interfaz de usuario de un


complemento. Observe que el modelo de programacin "El complemento es una interfaz de usuario"
requiere que el adaptador del complemento invalide QueryContract para permitir la tabulacin,
independientemente de si el complemento es de plena confianza o de confianza parcial.

Cumplimiento de los requisitos de accesibilidad para las UIs de los complementos que se muestran
desde las UIs de la aplicacin host.

Posibilidad de que las aplicaciones de WPF se ejecuten de forma segura en varios escenarios de
dominio de aplicacin.

Prevencin del acceso ilegal a los identificadores de ventana de la interfaz de usuario de los
complementos cuando stos se ejecutan con aislamiento de seguridad (es decir, un recinto de
seguridad de confianza parcial). Al llamar a ViewToContractAdapter, se garantiza esta seguridad:

Para el modelo de programacin "El complemento devuelve una interfaz de usuario", la nica
manera de pasar el identificador de ventana para una interfaz de usuario de complemento ms
all del lmite de aislamiento es llamar a ViewToContractAdapter.

Para el modelo de programacin "El complemento es una interfaz de usuario", es preciso


invalidar QueryContract en el adaptador del complemento y llamar a ViewToContractAdapter (tal
como se muestra en los ejemplos anteriores), as como llamar a la implementacin de

QueryContract del adaptador del complemento desde el adaptador del host.

Provisin de proteccin de ejecucin en varios dominios de aplicacin. Debido a las limitaciones con los
dominios de aplicacin, las excepciones no controladas que se producen en los dominios de aplicacin
del complemento hacen que se bloquee la aplicacin completa, aunque exista el lmite de aislamiento.
Sin embargo, WPF y el modelo de complementos de .NET Framework proporcionan una manera simple
de evitar este problema y mejorar la estabilidad de la aplicacin. Un complemento de WPF que
muestre una interfaz de usuario crea un objeto Dispatcher para el subproceso en el que se ejecuta el
dominio de aplicacin si la aplicacin host es una aplicacin de WPF. Para detectar todas las
excepciones no controladas que se produzcan en el dominio de aplicacin, controle el evento
UnhandledException del objeto Dispatcher del complemento de WPF. Puede obtener el objeto
Dispatcher mediante la propiedad CurrentDispatcher.

Limitaciones de los complementos de WPF


Ms all de las ventajas que WPF agrega a los comportamientos predeterminados que HwndSource, HwndHost
y los identificadores de ventana proporcionan, tambin hay limitaciones para las UIs de complementos que se
muestran desde aplicaciones host:

Las UIs de complementos que se muestran desde una aplicacin host no respetan el comportamiento
de recorte de la aplicacin host.

El concepto de espacio areo en los escenarios de interoperabilidad tambin se aplica a los


complementos.

Los servicios de interfaz de usuario de una aplicacin host, como la herencia de recursos, el enlace de
datos y los comandos, no estn disponibles automticamente para las UIs de los complementos. Para
proporcionar estos servicios al complemento, es preciso actualizar la canalizacin.

Una interfaz de usuario de complemento no se puede girar, escalar, sesgar ni transformar de ninguna
otra manera.

MCT: Luis Dueas

Pag 134 de 445

Manual de Windows Presentation Foundation

El contenido de las UIs de complementos que se representa mediante operaciones de dibujo desde el
espacio de nombres System.Drawing puede incluir mezclas alfa. Sin embargo, tanto la interfaz de
usuario del complemento como la interfaz de usuario de la aplicacin host que la contiene deben ser
100% opacas; en otras palabras, la propiedad Opacity de ambas interfaces debe estar establecida en
1.

Si la propiedad AllowsTransparency de una ventana en la aplicacin host que contiene una interfaz de
usuario de complemento est establecida en true, el complemento ser invisible. Esto es cierto aunque
la interfaz de usuario del complemento sea 100% opaca (es decir, aunque la propiedad Opacity tenga
el valor 1).

Una interfaz de usuario de complemento debe aparecer encima de los dems elementos de WPF en la
misma ventana de nivel superior.

Ninguna parte de la interfaz de usuario de un complemento puede representarse mediante


VisualBrush. En su lugar, el complemento puede tomar una instantnea de la interfaz de usuario
generada para crear un mapa de bits que se puede pasar a la aplicacin host mediante los mtodos
definidos por el contrato.

No es posible reproducir archivos multimedia desde un control MediaElement en una interfaz de


usuario de complemento.

Los eventos del mouse generados para la interfaz de usuario del complemento no los recibe ni los
provoca la aplicacin host, y la propiedad IsMouseOver de la interfaz de usuario de la aplicacin host
tiene el valor false.

Cuando el foco se desplaza entre los controles de una interfaz de usuario de complemento, la
aplicacin host no recibe ni provoca los eventos GotFocus y LostFocus.

La parte de una aplicacin host que contiene una interfaz de usuario de complemento aparece en
blanco al imprimirse.

Todos los distribuidores (Dispatcher) creados por la interfaz de usuario del complemento se deben
cerrar manualmente antes de descargar el complemento propietario si la aplicacin host contina
ejecutndose. El contrato puede implementar mtodos que permiten a la aplicacin host sealar el
complemento antes de que ste se descargue, permitiendo que la interfaz de usuario del complemento
cierre sus distribuidores.

Si una interfaz de usuario de complemento es un control InkCanvas o contiene un control InkCanvas,


no es posible descargar el complemento.

Optimizacin del rendimiento


De forma predeterminada, cuando se utilizan varios dominios de aplicacin, los diversos ensamblados de .NET
Framework requeridos por cada aplicacin se cargan en el dominio de esa aplicacin. Como resultado, el tiempo
requerido para crear nuevos dominios de aplicacin e iniciar aplicaciones en ellos puede afectar al rendimiento.
Sin embargo, .NET Framework proporciona un mtodo para reducir los tiempos de inicio indicando a las
aplicaciones que compartan los ensamblados en los diversos dominios de aplicacin si ya estn cargados. Para
ello, utilice el atributo LoaderOptimizationAttribute, que debe aplicarse al mtodo de punto de entrada (Main).
En este caso, slo debe utilizar cdigo para implementar la definicin de la aplicacin

2.5.2. Temas Cmo de Complementos de WPF


En los temas siguientes se muestra cmo crear complementos de Windows Presentation Foundation (WPF).

MCT: Luis Dueas

Pag 135 de 445

Manual de Windows Presentation Foundation

2.5.2.1. Cmo: Crear un Complemento que Devuelva una Interfaz de Usuario


En este ejemplo se muestra cmo crear un complemento que devuelve una interfaz de usuario (UI) de Windows
Presentation Foundation (WPF) a una aplicacin host WPF independiente.
El complemento devuelve una interfaz de usuario que es un control de usuario de WPF. El contenido del control
de usuario es un botn nico que muestra un cuadro de mensaje cuando se hace clic en l. La aplicacin WPF
independiente hospeda el complemento y muestra el control de usuario (devuelto por el complemento) como el
contenido de la ventana de la aplicacin principal.
Requisitos previos
En este ejemplo se resaltan las extensiones de WPF del modelo de complementos de .NET Framework que
habilitan este escenario y se supone lo siguiente:

Conocimientos del modelo de complementos de .NET Framework, lo que incluye la programacin de


canalizaciones, complementos y host. Si no est familiarizado con estos conceptos.

Conocimientos de las extensiones de WPF del modelo de complementos de .NET Framework.

Ejemplo
Para crear un complemento que devuelve una interfaz de usuario de WPF se necesita un cdigo concreto para
cada segmento de la canalizacin, el complemento y la aplicacin host.
Implementar el segmento de canalizacin del contrato
El contrato debe definir un mtodo para devolver una interfaz de usuario y su valor devuelto debe ser de tipo
INativeHandleContract. El mtodo GetAddInUI del contrato IWPFAddInContract lo muestra en el cdigo
siguiente.
using System.AddIn.Contract; // IContract, INativeHandleContract
using System.AddIn.Pipeline; // AddInContractAttribute
namespace Contracts
{
/// <summary>
/// Defines the services that an add-in will provide to a host application
/// </summary>
[AddInContract]
public interface IWPFAddInContract : IContract
{
// Return a UI to the host application
INativeHandleContract GetAddInUI();
}
}
Implementar el segmento de canalizacin de la vista de complemento
Dado que el complemento implementa las UIs que proporciona como subclases de FrameworkElement, el
mtodo en la vista de complemento que guarda correlacin con IWPFAddInView.GetAddInUI debe devolver un
valor de tipo FrameworkElement. En el cdigo siguiente se muestra la vista de complemento del contrato,
implementada como una interfaz.
using System.AddIn.Pipeline; // AddInBaseAttribute
using System.Windows; // FrameworkElement
namespace AddInViews
{
/// <summary>
/// Defines the add-in's view of the contract
/// </summary>
[AddInBase]
public interface IWPFAddInView
{
// The add-in's implementation of this method will return
// a UI type that directly or indirectly derives from
// FrameworkElement.
FrameworkElement GetAddInUI();
}
}
Implementar el segmento de canalizacin del adaptador del complemento
El mtodo del contrato devuelve una interfaz INativeHandleContract, pero el complemento devuelve un objeto
FrameworkElement (segn lo especificado en la vista de complemento). Por consiguiente, el objeto
FrameworkElement se debe convertir en una interfaz INativeHandleContract antes de cruzar el lmite de

MCT: Luis Dueas

Pag 136 de 445

Manual de Windows Presentation Foundation


aislamiento.

Este

trabajo

lo

realiza

el

adaptador

del

complemento

mediante

una

llamada

ViewToContractAdapter, como se muestra en el cdigo siguiente.


using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // AddInAdapterAttribute, FrameworkElementAdapters,
ContractBase
using System.Windows; // FrameworkElement
using AddInViews; // IWPFAddInView
using Contracts; // IWPFAddInContract
namespace AddInSideAdapters
{
/// <summary>
/// Adapts the add-in's view of the contract to the add-in contract
/// </summary>
[AddInAdapter]
public class WPFAddIn_ViewToContractAddInSideAdapter : ContractBase,
IWPFAddInContract
{
IWPFAddInView wpfAddInView;
public WPFAddIn_ViewToContractAddInSideAdapter(IWPFAddInView wpfAddInView)
{
// Adapt the add-in view of the contract (IWPFAddInView)
// to the contract (IWPFAddInContract)
this.wpfAddInView = wpfAddInView;
}
public INativeHandleContract GetAddInUI()
{
// Convert the FrameworkElement from the add-in to an INativeHandleContract
// that will be passed across the isolation boundary to the host application
FrameworkElement fe = this.wpfAddInView.GetAddInUI();
INativeHandleContract inhc = FrameworkElementAdapters.ViewToContractAdapter(fe);
return inhc;
}

}
}
Implementar el segmento de canalizacin de la vista de host

Dado que la aplicacin host mostrar un objeto FrameworkElement, el mtodo en la vista de host que guarda
correlacin con IWPFAddInHostView.GetAddInUI debe devolver un valor de tipo FrameworkElement. En el
cdigo siguiente se muestra la vista de host del contrato, implementada como una interfaz.
using System.Windows; // FrameworkElement
namespace HostViews
{
/// <summary>
/// Defines the host's view of the add-in
/// </summary>
public interface IWPFAddInHostView
{
// The view returns as a class that directly or indirectly derives from
// FrameworkElement and can subsequently be displayed by the host
// application by embedding it as content or sub-content of a UI that is
// implemented by the host application.
FrameworkElement GetAddInUI();
}
}
Implementar el segmento de canalizacin del adaptador del host
El mtodo del contrato devuelve una interfaz INativeHandleContract, pero la aplicacin host espera un objeto
FrameworkElement

(segn

lo

especificado

por

la

vista

de

host).

Por

consiguiente,

la

interfaz

INativeHandleContract se debe convertir en un objeto FrameworkElement despus de cruzar el lmite de


aislamiento. Este trabajo lo realiza el adaptador del host mediante una llamada a ContractToViewAdapter, como
se muestra en el cdigo siguiente.
using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // HostAdapterAttribute, FrameworkElementAdapters,
ContractHandle
using System.Windows; // FrameworkElement
using Contracts; // IWPFAddInContract
using HostViews; // IWPFAddInHostView
namespace HostSideAdapters
{
/// <summary>
/// Adapts the add-in contract to the host's view of the add-in
/// </summary>
[HostAdapter]
public class WPFAddIn_ContractToViewHostSideAdapter : IWPFAddInHostView
{
IWPFAddInContract wpfAddInContract;
ContractHandle wpfAddInContractHandle;
public WPFAddIn_ContractToViewHostSideAdapter(IWPFAddInContract
wpfAddInContract)

MCT: Luis Dueas

Pag 137 de 445

Manual de Windows Presentation Foundation


{
// Adapt the contract (IWPFAddInContract) to the host application's
// view of the contract (IWPFAddInHostView)
this.wpfAddInContract = wpfAddInContract;
// Prevent the reference to the contract from being released while the
// host application uses the add-in
this.wpfAddInContractHandle = new ContractHandle(wpfAddInContract);
}
public FrameworkElement GetAddInUI()
{
// Convert the INativeHandleContract that was passed from the add-in side
// of the isolation boundary to a FrameworkElement
INativeHandleContract inhc = this.wpfAddInContract.GetAddInUI();
FrameworkElement fe = FrameworkElementAdapters.ContractToViewAdapter(inhc);
return fe;
}
}
}
Implementar el complemento
Con el adaptador y la vista de complemento creados, el complemento (WPFAddIn1.AddIn) debe implementar el
mtodo IWPFAddInView.GetAddInUI para que se devuelva un objeto FrameworkElement (UserControl en este
ejemplo). La implementacin de UserControl, AddInUI, se muestra en el cdigo siguiente.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WPFAddIn1.AddInUI">
<StackPanel>
<Button Click="clickMeButton_Click" Content="Click Me!" />
</StackPanel>
</UserControl>
using System.Windows; // MessageBox, RoutedEventArgs
using System.Windows.Controls; // UserControl
namespace WPFAddIn1
{
public partial class AddInUI : UserControl
{
public AddInUI()
{
InitializeComponent();
}
void clickMeButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello from WPFAddIn1");
}
}
}
La implementacin de IWPFAddInView.GetAddInUI por parte del complemento nicamente tiene que devolver
una nueva instancia de AddInUI, como se muestra en el cdigo siguiente.
using System.AddIn; // AddInAttribute
using System.Windows; // FrameworkElement
using AddInViews; // IWPFAddInView
namespace WPFAddIn1
{
/// <summary>
/// Add-In implementation
/// </summary>
[AddIn("WPF Add-In 1")]
public class WPFAddIn : IWPFAddInView
{
public FrameworkElement GetAddInUI()
{
// Return add-in UI
return new AddInUI();
}
}
}
Implementar la aplicacin host
Con el adaptador y la vista de host creados, la aplicacin host puede utilizar el modelo de complementos de
.NET Framework para abrir la canalizacin, adquirir una vista de host del complemento y llamar al mtodo
IWPFAddInHostView.GetAddInUI. Estos pasos se muestran en el cdigo siguiente.
// Get add-in pipeline folder (the folder in which this application was launched from)
string appPath = Environment.CurrentDirectory;
// Rebuild visual add-in pipeline
string[] warnings = AddInStore.Rebuild(appPath);
if (warnings.Length > 0)
{
string msg = "Could not rebuild pipeline:";
foreach (string warning in warnings) msg += "\n" + warning;

MCT: Luis Dueas

Pag 138 de 445

Manual de Windows Presentation Foundation


MessageBox.Show(msg);
return;

}
// Activate add-in with Internet zone security isolation
Collection<AddInToken> addInTokens = AddInStore.FindAddIns(typeof(IWPFAddInHostView),
appPath);
AddInToken wpfAddInToken = addInTokens[0];
this.wpfAddInHostView =
wpfAddInToken.Activate<IWPFAddInHostView>(AddInSecurityLevel.Internet);
// Get and display add-in UI
FrameworkElement addInUI = this.wpfAddInHostView.GetAddInUI();
this.addInUIHostGrid.Children.Add(addInUI);

2.5.2.2. Cmo: Crear un Complemento que sea una Interfaz de Usuario


En este ejemplo se muestra cmo crear un complemento que es una interfaz de usuario (UI) de Windows
Presentation Foundation (WPF) hospedada por una aplicacin WPF independiente.
El complemento es una interfaz de usuario que es un control de usuario de WPF. El contenido del control de
usuario es un botn nico que muestra un cuadro de mensaje cuando se hace clic en l. La aplicacin WPF
independiente hospeda la interfaz de usuario de complemento como contenido de la ventana de la aplicacin
principal.
Ejemplo
Para crear un complemento que es una interfaz de usuario de WPF, se necesita un cdigo concreto para cada
segmento de la canalizacin, el complemento y la aplicacin host.
Implementar el segmento de canalizacin del contrato
Cuando un complemento es una interfaz de usuario, el contrato para el complemento debe implementar
INativeHandleContract. En el ejemplo, IWPFAddInContract implementa INativeHandleContract, como se
muestra en el cdigo siguiente.
using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // AddInContractAttribute
namespace Contracts
{
/// <summary>
/// Defines the services that an add-in will provide to a host application.
/// In this case, the add-in is a UI.
/// </summary>
[AddInContract]
public interface IWPFAddInContract : INativeHandleContract {}
}
Implementar el segmento de canalizacin de la vista de complemento
Dado que el complemento se implementa como una subclase del tipo FrameworkElement, la vista de
complemento tambin debe crear subclases de FrameworkElement. En el cdigo siguiente se muestra la vista
de complemento del contrato, implementada como la clase WPFAddInView.
using System.AddIn.Pipeline; // AddInBaseAttribute
using System.Windows.Controls; // UserControl
namespace AddInViews
{
/// <summary>
/// Defines the add-in's view of the contract.
/// </summary>
[AddInBase]
public class WPFAddInView : UserControl { }
}
Aqu, la vista de complemento se deriva de UserControl. Por consiguiente, la interfaz de usuario del
complemento tambin debe derivar de UserControl.
Implementar el segmento de canalizacin del adaptador del complemento
Aunque el contrato es INativeHandleContract, el complemento es un elemento FrameworkElement (como se
especifica en el segmento de canalizacin de la vista de complemento). Por consiguiente, el objeto
FrameworkElement se debe convertir en una interfaz INativeHandleContract antes de cruzar el lmite de
aislamiento.

Este

trabajo

lo

realiza

el

adaptador

del

complemento

mediante

una

llamada

ViewToContractAdapter, como se muestra en el cdigo siguiente.


using System; // IntPtr
using System.AddIn.Contract; // INativeHandleContract

MCT: Luis Dueas

Pag 139 de 445

Manual de Windows Presentation Foundation


using System.AddIn.Pipeline; // AddInAdapterAttribute, FrameworkElementAdapters, ContractBase
using AddInViews; // WPFAddInView
using Contracts; // IWPFAddInContract
namespace AddInSideAdapters
{
/// <summary>
/// Adapts the add-in's view of the contract to the add-in contract
/// </summary>
[AddInAdapter]
public class WPFAddIn_ViewToContractAddInSideAdapter : ContractBase, IWPFAddInContract
{
WPFAddInView wpfAddInView;
public WPFAddIn_ViewToContractAddInSideAdapter(WPFAddInView wpfAddInView)
{
// Adapt the add-in view of the contract (WPFAddInView)
// to the contract (IWPFAddInContract)
this.wpfAddInView = wpfAddInView;
}
/// <summary>
/// ContractBase.QueryContract must be overridden to:
/// * Safely return a window handle for an add-in UI to the host
///
application's application.
/// * Enable tabbing between host application UI and add-in UI, in the
///
"add-in is a UI" scenario.
/// </summary>
public override IContract QueryContract(string contractIdentifier)
{
if (contractIdentifier.Equals(typeof(INativeHandleContract).AssemblyQualifiedName))
{
return FrameworkElementAdapters.ViewToContractAdapter(this.wpfAddInView);
}
return base.QueryContract(contractIdentifier);
}
/// <summary>
/// GetHandle is called by the WPF add-in model from the host application's
/// application domain to to get the window handle for an add-in UI from the
/// add-in's application domain. GetHandle is called if a window handle isn't
/// returned by other means ie overriding ContractBase.QueryContract,
/// as shown above.
/// NOTE: This method requires UnmanagedCodePermission to be called
///
(full-trust by default), to prevent illegal window handle
///
access in partially trusted scenarios. If the add-in could
///
run in a partially trusted application domain
///
(eg AddInSecurityLevel.Internet), you can safely return a window
///
handle by overriding ContractBase.QueryContract, as shown above.
/// </summary>
public IntPtr GetHandle()
{
return FrameworkElementAdapters.ViewToContractAdapter(this.wpfAddInView).GetHandle();
}
}
}
En el modelo de complemento, donde un complemento devuelve una interfaz de usuario, el adaptador de
complemento convierte el elemento FrameworkElement en una interfaz INativeHandleContract mediante una
llamada al mtodo ViewToContractAdapter. En este modelo tambin es necesario llamar al mtodo
ViewToContractAdapter, aunque se debe implementar un mtodo desde el que escribir el cdigo para llamarlo.
Para ello, invalide QueryContract e implemente el cdigo que llama a ViewToContractAdapter si el cdigo que
est llamando a QueryContract espera una interfaz INativeHandleContract. En este caso, el llamador ser el
adaptador del host, que se aborda en una subseccin siguiente.
Nota:
Tambin necesita invalidar QueryContract en este modelo para permitir la tabulacin entre la interfaz de
usuario de la aplicacin host y la interfaz de usuario del complemento.
Dado que el adaptador del complemento implementa una interfaz que deriva de INativeHandleContract,
tambin debe implementar GetHandle, aunque esto se omite cuando se invalida QueryContract.
Implementar el segmento de canalizacin de la vista de host
En este modelo, la aplicacin host suele esperar que la vista de host sea una subclase de FrameworkElement. El
adaptador del host debe convertir la interfaz INativeHandleContract en un objeto FrameworkElement despus
de que la interfaz INativeHandleContract cruce el lmite de aislamiento. Puesto que la aplicacin host no llama a
un mtodo para obtener el objeto

FrameworkElement, la vista de host debe contener el objeto

FrameworkElement para poder "devolverlo". Por consiguiente, la vista de host debe derivar de una subclase de

MCT: Luis Dueas

Pag 140 de 445

Manual de Windows Presentation Foundation


FrameworkElement que pueda contener otras UIs, como UserControl. En el cdigo siguiente se muestra la vista
de host del contrato, implementada como la clase WPFAddInHostView.
using System.Windows.Controls; // UserControl
namespace HostViews
{
/// <summary>
/// Defines the host's view of the add-in
/// </summary>
public class WPFAddInHostView : UserControl { }
}
Implementar el segmento de canalizacin del adaptador del host
Si bien el contrato es una interfaz INativeHandleContract, la aplicacin host espera un objeto UserControl
(segn lo especificado por la vista de host). Por consiguiente, la interfaz INativeHandleContract se debe
convertir en un objeto FrameworkElement despus de cruzar el lmite de aislamiento, antes de que se
establezca como contenido de la vista de host (que deriva de UserControl).
Este trabajo lo realiza el adaptador del host, como se muestra en el cdigo siguiente.
using System.AddIn.Contract; // INativeHandleContract
using System.AddIn.Pipeline; // HostAdapterAttribute, FrameworkElementAdapters,
ContractHandle
using System.Windows; // FrameworkElement
using Contracts; // IWPFAddInContract
using HostViews; // WPFAddInHostView
namespace HostSideAdapters
{
/// <summary>
/// Adapts the add-in contract to the host's view of the add-in
/// </summary>
[HostAdapter]
public class WPFAddIn_ContractToViewHostSideAdapter : WPFAddInHostView
{
IWPFAddInContract wpfAddInContract;
ContractHandle wpfAddInContractHandle;
public WPFAddIn_ContractToViewHostSideAdapter(IWPFAddInContract
wpfAddInContract)
{
// Adapt the contract (IWPFAddInContract) to the host application's
// view of the contract (WPFAddInHostView)
this.wpfAddInContract = wpfAddInContract;
// Prevent the reference to the contract from being released while the
// host application uses the add-in
this.wpfAddInContractHandle = new ContractHandle(wpfAddInContract);
// Convert the INativeHandleContract for the add-in UI that was passed
// from the add-in side of the isolation boundary to a FrameworkElement
string aqn = typeof(INativeHandleContract).AssemblyQualifiedName;
INativeHandleContract inhc = (INativeHandleContract)wpfAddInContract.QueryContract(aqn);
FrameworkElement fe =
(FrameworkElement)FrameworkElementAdapters.ContractToViewAdapter(inhc);
// Add FrameworkElement (which displays the UI provided by the add-in) as
// content of the view (a UserControl)
this.Content = fe;
}
}
}
Como puede ver, el adaptador del host adquiere la interfaz INativeHandleContract llamando al mtodo
QueryContract del adaptador del complemento (ste es el punto donde INativeHandleContract cruza el lmite de
aislamiento).
A

continuacin,

el

adaptador

del

host

convierte

la

interfaz

INativeHandleContract

en

un

objeto

FrameworkElement llamando a ContractToViewAdapter. Finalmente, se establece el objeto FrameworkElement


como el contenido de la vista de host.
Implementar el complemento
Con el adaptador y la vista del complemento en su lugar, se puede implementar el complemento derivando de
la vista de complemento, como se muestra en el cdigo siguiente.
<addInViews:WPFAddInView
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:addInViews="clr-namespace:AddInViews;assembly=AddInViews"
x:Class="WPFAddIn1.AddInUI">
<Grid>
<Button Click="clickMeButton_Click" Content="Click Me!" />
</Grid>
</addInViews:WPFAddInView>

MCT: Luis Dueas

Pag 141 de 445

Manual de Windows Presentation Foundation

using System.AddIn; // AddInAttribute


using System.Windows; // MessageBox, RoutedEventArgs
using AddInViews; // WPFAddInView
namespace WPFAddIn1
{
/// <summary>
/// Implements the add-in by deriving from WPFAddInView
/// </summary>
[AddIn("WPF Add-In 1")]
public partial class AddInUI : WPFAddInView
{
public AddInUI()
{
InitializeComponent();
}
void clickMeButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello from WPFAddIn1");
}
}
}
En este ejemplo, se puede ver una ventaja interesante de este modelo: los desarrolladores de complementos
solamente necesitan implementar el complemento (dado que tambin es la interfaz de usuario ), en lugar de
una clase de complemento y una interfaz de usuario del complemento.
Implementar la aplicacin host
Con el adaptador y la vista de host creados, la aplicacin host puede utilizar el modelo de complementos de
.NET Framework para abrir la canalizacin y adquirir una vista de host del complemento. Estos pasos se
muestran en el cdigo siguiente.
// Get add-in pipeline folder (the folder in which this application was launched from)
string appPath = Environment.CurrentDirectory;
// Rebuild visual add-in pipeline
string[] warnings = AddInStore.Rebuild(appPath);
if (warnings.Length > 0)
{
string msg = "Could not rebuild pipeline:";
foreach (string warning in warnings) msg += "\n" + warning;
MessageBox.Show(msg);
return;
}
// Activate add-in with Internet zone security isolation
Collection<AddInToken> addInTokens = AddInStore.FindAddIns(typeof(WPFAddInHostView),
appPath);
AddInToken wpfAddInToken = addInTokens[0];
this.wpfAddInHostView =
wpfAddInToken.Activate<WPFAddInHostView>(AddInSecurityLevel.Internet);
// Display add-in UI
this.addInUIHostGrid.Children.Add(this.wpfAddInHostView);
La aplicacin host utiliza el cdigo tpico del modelo de complementos de .NET Framework para activar el
complemento, lo que implcitamente devuelve la vista de host a la aplicacin host. A continuacin, la aplicacin
host muestra la vista de host (que es un control UserControl) de un control Grid.
El cdigo para procesar las interacciones con la interfaz de usuario del complemento se ejecuta en el dominio
de aplicacin del complemento. Estas interacciones incluyen lo siguiente:

Controlar el evento Click de Button.


Mostrar el objeto MessageBox.

Esta actividad est completamente aislada de la aplicacin host.

2.6. Hospedar Aplicaciones de Windows Presentation Foundation


2.6.1. Informacin General sobre Aplicaciones de Explorador XAML de WPF
Las Aplicaciones del explorador XAML (XBAPs) combinan las caractersticas de aplicaciones web y aplicaciones
cliente enriquecidas. Al igual que las aplicaciones web, las XBAPs se pueden publicar en un servidor web e
iniciarse desde Internet Explorer. Al igual que las aplicaciones cliente enriquecidas, las XBAPs pueden
aprovechar las capacidades de WPF. El desarrollo de XBAPs es tambin similar al desarrollo de aplicaciones
cliente enriquecidas. En este tema se proporciona una introduccin simple, de alto nivel, al desarrollo de

MCT: Luis Dueas

Pag 142 de 445

Manual de Windows Presentation Foundation


aplicaciones XBAP y se recalcan las diferencias entre el desarrollo de aplicaciones XBAP y el desarrollo de
aplicaciones cliente enriquecidas estndar.
Implementar una aplicacin de explorador XAML (XBAP)
La manera ms simple de crear un nuevo proyecto de aplicacin XBAP es con Microsoft Visual Studio:
1.

En el men Archivo, elija Nuevo y haga clic en Proyecto.

2.

En el cuadro de dilogo Nuevo proyecto, en el panel Tipos de proyecto, elija Visual Basic o Visual C#.
En el panel Plantillas, haga clic en Aplicacin de explorador WPF.

3.

Asigne un nombre de proyecto y haga clic en Aceptar para crear el nuevo proyecto.

La plantilla de proyecto Aplicacin de explorador WPF crea un proyecto de aplicacin XBAP que incluye lo
siguiente:

Una definicin de aplicacin, Application.xaml.


Una pgina, Page1.xaml.

Puede agregar lo que desee.


Cuando se ejecuta una aplicacin XBAP, se inicia en una ventana del explorador en lugar de una ventana
independiente. Cuando se depura una aplicacin XBAP desde Visual Studio, la aplicacin se ejecuta con
permisos de zona de Internet y, por consiguiente, inicia excepciones de seguridad si se superan esos permisos.
Implementar una aplicacin de explorador XAML
Al generar una aplicacin XBAP, Microsoft build engine (MSBuild) genera como mnimo los tres archivos
siguientes:

Un archivo ejecutable. Contiene el cdigo compilado y tiene la extensin .exe.


Un manifiesto de aplicacin. Contiene los metadatos asociados a la aplicacin y tiene la extensin
.manifest.

Un manifiesto de implementacin. Este archivo contiene la informacin que ClickOnce utiliza para
implementar la aplicacin y tiene la extensin .xbap.

Publique las XBAPs en un servidor web (Microsoft Internet Information Services (IIS) o posterior). No es
necesario instalar .NET Framework en el servidor web, pero s debe registrar las extensiones de archivo y los
tipos Extensiones multipropsito de correo Internet (MIME) de WPF.
Para preparar la aplicacin XBAP para la implementacin, copie el archivo .exe y los manifiestos asociados en el
servidor web. Cree un hipervnculo en una pgina web para navegar al manifiesto de implementacin. Cuando
el usuario hace clic en el vnculo y navega al archivo .xbap, ClickOnce administra automticamente los
mecanismos de descarga e inicio de la aplicacin.
Borrar aplicaciones XBAP almacenadas en memoria cach
En algunas situaciones, despus de volver a generar e iniciar la aplicacin XBAP, es posible que se inicie una
versin anterior de la aplicacin XBAP. Por ejemplo, esto puede pasar cuando el nmero de versin de
ensamblado de la aplicacin XBAP es esttico y se inicia la aplicacin XBAP desde la lnea de comandos. En este
caso, dado que el nmero de versin entre la versin almacenada en memoria cach (la versin que se inici
previamente) y la nueva versin sigue siendo el mismo, no se descarga la nueva versin de la aplicacin XBAP
sino la versin almacenada en memoria cach.
En estas situaciones, puede quitar la versin almacenada en memoria cach utilizando el comando Mage (se
instala con Windows SDK) desde el smbolo del sistema:

Mage.exe -cc

MCT: Luis Dueas

Pag 143 de 445

Manual de Windows Presentation Foundation


De este modo se garantiza que se inicia la ltima versin de la aplicacin XBAP porque no se encuentra ninguna
versin almacenada en memoria cach. Si depura utilizando Visual Studio 2005 y presiona F5, deber iniciarse
la ltima versin de la aplicacin XBAP.
En general, se recomienda actualizar el nmero de versin de ensamblado con cada compilacin.
Consideraciones de seguridad sobre XBAP
Las XBAPs se deben ejecutar dentro de un recinto de seguridad de confianza parcial que est restringido al
conjunto de permisos de la zona de Internet. Por consiguiente, la implementacin debe admitir el subconjunto
de elementos de WPF que se admiten en la zona de Internet

2.6.2. Informacin General sobre Aplicaciones Hospedadas en Windows Media


Center para WPF
Microsoft Windows Media Center (WMC) es una aplicacin de entretenimiento multimedia digital que se instala
con Windows Vista Home Premium, con Windows Vista Ultimate y con Microsoft Windows XP Media Center
Edition 2005. WMC permite a los usuarios administrar y utilizar gran variedad de elementos multimedia, como
televisin (digital y de alta definicin), DVDs, msica, vdeo, radio y fotografas.

De manera estndar, un WMCequipo personal (PC) se puede utilizar para ver y reproducir elementos
multimedia digitales. Esto se denomina la experiencia del usuario a corta distancia, porque los usuarios
manejan WMC desde el PC, utilizando el mouse, el teclado y el monitor.
Sin embargo, un PC de WMC se puede configurar para admitir el control remoto o acciones del teclado remotas.
En esta situacin, los usuarios no tienen que encontrarse ante el PC de WMC para manejarlo. Esto se denomina
experiencia del usuario a larga distancia, y corresponde a configuraciones de WMC que incluyen monitores de
pantalla grande, as como hardware tradicional de entretenimiento domstico, como televisores y sistemas de
sonido.
La funcionalidad bsica que WMC ofrece est compuesta de un conjunto de aplicaciones que permiten
administrar y reproducir elementos multimedia digitales. Sin embargo, puede utilizar WPF para crear sus
propias aplicaciones personalizadas para las versiones Windows Vista de WMC.
En este tema se proporciona una introduccin a la programacin de aplicaciones de WPF para WMC y se
abarcan los temas siguientes:

Crear e implementar una aplicacin de WPF de juegos simple.


Programacin para experiencias del usuario de WMC a corta y larga distancia.
Personalizar controles de WPF para admitir WMC.
Utilizar controles nuevos especficos de WMC para WPF.

MCT: Luis Dueas

Pag 144 de 445

Manual de Windows Presentation Foundation

Aprovechar la compatibilidad en .NET Framework.


Integracin con WMC mediante API administradas.
Utilizar Visual Studio 2005 para mejorar el proceso de programacin.

Hospedar aplicaciones de WPF en WMC


WPF permite programar dos tipos de aplicaciones: independientes y hospedadas por explorador. Las
aplicaciones independientes proporcionan sus propias ventanas y cuadros de dilogo para hospedar el
contenido de la aplicacin. Existen dos tipos de aplicaciones hospedadas por explorador, las aplicaciones en
XAML dinmico y las XBAPs, ambas hospedados por Internet Explorer 7. Sin embargo, Internet Explorer 7 no
tiene conocimiento alguno de WPF; para habilitar la capacidad de que Internet Explorer 7 hospede contenido
WPF, WPF proporciona aplicaciones como Internet Explorer, un servidor proxy de hospedaje. Este servidor
proxy puede hospedar contenido WPF en nombre de otras aplicaciones, y se genera mediante la misma
infraestructura de Windows comn que Internet Explorer sabe cmo hospedar.
WMC tambin es capaz de hospedar este servidor proxy y, por consiguiente, puede hospedar aplicaciones de
WPF hospedadas por explorador. Esto significa que puede aprovechar la plataforma de programacin de
aplicaciones de WPF, en general, y las caractersticas de seguridad y navegacin de las aplicaciones hospedadas
por explorador, en particular.
En el resto de este tema se utiliza la aplicacin WordGame! para WMC.
Iniciar un aplicacin de WPF para WMC
La aplicacin WordGame! est compuesta de los tres archivos siguientes (el mnimo para todas las XBAPs):

wordgamewmc.exe. La XBAP.
wordgamewmc.exe.manifest. El manifiesto de aplicacin de ClickOnce.
wordgamewmc.xbap. El manifiesto de implementacin de ClickOnce.

Las XBAPs se inician utilizando ClickOnce, lo que exige configurar la aplicacin con los archivos de manifiesto de
implementacin y aplicacin. En particular, una XBAP se inicia cuando se examina su archivo .xbap o se hace
doble clic en l. Cuando se inicia, el comportamiento predeterminado es que ClickOnce descargue la aplicacin
en nombre de WPF, despus de lo cual WPF inicia Internet Explorer y navega en l hasta la aplicacin, como se
muestra en la ilustracin siguiente:

Sin embargo, para iniciar una aplicacin de WMC, el usuario abre o hace doble clic en archivo de vnculo (.mcl)
de WMC. Un archivo .mcl es un archivo de configuracin XML que se configura en Windows para que lo abra el
host de WMC (ehshell.exe) cuando se examina o se hace doble clic en l (consulte WMC SDK).
Nota:
.Los archivos .mcl son cmodos durante el proceso de programacin, pero no se recomiendan como

MCT: Luis Dueas

Pag 145 de 445

Manual de Windows Presentation Foundation

mecanismo para instalar e iniciar aplicaciones de WMC.


Cuando se abre un archivo .mcl, el host de WMC analiza y procesa las instrucciones de configuracin contenidas
en el archivo .mcl; la ms importante de ellas es el nombre de la aplicacin que se debe abrir. Este mecanismo
se utiliza para crear un archivo .mcl configurado para iniciar una XBAP:
<application url="http://localhost/wordgamewmc/wordgamewmc.xbap" />
Cuando el host de WMC procesa este archivo .mcl, el host de WMC navega hasta el archivo .xbap. Esto hace
que ClickOnce inicie la aplicacin en el propio host de WMC, como se muestra en la ilustracin siguiente:

Nota:
Si desea que WMC hospede una aplicacin de XAML dinmico, debe configurar el archivo .mcl con un
archivo .xaml, de este modo:
<application
url="http://localhost/loosexamlapplication/loosexamlpage.xaml" />
Sin ningn cambio de la propia XBAP y con la adicin de un solo archivo de configuracin, WMC puede hospedar
una aplicacin de WPF hospedada por explorador, tal cual.
Sin embargo, la experiencia del usuario de WMC es bastante concreta y, por motivos de coherencia y estilo, las
aplicaciones XBAP de WMC deben disearse para integrarse con esta experiencia del usuario de WMC. En el
resto de este tema se abarcan los aspectos fundamentales de la experiencia de usuario de WMC y cmo
generar XBAPs que tengan en cuenta dicha experiencia.
Experiencia de usuario de WMC
Proporcionar una experiencia del usuario coherente es una parte fundamental de la programacin de cualquier
aplicacin. Con respecto a los usuarios de WMC, la aplicacin debe intentar ser coherente en los aspectos
siguientes:

Tema. El estilo global de la interfaz de usuario de una aplicacin.


Diseo. Posicin y tamao de los controles.
Navegacin. Utilizar el teclado, el mouse y el control remoto para navegar por la interfaz de usuario
de una aplicacin.

Aunque en WMC SDK encontrar una explicacin detallada sobre WMC, en los temas siguientes se proporciona
informacin general de alto nivel.
Tema
Como se puede ver en la siguiente ilustracin, el tema de WMC tiene varios elementos diferenciadores:

MCT: Luis Dueas

Pag 146 de 445

Manual de Windows Presentation Foundation

El ms distintivo de ellos es un fondo azul vtreo y fuentes redondeadas grandes de color claro. El resultado es
crear un aspecto que pueda ser discernido con facilidad tanto por los usuarios a corta distancia, que estn
delante mismo del monitor, y a larga distancia, que pueden estar alejados del televisor. Aunque las aplicaciones
de WPF deben seguir este enfoque general con respecto al aspecto, WMC no expone de manera nativa esta
informacin para que la utilicen las aplicaciones de WPF. Afortunadamente, WPF s proporciona una
infraestructura enriquecida para aplicar estilos y temas que se puede aprovechar para reproducir con facilidad
el aspecto de WMC, si se desea. Como alternativa, puede utilizar WPF para crear una experiencia del usuario
completamente nueva y visualmente enriquecida, aunque debe tener presentes las consideraciones de diseo y
navegacin.
Por ejemplo, para crear un fondo de estilo WMC para las pginas, puede proceder como sigue:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="HomePage.xaml">
<!--MediaCenterThemes.xaml-->
<Application.Resources>
<LinearGradientBrush x:Key="PageGlassyBackground" StartPoint="0,0.5"
EndPoint="1,0.5">
<GradientStop Color="#ff2B6680" Offset="1.5" />
<GradientStop Color="#569dc2" Offset="0" />
</LinearGradientBrush>
...
</Application.Resources>
</Application>
Dado que los temas suelen estar compuestos de ms de un elemento, puede ser conveniente utilizar un
diccionario de recursos personalizado para encapsular los estilos del tema de WMC:
<ResourceDictionary>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
<LinearGradientBrush x:Key="PageGlassyBackground" StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Color="#ff2B6680" Offset="1.5" />
<GradientStop Color="#569dc2" Offset="0" />
</LinearGradientBrush>
...
</ResourceDictionary>
Para incorporar un diccionario de recursos a una aplicacin, se configura el elemento Application.Resources
de la definicin de aplicacin de manera que haga referencia al archivo del diccionario de recursos .xaml:
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="HomePage.xaml">
<!--MediaCenterThemes.xaml-->
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>

MCT: Luis Dueas

Pag 147 de 445

Manual de Windows Presentation Foundation


<ResourceDictionary Source="MediaCenterTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
En la ilustracin siguiente se muestra la aplicacin WordGame! actualizada con un complemento completo de
estilos y recursos para el tema de WMC.

WMC no le impide programar temas de aplicacin que incorporan los elementos especficos de la aplicacin y de
la marca. Sin embargo, existen varios aspectos del tema de una aplicacin que deben tenerse en cuenta al
disear cualquier aplicacin para lograr la experiencia del usuario de WMC, que incluyen:

Colores seguros para televisin: no utilice colores luminosos que sean susceptibles a mostrarse
borrosos (p. ej., verde, rojo).

Contraste: para que el texto se distinga visualmente del fondo, asegrese de que la eleccin de los
colores de primer plano y de fondo de los elementos visuales tenga un nivel adecuado de contraste.

Fuentes: puede mejorar la legibilidad utilizando fuentes de mayor tamao sin enlaces. Adems, quitar
las palabras innecesarias del contenido puede ayudar a crear reas de texto ms fciles de leer.

Botones: el aspecto de los botones debe ser simple.


Imgenes: al crear imgenes, tenga en cuenta la calidad de presentacin y el tamao, as como el
tamao de descarga.

Animacin: utilice la animacin cuando sea apropiado.

Consulte WMC SDK para obtener informacin detallada sobre los temas de aplicacin de WMC.
Diseo
Un problema puede no resultar evidente a primera vista se produce cuando un usuario desplaza el puntero del
mouse sobre el host de WMC, lo que hace que el host de WMC muestre elementos de la interfaz de usuario
adicionales para la navegacin controlada por mouse, como se muestra en la ilustracin siguiente:

En esta ilustracin, puede ver las partes superior izquierda e inferior derecha de la interfaz de usuario de la
aplicacin, cubiertas por el marco de navegacin. En esta situacin, puede actualizar el diseo de la interfaz de
usuario para que tenga en cuenta la interfaz de usuario de navegacin. Para WordGame!, esto implic mover el
ttulo de la aplicacin a la derecha de la interfaz de usuario y agregar una fila de 50 pxel de alto a la parte
inferior del elemento Grid que hospeda el contenido de la pgina principal:
<Grid>
...

MCT: Luis Dueas

Pag 148 de 445

Manual de Windows Presentation Foundation


<Grid.RowDefinitions>
<RowDefinition Height="5" />
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<!-- Game title -->
<TextBlock ... TextAlignment="Right">Word Game!</TextBlock>
...
</Grid>
El efecto de agregar estas filas se muestra en la ilustracin siguiente:

Por esta razn, las XBAPs para WMC tienen que ser sensibles a los distintos comportamientos de diseo y
coherencia de WMC.
Los aspectos de diseo fundamentales que debe tener en cuenta son:

Diseo de la aplicacin: el diseo de las aplicaciones debe ser simple y coherente, para facilitar al
usuario el desarrollo y la conservacin de la familiaridad con la interfaz de usuario de su aplicacin.

Diseo de WMC: el diseo de las aplicaciones debe, siempre que sea prctico, conservar la
coherencia con la experiencia del usuario de WMC general. Esto permite que los usuarios que ya estn
familiarizados con WMC se sientan cmodos antes con la aplicacin.

Vdeo: si la aplicacin muestra vdeo mediante las API administradas de WMC, WMC reproducir el
vdeo en la parte inferior izquierda de la pantalla. Por consiguiente, debe tenerlo en cuenta al disear
la interfaz de usuario.

Resolucin: la interfaz de usuario y el diseo de la aplicacin deben estar destinados para una
resolucin de 1024 x 768. WPF ofrece compatibilidad de diseo para a ayudarlo a disear la interfaz de
usuario para 1024 x 768 y asegurarse de que el diseo se conserve al cambiar el tamao de la interfaz
de usuario.

Navegacin
En esencia, el tema y el diseo rigen cmo se organizan los controles que componen la interfaz de usuario de la
aplicacin. La navegacin, por otro lado, dicta cmo los usuarios tienen acceso a los controles y se mueven
entre ellos.
El control que recibe los datos proporcionados por el usuario es el que tiene el foco. Para llevar el foco a un
control concreto cuando se muestra una pgina de la aplicacin XBAP, puede utilizar el marcado:
<!-- Set focus on guess character text box -->
<Page ... FocusManager.FocusedElement="{Binding ElementName=guessedChar}">
...
</Page>
Esto se debe hacer para admitir los modos de manejo a corta y larga distancia.
Para permitir a los usuarios navegar por los controles de una aplicacin de WMC en los modos de corta y larga
distancia, la aplicacin debe administrar la navegacin mediante un mouse, un teclado (conectado o remoto) y
control remoto. De manera predeterminada, la navegacin con el mouse y el teclado es igual que en cualquier
aplicacin de WPF, e incluye:

MCT: Luis Dueas

Pag 149 de 445

Manual de Windows Presentation Foundation

Hacer clic en los controles para desplazar el foco a ellos.


Utilizar la tecla de tabulacin para mover el foco de un control a otro.
Utilizar la propiedad IsDefault de un botn para especificar que se hace clic en l de forma
predeterminada cuando se presiona la tecla ENTRAR.

Utilizar la propiedad IsCancel de un botn para especificar que se hace clic en l de forma
predeterminada cuando se presiona la tecla ESC.

Para admitir el control remoto, es preciso admitir la navegacin direccional, lo que significa permitir a los
usuarios mover el foco de los controles haciendo clic en los botones arriba, abajo, izquierda y derecha del
dispositivo de control remoto. No es necesario escribir ningn cdigo especial para admitir la navegacin
direccional, siempre que utilice un subconjunto concreto de controles de WPF.
Actualizar los controles de WPF para WMC
Aunque WPF proporciona gran cantidad de controles, slo un subconjunto de ellos es adecuado para su uso en
las aplicaciones de WMC de manera predeterminada. El factor determinante es si es posible navegar hasta
ellos, manipularlos y salir de ellos mediante un dispositivo de control remoto. En la ilustracin siguiente se
muestra un subconjunto de controles de WPF que admiten datos proporcionados desde un dispositivo de control
remoto (mediante los estilos de WMC):

Estas limitaciones no impiden el uso de otros controles de WPF, aunque deber realizar tareas adicionales para
que funcionen con WMC. Por ejemplo, tomemos el control Slider, que se muestra hospedado en WMC en la
ilustracin siguiente:

De manera predeterminada, con un mouse, un teclado o un dispositivo de control remoto es posible mostrar un
Slider o navegar hasta l. Sin embargo, no es posible salir de Slider mediante un dispositivo de control remoto:
Slider interpreta las pulsaciones en los botones arriba, abajo, izquierda y derecha del dispositivo de control
remoto como intentos de aumentar o disminuir el valor de Slider.
En estas situaciones, una solucin consiste en crear un control compuesto que contenga el control deseado y,
adems, los controles adicionales aptos para el control remoto que permitan manipularlo con facilidad. Por
ejemplo, Slider se puede utilizar con dos botones, uno para disminuir el valor de Slider y otro para incrementar
el valor de Slider, mediante el cdigo siguiente:
<Page x:Class="SliderPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Custom Slider -->
<StackPanel Margin="50" Orientation="Horizontal" VerticalAlignment="Top">
<Button
Name="decrementButton"
Click="decrementButton_Click"
Margin="10"
FontSize="10"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Width="40" Height="40">
</Button>
<Slider
Name="slider"

MCT: Luis Dueas

Pag 150 de 445

Manual de Windows Presentation Foundation


Focusable="False"
Width="100" Margin="0,15,0,0"
Minimum="0" Maximum="10" Value="50"
Interval="1" TickFrequency="1" TickPlacement="BottomRight" />
<Button
Name="incrementButton"
Click="incrementButton_Click"
Margin="10"
FontSize="10"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Width="40" Height="40">
+
</Button>
</StackPanel>
</Page>
using System.Windows;
using System.Windows.Controls;
public partial class SliderPage : System.Windows.Controls.Page
{
//</SnippetSliderPageCodeBehind1>
public SliderPage()
{
InitializeComponent();
}
void decrementButton_Click(object sender, RoutedEventArgs e)
{
this.slider.Value--;
}
void incrementButton_Click(object sender, RoutedEventArgs e)
{
this.slider.Value++;
}
}
El resultado se muestra en la ilustracin siguiente.

Controles de WPF adicionales para WMC


Otro control problemtico es TextBox, mostrado en la ilustracin siguiente. Con un dispositivo de control
remoto, no es posible escribir caracteres en TextBox. Lo que se necesita es un control que permite al usuario
del dispositivo de control seleccionar uno o ms caracteres. Una tcnica comn que ya se utiliza en los
dispositivos mviles cuyo factor de forma impide disponer de un teclado completo, es mostrar un teclado en la
interfaz de usuario y permitir la seleccin de los caracteres necesarios.
En el ejemplo se incluye un control de teclado de software para aplicaciones de WPF destinadas a WMC, que se
muestra en la ilustracin siguiente:

Esto se implementa como la clase SoftKeyboardTextBox del ensamblado Keyboard.dll que se suministra con
el ejemplo y reside en el espacio de nombres MCEControls. Para utilizarlo, proceda como sigue:
1.

Agregue una referencia al ensamblado Keyboard que se distribuye con MCEControls.

2.

Agregue una declaracin de espacio de nombres XML al ensamblado en el contenido.

3.

Agregue XAML para declarar y configurar SoftKeyboardTextBox.

El resultado se muestra en el cdigo siguiente:


<Page
...
xmlns:MCEControls="clr-namespace:MCEControls;assembly=Keyboard" >

MCT: Luis Dueas

Pag 151 de 445

Manual de Windows Presentation Foundation


...
<MCEControls:SoftKeyboardTextBox
Name="guessedChar"
Grid.Column="0"
Margin="0,0,5,0"
Width="80"
MaxLength="1" />
...
</Page>
Utilizar las bibliotecas de clases de .NET Framework 3.0
Una aplicacin de WPF para WMC no se limita a los controles. Una aplicacin de WPF tambin puede aprovechar
.NET Framework al mximo para obtener funcionalidad adicional, y permitirle utilizar el mismo cdigo que para
aplicaciones de WPF independientes u hospedadas por explorador.
Por ejemplo, el cdigo necesario para guardar y cargar los datos de una aplicacin hospedada por WMC es igual
que para aplicaciones que no son de WMC, y lo mismo sucede con las restricciones de seguridad; dependiendo
de dnde se inicie, la aplicacin hospedada por WMC podr escribir en el disco local o no.
Por seguridad, una aplicacin puede utilizar el almacenamiento aislado para conservar archivos:
using System;
using System.ComponentModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Xml;
using System.Xml.Serialization;
...
public static PlayerScore Load()
{
try
{
// Load the playerscore.xml file from isolated storage
using (IsolatedStorageFile isf =
IsolatedStorageFile.GetUserStoreForApplication())
using (Stream stream = new IsolatedStorageFileStream("playerscore.xml",
FileMode.Open, isf))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(PlayerScore));
return (PlayerScore)xmlSerializer.Deserialize(stream);
}
}
catch (FileNotFoundException ex)
{
return new PlayerScore();
}
}
public static void Save(PlayerScore playerScore)
{
// Save the playerscore.xml file to isolated storage
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
using (Stream stream = new IsolatedStorageFileStream("playerscore.xml",
FileMode.Create, isf))
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(PlayerScore));
xmlSerializer.Serialize(stream, playerScore);
}
}
Integracin con las API administradas de WMC
Las aplicaciones de WPF para WMC tambin se pueden integrar con las funciones de WMC mediante un
conjunto de API administradas que se instala con el sistema operativo y que se encuentran en dos
ensamblados: Microsoft.MediaCenter.dll y Microsoft.MediaCenter.UI.dll.
Gracias a estas API, puede efectuar la integracin con una gama amplia de servicios de WMC, que incluyen la
inspeccin, configuracin y reproduccin de contenido multimedia. Encontrar ms informacin sobre ellas en
WMC SDK.
Un aspecto de estas funciones es integrar an ms la experiencia del usuario de la aplicacin con WMC. Por
ejemplo, si una aplicacin de WPF necesita notificar algo al usuario mediante un cuadro de mensaje, podra
mostrar uno similar al siguiente:

MCT: Luis Dueas

Pag 152 de 445

Manual de Windows Presentation Foundation

Sin embargo, el aspecto de un cuadro de mensaje estndar de WPF no es coherente con la experiencia del
usuario de WMC. Afortunadamente, las API administradas de WMC proporcionan su propio cuadro de mensajes
de tipo WMC que puede utilizar con cdigo como el siguiente:
using Microsoft.MediaCenter;
...
// Get media center host and show dialog box
MediaCenterEnvironment mce =
Microsoft.MediaCenter.Hosting.AddInHost.Current.MediaCenterEnvironment;
mce.Dialog(msg, "WordGame!", DialogButtons.Ok, 1000, true);
Este cdigo hace que se muestre un cuadro de dilogo de WMC como ste:

Es conveniente consultar WMC SDK para obtener conocimientos en profundidad sobre las API administradas de
WMC.
Nota:
No se puede ejecutar una XBAP que hace referencia a las API administradas de WMC a menos que la XBAP
se hospede en WMC.
Programar con Visual Studio
Hasta ahora, en este tema se han abarcado los problemas bsicos de programacin que deber tener en cuenta
al crear XBAPs para WMC, lo que incluye:

Crear una aplicacin XBAP tpica.


Utilizar un archivo .mcl para iniciar un XBAP en WMC.
Crear un tema WMC para una XBAP.
Hacer referencia a las API administradas de WMC.

stos son los problemas que probablemente necesitar abordar en cada XBAP que genere para WMC. En lugar
de volver a crear estos elementos personalmente cada vez que genere una XBAP para WMC, puede utilizar la
plantilla de proyecto Media Center Application (WPF) para Microsoft Visual Studio 2005 que se instala con WMC
SDK.
Nota:
Las plantillas de proyecto de WMC nicamente se instalan si se instalan Visual Studio 2005 y tambin
"Fidalgo".
La plantilla de proyecto Media Center Application (WPF) crea un proyecto de Visual Studio 2005 que incluye
estos elementos de manera predeterminada.
Para crear una nueva aplicacin con Media Center Application (WPF):
1.

Abra Visual Studio 2005.

2.

Elija Microsoft Visual Studio | Archivo | Nuevo | Proyecto | Visual C# | .NET Framework 3.0 |
Media Center Application (WPF).

MCT: Luis Dueas

Pag 153 de 445

Manual de Windows Presentation Foundation


En la lista siguiente se muestran los elementos clave que la plantilla de proyecto genera de manera
predeterminada:

Un archivo readme.txt, que incluye texto til sobre la compilacin y depuracin de XBAPs para WPF.
Referencias a los ensamblados administrados de WMC.
Un archivo MediaCenterTheme.xaml, que es un diccionario de recursos que contiene un conjunto
completo de estilos de WMC que, de manera predeterminada, se aplican a la pgina predeterminada,
Page1.xaml.

Un archivo .mcl, que se genera junto con el resultado de XBAP estndar.

Observe que existe una plantilla de proyecto equivalente para Microsoft Visual Basic.
Depurar proyectos
Para depurar una XBAP dentro del host de WMC en Visual Studio 2005, necesita hacer lo siguiente:
1.

En el Explorador de soluciones, haga clic con el botn secundario del mouse en el proyecto y elija
Propiedades | Depurar.

2.

Establezca Programa de inicio en c:\windows\system32\presentationhost.exe.

3.

Establezca Argumentos de la lnea de comandos en - debug.

4.

Ejecute la aplicacin, para ello, elija Microsoft Visual Studio | Depurar | Iniciar depuracin (o
presione F5).

5.

Haga

doble

clic

en

el

archivo

.mcl

que

se

genera

durante

el

proceso

de

compilacin

(\bin\debug\assemblyname.mcl).
La aplicacin especificada en el archivo .mcl se iniciar y hospedar en WMC.
Instalar una aplicacin de WPF para WMC
Una de las ventajas de utilizar WMC es su capacidad de ayudar a crear aplicaciones de Microsoft Windows
Installer (archivos .msi). .Los archivos .msi constituyen una manera til de distribuir la aplicacin de WPF a los
equipos del cliente WMC.
El procedimiento siguiente se ha utilizado para crear una aplicacin de Windows Installer simple para
WordGame!:
1.

En Visual Studio 2005, haga clic con el botn secundario del mouse en la solucin de XBAP en el
Explorador de soluciones y seleccione Agregar | Nuevo proyecto.

2.

En la lista Tipos de proyecto, seleccione

Otros tipos de proyectos | Instalacin e

implementacin.
3.

En la lista Plantillas, seleccione Proyecto de instalacin o Asistente para proyectos de


instalacin (ste ltimo le guiar en la configuracin inicial del proyecto de instalacin de Windows
Installer que se crea).

4.

Haga clic con el botn secundario en el nuevo proyecto de Windows Installer, elija Agregar | Archivo
y elija los archivos siguientes:
1.

WordGameWMC.mcl

2.

WordGameWMC.exe

3.

WordGameWMC.exe.manifest

4.

WordGameWMC.xbap

5.

WordList.txt

6.

Keyboard.dll

MCT: Luis Dueas

Pag 154 de 445

Manual de Windows Presentation Foundation


5.

En la ficha Sistema de archivos, elija Escritorio del usuario.

6.

En la lista de archivos, haga clic con el botn secundario del mouse y seleccione Crear acceso
directo a Escritorio del usuario.

7.

Seleccione Carpeta de la aplicacin | WordGameWMC.mcl.

8.

Vuelva a compilar el proyecto de Windows Installer.

Al compilar el proyecto de Windows Installer, se genera un archivo .msi en la carpeta de resultado de la


compilacin. A continuacin, se copia en el equipo cliente y se ejecuta para instalar la aplicacin. La instalacin
predeterminada consiste en crear una carpeta conforme con el formato siguiente:

c:\program files\CompanyName\ApplicationName\Application Files


Todos los archivos que se seleccionaron durante la configuracin del proyecto de Windows Installer se copian
en esta carpeta, junto con todos los ensamblados dependientes seleccionados por el proyecto de Windows
Installer.
Adems, se coloca en el escritorio un icono de acceso directo a WordGameWMC.mcl en el que se puede hacer
doble clic o que se puede examinar para iniciar la aplicacin dentro de WMC.
Nota:
El archivo de proyecto de la propia aplicacin deber actualizarse manualmente para asegurarse de que la
ruta de acceso al archivo .xbap que se agrega al archivo .mcl generado es correcta para la instalacin.
Esta instalacin es una demostracin que puede utilizar para observar los fundamentos de la creacin de una
aplicacin de Windows Installer para una aplicacin de WPF para WMC.
Para las aplicaciones de WPF reales para WMC, las tcnicas de instalacin deberan ser diferentes.
En primer lugar, la aplicacin debe instalar un archivo HTML que proporcione un vnculo a la aplicacin de WPF
hospedada por el servidor web real. El hospedaje en un servidor web permite crear y publicar nuevas versiones
de la aplicacin y que el equipo cliente las seleccione sin que el usuario tenga que reinstalar la aplicacin.
En segundo lugar, no se debe utilizar archivos .mcl. En su lugar, debe crear un programa de instalacin de
Windows que llame a la API MediaCenter.RegisterApplication de WMC, o ejecutar la utilidad de lnea de
comandos RegisterMceApp.exe. Consulte WMC SDK para obtener informacin ms detallada.

2.6.3. Host de Windows Presentation Foundation (PresentationHost.exe)


El host de Windows Presentation Foundation (WPF) (PresentationHost.exe) es la aplicacin que permite
hospedar aplicaciones de WPF en exploradores compatibles (incluidos Windows Internet Explorer 7 e Microsoft
Internet Explorer 6). De manera predeterminada, el host de Windows Presentation Foundation (WPF) se
registra como el ncleo y controlador MIME para el contenido de WPF hospedado por explorador, lo que incluye:

Archivos XAML dinmicos (.xaml) (sin compilar).


Aplicacin del explorador XAML (XBAP) (.xbap).

Para los archivos de estos tipos, el host de Windows Presentation Foundation (WPF):

Inicia el controlador HTML registrado para hospedar el contenido de Windows Presentation Foundation
(WPF).

Carga las versiones correctas de los ensamblados necesarios de common language runtime (CLR) y
Windows Presentation Foundation (WPF).

Se asegura de que se apliquen los niveles de permisos adecuados para la zona de implementacin.

En este tema se describen los parmetros de lnea de comandos que se utilizar con PresentationHost.exe

MCT: Luis Dueas

Pag 155 de 445

Manual de Windows Presentation Foundation


Uso
PresentationHost.exe [parameters] uri|filename
Parmetros
Parmetro

Descripcin

filename

Ruta de acceso del archivo que se va a activar. Tambin puede ser un URI.

-debug

Al activar una aplicacin, no se confirma en el almacn ni se ejecuta desde l.


nicamente funciona cuando se activa un archivo local.

-debugSecurityZoneURL
<url>

Se utiliza con un valor de URL para indicar a PresentationHost.exe que una


aplicacin se debe depurar como si se implementara desde la URL especificada.
Determina la zona de implementacin y el sitio de origen.

-embedding

Requerido por OLE. Si se especifica el parmetro -event o -debug, no es


necesario especificar el parmetro -embedding, puesto que se establece
internamente.

-event <nombreEvento>

Abre el evento de este nombre y lo seala cuando PresentationHost.exe se


inicializa y queda listo para hospedar contenido de WPF. PresentationHost.exe
finalizar si se produce un error al abrir el evento, por ejemplo, si an no se ha
creado.

Escenarios
Controlador de ncleo

PresentationHost.exe example.xbap
Controlador MIME

PresentationHost.exe -embedding example.xbap


Depuracin en Visual Studio

PresentationHost.exe -debug example.xbap


Depuracin en Visual Studio en una zona

PresentationHost.exe -debug -debugSecurityZoneURL http://www.example.com example.xbap

2.6.4. API No Administrada de WpfHostSupport


Estas interfaces estn pensadas slo para ser utilizadas por aplicaciones que hospedan contenido de Windows
Presentation Foundation (WPF).

2.6.4.1. IEnumRAWINPUTDEVICE
Esta interfaz enumera los dispositivos de entrada sin formato y slo la utiliza PresentationHost.exe.
Miembros
Miembro

Descripcin

IEnumRAWINPUTDEVIC:Next

Enumera

los

elementos

celt

siguientes

(es

decir,

las

estructuras

RAWINPUTDEVICE) en la lista del enumerador, y los devuelve en rgelt


junto con el nmero real de elementos enumerados en pceltFetched.
IEnumRAWINPUTDEVIC:Skip

Indica al enumerador que omita los siguientes elementos celt en la


enumeracin para que la siguiente llamada a IEnumRAWINPUTDEVIC:Next
no devuelva esos elementos.

IEnumRAWINPUTDEVIC:Reset

MCT: Luis Dueas

Restablece la secuencia de enumeracin al principio.

Pag 156 de 445

Manual de Windows Presentation Foundation

IEnumRAWINPUTDEVIC:Clone

Crea otro enumerador de dispositivo de entrada sin formato con el mismo


estado que el enumerador actual para iterar sobre la misma lista.

2.6.4.2. IWpfHostSupport
Las

aplicaciones

que

hospedan

contenido

de

Windows

Presentation

Foundation

(WPF)

mediante

PresentationHost.exe implementan esta interfaz para proporcionar un punto de integracin entre el host y
PresentationHost.exe.
Comentarios
Las aplicaciones de Win32 como los exploradores web pueden hospedar contenido de WPF, incluidas las
Aplicaciones del explorador XAML (XBAPs) y XAML dinmico. Para hospedar contenido de WPF, las aplicaciones
de Win32 crean una instancia del control WebBrowser. Para hospedarse, WPF crea una instancia de
PresentationHost.exe, que proporciona el contenido de WPF hospedado al host para mostrarlo en el control
WebBrowser.
La integracin habilitada por IWpfHostSupport permite a PresentationHost.exe:

Detectar y registrar los dispositivos de entrada sin formato (dispositivos de interfaz de usuario) en los
que la aplicacin host est interesada.

Recibir los mensajes de entrada de los dispositivos de entrada sin formato registrados y reenve los
mensajes adecuados a la aplicacin host.

Consultar la aplicacin host para obtener las interfaces de usuario personalizadas de progreso y
errores.

Miembros
Miembro

Descripcin

GetRawInputDevices

Permite que PresentationHost.exe detecte los dispositivos de entrada sin formato


(dispositivos de interfaz de usuario) en los que la aplicacin host est interesada.

FilterInputMessage

Lo llama PresentationHost.exe cada vez que se recibe un mensaje, a menos que se


devuelva E_NOTIMPL.

GetCustomUI

De manera predeterminada, PresentationHost.exe proporciona sus propias


interfaces de progreso de la implementacin y de errores de implementacin que se
muestran cuando se implementa el contenido de WPF.

2.7. Generar e Implementar Aplicaciones de WPF


La compilacin y el modelo de implementacin proporciona funciones para generar e implementar aplicaciones
local y remotamente, incluido lo siguiente:

MSBuild:

el

sistema

de

compilacin

de

.NET

situado

en

el

espacio

de

nombres

Microsoft.Build.Tasks.Windows.

Recursos: trabajar con recursos de interfaz de usuario.


Implementacin de ClickOnce: sistema de publicacin e implementacin de .NET.

2.7.1. Generar una Aplicacin de WPF


Las aplicaciones de Windows Presentation Foundation (WPF) pueden generarse como aplicaciones ejecutables
de .NET Framework (.exe), bibliotecas (.dll) o una combinacin de ambos tipos de ensamblados. En este tema
se explica inicialmente cmo generar aplicaciones de WPF simples desde el smbolo del sistema, antes de
mostrar cmo WPF aprovecha la extensibilidad de Microsoft build engine (MSBuild) para generar aplicaciones
ms complejas. Finalmente, en el tema se proporciona una descripcin detallada de los pasos clave en el
proceso de compilacin de MSBuild.
Generar una aplicacin de WPF con la compilacin desde la lnea de comandos

MCT: Luis Dueas

Pag 157 de 445

Manual de Windows Presentation Foundation


Una aplicacin de WPF escrita totalmente en cdigo (sin marcado) puede generarse con un compilador de la
lnea de comandos. Considere, por ejemplo, una aplicacin independiente de WPF escrita en C# que incluya los
archivos de cdigo fuente siguientes:

Un archivo de definicin de aplicacin (app.cs).


Una ventana (mainwindow.cs).

Esta aplicacin se genera con el compilador de C#, csc.exe, desde un smbolo del sistema, como en el ejemplo
siguiente:
csc.exe
/out:WPFApplication.exe
/target:winexe
app.cs mainwindow.cs
/reference:"C:\Program Files\Reference
Assemblies\Microsoft\Framework\v3.0\presentationframework.dll"
/reference:"C:\Program Files\Reference
Assemblies\Microsoft\Framework\v3.0\windowsbase.dll"
/reference:"C:\Program Files\Reference
Assemblies\Microsoft\Framework\v3.0\presentationcore.dll"
En este ejemplo:

El parmetro /out especifica el nombre del ensamblado ejecutable (WPFApplication.exe) compilado.


El parmetro /target especifica el tipo de ensamblado que se genera (un ejecutable de Microsoft
Windows).

Los archivos de cdigo fuente de C# que componen la aplicacin (app.cs y mainwindow.cs)


El parmetro /reference que identifica los ensamblados a los que se hace referencia que implementan
los tipos utilizado por la aplicacin.

Para generar aplicaciones ms complejas se puede utilizar la compilacin desde la lnea de comandos, aunque
el compilador no admite aplicaciones de WPF que incluyan cdigo fuente Lenguaje de marcado de aplicaciones
extensible (XAML). Asimismo, la compilacin desde la lnea de comandos no admite el conjunto completo de
requisitos de compilacin de las aplicaciones de WPF tpicas, incluida la administracin de la configuracin y la
generacin de manifiestos ClickOnce. Para admitir stos y otros requisitos de compilacin ms complejos, WPF
se integra con MSBuild y extiende su funcionalidad.
Generar una aplicacin de WPF mediante MSBuild
MSBuild es una tecnologa robusta y extensible que se introdujo con .NET Framework. El ncleo de la tecnologa
MSBuild est implementado en todos los ensamblados que se describen en la tabla siguiente.
Ensamblado

Descripcin

Microsoft.Build.Engine.dll

Lee y procesa los archivos de proyecto de MSBuild.

Microsoft.Build.Tasks.dll

Implementa la funcionalidad comn a todos los proyectos de MSBuild,


incluida la invocacin del compilador desde la lnea de comandos (por
ejemplo, csc.exe para C# y vbc.exe para Visual Basic).

Microsoft.Build.Utilities.dll

Expone clases de utilidad que extienden MSBuild con funcionalidad de


compilacin personalizada.

Microsoft.Build.Framework.dll

Implementa interfaces que definen cmo interacta la funcionalidad de


MSBuild con el motor de MSBuild.

Microsoft.Build.Conversion.dll

Permite la conversin del formato de los archivos de proyecto de Microsoft


Visual Studio .NET 2002 y Microsoft Visual Studio .NET 2003 heredados al
formato del archivo de proyecto de Microsoft Visual Studio 2005MSBuild.

Archivos de proyecto de MSBuild para WPF


Los ensamblados que componen MSBuild reciben el nombre de motor de MSBuild. Para generar aplicaciones, el
motor de MSBuild requiere normalmente la siguiente informacin:

Referencias a los archivos de cdigo fuente.


Referencias a los ensamblados dependientes.
Detalles de configuracin.

MCT: Luis Dueas

Pag 158 de 445

Manual de Windows Presentation Foundation

Requisitos de compilacin.

Esta informacin se empaqueta en archivos de XML compatibles con el esquema de MSBuild personalizado para
que MSBuild pueda procesarla. Estos archivos se denominan archivos de proyecto de MSBuild. A continuacin,
se incluye un archivo de proyecto de MSBuild para una versin de la aplicacin de WPF que generamos
previamente mediante un compilador de la lnea de comandos, al que se incorporaron archivos de cdigo fuente
de Lenguaje de marcado de aplicaciones extensible (XAML).
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AssemblyName>WPFApplication</AssemblyName>
<OutputType>winexe</OutputType>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
<Compile Include="App.xaml.cs" />
<Page Include="MainWindow.xaml" />
<Compile Include="MainWindow.xaml.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>
Este ejemplo contiene los elementos que son comunes a la mayora de los archivos de proyecto de MSBuild,
incluida la etiqueta Project, las propiedades, los elementos, los destinos y las tareas.
El elemento Project
Segn se especifica en el esquema de archivo de proyecto de MSBuild, un archivo de proyecto de MSBuild es un
archivo XML con Project como elemento de nivel superior:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
</Project>
El elemento Project es donde el motor de MSBuild inicia el procesamiento de un archivo de proyecto. Para
especificar la versin de MSBuild utilizada para el archivo de proyecto de MSBuild, se proporciona una
declaracin de espacio de nombres XML adecuada.
Propiedades
Las propiedades son variables que se utilizan para configurar los proyectos de MSBuild y proporcionar
informacin especfica de la compilacin al motor de MSBuild. Las propiedades se incluyen en elementos
PropertyGroup, como se muestra en el ejemplo siguiente.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AssemblyName>WPFApplication</AssemblyName>
<OutputType>winexe</OutputType>
</PropertyGroup>
...
</Project>
Algunas propiedades, como AssemblyName y OutputType, son comunes a todos los tipos de aplicacin y se
describen en Propiedades comunes de proyectos de MSBuild. En la tabla siguiente se muestran las propiedades
de MSBuild especficas de WPF.
Propiedad

Descripcin

OutputType

Especifica el tipo de ensamblado que se genera y tiene alguno de los valores


siguientes:
winexe: genera un ensamblado ejecutable (.exe). Las aplicaciones
independientes y los XBAPs se configuran con este tipo de salida.

library: genera un ensamblado de biblioteca (.dll). Los ensamblados


compartidos y las bibliotecas de controles personalizados se configuran con
este tipo de salida.

MCT: Luis Dueas

Pag 159 de 445

Manual de Windows Presentation Foundation

HostInBrowser

Especifica si una aplicacin de WPF se hospeda en un explorador, y tiene alguno de los


valores siguientes:
true: crea un XBAP, que incluye el ensamblado de aplicacin principal (.exe),
un manifiesto de implementacin (nombreDeAplicacin.xbap) y un manifiesto
de aplicacin (nombreDeAplicacin.exe.manifest).

false: crea una aplicacin independiente.

Si HostInBrowser es true, OutputType debe ser winexe.


Install

Especifica si XBAP se instala en el cliente. Install puede ser true o false, y tiene el
valor contrario de HostInBrowser.

GenerateManifests

Especifica si una aplicacin independiente se publica utilizando la implementacin de


ClickOnce, y tiene alguno de los valores siguientes:
true: crea el ejecutable de la aplicacin principal, un manifiesto de
implementacin (nombreDeAplicacin.application) y un manifiesto de
aplicacin (nombreDeAplicacin.exe.manifest).

false: crea simplemente el ejecutable de la aplicacin (.exe).

GenerateManifests se utiliza nicamente cuando Install tiene un valor de true.


UICulture

Especifica la configuracin regional para la que se va a generar el ensamblado.


Cuando se especifica, los archivos declarados como elementos de proyecto Resource y
los recursos especficos del idioma se generan en un ensamblado satlite para la
configuracin regional deseada. Sin embargo, el contenido neutral en cuanto al idioma
se genera en el ensamblado principal. De forma predeterminada, las aplicaciones no
se traducen y, por tanto, los archivos de recursos estn incrustados en el ensamblado
principal.
Nota:
Cuando se establece UICulture, se debe especificar el idioma de recursos neutral
mediante NeutralResourcesLanguageAttribute. Este atributo se debe agregar al
archivo AssemblyInfo de una aplicacin de WPF.

Elementos
Los elementos son entradas de MSBuild que procesa el motor de MSBuild durante el proceso de compilacin.
Los elementos se incluyen dentro de un elemento ItemGroup.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
<Compile Include="App.xaml.cs" />
<Page Include="MainWindow.xaml" />
<Compile Include="MainWindow.xaml.cs" />
</ItemGroup>
...
</Project>
El tipo de un elemento se puede configurar con metadatos; en el ejemplo anterior, las referencias de
ensamblado se configuran como elementos Reference y los archivos de cdigo fuente se configuran como
elementos Compile. Los elementos Reference y Compile son comunes a todas las aplicaciones de .NET
Framework.
En la tabla siguiente se muestran los elementos de MSBuild especficos de WPF.
Propiedad

Descripcin

ApplicationDefinition

Identifica el archivo de marcado de XAML que contiene la definicin de aplicacin


(un archivo de marcado XAML cuyo elemento raz es Application).
ApplicationDefinition es obligatorio cuando Install es true y OutputType es winexe.
Una aplicacin de WPF y, por tanto, un proyecto de MSBuild slo pueden tener un
elemento ApplicationDefinition.

MCT: Luis Dueas

Pag 160 de 445

Manual de Windows Presentation Foundation

Page

Identifica un archivo de marcado de XAML cuyo contenido se convierte a un formato


binario y se genera en un ensamblado. Los elementos Page se suelen implementar
junto con una clase de cdigo subyacente.
Los elementos Page ms comunes son archivos de XAML cuyos elementos de nivel
superior son alguno de los siguientes:
Window (System.Windows.Window).

Page (System.Windows.Controls.Page).

PageFunction (System.Windows.Navigation.PageFunction<(Of <(T>)>)).

ResourceDictionary (System.Windows.ResourceDictionary).

FlowDocument (System.Windows.Documents.FlowDocument).

UserControl (System.Windows.Controls.UserControl).

Resource

Identifica un archivo de recursos que se genera en un ensamblado de aplicacin.


Como se mencion anteriormente, UICulture procesa los elementos Resource.

Content

Identifica un archivo de contenido que se distribuye con una aplicacin. Los


metadatos que describen el archivo de contenido se generan en la aplicacin
(mediante AssemblyAssociatedContentFileAttribute).

Destinos
Los destinos determinan cmo se generan los proyectos y dependen de las propiedades y los elementos. Una
aplicacin de WPF debe tener un destino especfico del lenguaje y un destino especfico de WPF.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>
Los destinos son archivos independientes que terminan con la extensin .targets. Los archivos de destino que
se incluyen con .NET Framework se instalan en la ubicacin siguiente:

%WINDIR%\Microsoft.NET\Framework\vX.X.X
El destino especfico del lenguaje genera cdigo fuente especfico del lenguaje. El destino especfico del
lenguaje de C# es Microsoft.CSharp.targets y Microsoft.VisualBasic.targets para Visual Basic. Ambos destinos
se derivan y extienden el destino Microsoft.Common.targets, que realiza la mayora del trabajo de compilacin
comn independiente del lenguaje. Para obtener ms informacin sobre los destinos comunes y especficos del
lenguaje de MSBuild.
El destino Microsoft.WinFX.targets realiza el trabajo de compilacin especfico de WPF. Entre sus tareas se
incluye la compilacin del marcado XAML, la generacin de manifiestos para las aplicaciones XBAP y el
procesamiento de los recursos y archivos de contenido de WPF.
Tareas
Una tarea es una clase que realiza una accin de compilacin especfica. Los destinos combinan una o varias
tareas para definir un proceso de compilacin; cuando MSBuild procesa un destino, ejecuta las tareas incluidas
en l. Las tareas utilizadas por los destinos comunes y especficos del lenguaje se implementan mediante el
ensamblado Microsoft.Build.Tasks, y las tareas especficas de WPF se implementan mediante el ensamblado
PresentationBuildTasks.
Los destinos proporcionan compatibilidad para generar todas las aplicaciones de WPF estndar. Tambin es
posible utilizar combinaciones alternativas de tareas para implementar un comportamiento de compilacin
personalizado. Por ejemplo, la tarea MSBuild GetWinFXPath siguiente se utiliza para detectar la ruta de acceso
nativa del motor en tiempo de ejecucin de .NET Framework, que depende de si la tarea se ejecuta en un
procesador de 64 bits:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask
TaskName="Microsoft.Build.Tasks.Windows.GetWinFXPath"
AssemblyFile="C:\Program Files\Reference

MCT: Luis Dueas

Pag 161 de 445

Manual de Windows Presentation Foundation


Assemblies\Microsoft\Framework\v3.0\PresentationBuildTasks.dll" />
<Target Name="GetWinFXPathTask">
<GetWinFXPath
WinFXNativePath="c:\DOTNet3Native"
WinFXWowPath="c:\DOTNet3WowNative" />
</Target>
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>
Ejemplos de proyectos de MSBuild para Windows Presentation Foundation
Crear un proyecto de MSBuild para WPF utilizando Visual Studio
Visual Studio genera automticamente archivos de proyecto de MSBuild cuando se crean nuevas aplicaciones
de WPF mediante plantillas de proyecto de Visual Studio. Por ejemplo, la plantilla de proyecto de aplicacin de
WPF genera el archivo de proyecto siguiente (para C#):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.20726</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E0EA3EBA-718C-4122-B20C-EB97B7DC6604}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WpfApplication1</RootNamespace>
<AssemblyName>WpfApplication1</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};
{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="Window1.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Window1.xaml.cs">
<DependentUpon>Window1.xaml</DependentUpon>

MCT: Luis Dueas

Pag 162 de 445

Manual de Windows Presentation Foundation


<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and
uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
El nombre de la extensin de archivo de proyecto de MSBuild generado incorpora el lenguaje del cdigo fuente:

Para los proyectos escritos en C#, la extensin es .csproj.


Para los proyectos escritos en Visual Basic, la extensin es .vbproj.

El archivo de proyecto es ms grande que el de los ejemplos anteriores, debido en parte a varias propiedades
adicionales. Sin embargo, la informacin adicional es especfica de Visual Studio e incluye lo siguiente:

Configuracin del proyecto.


Configuracin de compilacin.
Asociacin de archivos de cdigo fuente.
Administracin de las propiedades, recursos y configuracin del proyecto predeterminados.

Configuracin del proyecto


Los detalles de configuracin del proyecto incluyen un identificador nico para el proyecto, un identificador
nico para el tipo de proyecto y varios datos que identifican la versin de .NET Framework y Visual Studio:
<Project
ToolsVersion="3.5"
DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProductVersion>9.0.20726</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E0EA3EBA-718C-4122-B20C-EB97B7DC6604}</ProjectGuid>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<ProjectTypeGuids>
{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};
{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
</ProjectTypeGuids>
</PropertyGroup>
...
</Project>
Configuracin de compilacin
Un proyecto escrito en Visual Studio predeterminado tiene dos configuraciones de compilacin: Debug y
Release. En un archivo de proyecto de MSBuild, stas se configuran mediante propiedades:
<Project ... >
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">
Debug
</Configuration>

MCT: Luis Dueas

Pag 163 de 445

Manual de Windows Presentation Foundation


<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WpfApplication1</RootNamespace>
<AssemblyName>WpfApplication1</AssemblyName>
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
...
</PropertyGroup>
...
</Project>
La propiedad Configuration especifica la configuracin de compilacin actual:
<Project ... >
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">
Debug
</Configuration>
...
</PropertyGroup>
...
</Project>
Asociacin de archivos de cdigo fuente
Visual Studio mantiene una asociacin entre los archivos de cdigo fuente relacionados, como los archivos de
marcado y de cdigo subyacente. Esto permite que Visual Studio visualice la asociacin en la ventana
Explorador de soluciones de Visual Studio:

La asociacin entre los archivos de cdigo fuente relacionados se realiza utilizando los metadatos
DependentUpon y SubType:
<Project ... >
...
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="Window1.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Window1.xaml.cs">
<DependentUpon>Window1.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
...
</Project>
En este proyecto, App.xaml (archivo de marcado) est asociado a App.xaml.cs (archivo de cdigo subyacente),
y Window1.xaml (archivo de marcado) est asociado a Window1.xaml.cs (archivo de cdigo subyacente).
Administracin de las propiedades, recursos y configuracin del proyecto predeterminados
Visual Studio permite modificar visualmente las propiedades de un proyecto escrito en Visual Studio. La
mayora de estas propiedades afectan al proceso de compilacin y se almacenan en el archivo de proyecto de
Visual Studio administrado por Visual Studio. Las plantillas de proyecto de Windows Presentation Foundation
(WPF) generan tambin archivos para proporcionar compatibilidad con los recursos y valores con
establecimiento inflexible de tipos. Todo esto se muestra en la siguiente ilustracin:

MCT: Luis Dueas

Pag 164 de 445

Manual de Windows Presentation Foundation

Se administran mediante el archivo de proyecto de MSBuild del modo siguiente:


<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
...
</Project>
Generar un proyecto de MSBuild para WPF
Los proyectos de MSBuild se pueden generar desde un smbolo del sistema o en Visual Studio.
Generar un proyecto de MSBuild para WPF desde el smbolo del sistema
Los proyectos de MSBuild se pueden generar llamando a msbuild.exe desde el smbolo del sistema de
Windows o desde el smbolo del sistema de Kit de desarrollo de software de Windows (SDK).
Generar un proyecto
Para generar un proyecto de MSBuild, ejecute msbuild.exe, pasando el nombre de archivo del proyecto de
MSBuild deseado:

msbuild.exe msbuildprojectfile.proj
Generar un proyecto especfico del lenguaje generado por Visual Studio
Los archivos de proyecto de MSBuild especficos del lenguaje generados por Visual Studio:

Tienen una extensin de archivo relevante (.csproj, .vbproj).

Incluyen un destino especfico del lenguaje (Microsoft.CSharp.targets, Microsoft.VisualBasic.targets).

A continuacin, se muestra cmo generar un proyecto de C# desde el smbolo del sistema:

msbuild.exe VSGeneratedProjectFileForCSharp.csproj
A continuacin, se muestra cmo generar un proyecto de Visual Basic desde el smbolo del sistema:

msbuild.exe VSGeneratedProjectFileForVisualBasic.vbproj
Generar una solucin generada por Visual Studio
msbuild.exe generar tambin archivos de solucin (.sln) generados por Visual Studio:

MCT: Luis Dueas

Pag 165 de 445

Manual de Windows Presentation Foundation


msbuild.exe VSGeneratedSolutionFile.sln
Generar un proyecto de MSBuild para WPF en Visual Studio
Si utiliza Visual Studio, no necesita generar los proyectos y las soluciones desde el smbolo del sistema; Visual
Studio permite generar ambos desde el IDE.
Generar un proyecto en Visual Studio
Para generar un proyecto en Visual Studio, haga clic con el botn secundario del mouse en el proyecto en el
Explorador de soluciones y elija Generar.
Generar una solucin en Visual Studio
Para generar una solucin, realice el procedimiento siguiente:

Presione F6 para generar la solucin.


Presione F5 para iniciar la depuracin de la solucin.
Elija Generar | Generar solucin.
Elija Depurar | Iniciar depuracin.
Elija Depurar | Iniciar sin depurar.

Al realizar alguna de estas operaciones para un proyecto o solucin, Visual Studio ejecuta msbuild.exe para
generar los archivos MSBuild correspondientes.
Canalizacin de compilacin de Windows Presentation Foundation
Cuando se genera un proyecto de WPF, se invoca la combinacin de destinos especficos del lenguaje y de WPF.
El proceso de ejecucin de estos destinos se denomina canalizacin de compilacin y los pasos principales se
muestran en la siguiente ilustracin.

Estos pasos se describen con mayor detalle en la siguientes secciones.


Inicializaciones previas a la compilacin
Antes de generar, MSBuild determina la ubicacin de herramientas y bibliotecas importantes, entre las que se
incluyen las siguientes:

.NET Framework.
Los directorios de Windows SDK.
La ubicacin de los ensamblados de referencia de WPF.
La propiedad de las rutas de bsqueda de ensamblados.

El directorio de los ensamblados de referencia (%ProgramFiles%\Reference Assemblies\Microsoft\Framework\


v3.0\) es la primera ubicacin en la que se buscan los ensamblados. Durante este paso, el proceso de
compilacin inicializa tambin las distintas propiedades y grupos de elementos, y efecta el trabajo de limpieza
necesario.
Resolver referencias

MCT: Luis Dueas

Pag 166 de 445

Manual de Windows Presentation Foundation


El proceso de compilacin busca y enlaza los ensamblados necesarios para generar el proyecto de aplicacin.
Esta lgica se incluye en la tarea ResolveAssemblyReference. Todos los ensamblados declarados como
Reference en el archivo de proyecto se proporcionan a la tarea junto con informacin sobre las rutas de
bsqueda y los metadatos de los ensamblados que ya estn instalados en el sistema. La tarea busca los
ensamblados y utiliza los metadatos del ensamblado instalado para filtrar los ensamblados de WPF bsicos que
no deben mostrarse en los manifiestos de salida. Esto es necesario para evitar informacin redundante en los
manifiestos de ClickOnce. Por ejemplo, como PresentationFramework.dll se puede considerar representativo de
una compilacin de aplicacin y de WPF y, puesto que todos los ensamblados de WPF estn en la misma
ubicacin en cada equipo que tiene .NET Framework instalado, no hay necesidad de incluir toda la informacin
sobre todos los ensamblados de referencia de .NET Framework en los manifiestos.
Generacin del marcado: Paso 1
En este paso, los archivos de XAML se analizan y generan para que el motor en tiempo de ejecucin no tenga
que encargarse de analizar XML y validar los valores de las propiedades. El archivo de XAML generado se
convierte en un token para que pueda cargarse mucho ms rpido en tiempo de ejecucin.
Durante este paso, se realizan las siguientes operaciones para cada archivo de XAML que es un elemento de
compilacin Page:
1.

El compilador de marcado analiza el archivo XAML.

2.

Se crea una representacin generada para el XAML y se copia a la carpeta obj\Release.

3.

Se crea una representacin de CodeDOM de una nueva clase parcial y se copia a la carpeta
obj\Release.

Adems, se genera un archivo de cdigo especfico del lenguaje para cada archivo XAML. Por ejemplo, para una
pgina Page1.xaml de un proyecto escrito en Visual Basic se genera un archivo Page1.g.vb; para una pgina
Page1.xaml de un proyecto escrito en C# se genera un archivo Page1.g.cs. ".g" en el nombre de archivo indica
que el archivo es cdigo generado que tiene una declaracin de clase parcial para el elemento de nivel superior
del archivo de marcado (como Page o Window). La clase se declara con el modificador partial de C# (Extends
en Visual Basic) para indicar que es otra declaracin de la clase en otro lugar, normalmente en el archivo
Page1.xaml.cs de cdigo subyacente.
La clase parcial se extiende desde la clase base correspondiente (como Page para una pgina) e implementa la
interfaz System.Windows.Markup.IComponentConnector. La interfaz IComponentConnector tiene mtodos que
inicializan un componente y conectan los nombres y eventos en elementos en su contenido. Por consiguiente, el
archivo de cdigo generado tiene una implementacin de mtodos como la siguiente:
public void InitializeComponent()
{
if (_contentLoaded) {
return;
}
_contentLoaded = true;
System.Uri resourceLocater =
new System.Uri(
"window1.xaml",
System.UriKind.RelativeOrAbsolute);
System.Windows.Application.LoadComponent(this, resourceLocater);
}
De forma predeterminada, la compilacin del marcado se ejecuta en el mismo AppDomain que el motor de
MSBuild. Esto proporciona una mejora del rendimiento importante. Este comportamiento se activa o desactiva
con la propiedad AlwaysCompileMarkupFilesInSeparateDomain y tiene la ventaja de que todos los ensamblados
de referencia se descargan al descargar el AppDomain independiente.
Generacin del marcado: Paso 2
No todas las pginas XAML se generan en el paso 1 de la compilacin de marcado. Los archivos XAML que
tienen referencias de tipos definidos localmente (referencias a tipos definidos en el cdigo en otro lugar del
mismo proyecto) no se generan en este momento. Esto se debe a que estos tipos definidos localmente slo
existen en el cdigo fuente y an no estn generados. Para determinar esto, el analizador utiliza heurstica que

MCT: Luis Dueas

Pag 167 de 445

Manual de Windows Presentation Foundation


implica la bsqueda de elementos como x:Name en el archivo de marcado. Cuando se encuentra este tipo de
instancia, la compilacin del archivo de marcado se pospone hasta que se hayan generado los archivos de
cdigo y, en ese momento, el segundo paso de la compilacin de marcado procesa estos archivos.
Clasificacin de archivos
El proceso de compilacin coloca los archivos de resultados en grupos de recursos diferentes en funcin del
ensamblado de aplicacin en el que se van a incluir. En una aplicacin no traducida tpica, todos los archivos de
datos marcados como Resource se colocan en el ensamblado principal (ejecutable o biblioteca). Cuando
UICulture se establece en el proyecto, todos los archivos XAML generados y los recursos explcitamente
marcados como especficos del lenguaje se colocan en el ensamblado de recursos satlite. Asimismo, todos los
recursos neutrales en cuanto al idioma se colocan en el ensamblado principal. Esta determinacin de ubicacin
de los archivos se realiza en este paso del proceso de compilacin.
Las acciones de compilacin de ApplicationDefinition, Page y Resource del archivo de proyecto se pueden
incrementar con los metadatos de Localizable (los valores permitidos son true y false), que indican si el archivo
es especfico del idioma o neutral en cuanto al idioma.
Compilacin bsica
El paso bsico de compilacin implica la compilacin de los archivos de cdigo. Esta compilacin est controlada
por los archivos de destino especficos del lenguaje Microsoft.CSharp.targets y Microsoft.VisualBasic.targets. Si
la heurstica ha determinado que basta con un solo paso del compilador de marcado, se genera el ensamblado
principal. Sin embargo, si uno o varios archivos XAML del proyecto tienen referencias a tipos definidos
localmente, se genera un archivo .dll temporal para que los ensamblados de aplicacin finales se puedan crear
una vez completado el segundo paso de compilacin del marcado.
Generacin de manifiestos
Al final del proceso de compilacin, cuando todos los ensamblados de aplicacin y archivos de contenido estn
listos, se generan los manifiestos de ClickOnce para la aplicacin.
El archivo de manifiesto de implementacin describe el modelo de implementacin: la versin actual, el
comportamiento de actualizacin y la identidad del editor junto con la firma digital. Se supone que este
manifiesto lo crean los administradores que controlan la implementacin. La extensin de archivo es .xbap
(para Aplicaciones del explorador XAML (XBAPs)) y .application para las aplicaciones instaladas. La primera se
indica a travs de la propiedad HostInBrowser del proyecto y, como resultado, el manifiesto identifica la
aplicacin como hospedada en el explorador.
El manifiesto de aplicacin (un archivo .exe.manifest) describe los ensamblados de la aplicacin y las
bibliotecas dependientes, e incluye los permisos necesarios para la aplicacin. Se supone que este archivo lo
crea el desarrollador de la aplicacin. Para iniciar una aplicacin ClickOnce, un usuario abre el archivo de
manifiesto de implementacin de la aplicacin.
Estos archivos de manifiesto siempre se crean para XBAPs. Para las aplicaciones instaladas, no se crean a
menos que la propiedad GenerateManifests se especifique en el archivo de proyecto con el valor true
Los XBAPs obtienen dos permisos adicionales adems de los permisos asignados a las aplicaciones tpicas de
zona de Internet: WebBrowserPermission y MediaPermission. El sistema de compilacin de WPF declara esos
permisos en el manifiesto de la aplicacin.
Compatibilidad con la compilacin incremental
El sistema de compilacin de WPF proporciona compatibilidad con compilaciones incrementales. Es bastante
inteligente a la hora de detectar los cambios efectuados en el marcado o el cdigo, y slo detecta los artefactos
afectados por el cambio. El mecanismo de compilacin incremental utiliza los archivos siguientes:

Un archivo $(nombreDeEnsamblado)_MarkupCompiler.Cache para mantener el estado del compilador.

MCT: Luis Dueas

Pag 168 de 445

Manual de Windows Presentation Foundation

Un archivo $(nombreDeEnsamblado)_MarkupCompiler.lref para almacenar en cach los archivos XAML


con referencias a tipos definidos localmente.

A continuacin, se incluye un conjunto de reglas que rigen la compilacin incremental:

El archivo es la unidad ms pequea en la que el sistema de compilacin detecta un cambio. Por tanto,
para un archivo de cdigo, el sistema de compilacin no puede determinar si se ha cambiado un tipo o
se ha agregado cdigo. Lo mismo se aplica a los archivos de proyecto.

El mecanismo de compilacin incremental debe saber que una pgina XAML define una clase o utiliza
otras clases.

Si las entradas Reference cambian, vuelva a generar todas las pginas.

Si un archivo de cdigo cambia, vuelva a generar todas las pginas con referencias de tipos definidos
localmente.

Si un archivo XAML cambia:

Si XAML se declara como Page en el proyecto: si XAML no tiene referencias de tipos definidos
localmente, vuelva a generar ese XAML adems de todas las pginas XAML con referencias
locales; si XAML tiene referencias locales, vuelva a generar todas las pginas XAML con referencias
locales.

Si XAML se declara como ApplicationDefinition en el proyecto: vuelva a generar todas las


pginas XAML (razn: cada XAML hace referencia a un tipo Application que puede haber
cambiado).

Si el archivo de proyecto declara un archivo de cdigo como definicin de aplicacin en lugar de un


archivo XAML:

Compruebe si el valor de ApplicationClassName en el archivo de proyecto ha cambiado (hay


un nuevo tipo de aplicacin?). En ese caso, vuelva a generar toda la aplicacin.

De lo contrario, vuelva a generar todas las pginas XAML con referencias locales.

Si un archivo de proyecto cambia: aplique todas las reglas anteriores y determine lo que tiene que
volver a generar. Los cambios en las propiedades siguientes desencadenan una recompilacin
completa: AssemblyName, IntermediateOutputPath, RootNamespace y HostInBrowser.

Las situaciones de recompilacin posibles son las siguientes:

Se vuelve a generar toda la aplicacin.


Slo se vuelven a generar los archivos XAML que tienen referencias de tipos definidos localmente.
No se vuelve a generar nada (si no ha cambiado nada en el proyecto).

2.7.2. Implementar una Aplicacin de WPF


Una vez generadas las aplicaciones de Windows Presentation Foundation (WPF), es preciso implementarlas.
Windows y .NET Framework incluyen varias tecnologas de implementacin, como las siguientes:

Implementacin de XCopy.
Microsoft Windows Installer.
Implementacin de ClickOnce.
Windows Conexin a escritorio remoto (RDC).

La tecnologa de implementacin que se utiliza para implementar una aplicacin de WPF depende del tipo de
esta ltima. En WPF, hay tres tipos de aplicacin:

Aplicaciones independientes.
Aplicaciones del explorador XAML (XBAPs).
Pginas Lenguaje de marcado de aplicaciones extensible (XAML) hospedadas por explorador.

MCT: Luis Dueas

Pag 169 de 445

Manual de Windows Presentation Foundation


En este tema se proporciona alguna informacin general sobre cada tecnologa de implementacin y su uso,
adems de los requisitos de implementacin de cada tipo de aplicacin de WPF.
Tecnologas de implementacin
Implementacin de XCopy
La implementacin de XCopy se refiere al uso del programa de lnea de comandos XCopy para copiar los
archivos de una ubicacin a otra. La implementacin de XCopy es adecuada en las circunstancias siguientes:

Una aplicacin es autnoma; no necesita actualizar el cliente para ejecutarse.


Los archivos la aplicacin se deben mover de una ubicacin a otra; por ejemplo, de la ubicacin de
compilacin (disco local, recurso compartido de archivos UNC, etc.) a la ubicacin de publicacin (sitio
web, recurso compartido de archivos UNC, etc.).

Una aplicacin no requiere la integracin en el shell (acceso directo del men de Inicio, icono de
escritorio, etc.).

Aunque XCopy es adecuado para escenarios de implementacin simples, presenta limitaciones cuando se
requieren funciones de implementacin ms complejas. En particular, al utilizar Xcopy se provoca una
sobrecarga al crear, ejecutar y mantener los scripts necesarios para administrar la implementacin de una
manera robusta. Adems, XCopy no admite el control de versiones, la desinstalacin ni la reversin.
Microsoft Windows Installer
Windows Installer permite empaquetar las aplicaciones como aplicaciones ejecutables autnomas que se
pueden distribuir con facilidad a los clientes y ejecutar. Adems, Windows Installer se instala con Windows y
habilita la integracin con el escritorio, el men Inicio, y el panel de control Agregar o quitar programas.
Windows Installer simplifica la instalacin y desinstalacin de aplicaciones, pero no proporciona los medios para
asegurarse de que las aplicaciones instaladas se mantengan actualizadas desde el punto de vista de su versin.
Implementacin ClickOnce
ClickOnce habilita la implementacin de aplicaciones de tipo web para aplicaciones no web: las aplicaciones se
publican e inician desde servidores web. Aunque ClickOnce no admite la gama completa de caractersticas de
cliente que s poseen las aplicaciones instaladas con Windows Installer, admite un subconjunto que incluye lo
siguiente:

Integracin con el men Inicio y el panel de control Agregar o quitar programas, para aplicaciones
independientes.

Control de versiones, reversin y desinstalacin.


Modo de instalacin en lnea, que siempre inicia una aplicacin desde la ubicacin de implementacin.

Conexiones de Escritorio remoto


Las aplicaciones de WPF se pueden ejecutar utilizando Terminal Services. Para ello es preciso instalar la
aplicacin de WPF en un servidor con Terminal Services. As, un cliente podr usar Conexin a escritorio remoto
(RDC) para conectarse al servidor y ejecutar remotamente la aplicacin de WPF.
Nota:
En algunas configuraciones, WPF proporciona una experiencia de representacin optimizada a los usuarios
de Conexin a escritorio remoto (RDC) de las aplicaciones de WPF.
Implementar aplicaciones de WPF
Las opciones de implementacin para una aplicacin de WPF dependen del tipo de aplicacin. Desde la
perspectiva de la implementacin, WPF tiene tres tipos de aplicacin significativos, que son las aplicaciones
XAML slo de marcado, las XBAPs y las aplicaciones independientes.
Implementar aplicaciones XAML slo de marcado
Las pginas XAML slo de marcado se suelen publicar en servidores web, como las pginas HTML, y se exploran
mediante Internet Explorer. WPF utiliza ClickOnce para facilitar la exploracin, aunque est oculto a los usuarios

MCT: Luis Dueas

Pag 170 de 445

Manual de Windows Presentation Foundation


finales. Adems, las pginas XAML slo de marcado se ejecutan dentro de un recinto de seguridad de confianza
parcial con restricciones definidas por el conjunto de permisos de zona de Internet. Esto proporciona un recinto
de seguridad equivalente al de las aplicaciones web basadas en HTML.
Las pginas XAML slo de marcado se pueden instalar en el disco local utilizando XCopy o Windows Installer.
Estas pginas se pueden iniciar utilizando Internet Explorer o Windows Explorer.
Implementar aplicaciones de explorador XAML
Las XBAPs son aplicaciones compiladas que necesitan los tres archivos siguientes para implementarse:

nombreDeAplicacin.exe: archivo de aplicacin del ensamblado ejecutable.


nombreDeAplicacin.xbap: manifiesto de implementacin.
nombreDeAplicacin.exe.manifest: manifiesto de la aplicacin.

Estos archivos se crean al generar una XBAP mediante MSBuild. Al igual que las pginas XAML slo de marcado,
las XBAPs se suelen publicar en un servidor web y se exploran mediante Internet Explorer.
Las XBAPs se pueden implementar en clientes utilizando XCopy o Windows Installer. Sin embargo, al
implementar XBAPs de esta manera deben tenerse en cuenta dos cosas:
1.

La XBAP no se actualiza automticamente cuando se publica una nueva versin.

2.

La XBAP se ejecuta con permisos de plena confianza, un comportamiento incoherente con el modelo de
seguridad de confianza parcial de las aplicaciones web.

Implementar aplicaciones independientes


Las aplicaciones independientes se implementan utilizando ClickOnce o Windows Installer. De cualquier modo,
las aplicaciones independientes requieren plena confianza para ejecutarse. La plena confianza se concede
automticamente a las aplicaciones independientes que se implementan mediante Windows Installer. Las
aplicaciones independientes que se implementan mediante ClickOnce no reciben la plena confianza de manera
automtica. En lugar de ello, ClickOnce muestra un cuadro de dilogo de advertencia de seguridad que el
usuario debe aceptar antes de instalar cualquier aplicacin independiente. Si el usuario acepta, se instala la
aplicacin independiente y se le otorgan permisos de plena confianza. En caso contrario, no se instala la
aplicacin independiente.
Instalar .NET Framework 3.0
Para ejecutar una aplicacin de WPF, Microsoft .NET Framework debe estar instalado en el cliente. Internet
Explorer 7 detecta automticamente si el cliente tiene .NET Framework instalado al examinar aplicaciones de
WPF hospedadas por explorador. Si no lo est, Internet Explorer 7 pide al usuario que lo instale.
Para detectar si .NET Framework est instalado, Internet Explorer 7 incluye una aplicacin de programa previo
que se registra como controlador Extensiones multipropsito de correo Internet (MIME) de reserva para los
archivos de contenido con las extensiones siguientes: .xaml, .xps, .xbap y .application. Cuando se navega a
estos tipos de archivo y .NET Framework no est instalado en el cliente, la aplicacin de programa previo pide
permiso para instalarlo. Si no se concede este permiso, no se instala .NET Framework ni la aplicacin.
Si se concede el permiso, Internet Explorer 7 descarga e instala .NET Framework mediante Servicio de
transferencia inteligente en segundo plano de Microsoft (BITS) deshabilitado. Despus de instalar .NET
Framework correctamente, se inicia el archivo solicitado originalmente en una nueva ventana del explorador.
La deteccin automtica de .NET Framework est disponible en los clientes de Windows Vista, Microsoft
Windows XP Service Pack 2 (SP2) y Microsoft Windows Server 2003 (SP1) que tengan Internet Explorer 7
instalado.

2.7.3. Temas Cmo de Generar e Implementar

MCT: Luis Dueas

Pag 171 de 445

Manual de Windows Presentation Foundation


En los temas siguientes se muestra cmo crear archivos de proyecto para los diversos tipos de aplicacin de
WPF.

2.7.3.1. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin


Independiente de WPF
Este archivo de proyecto de ejemplo es para una aplicacin independiente de Windows Presentation Foundation
(WPF), con una definicin de aplicacin, App, que se configura para abrir automticamente una ventana,
MainWindow, que se define mediante Lenguaje de marcado de aplicaciones extensible (XAML) y cdigo
subyacente. Los detalles principales de la configuracin incluyen:

OutputType. Se establece en winexe.


App.xaml. Archivo de definicin de la aplicacin que se va a configurar como un elemento

ApplicationDefinition.

MainWindow.xaml. Archivo XAML declarado como elemento Page.


MainWindow.xaml.cs. Archivo de cdigo subyacente declarado como elemento Compile.

Puede reutilizar o modificar este archivo de proyecto para adaptarlo a sus necesidades, siempre que los
archivos a los que hace referencia se encuentren en la ubicacin desde la que hace referencia a ellos. Como
alternativa, puede hacer que se genere automticamente un archivo de proyecto para una aplicacin
independiente mediante la plantilla de proyecto Aplicacin para Windows (WPF) de Microsoft Visual Studio
2005.
Este archivo de proyecto es para un proyecto de C# y, por tanto, incluye el elemento Import de
Microsoft.CSharp.targets. Microsoft Visual Studio 2005 asigna a los archivos de proyecto de C# una
extensin .csproj. Un proyecto de Microsoft Visual Basic .NET creado en Microsoft Visual Studio 2005 tendra
normalmente la extensin .vbproj e incluira el elemento Import de Microsoft.VisualBasic.targets.
Ejemplo
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>WPFStandaloneApplication</RootNamespace>
<AssemblyName>WPFStandaloneApplication</AssemblyName>
<WarningLevel>4</WarningLevel>
<OutputType>winexe</OutputType>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>false</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />

MCT: Luis Dueas

Pag 172 de 445

Manual de Windows Presentation Foundation


</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
<Page Include="MainWindow.xaml" />
<Compile Include="MainWindow.xaml.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

2.7.3.2. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin


de Navegacin Independiente de WPF
Este ejemplo de archivo de proyecto es para una aplicacin de navegacin independiente de Windows
Presentation Foundation (WPF), con una definicin de aplicacin, App, configurada para abrir automticamente
una pgina, HomePage, que se define mediante Lenguaje de marcado de aplicaciones extensible (XAML) y
cdigo subyacente. HomePage se abrir en una NavigationWindow. Los detalles principales de la configuracin
incluyen:

OutputType. Se establece en winexe.

App.xaml. Archivo de definicin de la aplicacin que se va a configurar como un elemento

ApplicationDefinition.

HomePage.xaml. Archivo XAML declarado como elemento Page.

HomePage.xaml.cs. Archivo de cdigo subyacente declarado como elemento Compile.

Puede reutilizar o modificar este archivo de proyecto para adaptarlo a sus necesidades, siempre que los
archivos a los que hace referencia se encuentren en la ubicacin desde la que hace referencia a ellos. Como
alternativa, puede tener un archivo de proyecto para una aplicacin de navegacin independiente generada
automticamente para usted utilizando la plantilla de proyecto Aplicacin para Windows (WPF) de Microsoft
Visual Studio 2005 y reemplazando al Window predeterminado por un Page.
Este archivo de proyecto es para un proyecto de C# y, por tanto, incluye el elemento Import de
Microsoft.CSharp.targets. Microsoft Visual Studio 2005 asigna a los archivos de proyecto de C# una
extensin .csproj. Un proyecto de Microsoft Visual Basic .NET creado en Microsoft Visual Studio 2005 tendra
normalmente la extensin .vbproj e incluira el elemento Import de Microsoft.VisualBasic.targets.
Ejemplo
<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>WPFStandaloneNavigationApplication</RootNamespace>
<AssemblyName>WPFStandaloneNavigationApplication</AssemblyName>
<WarningLevel>4</WarningLevel>
<OutputType>winexe</OutputType>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>false</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>

MCT: Luis Dueas

Pag 173 de 445

Manual de Windows Presentation Foundation


<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
<Page Include="HomePage.xaml" />
<Compile Include="HomePage.xaml.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

2.7.3.3. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin


de Explorador XAML de WPF
Este ejemplo de archivo de proyecto es para una Aplicacin del explorador XAML (XBAP) con un archivo de
definicin de aplicacin, App, configurado para abrir automticamente una pgina, HomePage, definida
mediante XAML y cdigo subyacente. Los detalles principales de la configuracin incluyen:

OutputType. Se establece en winexe.

HostInBrowser. Se debe establecer en true porque las Aplicaciones del explorador XAML (XBAPs) deben
hospedarse en el explorador.

Install. Se debe establecer en false porque las Aplicaciones del explorador XAML (XBAPs) no se
instalan.

TargetZone. Se debe establecer en "Internet", porque las Aplicaciones del explorador XAML (XBAPs) se
ejecutan en la zona de seguridad de Internet.

StartAction. Se debe establecer en "Program".

StartProgram. Se debe establecer en el programa que administra el proceso de hospedar la aplicacin


en el explorador.

StartArguments. Se debe establecer en la ruta de acceso al manifiesto de aplicaciones, cuya extensin


es .xbap.

App.xaml. Archivo de definicin de la aplicacin que se va a configurar como un elemento

ApplicationDefinition.

HomePage.xaml. Archivo XAML declarado como elemento Page.

HomePage.xaml.cs. Archivo de cdigo subyacente declarado como elemento Compile.

XBAPApplication_TemporaryKey.pfx. Un archivo de claves de manifiesto temporal que necesitan las


aplicaciones que se implementan mediante ClickOnce, lo que incluye las XBAPs.

Puede reutilizar o modificar este archivo de proyecto para adaptarlo a sus necesidades, siempre que los
archivos a los que hace referencia se encuentren en la ubicacin desde la que hace referencia a ellos. Como
alternativa, puede hacer que se genere automticamente un archivo de proyecto para una XBAP mediante la
plantilla de proyecto Aplicacin del explorador XAML (WPF) de Microsoft Visual Studio 2005.
Este archivo de proyecto es para un proyecto de C# y, por tanto, incluye el elemento Import de
Microsoft.CSharp.targets. Microsoft Visual Studio 2005 asigna a los archivos de proyecto de C# una
extensin .csproj. Un proyecto de Microsoft Visual Basic .NET creado en Microsoft Visual Studio 2005 tendra
normalmente la extensin .vbproj e incluira el elemento Import de Microsoft.VisualBasic.targets.
Ejemplo

MCT: Luis Dueas

Pag 174 de 445

Manual de Windows Presentation Foundation


<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>XBAPApplication</RootNamespace>
<AssemblyName>XBAPApplication</AssemblyName>
<WarningLevel>4</WarningLevel>
<OutputType>winexe</OutputType>
<EnableSecurityDebugging>false</EnableSecurityDebugging>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<MapFileExtensions>False</MapFileExtensions>
<HostInBrowser>True</HostInBrowser>
<Install>False</Install>
<TargetZone>Internet</TargetZone>
<StartAction>Program</StartAction>
<StartProgram>$(WINDIR)\System32\PresentationHost.exe</StartProgram>
<ApplicationExtension>.xbap</ApplicationExtension>
<StartArguments>-debug
"$(MSBuildProjectDirectory)\bin\$(Configuration)\$(AssemblyName)$(ApplicationExtension)"</S
tartArguments>
<SignManifests>True</SignManifests>
<BootstrapperEnabled>false</BootstrapperEnabled>
<ManifestKeyFile>XBAPApplication_TemporaryKey.pfx</ManifestKeyFile>
<ManifestCertificateThumbprint>F2E49D0E8A6FE749DE85D224F5557B875DFD5577</ManifestCertificat
eThumbprint>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml" />
<Page Include="HomePage.xaml" />
<Compile Include="HomePage.xaml.cs" />
</ItemGroup>
<ItemGroup>
<None Include="XBAPApplication_TemporaryKey.pfx" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

2.7.3.4. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Biblioteca de


Controles Personalizados de WPF
Este archivo de proyecto de ejemplo es para una biblioteca de controles personalizada de Windows Presentation
Foundation (WPF), con un nico control de usuario, WPFUserControl. Los detalles principales de la configuracin
incluyen:

OutputType. Se establece en library.


WPFUserControl.xaml. Archivo XAML declarado como elemento Page.
WPFUserControl.xaml.cs. Archivo de cdigo subyacente declarado como elemento Compile.

Puede reutilizar o modificar este archivo de proyecto para adaptarlo a sus necesidades, siempre que los
archivos a los que hace referencia se encuentren en la ubicacin desde la que hace referencia a ellos.
Alternativamente, puede hacer que se genere automticamente un archivo de proyecto para un control
personalizado mediante la plantilla de proyecto Biblioteca de controles personalizados (WPF) en Microsoft Visual
Studio 2005.
Este archivo de proyecto es para un proyecto de C# y, por tanto, incluye el elemento Import de
Microsoft.CSharp.targets. Microsoft Visual Studio 2005 asigna a los archivos de proyecto de C# una

MCT: Luis Dueas

Pag 175 de 445

Manual de Windows Presentation Foundation


extensin .csproj. Un proyecto de Microsoft Visual Basic .NET creado en Microsoft Visual Studio 2005 tendra
normalmente la extensin .vbproj e incluira el elemento Import de Microsoft.VisualBasic.targets.
Ejemplo
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>WPFCustomControlLibrary</RootNamespace>
<AssemblyName>WPFCustomControlLibrary</AssemblyName>
<WarningLevel>4</WarningLevel>
<OutputType>library</OutputType>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Page Include="WPFUserControl.xaml" />
<Compile Include="WPFUserControl.xaml.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<AppDesigner Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

2.7.3.5. Cmo: Crear un Archivo de Proyecto de Ejemplo para una Aplicacin


Independiente de WPF que slo contiene Cdigo
Este archivo de proyecto del ejemplo es para una aplicacin de Windows Presentation Foundation (WPF)
independiente escrita completamente en cdigo; es decir, sin Lenguaje de marcado de aplicaciones extensible
(XAML). Los detalles principales de la configuracin incluyen:

OutputType. Se establece en winexe.


Todos los archivos de cdigo .cs de C#. Se compilan automticamente utilizando un elemento

Compile cuyo atributo Include se establece en *.cs.


Puede reutilizar o modificar este archivo de proyecto para adaptarlo a sus necesidades, siempre que los
archivos a los que hace referencia se encuentren en la ubicacin desde la que hace referencia a ellos. Como
alternativa, puede hacer que se genere automticamente un archivo de proyecto para una aplicacin
independiente mediante la plantilla de proyecto Aplicacin para Windows (WPF) de Microsoft Visual Studio

MCT: Luis Dueas

Pag 176 de 445

Manual de Windows Presentation Foundation


2005. Adems, necesitar quitar el cdigo generado de manera predeterminada y los archivos XAML: App.xaml,
App.xaml.cs, Window1.xaml, y Window1.xaml.cs.
Este archivo de proyecto es para un proyecto de C# y, por tanto, incluye el elemento Import de
Microsoft.CSharp.targets. Microsoft Visual Studio 2005 asigna a los archivos de proyecto de C# una
extensin .csproj. Un proyecto de Microsoft Visual Basic .NET creado en Microsoft Visual Studio 2005 tendra
normalmente la extensin .vbproj e incluira el elemento Import de Microsoft.VisualBasic.targets.
Ejemplo
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>WPFStandaloneApplicationCodeOnly</RootNamespace>
<AssemblyName>WPFStandaloneApplicationCodeOnly</AssemblyName>
<WarningLevel>4</WarningLevel>
<OutputType>winexe</OutputType>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<BootstrapperEnabled>false</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<Compile Include="*.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

2.7.3.6. Cmo: Configurar IIS 5.0 e IIS 6.0 para Implementar Aplicaciones de
WPF
Puede implementar una aplicacin de Windows Presentation Foundation (WPF) desde la mayora de los
servidores web, siempre que estn configurados con los tipos Extensiones multipropsito de correo Internet
(MIME) adecuados. De manera predeterminada, Microsoft Internet Information Services (IIS) 7.0 se configura
con estos tipos MIME, pero Microsoft Internet Information Services (IIS) 5.0 y Microsoft Internet Information
Services (IIS) 6.0, no.
En este tema se describe cmo configurar Microsoft Internet Information Services (IIS) 5.0 y Microsoft Internet
Information Services (IIS) 6.0 para implementar aplicaciones de WPF.
Nota:

MCT: Luis Dueas

Pag 177 de 445

Manual de Windows Presentation Foundation

Puede comprobar la cadena UserAgent del Registro para determinar si un sistema tiene .NET Framework
instalado. Para obtener informacin detallada y un script que examina la cadena UserAgent para determinar
si .NET Framework est instalado en un sistema.
Ajustar la configuracin de la expiracin del contenido
Debe ajustar el valor de la expiracin del contenido a 1 minuto. En el siguiente procedimiento se indica cmo
hacerlo con IIS.
1.

Haga clic en el men Inicio, seleccione Herramientas administrativas y, a continuacin, haga clic
en Administrador de Internet Information Services (IIS). Tambin puede iniciar esta aplicacin
desde la lnea de comandos con "%SystemRoot%\system32\inetsrv\iis.msc".

2.

Expanda el rbol de IIS hasta encontrar el nodo Sitio web predeterminado.

3.

Haga clic con el botn secundario en Sitio web predeterminado y seleccione Propiedades en el
men contextual.

4.

Seleccione la ficha Encabezados HTTP y haga clic en "Habilitar expiracin de contenido".

5.

Establezca el contenido para que expire transcurrido 1 minuto.


Registrar tipos MIME y extensiones de archivo

Debe registrar varios tipos MIME y extensiones de archivo para que el explorador del sistema cliente pueda
cargar el controlador correcto. Debe agregar los tipos siguientes:
Extensin

Tipo MIME

.manifest

application/manifest

.xaml

application/xaml+xml

.application

application/x-ms-application

.xbap

application/x-ms-xbap

.deploy

application/octet-stream

.xps

application/vnd.ms-xpsdocument

Nota:
No necesita registrar los tipos MIME ni las extensiones de archivo en los sistemas cliente. Se registran
automticamente al instalar Microsoft .NET Framework.
En el ejemplo de Microsoft Visual Basic Scripting (VBScript) siguiente se agregan automticamente los tipos
MIME necesarios a IIS. Para utilizar el script, copie el cdigo en un archivo .vbs de su servidor. A continuacin,
ejecute el script desde la lnea de comandos o haga doble clic en l desde el Microsoft Windows Explorer.
' This script adds the necessary Windows Presentation Foundation MIME types
' to an IIS Server.
' To use this script, just double-click or execute it from a command line.
' Running this script multiple times results in multiple entries in the IIS MimeMap.
Dim MimeMapObj, MimeMapArray, MimeTypesToAddArray, WshShell, oExec
Const ADS_PROPERTY_UPDATE = 2
' Set the MIME types to be added
MimeTypesToAddArray = Array(".manifest", "application/manifest", ".xaml", _
"application/xaml+xml", ".application", "application/x-ms-application", _
".deploy", "application/octet-stream", ".xbap", "application/x-ms-xbap", _
".xps", "application/vnd.ms-xpsdocument")
' Get the mimemap object
Set MimeMapObj = GetObject("IIS://LocalHost/MimeMap")
' Call AddMimeType for every pair of extension/MIME type
For counter = 0 to UBound(MimeTypesToAddArray) Step 2
AddMimeType MimeTypesToAddArray(counter), MimeTypesToAddArray(counter+1)
Next
' Create a Shell object
Set WshShell = CreateObject("WScript.Shell")
' Stop and Start the IIS Service

MCT: Luis Dueas

Pag 178 de 445

Manual de Windows Presentation Foundation


Set oExec = WshShell.Exec("net stop w3svc")
Do While oExec.Status = 0
WScript.Sleep 100
Loop
Set oExec = WshShell.Exec("net start w3svc")
Do While oExec.Status = 0
WScript.Sleep 100
Loop
Set oExec = Nothing
' Report status to user
WScript.Echo "Windows Presentation Foundation MIME types have been registered."
' AddMimeType Sub
Sub AddMimeType (Ext, MType)
' Get the mappings from the MimeMap property.
MimeMapArray = MimeMapObj.GetEx("MimeMap")
' Add a new mapping.
i = UBound(MimeMapArray) + 1
Redim Preserve MimeMapArray(i)
Set MimeMapArray(i) = CreateObject("MimeMap")
MimeMapArray(i).Extension = Ext
MimeMapArray(i).MimeType = MType
MimeMapObj.PutEx ADS_PROPERTY_UPDATE, "MimeMap", MimeMapArray
MimeMapObj.SetInfo
End Sub
Nota:
Si ejecuta este script varias veces, se crean varias entradas de asignacin MIME en la metabase de
Microsoft Internet Information Services (IIS) 5.0 o Microsoft Internet Information Services (IIS) 6.0.
Despus de haber ejecutado este script, puede que no vea los tipos MIME adicionales de Microsoft Internet
Information Services (IIS) 5.0 o Microsoft Internet Information Services (IIS) 6.0 Microsoft Management
Console (MMC). Sin embargo, estos tipos MIME se han agregado a la metabase de Microsoft Internet
Information Services (IIS) 5.0 o Microsoft Internet Information Services (IIS) 6.0. El script siguiente mostrar
todos los tipos MIME en la metabase de Microsoft Internet Information Services (IIS) 5.0 o Microsoft Internet
Information Services (IIS) 6.0.
' This script lists the MIME types for an IIS Server.
' To use this script, just double-click or execute it from a command line
' by calling cscript.exe
dim mimeMapEntry, allMimeMaps
' Get the mimemap object.
Set mimeMapEntry = GetObject("IIS://localhost/MimeMap")
allMimeMaps = mimeMapEntry.GetEx("MimeMap")
' Display the mappings in the table.
For Each mimeMap In allMimeMaps
WScript.Echo(mimeMap.MimeType & " (" & mimeMap.Extension + ")")
Next
Guarde el script como un archivo .vbs (por ejemplo, DiscoverIISMimeTypes.vbs) y ejectelo desde el smbolo del
sistema utilizando el comando siguiente:

cscript DiscoverIISMimeTypes.vbs

2.7.3.7. Configurar Visual Studio 2005 para Depurar una Aplicacin de


Explorador XAML
PresentationHost.exe administra la ejecucin de las XBAPs y proporciona los medios para depurarlas.
Configurar Visual Studio
Para configurar Microsoft Visual Studio 2005 a fin de depurar una XBAP
1. Con un proyecto seleccionado en el Explorador de soluciones, en el men Proyecto haga clic en
Propiedades.
2. En el Diseador de proyectos, haga clic en la ficha Depurar.
3. En la seccin Accin de inicio, seleccione Programa externo de inicio y escriba lo siguiente:

C:\WINDOWS\System32\PresentationHost.exe
4. En la seccin Opciones de inicio, escriba lo siguiente en el cuadro de texto Argumentos de la lnea de
comandos:

-debug nombre_de_archivo
El valor del nombre_de_archivo del parmetro -debug es el nombre del archivo .xbap; por ejemplo:

-debug c:\example.xbap

MCT: Luis Dueas

Pag 179 de 445

Manual de Windows Presentation Foundation

Nota:
sta es la configuracin predeterminada para las soluciones que se crean con la plantilla del proyecto
Aplicacin del explorador XAML (WPF) de Visual Studio 2005.

2.7.3.8. Configurar Visual Studio para Depurar una Aplicacin de Explorador


XAML y Llamar a un Servicio Web
Las Aplicaciones del explorador XAML (XBAPs) se ejecutan dentro de un recinto de seguridad de confianza
parcial que est restringido al conjunto de permisos de la zona Internet. Este conjunto de permisos restringe
las llamadas a aquellos servicios web que se encuentren en el sitio de origen de la aplicacin XBAP. Sin
embargo, al depurar una XBAP desde Microsoft Visual Studio 2005, no se considera que tiene el mismo sitio de
origen que el servicio web al que hace referencia. Esto hace que se inicien excepciones de seguridad cuando la
XBAP intenta llamar al servicio web. Sin embargo, se puede configurar un proyecto Aplicacin del explorador
XAML (WPF) de Microsoft Visual Studio 2005 para simular que tiene el mismo sitio de origen que el servicio web
al que llama durante la depuracin. Esto permite que la XBAP llame sin ningn riesgo al servicio web sin que se
inicien excepciones de seguridad.
Configurar Visual Studio
Para configurar Microsoft Visual Studio 2005 para depurar una XBAP que llama a un servicio web:
1.
2.

Configure Microsoft Visual Studio 2005 para depurar XBAPs.


Con un proyecto seleccionado en el Explorador de soluciones, en el men Proyecto haga clic en
Propiedades.

3.
4.

En el Diseador de proyectos, haga clic en la ficha Depurar.


En la seccin Opciones de inicio, agregue el parmetro de lnea de comandos siguiente al cuadro de
texto Argumentos de la lnea de comandos:

-debugSecurityZoneURL URL
El valor de URL del parmetro -debugSecurityZoneURL es la URL de la ubicacin que desea indicar
como sitio de origen simulado de la aplicacin.
A modo de ejemplo, supongamos que una Aplicacin del explorador XAML (XBAP) utiliza un servicio web con la
URL siguiente:

http://services.msdn.microsoft.com/ContentServices/ContentService.asmx
La URL del sitio de origen de este servicio web es:

http://services.msdn.microsoft.com
Por consiguiente, el parmetro de lnea de comandos -debugSecurityZoneURL completo con su valor es:

-debugSecurityZoneURL http://services.msdn.microsoft.com

2.7.3.9. Cmo: Determinar la Versin Instalada de Windows Presentation


Foundation
El nmero de versin para versin instalada actualmente de Windows Presentation Foundation (WPF) se
encuentra en el Registro.
Para buscar el nmero de versin:
1. En el men Inicio, haga clic en Ejecutar.
2. En Abrir, escriba regedit.exe.
3. Abra la clave siguiente:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0\Setup\Windows


Presentation Foundation

MCT: Luis Dueas

Pag 180 de 445

Manual de Windows Presentation Foundation


El nmero de versin de WPF se almacena en el valor Version.

2.7.3.10. Cmo: Detectar si .NET Framework 3.0 est Instalado


Antes de que los administradores puedan implementar aplicaciones Microsoft .NET Framework en un sistema,
deben confirmar primero que est presente el tiempo de ejecucin de .NET Framework. En este tema se
proporciona un script escrito en HTML/JavaScript que los administradores pueden utilizar para determinar si
.NET Framework est presente en un sistema.
Detectar la cadena de agente de usuario ".NET CLR"
Cuando se instala .NET Framework, el archivo MSI agrega ".NET CLR" y el nmero de versin a la cadena
UserAgent. En el ejemplo siguiente se muestra un script incrustado en una pgina HTML simple. El script busca
la cadena UserAgent para determinar si .NET Framework est instalado, y muestra un mensaje de estado sobre
los resultados de la bsqueda.
<HTML>
<HEAD>
<TITLE>Test for the .NET Framework 3.0</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8" />
<SCRIPT LANGUAGE="JavaScript">
<!-var dotNETRuntimeVersion = "3.0.04425.00";
function window::onload()
{
if (HasRuntimeVersion(dotNETRuntimeVersion))
{
result.innerText =
"This machine has the correct version of the .NET Framework 3.0: "
+ dotNETRuntimeVersion
}
else
{
result.innerText =
"This machine does not have the correct version of the .NET Framework 3.0."
}
result.innerText += "\n\nThis machine's userAgent string is: " +
navigator.userAgent + ".";
}
//
// Retrieve the version from the user agent string and
// compare with the specified version.
//
function HasRuntimeVersion(versionToCheck)
{
var userAgentString =
navigator.userAgent.match(/.NET CLR [0-9.]+/g);
if (userAgentString != null)
{
var i;
for (i = 0; i < userAgentString.length; ++i)
{
if (CompareVersions(GetVersion(versionToCheck),
GetVersion(userAgentString[i])) <= 0)
return true;
}
}
return false;

}
//
// Extract the numeric part of the version string.
//
function GetVersion(versionString)
{
var numericString =
versionString.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/i);
return numericString.slice(1);
}
//
// Compare the 2 version strings by converting them to numeric format.
//
function CompareVersions(version1, version2)
{
for (i = 0; i < version1.length; ++i)
{
var number1 = new Number(version1[i]);
var number2 = new Number(version2[i]);

MCT: Luis Dueas

Pag 181 de 445

Manual de Windows Presentation Foundation


if (number1 < number2)
return -1;
if (number1 > number2)
return 1;
}
return 0;
}
-->
</SCRIPT>
</HEAD>
<BODY>
<div id="result" />
</BODY>
</HTML>
Si la bsqueda de la versin de ".NET CLR " se realiza correctamente, aparece el tipo siguiente de mensaje de
estado:

This machine has the correct version of the .NET Framework 3.0: 3.0.04425.00
This machine's userAgent string is: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1;
.NET CLR 2.0.50727; .NET CLR 3.0.04425.00).
De lo contrario, aparece un mensaje de estado del tipo siguiente:

This machine does not have correct version of the .NET Framework 3.0.
This machine's userAgent string is: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1;
.NET CLR 2.0.50727).

2.7.3.11. Cmo: Detectar si .NET Framework 3.5 est Instalado


Antes de que los administradores puedan implementar aplicaciones Windows Presentation Foundation (WPF) en
un sistema cuyo destino sea .NET Framework 3.5, debern confirmar si est presente el motor en tiempo de
ejecucin de .NET Framework 3.5. En este tema se proporciona un script escrito en HTML/JavaScript que los
administradores pueden utilizar para determinar si .NET Framework 3.5 est presente en un sistema.
Ejemplo
Cuando se instala .NET Framework 3.5, MSI agrega ".NET CLR" y el nmero de versin a la cadena UserAgent.
En el ejemplo siguiente se muestra un script incrustado en una pgina HTML simple. El script busca la cadena
UserAgent para determinar si .NET Framework 3.5 est instalado y muestra un mensaje de estado sobre los
resultados de la bsqueda.
<HTML>
<HEAD>
<TITLE>Test for the .NET Framework 3.5</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8" />
<SCRIPT LANGUAGE="JavaScript">
<!-var dotNETRuntimeVersion = "3.5.0.0";
function window::onload()
{
if (HasRuntimeVersion(dotNETRuntimeVersion))
{
result.innerText =
"This machine has the correct version of the .NET Framework 3.5."
}
else
{
result.innerText =
"This machine does not have the correct version of the .NET Framework 3.5." +
" The required version is v" + dotNETRuntimeVersion + ".";
}
result.innerText += "\n\nThis machine's userAgent string is: " +
navigator.userAgent + ".";
}
//
// Retrieve the version from the user agent string and
// compare with the specified version.
//
function HasRuntimeVersion(versionToCheck)
{
var userAgentString =
navigator.userAgent.match(/.NET CLR [0-9.]+/g);

MCT: Luis Dueas

Pag 182 de 445

Manual de Windows Presentation Foundation


if (userAgentString != null)
{
var i;
for (i = 0; i < userAgentString.length; ++i)
{
if (CompareVersions(GetVersion(versionToCheck),
GetVersion(userAgentString[i])) <= 0)
return true;
}
}
return false;
}
//
// Extract the numeric part of the version string.
//
function GetVersion(versionString)
{
var numericString =
versionString.match(/([0-9]+)\.([0-9]+)\.([0-9]+)/i);
return numericString.slice(1);
}
//
// Compare the 2 version strings by converting them to numeric format.
//
function CompareVersions(version1, version2)
{
for (i = 0; i < version1.length; ++i)
{
var number1 = new Number(version1[i]);
var number2 = new Number(version2[i]);
if (number1 < number2)
return -1;
if (number1 > number2)
return 1;
}
return 0;
}
-->
</SCRIPT>
</HEAD>
<BODY>
<div id="result" />
</BODY>
</HTML>
Si la bsqueda de la versin de ".NET CLR " se realiza correctamente, aparecer el siguiente tipo de mensaje de
estado:

This machine has the correct version of the .NET Framework 3.5.
This machine's userAgent string is: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727;
.NET CLR 1.1.4322; InfoPath.2; .NET CLR 3.0.590; .NET CLR 3.5.20726; MS-RTC LM 8).
De lo contrario, aparecer el siguiente tipo de mensaje de estado:

This machine does not have the correct version of the .NET Framework 3.5. The required version is v3.5.0.0.
This machine's userAgent string is: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727;
.NET CLR 1.1.4322; InfoPath.2; .NET CLR 3.0.590; MS-RTC LM 8).

2.7.3.12. Cmo: Detectar si est Instalado el Complemento XBAP para Firefox


Antes de que los administradores puedan implementar Aplicaciones del explorador XAML (XBAPs) en equipos
cliente con Firefox 2.0+ como explorador, debern confirmar que est instalado Firefox 2.0+. En este tema se
proporciona un script escrito en HTML/JavaScript que los administradores pueden utilizar para determinar si
Firefox 2.0+ est presente en un sistema.
Ejemplo
Cuando se instala .NET Framework 3.5, el equipo cliente se configura con un complemento para Firefox 2.0+
que permite a Firefox 2.0+ hospedar Aplicaciones del explorador XAML (XBAPs). En el siguiente script de
ejemplo se comprueba si est hospedado en Firefox 2.0+ antes de comprobar el complemento de Windows
Presentation Foundation. Sea cual sea el resultado, el script muestra el mensaje de estado correspondiente.
<HTML>
<HEAD>

MCT: Luis Dueas

Pag 183 de 445

Manual de Windows Presentation Foundation


<TITLE>Test for the Firefox Plugin for WPF</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8" />
<SCRIPT type="text/javascript">
<!-function OnLoad()
{
// Check if browser is Firefox
if( navigator.plugins.length == 0 ) {
document.writeln("The browser must be Firefox 2.0+.");
return;
}
// Check for WPF plugin and report
var msg = "Windows Presentation Foundation Plugin for Mozilla Firefox is ";
var wpfPlugin = navigator.plugins["Windows Presentation Foundation"];
if( wpfPlugin != null ) {
document.writeln(msg + " installed.");
}
else {
document.writeln(msg + " not installed. Please install or reinstall the .NET
Framework 3.5.");
}
}
-->
</SCRIPT>
</HEAD>
<BODY onload="OnLoad()" />
</HTML>
Si la bsqueda del complemento de Windows Presentation Foundation se realiza correctamente, aparecer el
siguiente mensaje de estado:

Windows Presentation Foundation Plugin for Mozilla Firefox is installed.


De lo contrario, aparecer el siguiente mensaje de estado:

Windows Presentation Foundation Plugin for Mozilla Firefox is not installed. Please install or reinstall the .NET
Framework 3.5.
Si el script est hospedado en un explorador diferente de Firefox 2.0+, aparecer el mensaje de estado
siguiente:

The browser must be Firefox 2.0+.

2.8. Rendimiento
Para obtener un rendimiento ptimo de la aplicacin, se requiere una reflexin previa sobre el diseo de la
aplicacin y una comprensin de las prcticas recomendadas para el desarrollo de aplicaciones Windows
Presentation Foundation (WPF). Los temas de esta seccin proporcionan informacin adicional sobre cmo
generar aplicaciones WPF de alto rendimiento.

2.8.1. Niveles de Representacin de Grficos


Un nivel de representacin define un nivel de rendimiento y funcionalidad del hardware grfico de un dispositivo
en el que se ejecuta una aplicacin dWPF.
Hardware grfico
Las caractersticas del hardware grfico que ms afectan a los niveles de representacin son:

RAM de vdeo: la cantidad de memoria de vdeo en el hardware grfico determina el tamao y el


nmero de bferes que se pueden utilizar para la composicin de grficos.

Sombreador de pxeles: un sombreador de pxeles es una funcin de procesamiento de grficos que


calcula los efectos por pxel. Segn la resolucin de los grficos mostrados, puede haber varios
millones de pxeles que deban procesarse en cada cuadro mostrado.

Sombreador de vrtices: un sombreador de vrtices es una funcin de procesamiento de grficos


que realiza operaciones matemticas con los datos de los vrtices del objeto.

Compatibilidad con texturas mltiples: la compatibilidad con texturas mltiples hace referencia a
la capacidad de aplicar dos o ms texturas distintas durante una operacin de mezcla en un objeto
grfico 3D. El grado de compatibilidad con texturas mltiples viene determinado por el nmero de
unidades de textura mltiple en el hardware grfico.

MCT: Luis Dueas

Pag 184 de 445

Manual de Windows Presentation Foundation


El sombreador de pxeles, el sombreador de vrtices y las caractersticas de texturas mltiples se utilizan para
definir niveles de versin de DirectX especficos que, a su vez, se utilizan para definir los diferentes niveles de
representacin en WPF.
Representar definiciones de nivel
Las caractersticas del hardware grfico determinan la capacidad de representacin de una aplicacin de WPF.
El sistema WPF define tres niveles de representacin:

Nivel de representacin 0 Sin aceleracin de hardware grfico. El nivel de versin de DirectX es


inferior a la versin 7.0.

Nivel de representacin 1 Aceleracin parcial del hardware grfico. El nivel de versin de DirectX es
mayor o igual a la versin 7.0 y menor que la versin 9.0.

Nivel de representacin 2 La mayora de las caractersticas grficas utilizan la aceleracin de


hardware grfico. El nivel de versin de DirectX es mayor o igual a la versin 9.0.

La propiedad Tier permite recuperar el nivel de representacin en el tiempo de ejecucin de la aplicacin, lo que
permite a los programadores determinar si el dispositivo puede admitir ciertas caractersticas de aceleracin de
grficos por hardware. La aplicacin puede tomar a continuacin diferentes rutas de cdigo en tiempo de
ejecucin en funcin del nivel de representacin que admita el dispositivo.
Nivel de representacin 0
Un valor de nivel de representacin 0 significa que no hay ninguna aceleracin de hardware grfico disponible
para la aplicacin en el dispositivo. En este nivel, los programadores deben suponer que el software
representar todos los grficos, sin aceleracin de hardware. La funcionalidad de este nivel corresponde a una
versin de DirectX inferior a la 7.0.
Nivel de representacin 1
Un valor de nivel de representacin de 1 significa que en la tarjeta de vdeo est disponible una aceleracin
parcial del hardware grfico. Esto corresponde a una versin de DirectX mayor o igual a 7.0 y menor que 9.0.
Las caractersticas y funciones siguientes son aceleradas por hardware para el nivel de representacin 1:
Caracterstica

Notas

Representacin
de 2D

Se admite la mayor parte de la representacin 2D.

Rasterizacin 3D

Se admite la mayora de la rasterizacin 3D. Sin embargo, WPF utilizar el software


para calcular las intensidades de luz de vrtice, que se pasan a continuacin al
hardware como un color de vrtice. Esto significa que la iluminacin es mucho ms
lenta en el nivel 1.

Filtrado
anisotrpico 3D

Cuando el nivel de representacin > = 1, WPF intenta utilizar filtrado anisotrpico al


representar contenido 3D. El filtrado anisotrpico hace referencia a la mejora de la
calidad de imagen de las texturas en superficies que se encuentran lejos y formando un
ngulo agudo respecto a la cmara.

Asignacin del
mip 3D

Cuando el nivel de la representacin > = 1, WPF intenta utilizar asignacin de mip al


representar contenido 3D. La asignacin de mip mejora la calidad de la representacin
de texturas cuando una textura ocupa un campo de vista menor en Viewport3D.

Las caractersticas y funciones siguientes no son aceleradas por hardware para el nivel de representacin 1:
Caracterstica

Notas

Efectos de mapa de bits

Utilizar un efecto del mapa de bits en un elemento visual fuerza la


representacin del elemento visual sin aceleracin de hardware.

Contenido impreso

Todo el contenido impreso se representa utilizando el conducto de


software WPF.

Contenido rasterizado

Todo

MCT: Luis Dueas

el

contenido

representado

usando

el

mtodo

Render

de

Pag 185 de 445

Manual de Windows Presentation Foundation

utilizando un objeto
RenderTargetBitmap

RenderTargetBitmap.

Contenido en mosaico que


utiliza TileBrush

Contenido en mosaico en el que la propiedad TileMode de TileBrush est


establecida en Tile.

Superficies que superan el


tamao de textura mximo
del hardware grfico

La mayora de las tarjetas de vdeo no admiten superficies mayores de


2048x2048 o 4096x4096 pxeles de tamao.

Cualquier operacin cuyos


requisitos de RAM de vdeo
superen la memoria del
hardware grfico

Puede supervisar el uso de RAM de vdeo de la aplicacin utilizando la


herramienta Herramientas de generacin de perfiles de rendimiento de
WPF, que est incluida en Windows SDK.

Ventanas superpuestas

Las ventanas superpuestas permiten a las aplicaciones WPF representar


contenido en la pantalla en una ventana no rectangular. En Windows
Vista, las ventanas superpuestas se aceleran mediante hardware. En otros
sistemas, tales como Windows XP, las ventanas superpuestas se
representan mediante software, sin aceleracin de hardware.
Puede habilitar las ventanas superpuestas en WPF estableciendo las
siguientes propiedades Window:
WindowStyle = None

AllowsTransparency = true

Background = Transparent

Degradados radiales

Cualquier uso de RadialGradientBrush.

Clculos de iluminacin 3D

WPF realiza la iluminacin por vrtices, lo que significa que debe


calcularse una intensidad de luz en cada vrtice para cada material que se
aplique a una malla. En el nivel 1, los clculos se realizan mediante
software. En el nivel 2, los clculos se realizan en el hardware.

Representacin de texto

La representacin de fuentes por debajo del nivel de pxel utiliza


sombreadores de pxeles disponibles en el hardware grfico.

Suavizado 3D (anti-aliasing)

Cualquier uso del suavizado 3D (anti-aliasing).

Las caractersticas del hardware grfico siguientes definen el nivel de representacin 1:


Caracterstica

Notas

Versin de DirectX

Debe ser mayor o igual a 7,0 y menor que 9,0.

RAM de vdeo

Debe ser mayor o igual a 30 MB.

Unidades de mltiples texturas

El nmero de unidades debe ser mayor o igual a 2.

La tabla siguiente muestra tarjetas grficas comunes que permiten la representacin de nivel 1:
Manufacturer

Modelo

ATI

Modelos Radeon: 256, 7000, 7500, 8500, 9000, 9100, 9200 y 9250

Intel

Modelos Intel Extreme Graphics: 845G, 845GE, 845GL y 845GV


Modelos Intel Extreme Graphics II: 852GME, 855GM, 855GME, 865G y 865GV

NVidia

GeForce
Modelos
Modelos
Modelos

256
GeForce2: GTS, MX, MX100, MX200, MX400, Pro, Ti y Ultra
GeForce3: Ti200 y Ti500
GeForce4: MX420, MX440, MX460, MX4000, Ti4200, Ti4400, Ti4600 y Ti4800

Nivel de representacin 2
Un valor de nivel de representacin 2 significa que la mayora de las caractersticas grficas de WPF deben
utilizar la aceleracin de hardware, siempre y cuando no se hayan agotado los recursos necesarios del sistema.
Esto corresponde a una versin de DirectX mayor o igual a 9,0.

MCT: Luis Dueas

Pag 186 de 445

Manual de Windows Presentation Foundation


Las caractersticas y funciones siguientes son aceleradas por hardware para el nivel de representacin 2:
Caracterstica

Notas

Caractersticas del
nivel 1

Incluye todas las caractersticas del nivel 1.

Degradados
radiales

Aunque sea compatible, evite el uso de RadialGradientBrush en objetos grandes.

Clculos de
iluminacin 3D

WPF realiza la iluminacin por vrtices, lo que significa que debe calcularse una
intensidad de luz en cada vrtice para cada material que se aplique a una malla. En el
nivel 1, los clculos se realizan mediante software. En el nivel 2, los clculos se
realizan en el hardware.

Representacin de
texto

La representacin de fuentes por debajo del nivel de pxel utiliza sombreadores de


pxeles disponibles en el hardware grfico.

Suavizado 3D
(anti-aliasing)

El suavizado (anti-aliasing) 3D solamente se admite en Windows Vista.

Las caractersticas y funciones siguientes no son aceleradas por hardware para el nivel de representacin 2:
Caracterstica

Notas

Efectos de mapa de bits

Utilizar un efecto del mapa de bits en un elemento visual fuerza la


representacin del elemento visual sin aceleracin de hardware.

Contenido impreso

Todo el contenido impreso se representa utilizando el conducto de


software WPF.

Contenido rasterizado que


utiliza RenderTargetBitmap

Contenido
representado
RenderTargetBitmap.

Contenido en mosaico que


utiliza TileBrush

Contenido en mosaico en el que la propiedad TileMode de TileBrush est


establecida en Tile.

Superficies que superan el


tamao de textura mximo
del hardware grfico

Para la mayora del hardware grfico, las superficies grandes tienen un


tamao de 2048x2048 o 4096x4096 pxeles.

Cualquier operacin cuyos


requisitos de RAM de vdeo
superen la memoria del
hardware grfico

Puede supervisar el uso de RAM de vdeo de la aplicacin utilizando la


herramienta Herramientas de generacin de perfiles de rendimiento de
WPF, que est incluida en Windows SDK.

Ventanas superpuestas

Las ventanas superpuestas permiten a las aplicaciones WPF representar


contenido en la pantalla en una ventana no rectangular. En Windows
Vista, las ventanas superpuestas se aceleran mediante hardware. En otros
sistemas, tales como Windows XP, las ventanas superpuestas se
representan mediante software, sin aceleracin de hardware.
Puede habilitar las ventanas superpuestas en WPF estableciendo las
siguientes propiedades Window:
WindowStyle = None

usando

AllowsTransparency = true

Background = Transparent

el

mtodo

Render

de

Las caractersticas del hardware grfico siguientes definen el nivel de representacin 2:


Caracterstica

Notas

Versin de DirectX

Debe ser mayor o igual a 9,0.

RAM de vdeo

Debe ser mayor o igual a 120 MB.

Sombreador de pxeles

El nivel de versin debe mayor o igual a 2.0.

Sombreador de vrtices

El nivel de versin debe mayor o igual a 2.0.

MCT: Luis Dueas

Pag 187 de 445

Manual de Windows Presentation Foundation

Unidades de mltiples texturas

El nmero de unidades debe ser mayor o igual a 4.

La tabla siguiente muestra tarjetas grficas comunes que permiten la representacin de nivel 2:
Manufacturer

Modelo

ATI

Modelos Radeon: 9550, 9600, 9800 y serie X

Intel

Modelos Intel GMA900: 915G


Modelos Intel GMA950: 945G

NVidia

Serie GeForce FX, 6xxx y 7xxx

Otros recursos
Los recursos siguientes pueden ayudarle a analizar las caractersticas de rendimiento de la aplicacin WPF.
Configuracin del Registro en la representacin de grficos
WPF proporciona cuatro valores del Registro para controlar la representacin de WPF:
Valor

Descripcin

Deshabilitar la opcin de
aceleracin de hardware

Especifica si la aceleracin de hardware debe estar habilitada.

Valor mximo de muestreo


mltiple

Especifica el grado de muestreo mltiple para el suavizado (antialiasing) de contenido 3D.

Valor de fecha de controlador


de vdeo necesario

Especifica si el sistema deshabilita la aceleracin de hardware para los


controladores publicados antes de noviembre de 2004.

Utilizar la opcin de
rasterizador de referencia

Especifica si WPF debe utilizar el rasterizador de referencia.

Cualquier utilidad de configuracin externa que pueda hacer referencia a los valores del Registro de WPF puede
tener acceso a estos valores. Estos valores se pueden crear o modificar tambin mediante el acceso directo a
los valores utilizando el Editor del Registro de Windows.
Herramientas de generacin de perfiles de rendimiento para WPF
WPF proporciona un conjunto de herramientas de creacin de perfiles de rendimiento que permiten analizar el
funcionamiento en tiempo de ejecucin de la aplicacin y determinar los tipos de optimizacin del rendimiento
que se pueden aplicar. La tabla siguiente muestra las cinco herramientas de generacin de perfiles de
rendimiento que se incluyen en la herramienta Windows SDK, WPFPerf:
Herramienta

Descripcin

Event Trace

Se utiliza para analizar eventos y generar archivos de registro de eventos.

Perforator

Se utiliza para analizar el comportamiento de representacin.

Trace Viewer

Registro, presentacin y examen de archivos de registro de Event Tracing for Windows


(ETW) en formato de interfaz de usuario de WPF.

Visual Profiler

Se utiliza para generar perfiles de uso de servicios WPF, tales como el diseo y el
control de eventos, mediante elementos del rbol visual.

Working Set
Viewer

Se utiliza para analizar las caractersticas del espacio de trabajo de la aplicacin.

El conjunto de herramientas Visual Profiler ofrece una vista grfica y enriquecida de los datos de rendimiento.
En esta captura de pantalla, la seccin CPU Usage de Visual Profiles ofrece un desglose preciso del uso, por
parte de un objeto, de servicios de WPF tales como la representacin y el diseo.
Resultados de la presentacin de Visual Profiler

MCT: Luis Dueas

Pag 188 de 445

Manual de Windows Presentation Foundation

Herramienta de diagnstico de DirectX


La herramienta de diagnstico de DirectX, Dxdiag.exe, est diseada para ayudarle a solucionar problemas
relacionados con DirectX. La carpeta de instalacin predeterminada para la herramienta de diagnstico de
DirectX es: ~\Windows\System32
Al ejecutar la herramienta de diagnstico de DirectX, la ventana principal contiene un conjunto de fichas que
permiten mostrar y diagnosticar informacin relacionada con DirectX. Por ejemplo, la ficha System proporciona
informacin del sistema sobre el equipo y especifica la versin de DirectX que est instalada en el equipo.
Ventana principal de la herramienta de diagnstico de DirectX

2.8.2. Optimizar WPF: Rendimiento de Aplicaciones


Esta seccin est diseada como referencia para los programadores de aplicaciones de Windows Presentation
Foundation (WPF) que buscan maneras de mejorar el rendimiento de sus aplicaciones. Si usted es un
programador que desconoce las plataformas Microsoft .NET Framework y WPF, primero deber familiarizarse
con ambas. En esta seccin se da por supuesto un conocimiento prctico de las dos y est escrita para
programadores que ya tienen conocimientos suficientes para programar aplicaciones que funcionan. La
informacin de esta seccin se basa en la versin 1.0 de WPF.
Nota:
Los datos de rendimiento proporcionados en esta seccin se basan en aplicaciones de WPF que se ejecutan
en un PC a 2,8 GHz con 512 de RAM y una tarjeta grfica ATI Radeon 9700.

2.8.2.1. Planear para Mejorar el Rendimiento de Aplicaciones


La consecucin de los objetivos de rendimiento depende de lo bien que desarrolle su estrategia de rendimiento.
La planeacin es la primera fase del desarrollo de cualquier producto. En este tema se describen algunas reglas
muy simples para desarrollar una estrategia de rendimiento acertada.
Pensar en trminos de escenarios

MCT: Luis Dueas

Pag 189 de 445

Manual de Windows Presentation Foundation


Los escenarios pueden ayudarle a centrarse en los componentes crticos de la aplicacin. Los escenarios suelen
derivarse de los clientes, as como de los productos de la competencia. Estudie siempre a sus clientes y
averige qu es lo que les interesa de su producto y de los productos de la competencia. Los comentarios de
sus clientes pueden ayudarle a determinar el escenario principal de la aplicacin. Por ejemplo, si va a disear
un componente que se usar en el inicio, es probable que solamente se llame a este componente una vez,
cuando se inicia la aplicacin. En este caso, el escenario clave es el momento del inicio. Otros ejemplos de
escenarios clave podran ser la velocidad de los fotogramas en las secuencias de animacin o el espacio de
trabajo mximo permitido para la aplicacin.
Definir los objetivos
Los objetivos le ayudan a determinar si el rendimiento de una aplicacin es superior o inferior. Debe definir
objetivos para todos los escenarios. Todos los objetivos de rendimiento que defina debern basarse en las
expectativas de sus clientes. Puede ser difcil establecer los objetivos de rendimiento desde el principio del ciclo
de programacin, cuando todava quedan muchos problemas sin resolver. Sin embargo, es mejor fijar un
objetivo inicial y revisarlo posteriormente que no tener ningn objetivo en absoluto.
Entender la plataforma
Mantenga en todo momento el ciclo de medir, investigar, refinar y corregir durante el ciclo de programacin de
la aplicacin. Desde el principio hasta el final del ciclo de programacin, es preciso medir el rendimiento de la
aplicacin en un entorno confiable y estable. Debe evitar las variaciones producidas por factores externos. Por
ejemplo, al realizar pruebas de rendimiento, debe deshabilitar los antivirus y las actualizaciones automticas,
como SMS, para que no afecten a los resultados de dichas pruebas. Despus de medir el rendimiento de la
aplicacin, deber identificar los cambios que darn lugar a las mayores mejoras. Cuando haya modificado la
aplicacin, inicie de nuevo el ciclo.
Convertir el ajuste del rendimiento en un proceso reiterativo
Debe conocer el costo relativo de cada caracterstica que va a utilizar. Por ejemplo, el uso de la reflexin en
Microsoft .NET Framework suele afectar intensamente al rendimiento por lo que se refiere a los recursos
informticos, de modo que es importante utilizarla juiciosamente. Esto no significa que haya que evitar el uso
de la reflexin, nicamente que debe asegurarse de equilibrar los requisitos de rendimiento de la aplicacin con
las exigencias de rendimiento de las caractersticas que utilice.
Aumentar progresivamente la riqueza grfica
Una tcnica clave para crear un enfoque escalable que permita lograr un rendimiento adecuado de las
aplicaciones de WPF es aumentar progresivamente la riqueza grfica y la complejidad. Empiece siempre
utilizando los recursos que menos afectan al rendimiento para lograr los objetivos del escenario. Cuando haya
logrado estos objetivos, aumente progresivamente la riqueza grfica mediante caractersticas que afectan con
mayor intensidad al rendimiento, teniendo siempre presentes los objetivos del escenario. Recuerde que WPF es
una plataforma extremadamente completa que proporciona caractersticas grficas muy ricas. El uso irreflexivo
de caractersticas que afectan intensamente al rendimiento puede impactar negativamente en el rendimiento de
la aplicacin en su conjunto.
La extensibilidad es inherente a los controles de WPF, lo que permite una personalizacin generalizada de su
aspecto sin modificar su comportamiento de control. Aprovechando los estilos, las plantillas de datos y las
plantillas de control puede crear y modificar gradualmente una interfaz de usuario (UI) personalizable adaptada
a los requisitos de rendimiento. Demo Photo Store muestra cmo crear con facilidad una separacin entre la
interfaz de usuario (UI) bsica y la lgica de la aplicacin. Una vez creada esta separacin, le permite
incrementar gradualmente la riqueza grfica.

2.8.2.2. Aprovechar el Hardware

MCT: Luis Dueas

Pag 190 de 445

Manual de Windows Presentation Foundation


La arquitectura interna de WPF tiene dos canalizaciones de representacin, la de hardware y la de software. En
este tema se proporciona informacin sobre estas canalizaciones de representacin a fin de ayudarle a tomar
las decisiones relativas a la optimizacin del rendimiento de las aplicaciones.
Canalizacin de representacin de hardware
Uno de los factores ms importantes para determinar el rendimiento de WPF es que est limitado por la
representacin: cuantos ms pxeles se deben representar, mayor es el costo de rendimiento. Sin embargo,
cuanta ms representacin se pueda descargar a la unidad de procesamiento de grficos (GPU), mayores
ventajas de rendimiento se pueden conseguir. La canalizacin de representacin de hardware de las
aplicaciones de WPF aprovecha plenamente las caractersticas de Microsoft DirectX en el hardware que admite
como mnimo la versin 7.0 de Microsoft DirectX. Se puede obtener mayor nivel de optimizacin con hardware
que admita las caractersticas de Microsoft DirectX versin 7.0 y de PixelShader 2.0+.
Canalizacin de representacin de software
En la canalizacin de representacin de software de WPF, la CPU impone la totalidad de la limitacin. WPF
aprovecha los conjuntos de instrucciones de SSE y SSE2 de la CPU para implementar un rasterizador de
software optimizado con caractersticas completas. El recurso al software se realiza sin fisuras en cualquier
momento en que no es posible representar las funcionalidades de la aplicacin mediante la canalizacin de
representacin de hardware.
El principal problema de rendimiento que encontrar al representar en modo de software tiene que ver con la
velocidad de relleno, que es el nmero de pxeles que se representan. Si le preocupa el rendimiento en el modo
de representacin de software, intente minimizar la cantidad de veces que se vuelve a dibujar un pxel. Por
ejemplo, si tiene una aplicacin con fondo azul que, a continuacin, representa una imagen ligeramente
transparente sobre l, se representarn dos veces todos los pxeles de la aplicacin. Como resultado, se tardar
el doble en representar la aplicacin con la imagen que si tuviera nicamente el fondo azul.
Niveles de representacin de grficos
Puede ser muy difcil predecir la configuracin de hardware en la que la aplicacin se va a ejecutar. Sin
embargo, puede ser conveniente estudiar un diseo que permita a la aplicacin cambiar sin fisuras las
caractersticas cuando se ejecute en distintos hardwares, para que pueda aprovechar al mximo cada
configuracin de hardware diferente.
Para lograrlo, WPF proporciona funcionalidades que permiten determinar la capacidad grfica de un sistema en
tiempo de ejecucin. La capacidad grfica se determina categorizando la tarjeta de vdeo en tres niveles de
capacidad de representacin. WPF expone una API que permite a una aplicacin consultar el nivel de capacidad
de representacin. La aplicacin puede tomar a continuacin diferentes rutas de cdigo en tiempo de ejecucin
en funcin del nivel de representacin que admita el hardware.
Las caractersticas del hardware grfico que ms afectan a los niveles de representacin son:

RAM de vdeo: la cantidad de memoria de vdeo en el hardware grfico determina el tamao y el


nmero de bferes que se pueden utilizar para la composicin de grficos.

Sombreador de pxeles: un sombreador de pxeles es una funcin de procesamiento de grficos que


calcula los efectos por pxel. Segn la resolucin de los grficos mostrados, puede haber varios
millones de pxeles que deban procesarse en cada fotograma mostrado.

Sombreador de vrtices: un sombreador de vrtices es una funcin de procesamiento de grficos


que realiza operaciones matemticas con los datos de los vrtices del objeto.

Compatibilidad con texturas mltiples: la compatibilidad con texturas mltiples hace referencia a
la capacidad de aplicar dos o ms texturas distintas durante una operacin de mezcla en un objeto
grfico 3D. El grado de compatibilidad con texturas mltiples viene determinado por el nmero de
unidades de textura mltiple en el hardware grfico.

MCT: Luis Dueas

Pag 191 de 445

Manual de Windows Presentation Foundation


El sombreador de pxeles, el sombreador de vrtices y las caractersticas de texturas mltiples se utilizan para
definir niveles de versin de DirectX especficos que, a su vez, se utilizan para definir los diferentes niveles de
representacin en WPF.
Las caractersticas del hardware grfico determinan la capacidad de representacin de una aplicacin de WPF.
El sistema WPF define tres niveles de representacin:

Nivel de representacin 0 Sin aceleracin de hardware grfico. El nivel de versin de DirectX es


inferior a la versin 7.0.

Nivel de representacin 1 Aceleracin parcial del hardware grfico. El nivel de versin de DirectX es
mayor o igual a la versin 7.0 y menor que la versin 9.0.

Nivel de representacin 2 La mayora de las caractersticas grficas utilizan la aceleracin de


hardware grfico. El nivel de versin de DirectX es mayor o igual a la versin 9.0.

2.8.2.3. Presentacin y Diseo


El diseo de la aplicacin WPF puede afectar a su rendimiento creando sobrecarga innecesaria para calcular el
diseo y validar referencias de objeto. La construccin de objetos, particularmente en tiempo de ejecucin,
puede afectar a las caractersticas de rendimiento de la aplicacin.
En este tema se proporcionan recomendaciones de rendimiento en estas reas.
Diseo
El trmino "paso de diseo" describe el proceso de medir y organizar los miembros de una coleccin de
secundarios del objeto derivado Panel y, a continuacin, dibujarlos en la pantalla. El paso de diseo es un
proceso matemticamente intensivo: cuanto mayor sea el nmero de elementos secundarios de la coleccin,
mayor ser el nmero de clculos requeridos. Por ejemplo, cada vez que un objeto UIElement secundario de la
coleccin cambia de posicin, puede activar un nuevo paso por el sistema de diseo. Debido a la estrecha
relacin entre las caractersticas de objeto y el comportamiento de diseo, es importante entender el tipo de
eventos que puede invocar el sistema de diseo. La aplicacin rendir mejor reduciendo tanto como sea posible
cualquier invocacin innecesaria del paso de diseo.
El sistema de diseo completa dos pasos por cada miembro secundario de una coleccin: un paso de medida y
paso de organizacin. Cada objeto secundario proporciona su propia implementacin reemplazada de los
mtodos Measure y Arrange para proporcionar su propio comportamiento de diseo concreto. En su versin
ms simple, el diseo es un sistema recursivo que conduce a la configuracin del tamao, posicin y
representacin de un elemento en la pantalla.

Un objeto UIElement secundario comienza el proceso de diseo con la medicin de sus propiedades
bsicas.

Se evalan las propiedades del objeto FrameworkElement relacionadas con el tamao, tales como
Width, Height y Margin.

Se aplica la lgica concreta de Panel, tal como la propiedad Dock de DockPanel o la propiedad
Orientation de StackPanel.

El contenido se organiza o se coloca una vez medidos todos los objetos secundarios.
La coleccin de objetos secundarios se dibuja en la pantalla.

Se invoca de nuevo el proceso de paso de diseo si se produce cualquiera de las acciones siguientes:

Se agrega un objeto secundario a la coleccin.


Se aplica un objeto LayoutTransform al objeto secundario.
Se llama al mtodo UpdateLayout para el objeto secundario.
Cuando se produce un cambio en el valor de una propiedad de dependencia marcada con metadatos
que afectan a la medida o a los pasos de organizacin.

Utilizar el panel ms eficaz cuando sea posible

MCT: Luis Dueas

Pag 192 de 445

Manual de Windows Presentation Foundation


La complejidad del proceso del diseo est basada directamente en el comportamiento de diseo de los
elementos derivados de Panel que utiliza. Por ejemplo, un control Grid o StackPanel proporciona mucha ms
funcionalidad que un control Canvas. El precio de este mayor aumento de la funcionalidad es un aumento
mayor de los costes de rendimiento. Sin embargo, si no requiere la funcionalidad que proporciona un control
Grid, debera utilizar alternativas menos costosas, tales como un control Canvas o un panel personalizado.
Actualizar en lugar de reemplazar una propiedad RenderTransform
Quiz pueda actualizar un objeto Transform en lugar de reemplazarlo como valor de una propiedad
RenderTransform. Esto es particularmente cierto en escenarios que impliquen animacin. Actualizando un
objeto Transform existente, evitar iniciar un clculo de diseo innecesario.
Generar un rbol descendente
Cuando se agrega o se quita un nodo del rbol lgico, se provocan invalidaciones de propiedad en el elemento
primario del nodo y en todos sus elementos secundarios. Como resultado, siempre debe seguirse un modelo de
construccin descendente, para evitar el costo de invalidaciones innecesarias en nodos ya validados. La tabla
siguiente muestra la diferencia en velocidad de ejecucin entre la generacin de un rbol descendente frente a
uno ascendente, donde el rbol tiene 150 niveles de profundidad con un objeto TextBlock y un objeto
DockPanel nicos en cada nivel.
Accin

Generacin del rbol (en


ms)

Representacin: incluye la generacin del rbol (en


ms)

Ascendente

366

454

Descendente

11

96

En el siguiente ejemplo de cdigo se muestra cmo crear un rbol descendente.


private void OnBuildTreeTopDown(object sender, RoutedEventArgs e)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = "Default";
DockPanel parentPanel = new DockPanel();
DockPanel childPanel;
myCanvas.Children.Add(parentPanel);
myCanvas.Children.Add(textBlock);
for (int i = 0; i < 150; i++)
{
textBlock = new TextBlock();
textBlock.Text = "Default";
parentPanel.Children.Add(textBlock);
childPanel = new DockPanel();
parentPanel.Children.Add(childPanel);
parentPanel = childPanel;
}
}

2.8.2.4. Imgenes y Grficos 2D


WPF proporciona una gama amplia de grficos 2D y funcionalidad de creacin de imgenes que se pueden
optimizar para los requisitos de la aplicacin. En este tema se proporciona informacin sobre la optimizacin del
rendimiento en esas reas.
Dibujos y formas
WPF proporciona objetos Drawing y Shape para representar el contenido de los dibujos grficos. Sin embargo,
los objetos Drawing son estructuras ms sencillas que los objetos Shape y proporcionan mejores caractersticas
de rendimiento.
Un objeto Shape permite dibujar una forma grfica en la pantalla. Dado que se derivan de la clase
FrameworkElement, los objetos Shape se pueden utilizar dentro de los paneles y de la mayora de los controles.
WPF ofrece varias capas de acceso a los grficos y a los servicios de representacin. En la capa superior, los
objetos Shape son fciles de utilizar y proporcionan numerosas caractersticas tiles, tales como la
administracin del diseo y el control de eventos. WPF proporciona varios objetos de forma listos para usar.

MCT: Luis Dueas

Pag 193 de 445

Manual de Windows Presentation Foundation


Todos los objetos de formas heredan de la clase Shape. Los objetos de formas disponibles incluyen Ellipse,
Line, Path, Polygon, Polyline y Rectangle.
Por otro lado, los objetos Drawing no se derivan de la clase FrameworkElement y proporcionan una
implementacin ms ligera para representar formas, imgenes y texto.
Hay cuatro tipos de objetos Drawing:

GeometryDrawing dibuja una forma.


ImageDrawing dibuja una imagen.
GlyphRunDrawing dibuja texto.
DrawingGroup dibuja otros dibujos. Utilice un grupo de dibujo para combinar otros dibujos en un nico
dibujo compuesto.

El objeto GeometryDrawing se utiliza para representar contenido de geometra. La clase Geometry y las clases
concretas que se derivan de ella, tales como CombinedGeometry, EllipseGeometry y PathGeometry,
proporcionan un medio para representar grficos 2D, adems de compatibilidad con las pruebas de
posicionamiento y el recorte. Los objetos de geometra se pueden utilizar para definir la regin de un control,
por ejemplo, o definir la regin de recorte que se aplicar a una imagen. Los objetos de geometra pueden ser
regiones simples, tales como rectngulos y crculos, o bien regiones compuestas creadas a partir de dos o ms
objetos de geometra. Las regiones de geometra ms complejas se pueden crear combinando objetos
derivados de PathSegment, como ArcSegment, BezierSegment y QuadraticBezierSegment.
Aparentemente, la clase Geometry y la clase Shape son bastante similares. Ambas se utilizan para representar
grficos 2D y tienen clases concretas similares que se derivan de ellas, por ejemplo, EllipseGeometry y Ellipse.
Sin embargo, existen diferencias importantes entre estos dos conjuntos de clases. En primer lugar, la clase
Geometry carece de parte de la funcionalidad de la clase Shape, como la capacidad de dibujarse a s misma.
Para dibujar un objeto de geometra, deber utilizarse otra clase, del tipo de DrawingContext, Drawing o Path
(cabe destacar que Path es una forma) para realizar la operacin de dibujo. Las propiedades de representacin,
tales como el relleno, el trazo y el grosor del trazo pertenecen a la clase que dibuja el objeto de geometra,
mientras que un objeto de forma contiene estas propiedades. Podemos pensar en esta diferencia de la siguiente
manera: un objeto de geometra define una regin, un crculo por ejemplo, mientras que un objeto de forma
define una regin, define cmo se rellena y perfila esa regin, y participa en el sistema de diseo.
Puesto que los objetos Shape se derivan de la clase FrameworkElement, utilizarlos puede aumentar
significativamente el consumo de memoria de la aplicacin. Si realmente no necesita las caractersticas de
FrameworkElement para el contenido grfico, es conveniente utilizar los objetos Drawing, ms ligeros.
Objetos StreamGeometry
El objeto StreamGeometry constituye una alternativa ligera a PathGeometry para crear formas geomtricas.
Utilice una StreamGeometry si necesita describir una geometra compleja. StreamGeometry est optimizada
para administrar muchos objetos PathGeometry y registra un rendimiento mejor que cuando se utilizan varios
objetos PathGeometry individuales.
En el ejemplo siguiente se utiliza la sintaxis de atributo para crear una StreamGeometry triangular en XAML.
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Path Data="F0 M10,100 L100,100 100,50Z"
StrokeThickness="1" Stroke="Black"/>
</StackPanel>
</Page>
Objetos DrawingVisual
El objeto DrawingVisual es una clase de dibujo ligera que se utiliza para representar formas, imgenes o texto.
Esta clase se considera ligera porque no proporciona administracin del diseo ni control de eventos, lo que
mejora su rendimiento. Por esta razn, los dibujos son idneos para fondos e imgenes prediseadas.

MCT: Luis Dueas

Pag 194 de 445

Manual de Windows Presentation Foundation


Imgenes
La creacin de imgenes de WPF proporciona una mejora significativa con respecto a las funciones de creacin
de imgenes de las versiones anteriores de Windows. Las funciones de creacin de imgenes, tales como la
presentacin de mapas de bits o el uso de imgenes en controles comunes, se administraban principalmente
por las interfaces de programacin de aplicaciones (API) de la interfaz de dispositivo grfico (GDI) o de la GDI+
de Microsoft Windows. Estas API proporcionaban la funcionalidad bsica para la creacin de imgenes, pero
carecan de caractersticas tales como compatibilidad con la extensibilidad de cdec y con imgenes de alta
fidelidad. La API de creacin de imgenes de WPF se ha rediseado para superar las limitaciones de GDI y
GDI+ y proporcionar un nuevo conjunto de API para mostrar y utilizar imgenes en las aplicaciones.
Al utilizar imgenes, tenga en cuenta las recomendaciones siguientes para obtener el mejor rendimiento:

Si su aplicacin le exige que muestre imgenes en miniatura, puede ser conveniente crear una versin
de dimensiones reducidas de la imagen. De manera predeterminada, WPF carga la imagen y la
descodifica a su tamao completo. Si slo desea una versin en miniatura de la imagen, WPF
descodifica innecesariamente la imagen a su tamao completo y, a continuacin, la reduce a la escala
en miniatura. Para evitar este consumo de recursos innecesario, puede solicitar a WPF que
descodifique la imagen a un tamao en miniatura o bien solicitar a WPF que cargue una imagen en
miniatura.

Siempre descodifique la imagen al tamao deseado y no al tamao predeterminado. Como hemos


explicado anteriormente, solicite a WPF que descodifique la imagen al tamao deseado y no al tamao
completo predeterminado. De este modo, no slo mejorar el espacio de trabajo de la aplicacin, sino
tambin la velocidad de ejecucin.

Si es posible, combine las imgenes en una imagen nica, como una tira cinematogrfica creada de
varias imgenes.

BitmapScalingMode
Al animar la escala de un mapa de bits, el algoritmo de remuestreo predeterminado de las imgenes de alta
calidad, a veces, puede consumir tantos recursos del sistema que cause la degradacin de la velocidad de los
fotogramas, lo que provoca el parpadeo de las animaciones. Estableciendo la propiedad BitmapScalingMode del
objeto RenderOptions en LowQuality, puede crear una animacin ms suavizada al escalar un mapa de bits. El
modo LowQuality indica al motor de representacin de WPF que cambie de un algoritmo optimizado para la
calidad a un algoritmo optimizado para la velocidad al procesar las imgenes.
En el siguiente ejemplo se muestra cmo establecer el valor de BitmapScalingMode para un objeto de imagen.
// Set the bitmap scaling mode for the image to render faster.
RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality);
CachingHint
De manera predeterminada, WPF no almacena en memoria cach el contenido representado de los objetos
TileBrush, como DrawingBrush y VisualBrush. En escenarios estticos donde no cambia el contenido ni el uso de
TileBrush en la escena, esto tiene sentido dado que conserva la memoria de vdeo. No tiene tanto sentido
cuando se usa un objeto TileBrush con contenido esttico de forma no esttica; por ejemplo, cuando se asigna
un objeto DrawingBrush o VisualBrush esttico a la superficie de un objeto 3D que gira. El comportamiento
predeterminado de WPF es volver a representar el contenido completo de cada fotograma de DrawingBrush o
VisualBrush, aunque no cambie el contenido.
Si se establece el valor de la propiedad CachingHint del objeto RenderOptions en Cache, podr aumentar el
rendimiento utilizando versiones almacenadas en memoria cach de los objetos de pincel en mosaico.
Los valores de las propiedades CacheInvalidationThresholdMaximum y CacheInvalidationThresholdMinimum son
valores de tamao relativos que determinan cundo se debe regenerar el objeto TileBrush debido a cambios en
la escala. Por ejemplo, si establece el valor de la propiedad CacheInvalidationThresholdMaximum en 2,0, la

MCT: Luis Dueas

Pag 195 de 445

Manual de Windows Presentation Foundation


memoria cach del objeto TileBrush slo necesita regenerarse cuando su tamao supere el doble del tamao de
la cach actual.
En el ejemplo siguiente se muestra cmo utilizar la opcin de sugerencia de almacenamiento en cach para
DrawingBrush.
// Set the minimum and maximum relative sizes for regenerating the tiled brush.
RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5);
RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0);
// The tiled brush will be regenerated when the size is
//
0.5x, 0.25x (and so forth)
// and
//
2x, 4x, 8x (and so forth)
// of the original size.
// Set the caching hint option for the brush.
RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache);

2.8.2.5. Comportamiento de Objetos


Entender el comportamiento intrnseco de los objetos de WPF le ayudar a alcanzar el equilibrio adecuado entre
funcionalidad y rendimiento.
No quitar los controladores de eventos de los objetos puede hacer que los objetos se mantengan activos
El delegado que un objeto pasa a su evento es, en realidad, una referencia a ese objeto. Por consiguiente, los
controladores de eventos pueden mantener los objetos activos durante ms tiempo de lo esperado. Al realizar
la limpieza de un objeto que se ha registrado para escuchar a fin de detectar el evento de un objeto, es
esencial quitar ese delegado antes de liberar el objeto. Mantener activos objetos innecesarios aumenta el uso
de memoria por parte de la aplicacin. Esto se cumple especialmente cuando el objeto es la raz de un rbol
lgico o de un rbol visual.
WPF introduce un modelo de agentes de escucha de evento dbil para los eventos que puede resultar de
utilidad en aquellos casos en que resulta difcil seguir la traza de las relaciones de vigencia del objeto entre el
origen y el agente de escucha. Algunos eventos de WPF existentes utilizan este modelo. Si implementa objetos
con eventos personalizados, este modelo puede resultarle de utilidad.
Hay varias herramientas, tales como el generador de perfiles de CLR y el visor de espacio de trabajo, que
pueden proporcionar informacin sobre el uso de memoria por parte de un proceso especificado. El generador
de perfiles de CLR incluye varias vistas muy tiles del perfil de asignacin, entre las que se incluye un
histograma de tipos asignados, grficos de asignacin y llamadas, una escala temporal que muestra
recolecciones de elementos no utilizados de varias generaciones y el estado resultante del montn administrado
despus de esas recolecciones, as como un rbol de llamadas que muestra las asignaciones por mtodo y las
cargas de ensamblado.
El visor de espacio de trabajo es una herramienta de anlisis de rendimiento de WPF que proporciona
informacin sobre el uso de memoria de un proceso especificado. Esta herramienta permite generar una
captura de la informacin de uso de memoria de la aplicacin en un estado de aplicacin concreto.
Objetos y propiedades de dependencia
En general, tener acceso a una propiedad de dependencia de un objeto DependencyObject no es ms lento que
tener acceso a una propiedad de CLR. Aunque al establecer un valor de la propiedad se produce una pequea
sobrecarga de rendimiento, la obtencin de un valor es tan rpida como en una propiedad de CLR. Esta
pequea sobrecarga de rendimiento se compensa con el hecho de que las propiedades de dependencia admiten
caractersticas robustas, tales como enlace de datos, animacin, herencia y estilos.
Optimizacin de las propiedades de dependencia
Deben

extremarse

las

precauciones

al

definir

propiedades

de

dependencia

en

la

aplicacin.

Si

DependencyProperty slo afecta a las opciones de metadatos de tipo de representacin, y no a otras opciones
de metadatos como AffectsMeasure, debe marcarla como a tal invalidando sus metadatos.

MCT: Luis Dueas

Pag 196 de 445

Manual de Windows Presentation Foundation


Puede ser ms eficaz hacer que un controlador de cambio de propiedad invalide manualmente los pases de
medida, organizacin y representacin si no todos los cambios afectan realmente a la medicin, organizacin y
representacin. Por ejemplo, podra optar por representar de nuevo un fondo nicamente cuando un valor sea
superior a un lmite establecido. En este caso, el controlador de cambio de propiedad nicamente invalidara la
representacin cuando el valor superase ese lmite establecido.
Hacer que una propiedad de dependencia se pueda heredar consume recursos
De manera predeterminada, las propiedades de dependencia registradas no se pueden heredar. Sin embargo,
puede hacer explcitamente que cualquier propiedad sea heredable. Aunque se trata de una caracterstica til,
convertir una propiedad en heredable afecta negativamente al rendimiento, porque aumenta el tiempo que se
tarda en invalidar las propiedades.
RegisterClassHandler debe utilizarse con prudencia
Aunque llamar a RegisterClassHandler permite guardar el estado de instancia, es importante ser consciente de
que se llama al controlador en cada instancia, lo que puede dar lugar a problemas de rendimiento. nicamente
debe utilizar RegisterClassHandler cuando la aplicacin necesite que se guarde el estado de instancia.
Establecer el valor predeterminado de una propiedad de dependencia durante el registro
Al crear una DependencyProperty que requiere un valor predeterminado, establezca el valor mediante los
metadatos predeterminados que se pasan como parmetro al mtodo Register de DependencyProperty. Utilice
esta tcnica en lugar de establecer el valor de la propiedad en un constructor o en cada instancia de un
elemento.
Establecer el valor de PropertyMetadata mediante el Registro
Al crear una DependencyProperty, si lo desea puede establecer PropertyMetadata mediante los mtodos
Register o OverrideMetadata. Aunque el objeto podra tener un constructor esttico para llamar a
OverrideMetadata, no es la solucin ptima y afecta negativamente al rendimiento. Para obtener el mximo
rendimiento, establezca PropertyMetadata durante la llamada a Register.
Objetos Freezable
Un objeto Freezable es un tipo especial de objeto que tiene dos estados: no inmovilizado e inmovilizado.
Inmovilizar los objetos siempre que es posible mejora el rendimiento de la aplicacin y reduce su espacio de
trabajo.
Cada objeto Freezable tiene un evento Changed que se provoca cada vez que cambia. Sin embargo, las
notificaciones de cambio son costosas por lo que se refiere al rendimiento de la aplicacin.
Estudie el ejemplo siguiente, en el que cada Rectangle utiliza el mismo objeto Brush:
rectangle_1.Fill = myBrush;
rectangle_2.Fill = myBrush;
rectangle_3.Fill = myBrush;
// ...
rectangle_10.Fill = myBrush;
De manera predeterminada, WPF proporciona un controlador para el evento

Changed

del

objeto

SolidColorBrush a fin de invalidar la propiedad Fill del objeto Rectangle. En este caso, cada vez que
SolidColorBrush tiene que iniciar su evento Changed, es preciso invocar la funcin de devolucin de llamada
para cada Rectangle: la acumulacin de estas invocaciones de la funcin de devolucin de llamada conlleva
importante reduccin del rendimiento. Adems, agregar y quitar controladores en este punto tambin supone
una intensa carga para el rendimiento, puesto que para hacerlo la aplicacin tiene que recorrer la lista
completa. Si en el escenario de aplicacin SolidColorBrush nunca cambia, estar pagando el costo de mantener
innecesariamente los controladores de eventos Changed.
Inmovilizar un objeto Freezable puede mejorar su rendimiento, porque ya no es preciso dedicar recursos a
mantener notificaciones de cambio. En la tabla siguiente se muestra el tamao de un SolidColorBrush simple

MCT: Luis Dueas

Pag 197 de 445

Manual de Windows Presentation Foundation


cuando su propiedad IsFrozen est establecida en true, en comparacin con cuando no lo est. Se basa en el
supuesto de que se aplica un pincel a la propiedad Fill de diez objetos Rectangle.
Estado

Tamao

SolidColorBrush inmovilizado

212 bytes

SolidColorBrush no inmovilizado

972 bytes

En el ejemplo de cdigo siguiente se muestra este concepto:


Brush frozenBrush = new SolidColorBrush(Colors.Blue);
frozenBrush.Freeze();
Brush nonFrozenBrush = new SolidColorBrush(Colors.Blue);
for (int i = 0; i < 10; i++)
{
// Create a Rectangle using a non-frozed Brush.
Rectangle rectangleNonFrozen = new Rectangle();
rectangleNonFrozen.Fill = nonFrozenBrush;
// Create a Rectangle using a frozed Brush.
Rectangle rectangleFrozen = new Rectangle();
rectangleFrozen.Fill = frozenBrush;

}
Los controladores modificados de objetos Freezable no inmovilizados pueden mantener los objetos
activos
El delegado que un objeto pasa al evento Changed de un objeto Freezable es, en realidad, una referencia a ese
objeto. Por consiguiente, los controladores de eventos Changed pueden mantener los objetos activos durante
ms tiempo de lo esperado. Al realizar la limpieza de un objeto que se ha registrado para escuchar a fin de
detectar el evento Changed de un objeto Freezable, es esencial quitar ese delegado antes de liberar el objeto.
WPF tambin enlaza internamente los eventos Changed. Por ejemplo, todas las propiedades de dependencia
que aceptan Freezable como valor escucharn automticamente para detectar los eventos Changed. La
propiedad Fill, que acepta un Brush, muestra este concepto.
Brush myBrush = new SolidColorBrush(Colors.Red);
Rectangle myRectangle = new Rectangle();
myRectangle.Fill = myBrush;
Al asignar myBrush a myRectangle.Fill, un delegado que seala hacia atrs al objeto Rectangle se agregar al
evento Changed del objeto SolidColorBrush. Esto significa que el cdigo siguiente realmente no hace que
myRect sea apto para la recoleccin de elementos no utilizados:
myRectangle = null;
En este caso, myBrush mantiene myRectangle activo y le devolver la llamada cuando provoque su evento
Changed. Observe que al asignar myBrush a la propiedad Fill de un nuevo Rectangle, simplemente se agrega
otro controlador de eventos a myBrush.
La manera recomendada de limpiar estos tipos de objetos es quitar Brush de la propiedad Fill, lo que, a su vez,
quitar el controlador de eventos de Changed.
myRectangle.Fill = null;
myRectangle = null;
Virtualizacin de la interfaz de usuario
WPF tambin proporciona una variacin del elemento StackPanel que "virtualiza" automticamente el contenido
secundario enlazado a datos. En este contexto, el trmino "virtualizar" se refiere a una tcnica por la que se
genera un subconjunto de elementos UIElements a partir de un nmero mayor de elementos de datos en
funcin de los elementos que estn visibles en pantalla. Generar un gran nmero de elementos de interfaz de
usuario cuando slo pueden estar en pantalla algunos de ellos en un momento dado, requiere un uso intensivo,
tanto de la memoria como del procesador. VirtualizingStackPanel (a travs de una funcionalidad proporcionada
por VirtualizingPanel) calcula los elementos visibles y trabaja con ItemContainerGenerator desde un
ItemsControl (como ListBox o ListView) para crear nicamente los UIElements correspondientes a los
elementos visibles.
Para optimizar el rendimiento, los objetos visuales correspondientes a estos elementos se generan o mantienen
activos nicamente si estn visibles en la pantalla. Cuando ya no se encuentran en el rea visible del control,
los objetos visuales se pueden quitar. Esto no debe confundirse con la virtualizacin de datos, donde los objetos

MCT: Luis Dueas

Pag 198 de 445

Manual de Windows Presentation Foundation


de datos no estn presentes en absoluto en la coleccin local, sino que se transmiten a medida que se
necesitan.
En la tabla siguiente se muestra el tiempo transcurrido para agregar y representar 5000 elementos TextBlock
en un StackPanel y en un VirtualizingStackPanel. En este escenario, las mediciones representan el tiempo
transcurrido entre el momento de asociar una cadena de texto a la propiedad ItemsSource de un objeto
ItemsControl hasta el momento en que los elementos de panel muestran la cadena de texto.
Panel host

Tiempo de representacin (ms)

StackPanel

3210

VirtualizingStackPanel

46

2.8.2.6. Recursos de Aplicacin


WPF permite compartir los recursos de aplicacin, a fin de permitirle utilizar una apariencia o un
comportamiento coherentes en elementos de tipos parecidos. En este tema se proporcionan algunas
recomendaciones en este sentido que pueden ayudarle a mejorar el rendimiento de sus aplicaciones.
Compartir recursos
Si

la

aplicacin

utiliza

controles

personalizados

define

recursos

en

un

diccionario

de

recursos

(ResourceDictionary) (o nodo de recursos XAML), se recomienda que defina los recursos en el nivel del objeto
Application o Window, o bien que los defina en el tema predeterminado para los controles personalizados.
Definir los recursos en un control ResourceDictionary personalizado afecta negativamente al rendimiento para
cada instancia de ese control. Por ejemplo, si ha realizado operaciones de pincel que deterioran el rendimiento
definidas como parte de la definicin de recurso de un control personalizado y muchas instancias del control
personalizado, el espacio de trabajo de la aplicacin aumentar significativamente.
Para ilustrar este punto, estudie lo siguiente. Supongamos que est programando un juego de cartas mediante
WPF. Para la mayora de los juegos de cartas, necesita 52 cartas con 52 caras diferentes. Decide implementar
un control de carta personalizado y definen 52 pinceles (cada uno de ellos representa una cara de carta) en los
recursos del control de carta personalizado. En la aplicacin principal, crea inicialmente 52 instancias del control
de carta personalizado. Cada instancia del control de carta personalizado genera 52 instancias de objetos
Brush, con lo que tenemos un total de 52 * 52 objetos Brush en la aplicacin. Si saca los pinceles de los
recursos del control personalizado y los coloca en el nivel del objeto Application o Window, o los define en el
tema predeterminado del control personalizado, reducir el espacio de trabajo de la aplicacin, puesto que
ahora compartir los 52 pinceles entre las 52 instancias del control de carta.
Compartir un pincel sin copiar
Si tiene varios elementos que utilizan el mismo objeto Brush, defina el pincel como un recurso y haga
referencia a l, en lugar de definir el pincel insertado en XAML. Este mtodo crear una instancia y la
reutilizar, mientras que al definir los pinceles insertados en XAML, se crea una nueva instancia para cada
elemento.
En el ejemplo de marcado siguiente se ilustra este punto:
<StackPanel.Resources>
<LinearGradientBrush x:Key="myBrush" StartPoint="0,0.5" EndPoint="1,0.5"
Opacity="0.5">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="GoldenRod" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</StackPanel.Resources>
<!-- Non-shared Brush object. -->
<Label>
Label 1

MCT: Luis Dueas

Pag 199 de 445

Manual de Windows Presentation Foundation


<Label.Background>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5" Opacity="0.5">
<LinearGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="GoldenRod" Offset="0" />
<GradientStop Color="White" Offset="1" />
</GradientStopCollection>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Label.Background>
</Label>
<!-- Shared Brush object. -->
<Label Background="{StaticResource myBrush}">Label 2</Label>
<Label Background="{StaticResource myBrush}">Label 3</Label>
Utilizar recursos estticos siempre que sea posible
Un recurso esttico proporciona un valor para cualquier atributo de propiedad XAML buscando una referencia a
un recurso ya definido. El comportamiento de bsqueda de ese recurso es anlogo a la bsqueda en tiempo de
compilacin.
Un recurso dinmico, por otro lado, crear una expresin temporal durante la compilacin inicial y, de este
modo, diferir la consulta de recursos hasta que el valor de recurso solicitado se necesite realmente para
construir un objeto. El comportamiento de bsqueda de ese recurso es anlogo a la bsqueda en tiempo de
ejecucin, que afecta negativamente al rendimiento. Siempre que sea posible, utilice recursos estticos en la
aplicacin, y utilice los recursos dinmicos nicamente cuando sea necesario.
En el ejemplo de marcado siguiente se muestra el uso de ambos tipos de recursos:
<StackPanel.Resources>
<SolidColorBrush x:Key="myBrush" Color="Teal"/>
</StackPanel.Resources>
<!-- StaticResource reference -->
<Label Foreground="{StaticResource myBrush}">Label 1</Label>
<!-- DynamicResource reference -->
<Label Foreground="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">Label
2</Label>

2.8.2.7. Texto
WPF incluye compatibilidad con la presentacin de contenido de texto mediante controles de interfaz de usuario
(UI) de caractersticas enriquecidas. En general, puede dividir la representacin de texto en tres capas:
1.

Utilizar directamente los objetos Glyphs y GlyphRun.

2.

Utilizar el objeto FormattedText.

3.

Utilizar controles de alto nivel, como los objetos TextBlock y FlowDocument.

En este tema se proporcionan recomendaciones para mejorar el rendimiento de la representacin de texto.


Representar texto en el nivel de glifos
Windows Presentation Foundation (WPF) proporciona compatibilidad con texto avanzado que incluye marcado
de nivel de glifos con acceso directo a Glyphs para los clientes que desean interceptar y conservar el texto
despus de darle formato. Estas caractersticas proporcionan compatibilidad vital para los distintos requisitos de
representacin de texto de cada uno de los escenarios siguientes.

Presentacin en pantalla de documentos de formato fijo.

Escenarios de impresin.

Lenguaje de marcado de aplicaciones extensible (XAML) como lenguaje de dispositivos de


impresin.

Escritor de documentos XPS de Microsoft.


Controladores de impresora anteriores, salida de aplicaciones de Win32 en formato fijo.
Formato de colas de impresin.

Representacin de documentos de formato fijo, incluidos clientes de versiones anteriores de Windows


y otros dispositivos informticos.

MCT: Luis Dueas

Pag 200 de 445

Manual de Windows Presentation Foundation

Nota:
Glyphs y GlyphRun se han diseado para la presentacin de documentos de formato fijo y escenarios de
impresin. Windows Presentation Foundation (WPF) proporciona varios elementos para escenarios
generales de diseo e interfaz de usuario (UI), como Label y TextBlock.
En los ejemplos siguientes se muestra cmo definir las propiedades de un objeto Glyphs en Lenguaje de
marcado de aplicaciones extensible (XAML). El objeto Glyphs representa la salida de GlyphRun en XAML. En los
ejemplos se supone que las fuentes Arial, Courier New y Times New Roman estn instaladas en la carpeta
C:\WINDOWS\Fonts del equipo local.
<!-- The example shows how to use a Glyphs object. -->
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<StackPanel Background="PowderBlue">
<Glyphs
FontUri
= "C:\WINDOWS\Fonts\TIMES.TTF"
FontRenderingEmSize = "100"
StyleSimulations
= "BoldSimulation"
UnicodeString
= "Hello World!"
Fill
= "Black"
OriginX
= "100"
OriginY
= "200" />
</StackPanel>
</Page>
Utilizar DrawGlyphRun
Si tiene un control personalizado y desea representar glifos, utilice el mtodo DrawGlyphRun.
WPF tambin proporciona servicios del nivel inferior para dar formato personalizado al texto mediante el objeto
FormattedText. La manera ms eficaz de representar texto en Windows Presentation Foundation (WPF) es
generar el contenido de texto en el nivel de glifos mediante Glyphs y GlyphRun. Sin embargo, el costo de esta
eficacia es la prdida de las caractersticas de formato de texto enriquecido fciles de usar integradas en los
controles de Windows Presentation Foundation (WPF), como TextBlock y FlowDocument.
Objeto FormattedText
El objeto FormattedText permite dibujar texto con varias lneas, en el que se puede dar formato a cada carcter
individualmente.
Para crear texto con formato, llame al constructor FormattedText para crear un objeto FormattedText. Una vez
creada la cadena de texto con formato inicial, puede aplicarle varios estilos de formato. Si desea que la
aplicacin implemente su propio diseo, el objeto FormattedText es ms adecuado que usar control, como
TextBlock.
El objeto FormattedText proporciona la funcin de formato de texto de bajo nivel. Puede aplicar varios estilos
de formato a uno o ms caracteres. Por ejemplo, podra llamar a los mtodos SetFontSize y SetForegroundBrus
para cambiar el formato de los cinco primeros caracteres del texto.
En el ejemplo de cdigo siguiente se crea un objeto FormattedText y se representa.
protected override void OnRender(DrawingContext drawingContext)
{
string testString = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
do eiusmod tempor";
// Create the initial formatted text string.
FormattedText formattedText = new FormattedText(testString,
CultureInfo.GetCultureInfo("en-us"),FlowDirection.LeftToRight,
new Typeface("Verdana"),32,Brushes.Black);
// Set a maximum width and height. If the text overflows these values, an ellipsis
"..." appears.
formattedText.MaxTextWidth = 300;
formattedText.MaxTextHeight = 240;
// Use a larger font size beginning at the first (zero-based) character and
continuing for 5 characters.
// The font size is calculated in terms of points -- not as device-independent
pixels.
formattedText.SetFontSize(36 * (96.0 / 72.0), 0, 5);
// Use a Bold font weight beginning at the 6th character and continuing for 11
characters.
formattedText.SetFontWeight(FontWeights.Bold, 6, 11);

MCT: Luis Dueas

Pag 201 de 445

Manual de Windows Presentation Foundation


// Use a linear gradient brush beginning at the 6th character and continuing for 11
characters.
formattedText.SetForegroundBrush(new LinearGradientBrush(Colors.Orange,
Colors.Teal,90.0),6, 11);
// Use an Italic font style beginning at the 28th character and continuing for 28
characters.
formattedText.SetFontStyle(FontStyles.Italic, 28, 28);
// Draw the formatted text string to the DrawingContext of the control.
drawingContext.DrawText(formattedText, new Point(10, 0));
}
Controles FlowDocument, TextBlock y Label
WPF incluye varios controles para dibujar texto en la pantalla. Cada control se destina a un escenario diferente
y tiene su propia lista de caractersticas y limitaciones.
FlowDocument afecta al rendimiento ms que TextBlock o Label
En general, el elemento TextBlock se debe usar cuando se necesita una compatibilidad de texto limitada, como
una frase breve en una interfaz de usuario (UI). Label se puede usar cuando se necesita una compatibilidad de
texto mnima. El elemento FlowDocument es un contenedor para documentos dinmicos que admite
presentacin enriquecida de contenido y, por consiguiente, afecta ms al rendimiento mayor que los controles
TextBlock o Label.
Evitar el uso de TextBlock en FlowDocument
El elemento TextBlock se deriva de UIElement. El elemento Run se deriva de TextElement, cuyo uso consume
menos recursos que un objeto derivado de UIElement. Siempre que sea posible, utilice Run en lugar de
TextBlock para mostrar contenido de texto en FlowDocument.
En el ejemplo de marcado siguiente se muestran dos maneras de establecer contenido de texto dentro de
FlowDocument:
<FlowDocument>
<!-- Text content within a Run (more efficient). -->
<Paragraph>
<Run>Line one</Run>
</Paragraph>
<!-- Text content within a TextBlock (less efficient). -->
<Paragraph>
<TextBlock>Line two</TextBlock>
</Paragraph>
</FlowDocument>
Evitar el uso de Run para establecer propiedades de texto
En general, utilizar Run dentro de TextBlock constituye una carga mayor para el rendimiento que no utilizar un
objeto Run explcito en absoluto. En lugar de utilizar Run para establecer propiedades de texto, establezca
directamente esas propiedades en TextBlock.
En el ejemplo de marcado siguiente se muestran estas dos maneras de establecer una propiedad de texto; en
este caso, la propiedad FontWeight:
<!-- Run is used to set text properties. -->
<TextBlock>
<Run FontWeight="Bold">Hello, world</Run>
</TextBlock>
<!-- TextBlock is used to set text properties, which is more efficient. -->
<TextBlock FontWeight="Bold">
Hello, world
</TextBlock>
En la tabla siguiente se muestra el costo de mostrar 1000 objetos TextBlock con y sin un objeto Run explcito.
Tipo de TextBlock

Tiempo de creacin
(ms)

Tiempo de representacin
(ms)

Propiedades de texto de configuracin de Run

146

540

Propiedades de texto de configuracin de


TextBlock

43

453

Evitar el enlace de datos a la propiedad Label.Content


Imagine un escenario donde hay un objeto Label que se actualiza con frecuencia a partir de un origen String. Al
efectuar un enlace de datos de la propiedad Content del elemento Label al objeto de origen String, puede
experimentar un rendimiento insuficiente. Cada vez que se actualiza el objeto String de origen, se descarta el

MCT: Luis Dueas

Pag 202 de 445

Manual de Windows Presentation Foundation


objeto String anterior y se crea un nuevo objeto String. Dado que un objeto String es inmutable, no se puede
modificar. Esto, a su vez, hace que el ContentPresenter del objeto Label descarte su contenido anterior y vuelva
a generar nuevo contenido para mostrar el nuevo objeto String.
La solucin a este problema es simple. Si Label no est establecido en un valor de ContentTemplate
personalizado, reemplace Label con TextBlock y enlace los datos su propiedad Text a la cadena de origen.
Propiedad enlazada a datos

Tiempo de actualizacin (ms)

Label.Content

835

TextBlock.Text

242

Hyperlink
El objeto Hyperlink es un elemento de contenido dinmico insertado que permite hospedar hipervnculos dentro
del contenido dinmico.
Combinar hipervnculos en un solo objeto TextBlock
Puede optimizar el uso de varios elementos Hyperlink agrupndolos dentro del mismo TextBlock. Esto ayuda a
minimizar el nmero de objetos que se crean en la aplicacin. Por ejemplo, puede que desee mostrar varios
hipervnculos, como los siguientes:
MSN Home | My MSN
En el ejemplo de marcado siguiente se muestran varios elementos TextBlock utilizados para mostrar los
hipervnculos:
<!-- Hyperlinks in separate TextBlocks. -->
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN
Home</Hyperlink>
</TextBlock>
<TextBlock Text=" | "/>
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My MSN</Hyperlink>
</TextBlock>
En el ejemplo de marcado siguiente se muestra una manera ms eficaz de mostrar los hipervnculos; esta vez,
se utiliza un solo TextBlock:
<!-- Hyperlinks combined in the same TextBlock. -->
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="http://www.msn.com">MSN
Home</Hyperlink>
<Run Text=" | " />
<Hyperlink TextDecorations="None" NavigateUri="http://my.msn.com">My MSN</Hyperlink>
</TextBlock>
Mostrar hipervnculos subrayados slo en los eventos MouseEnter
Un objeto TextDecoration es una ornamentacin visual que se puede agregar al texto; sin embargo, la creacin
de instancias puede afectar negativamente al rendimiento. Si realiza un uso excesivo de elementos Hyperlink,
puede ser conveniente mostrar la lnea de subrayado nicamente al desencadenar un evento, como el evento
MouseEnter.
Hipervnculo que aparece al desencadenar MouseEnter

En el ejemplo de marcado siguiente se muestra Hyperlink con y sin subrayado:


<!-- Hyperlink with default underline. -->
<Hyperlink NavigateUri="http://www.msn.com">MSN Home</Hyperlink>
<Run Text=" | " />
<!-- Hyperlink with no underline. -->
<Hyperlink Name="myHyperlink" TextDecorations="None"
MouseEnter="OnMouseEnter"
MouseLeave="OnMouseLeave"
NavigateUri="http://www.msn.com">

MCT: Luis Dueas

Pag 203 de 445

Manual de Windows Presentation Foundation


My MSN
</Hyperlink>
En la tabla siguiente se muestra el costo para el rendimiento de mostrar 1000 elementos Hyperlink con y sin un
subrayado.
Hyperlink

Tiempo de creacin (ms)

Tiempo de representacin (ms)

Con subrayado

289

1130

Sin subrayado

299

776

Caractersticas de formato de texto


WPF proporciona servicios de formato de texto enriquecido, como la inclusin automtica de guiones de
divisin. Estos servicios puede afectar negativamente al rendimiento de la aplicacin y nicamente deben
utilizarse cuando se necesiten.
Evitar el uso innecesario de guiones
La divisin automtica con guiones busca los puntos de interrupcin del guin en las lneas de texto y permite
posiciones de salto de lnea adicionales en los objetos TextBlock y FlowDocument. De manera predeterminada,
la caracterstica de divisin automtica con guiones est deshabilitada en estos objetos. Puede habilitar esta
caracterstica estableciendo la propiedad IsHyphenationEnabled del objeto en true. Sin embargo, habilitar esta
caracterstica hace que WPF inicie la interoperabilidad con Modelo de objetos componentes (COM), lo que puede
afectar al rendimiento de la aplicacin. Se recomienda no utilizar la divisin automtica con guiones a menos
que lo necesite.
Prestar atencin al utilizar figuras
Un elemento Figure representa una parte de contenido dinmico que puede tener una posicin absoluta dentro
de una pgina de contenido. En algunos casos, una Figure puede hacer que se cambie automticamente el
formato de una pgina si su posicin est en conflicto con el contenido que ya se ha dispuesto en la pgina.
Puede minimizar la posibilidad de cambios de formato innecesarios agrupando los elementos Figure contiguos o
declarndolos cerca de la parte superior del contenido en un escenario de tamao de pgina fijo.
Prrafo ptimo
La caracterstica de prrafo ptimo del objeto FlowDocument dispone los prrafos de modo que el espacio en
blanco se distribuya del modo ms uniforme posible. De manera predeterminada, la caracterstica de prrafo
ptimo

est

deshabilitada.

Puede

habilitar

esta

caracterstica

estableciendo

la

propiedad

IsOptimalParagraphEnabled del objeto en true. Sin embargo, habilitar esta caracterstica afecta al rendimiento
de la aplicacin. Se recomienda no utilizar la caracterstica de prrafo ptimo a menos que lo necesite.

2.8.2.8. Enlace de Datos


El enlace de datos de Windows Presentation Foundation (WPF) proporciona un mtodo simple y coherente para
que las aplicaciones presenten e interacten con datos. Los elementos se pueden enlazar a los datos de
diversos orgenes de datos en forma de objetos CLR y XML.
En este tema se proporcionan recomendaciones sobre el rendimiento del enlace de datos.
Cmo se resuelven las referencias de enlace de datos
Antes de explicar los problemas de rendimiento de enlace de datos, vale la pena explorar cmo el motor de
enlace de datos de Windows Presentation Foundation (WPF) resuelve las referencias de objeto para el enlace.
El origen de un enlace de datos de Windows Presentation Foundation (WPF) puede ser cualquier objeto CLR. Es
posible enlazar a propiedades, subpropiedades o indizadores de un objeto CLR. Las referencias de enlace se
resuelven utilizando reflexin Microsoft .NET Framework o una interfaz ICustomTypeDescriptor. Estos son tres
mtodos para resolver referencias de objeto para el enlace.

MCT: Luis Dueas

Pag 204 de 445

Manual de Windows Presentation Foundation


El primer mtodo implica el uso de la reflexin. En este caso, el objeto PropertyInfo se utiliza para detectar los
atributos de la propiedad y proporcionar acceso a los metadatos de propiedad. Cuando se utiliza la interfaz
ICustomTypeDescriptor, el motor de enlace de datos utiliza esta interfaz para tener acceso a los valores de
propiedad. La interfaz ICustomTypeDescriptor es especialmente til en aquellos casos en los que el objeto no
tiene un conjunto esttico de propiedades.
Las

notificaciones

de

cambios

de

propiedad

se

pueden

proporcionar

implementando

la

interfaz

INotifyPropertyChanged o utilizando las notificaciones de cambios asociadas al objeto TypeDescriptor. Sin


embargo, la estrategia preferida para implementar notificaciones de cambios de propiedades es utilizar
INotifyPropertyChanged.
Si el objeto de origen es un objeto CLR y la propiedad de origen es una propiedad CLR, el motor de enlace de
datos de Windows Presentation Foundation (WPF) tiene que utilizar primero la reflexin en el objeto de origen
para obtener el objeto TypeDescriptor y, a continuacin, consultar un objeto PropertyDescriptor. Esta secuencia
de operaciones de reflexin puede necesitar mucho tiempo, desde la perspectiva del rendimiento.
El segundo mtodo para resolver referencias a objetos implica un objeto de origen CLR que implementa la
interfaz INotifyPropertyChanged y una propiedad de origen que es una propiedad CLR. En este caso, el motor
de enlace de datos utiliza directamente la reflexin en el tipo de origen y obtiene la propiedad necesaria. Este
mtodo contina sin ser el ptimo, pero sus requisitos de espacio de trabajo son menores que los del primer
mtodo.
El tercer mtodo para resolver referencias de objeto implica un objeto de origen que es un objeto
DependencyObject y una propiedad que es un objeto DependencyProperty. En este caso, el motor de enlace de
datos no necesita utilizar la reflexin. En su lugar, el motor de propiedad y el motor de enlace de datos
resuelven juntos la referencia de propiedad de manera independiente. ste es el mtodo ptimo para resolver
referencias de objeto utilizadas para el enlace de datos.
La tabla siguiente compara la velocidad de enlace de datos de la propiedad Text de mil elementos TextBlock
utilizando estos tres mtodos.
Enlazar la propiedad Text de un TextBlock

Tiempo de
enlace (ms)

Tiempo de representacin,
incluido el enlace (ms)

A una propiedad de un objeto CLR

115

314

A una propiedad de un objeto CLR que


implementa INotifyPropertyChanged

115

305

A un objeto DependencyProperty de un objeto


DependencyObject.

90

263

Enlazar a objetos CLR grandes


Hay un impacto significativo sobre el rendimiento cuando se realiza el enlace de datos a un objeto CLR nico
con miles de propiedades. Puede minimizar este impacto dividiendo el objeto nico en varios objetos CLR con
menos propiedades. La tabla muestra los tiempos de enlace y representacin para el enlace de datos a un
objeto CLR grande nico frente a varios objetos menores.
Enlace de datos de 1000 objetos
TextBlock

Tiempo de enlace
(ms)

Tiempo de representacin, incluido el


enlace (ms)

A un objeto CLR con 1000


propiedades

950

1200

A 1000 objetos CLR con una


propiedad

115

314

Enlazar a una propiedad ItemsSource

MCT: Luis Dueas

Pag 205 de 445

Manual de Windows Presentation Foundation


Considere un escenario en el que tenga un objeto CLRList<(Of <(T>)>) que contiene una lista de empleados
que desea mostrar en un control ListBox. Para crear una correspondencia entre estos dos objetos, enlazara la
lista de empleados a la propiedad ItemsSource del control ListBox. No obstante, suponga que tiene un nuevo
empleado que se incorpora al grupo. Podra pensar que, para insertar esta nueva persona en los valores ListBox
enlazados, agregara simplemente esta persona a la lista de empleados y esperara que el cambio fuera
reconocido automticamente por el motor de enlace de datos. Esa suposicin se demostrara falsa; en realidad,
el cambio no se reflejara automticamente en ListBox. Esto se debe a que el objeto CLR List<(Of <(T>)>) no
produce automticamente un evento de cambio de coleccin. Para que el control ListBox captara los cambios,
tendra que volver a crear la lista de empleados y asociarla de nuevo a la propiedad ItemsSource del control
ListBox. Aunque esta solucin funciona, introduce un impacto enorme sobre el rendimiento. Cada vez que se
reasigna la propiedad ItemsSource del control ListBox a un nuevo objeto, el control ListBox desecha primero
sus elementos anteriores y regenera la lista completa. El impacto sobre el rendimiento se magnifica si el control
ListBox se asigna a un objeto DataTemplate complejo.
Una

solucin

muy

eficaz a

este

problema

es

convertir

la

lista

de

empleados

en

una

coleccin

ObservableCollection<(Of <(T>)>). Un objeto ObservableCollection<(Of <(T>)>) provoca una notificacin de


cambios que el motor de enlace de datos puede recibir. El evento agrega o quita un elemento de un control
ItemsControl sin necesidad de regenerar la lista completa.
La tabla siguiente muestra el tiempo necesario para actualizar el control ListBox (con virtualizacin de la
interfaz de usuario desactivada) cuando se agrega un elemento. El nmero de la primera fila representa el
tiempo transcurrido cuando el objeto CLR List<(Of <(T>)>) se enlaza a la propiedad ItemsSource de un
elemento ListBox. El nmero en la segunda fila representa el tiempo transcurrido cuando una coleccin
ObservableCollection<(Of <(T>)>) se enlaza a la propiedad ItemsSource de un elemento ListBox. Observe los
significativos ahorros de tiempo mediante la estrategia de enlace de datos de ObservableCollection<(Of
<(T>)>).
Enlace de datos de ItemsSource

Tiempo de actualizacin para 1 elemento (ms)

A un objeto CLR List<(Of <(T>)>)

1656

A una coleccin ObservableCollection<(Of <(T>)>)

20

Enlazar IList a ItemsControl no IEnumerable


Si puede elegir entre enlazar un objeto IList<(Of <(T>)>) o una interfaz IEnumerable a un objeto
ItemsControl, elija el objeto IList<(Of <(T>)>). Enlazar la interfaz IEnumerable a un control ItemsControl
obliga a WPF a crear un objeto IList<(Of <(T>)>) contenedor, lo que significa que el rendimiento se ve
afectado por la sobrecarga innecesaria de un segundo objeto.
No convierta objetos CLR en XML solamente para el enlace de datos.
WPF permite enlazar datos a contenido XML; no obstante, en enlace de datos a contenido XML es ms lento que
el enlace de datos a objetos CLR. No convierta datos de objetos CLR en XML si su nico propsito es el enlace
de datos.

2.8.2.9. Otras Recomendaciones


En este tema se proporcionan recomendaciones de rendimiento adems de las que se abordan en los temas de
la seccin Optimizar WPF: Rendimiento de aplicaciones.
Opacidad en los pinceles comparada con opacidad en los elementos
Cuando se utiliza un objeto Brush para establecer la propiedad Fill o Stroke de un elemento, es mejor
establecer el valor de Brush.Opacity en lugar de la propiedad Opacity del elemento. Modificar la propiedad
Opacity de un elemento puede hacer que WPF cree una superficie temporal.
Navegacin hasta un objeto

MCT: Luis Dueas

Pag 206 de 445

Manual de Windows Presentation Foundation


El objeto NavigationWindow se deriva de la clase Window y la extiende aportando compatibilidad de navegacin
de contenido, gracias, principalmente, a la adicin de NavigationService y del diario. Puede actualizar el rea
cliente de NavigationWindow especificando un identificador de recursos uniforme (URI) o un objeto. En el
ejemplo siguiente se muestran ambos mtodos:
private void buttonGoToUri(object sender, RoutedEventArgs args)
{
navWindow.Source = new Uri("NewPage.xaml", UriKind.RelativeOrAbsolute);
}
private void buttonGoNewObject(object sender, RoutedEventArgs args)
{
NewPage nextPage = new NewPage();
nextPage.InitializeComponent();
navWindow.Content = nextPage;
}
Cada objeto NavigationWindow tiene un diario que graba el historial de navegacin del usuario en esa ventana.
Uno de los propsitos del diario es permitir a los usuarios desandar sus pasos.
Cuando se navega mediante identificador de recursos uniforme (URI), el diario almacena slo la referencia al
identificador de recursos uniforme (URI). Esto significa que cada vez que se vuelve a visitar la pgina, se
reconstruye dinmicamente, lo que puede tardar tiempo segn complejidad de la pgina. En este caso, el costo
de almacenamiento en el diario es bajo, pero el tiempo de reconstitucin de la pgina es potencialmente alto.
Cuando se navega mediante un objeto, el diario almacena el rbol visual completo del objeto. Esto significa que
cada vez que vuelve a visitar la pgina, se representa inmediatamente sin tener que reconstruirla. En este
caso, el costo de almacenamiento en el diario es alto, pero el tiempo de reconstitucin de la pgina es bajo.
Cuando se utiliza el objeto NavigationWindow, es preciso tener presente cmo afecta la compatibilidad con el
diario al rendimiento de la aplicacin.
Pruebas de posicionamiento en superficies 3D de gran tamao
Las pruebas de posicionamiento en superficies 3D de gran tamao es una operacin que afecta intensamente al
rendimiento por lo que se refiere al consumo de CPU. Esto se cumple especialmente cuando la superficie 3D se
anima. Deshabilite las pruebas de posicionamiento en estas superficies si no las necesita. Los objetos que se
derivan de UIElement pueden deshabilitar las pruebas de posicionamiento estableciendo la propiedad
IsHitTestVisible en false.
Evento CompositionTarget.Rendering
El evento CompositionTarget.Rendering hace que WPF se anime de manera continua. Si utiliza este evento,
desascielo en cada oportunidad que se presente.
Evitar el uso de ScrollBarVisibility=Auto
Siempre

que

sea

posible,

evite

utilizar

el

valor

ScrollBarVisibility.Auto

para

las

propiedades

HorizontalScrollBarVisibility y VerticalScrollBarVisibility. Estas propiedades se definen para los objetos


RichTextBox, ScrollViewer y TextBox, adems de cmo propiedad asociada del objeto ListBox. En su lugar,
establezca ScrollBarVisibility en Disabled, Hidden o Visible.
El valor Auto es para casos de espacio limitado, en que las barras de desplazamiento slo deben mostrarse
cuando se necesiten. Por ejemplo, puede ser til utilizar este valor de ScrollBarVisibility con un control ListBox
de 30 elementos, en oposicin a un control TextBox con centenares de lneas de texto.
Configurar el servicio de almacenamiento en memoria cach de las fuentes para reducir el tiempo de inicio
El servicio WPF Font Cache comparte los datos de fuentes entre las aplicaciones de WPF. La primera aplicacin
de WPF que se ejecuta inicia este servicio an no est en ejecucin. Si utiliza Windows Vista, puede establecer
el servicio "Windows Presentation Foundation (WPF) Font Cache 3.0.0.0" de "Manual" (el valor predeterminado)
a "Automtico (inicio retrasado)" para reducir el tiempo de inicio de las aplicaciones de WPF.
Mejoras de representacin de Terminal Services

MCT: Luis Dueas

Pag 207 de 445

Manual de Windows Presentation Foundation


Una conexin a escritorio remoto permite a un cliente ejecutar remotamente las aplicaciones en un servidor
mientras las muestra en el cliente. El servidor puede ser un servidor de Windows Terminal Server, que es capaz
de prestar servicio a varias conexiones simultneas a escritorios remotos, o una versin de Windows, que
puede prestar servicio a una sola conexin a escritorio remoto. Cuando un usuario ejecuta una aplicacin a
travs de una conexin a escritorio remoto, la aplicacin se ejecuta en el servidor; la actividad del teclado y del
mouse en el cliente se transmiten al servidor, mientras que la interfaz de usuario de la aplicacin resultante se
genera en el servidor como mapas de bits que se transmiten al cliente.
Sin embargo, enviar mapas de bits al cliente a travs de la red para simular una interfaz de usuario no ofrece el
mismo rendimiento que representar la interfaz de usuario localmente en el cliente. Por fortuna, las aplicaciones
de WPF que se ejecutan a travs de una sesin de Conexin a escritorio remoto (RDC) pueden aprovechar la
compatibilidad con la representacin especial de Windows Vista para representarse en el cliente.
Para sacar partido de ello, se necesita lo siguiente:

Debe instalarse el servidor con Windows Vista Ultimate o Windows Vista Enterprise.

El servidor debe tener memoria suficiente para satisfacer los requisitos de memoria del Administrador
de ventanas de escritorio (DWM) (no es imprescindible cumplir otros requisitos de DWM, como los
relativos a las tarjetas de vdeo).

El cliente debe tener la misma compilacin de Vista que el servidor.

El cliente debe poder ejecutar el Administrador de ventanas de escritorio (DWM) de Windows Vista.
DWM est habilitado cuando el servicio de administracin de sesin del Administrador de ventanas de
escritorio est en ejecucin.

El cliente no debe ejecutar aplicaciones que puedan deshabilitar DWM, tales como rea de encuentro o
Asistencia remota.

El cliente no puede realizar saltos mltiples al servidor que contiene la aplicacin WPF deseada. Saltos
mltiples se refiere a crear una sesin a partir de otra.

La configuracin de la conexin a escritorio remoto del cliente debe incluir lo siguiente:

Composicin del escritorio debe estar seleccionada en Conexin a Escritorio remoto |


Opciones | Experiencia.

Temas debe estar seleccionada en Conexin a Escritorio remoto | Opciones |


Experiencia.

Color de 32 bits debe estar seleccionada en Conexin a Escritorio remoto | Opciones |


Mostrar | Colores.

2.8.2.10. Herramientas y Recursos de Rendimiento de WPF


WPF proporciona un conjunto de herramientas de creacin de perfiles de rendimiento que permiten analizar el
funcionamiento de la aplicacin en tiempo de ejecucin y determinar los tipos de optimizacin de rendimiento
que se pueden aplicar. En la tabla siguiente se muestran las cinco herramientas de generacin de perfiles de
rendimiento que se incluyen en la herramienta Windows SDK, WPFPerf:
Herramienta

Description

Event Trace

Se utiliza para analizar eventos y generar archivos de registro de eventos.

Perforator

Se utiliza para analizar el comportamiento de representacin.

Trace Viewer

Registro, presentacin y examen de archivos de registro de Event Tracing for Windows


(ETW) en formato de interfaz de usuario de WPF.

MCT: Luis Dueas

Pag 208 de 445

Manual de Windows Presentation Foundation

Visual Profiler

Se utiliza para generar perfiles de uso de servicios WPF, tales como el diseo y el
control de eventos, mediante elementos del rbol visual.

Working Set
Viewer

Se utiliza para analizar las caractersticas del espacio de trabajo de la aplicacin.

El conjunto de herramientas Visual Profiler ofrece una vista grfica y enriquecida de los datos de rendimiento.
En esta captura de pantalla, la seccin CPU Usage de Visual Profiler ofrece un desglose preciso del uso, por
parte de un objeto, de servicios de WPF tales como la representacin y el diseo.
Resultados de la presentacin de Visual Profiler

Ver el rbol visual con XamlPad


Si analiza la jerarqua del rbol visual mediante XAMLPad, puede formarse una idea del funcionamiento de la
expansin de la plantilla de control. Saber esto puede ayudarle a entender los costos de rendimiento y las
ventajas del diseo de la interfaz de usuario que est creando.
XamlPad proporciona una opcin para ver y explorar el rbol visual que corresponde al contenido de XAML
actualmente definido. Haga clic en el botn Show Visual Tree en la barra de mens para mostrar el rbol visual.
A continuacin se ilustra la expansin del contenido de XAML en los nodos del rbol visual en el panel Visual
Tree Explorer de XamlPad:
Panel Visual Tree Explorer de XamlPad

Observe que cada uno de los controles Label, TextBox y Button muestra una jerarqua de objetos visuales
independiente en el panel Visual Tree Explorer de XamlPad. Esto se debe a que los controles de WPF tienen una
ControlTemplate que contiene el rbol visual de ese control. Al hacer referencia explcitamente a un control, se
hace referencia implcitamente a su jerarqua visual.
Puede ver los valores de las propiedades de un elemento en Visual Tree Explorer seleccionando el elemento. El
panel Property Tree Explorer, situado debajo del panel Visual Tree Explorer, muestra los valores de las
propiedades actuales del objeto visual seleccionado.

MCT: Luis Dueas

Pag 209 de 445

Manual de Windows Presentation Foundation


Panel Property Tree Explorer de XamlPad

Compatibilidad de la traza de depuracin de WPF


La clase PresentationTraceSources ofrece compatibilidad con la traza de depuracin destinada especficamente
a las aplicaciones de WPF. La traza es un sistema de diagnstico mediante el cual se puede realizar el
seguimiento de la progresin de una aplicacin. Se suele usar la informacin del informe de instrucciones de
traza, de forma muy parecida al mtodo WriteLine. Sin embargo, se pueden activar y desactivar las
instrucciones de traza usando un archivo de configuracin. Adems, se puede personalizar el resultado de las
instrucciones de traza.

3. Elementos Fundamentales de WPF


Los elementos fundamentales de WPF admiten el modelo de programacin global. Incluyen caractersticas que
extienden los conceptos de CLR, como las propiedades, los eventos, las acciones del usuario, los comandos y
otras caractersticas del modelo de programacin, como estilos, plantillas, subprocesamiento, recursos y trabajo
con rboles de elementos. XAML para WPF y los modelos de contenido tambin se documentan en esta seccin.

3.1. Arquitectura de WPF


En este tema se proporciona un paseo guiado de la jerarqua de clases de Windows Presentation Foundation
(WPF). En l se explican la mayora de los subsistemas principales de WPF y se describe cmo interactan.
Tambin se detallan algunas de las decisiones tomadas por los arquitectos de WPF.
System.Object
El modelo de programacin primario de WPF se expone a travs de cdigo administrado. En las primeras fases
del proceso de diseo de WPF, hubo varios debates acerca de dnde se debera fijar el lmite entre los
componentes administrados del sistema y los no administrados. CLR proporciona varias caractersticas que
pueden hacer el proceso ms slido y productivo (como son la administracin de memoria, el control de
errores, el sistema de tipos comn, etc.) pero todas ellas tienen su costo.
Los componentes principales de WPF se muestran en la ilustracin siguiente. Las secciones rojas del diagrama
(PresentationFramework, PresentationCore y milcore) son los componentes principales del cdigo de WPF. De
stos, slo uno es un componente no administrado, milcore. Milcore se ha escrito en cdigo no administrado
para conseguir una estrecha integracin con DirectX. La visualizacin en WPF se realiza a travs del motor de
DirectX, lo que permite una representacin eficaz mediante hardware y software. WPF tambin requiri un
control preciso sobre la memoria y la ejecucin. El motor de composicin de milcore es sumamente sensible al
rendimiento, y requiri renunciar a muchas de las ventajas de CLR para obtener mejoras en el rendimiento.

MCT: Luis Dueas

Pag 210 de 445

Manual de Windows Presentation Foundation

La comunicacin entre las partes administradas y no administradas de WPF se describe ms adelante en este
tema. A continuacin se describe el resto del modelo de programacin administrado.
System.Threading.DispatcherObject
La mayora de los objetos de WPF se derivan de DispatcherObject, que proporciona las estructuras bsicas para
tratar con la simultaneidad y el subprocesamiento. WPF est basado en un sistema de mensajera
implementado por el distribuidor. Funciona de modo similar al conocido suministro de mensajes de Win32; de
hecho, el distribuidor de WPF utiliza los mensajes de User32 para realizar las llamadas entre subprocesos.
Es necesario comprender dos conceptos bsicos al hablar de simultaneidad en WPF: el distribuidor y la afinidad
de subprocesos.
Durante la fase de diseo de WPF, el objetivo era adoptar un nico subproceso de ejecucin, pero perteneciente
a un modelo con afinidad y sin subprocesos. La afinidad de subprocesos se produce cuando un componente
utiliza la identidad del subproceso que se est ejecutando para almacenar algn tipo de estado. La forma ms
comn de esta afinidad es utilizar el almacenamiento local de subprocesos (TLS) para almacenar el estado. La
afinidad de subprocesos requiere que cada subproceso lgico de ejecucin sea propiedad de un nico
subproceso fsico en el sistema operativo, lo que puede consumir mucha memoria. Finalmente, el modelo de
subprocesamiento de WPF se mantuvo sincronizado con el modelo de subprocesamiento de User32 existente,
que consiste en la ejecucin de un solo subproceso con afinidad de subprocesos. La principal razn para esto
fue la interoperabilidad; los sistemas como OLE 2.0, el Portapapeles e Internet Explorer requieren la ejecucin
de afinidad con subproceso nico (STA).
Dado que disponemos de objetos con subprocesamiento STA, necesitamos un medio de comunicacin entre
subprocesos y estar seguros de que nos encontramos en el subproceso correcto. A continuacin se describe la
funcin del distribuidor. El distribuidor es un sistema de envo de mensajes bsico que dispone de varias colas
con prioridad. Por ejemplo, son mensajes las notificaciones de entrada sin formato (el mouse se ha movido),
las funciones de marco de trabajo (diseo) o los comandos de usuario (ejecutar este mtodo). Al realizar una
derivacin de DispatcherObject, se crea un objeto de CLR que tiene el comportamiento de STA y al que se le
proporcionar un puntero a un distribuidor en el momento de la creacin.
System.Windows.DependencyObject
Una de las principales filosofas arquitectnicas utilizadas al crear WPF fue la preferencia por las propiedades en
lugar de los mtodos o los eventos. Las propiedades son declarativas y le permiten especificar ms fcilmente
la intencin en lugar de la accin. Esto tambin permiti el uso de un sistema basado en modelos, o en datos,
para mostrar el contenido de la interfaz de usuario. Esta filosofa tena como objetivo crear ms propiedades
con las que poder enlazar, y as tener un mejor control del comportamiento de una aplicacin.
Para conseguir que ms partes del sistema estuviesen controladas por propiedades, era necesario un sistema
de propiedades ms completo que el proporcionado por CLR. Un ejemplo sencillo de esto son las notificaciones
de cambios. Para poder habilitar los enlaces bidireccionales, ser necesario que ambos lados del enlace admitan
la notificacin de cambios. Para poder tener el comportamiento vinculado a los valores de propiedad, deber

MCT: Luis Dueas

Pag 211 de 445

Manual de Windows Presentation Foundation


recibir una notificacin cuando cambie el valor de la propiedad. Microsoft .NET Framework tiene una interfaz,
INotifyPropertyChange, que permite a un objeto publicar las notificaciones de cambios, aunque es opcional.
WPF proporciona un sistema de propiedades ms completo, derivado del tipo DependencyObject. El sistema de
propiedades puede considerarse un sistema de "dependencias" porque realiza el seguimiento de las
dependencias entre las expresiones de las propiedades y vuelve a validar automticamente los valores de las
propiedades cuando cambian las dependencias. Por ejemplo, si tenemos una propiedad que hereda (como
FontSize), el sistema se actualiza automticamente si la propiedad cambia en un elemento primario de un
elemento que hereda el valor.
La base del sistema de propiedades de WPF es el concepto de una expresin de propiedad. En esta primera
versin de WPF, el sistema de expresin de propiedades es cerrado y todas las expresiones que se
proporcionan forman parte del marco de trabajo. Las expresiones son el motivo de que el sistema de
propiedades no tenga caractersticas de enlace de datos, de estilo o de herencia incluidas en el cdigo, sino que
son proporcionadas por capas posteriores dentro del marco de trabajo.
El sistema de propiedades tambin proporciona almacenamiento disperso de valores de propiedades. Debido a
que los objetos pueden tener docenas (o incluso cientos) de propiedades, y la mayora de los valores est en su
estado predeterminado (heredado, establecido por estilos, etc.), no todas las instancias de un objeto necesitan
tener definidas todas las propiedades.
La ltima de las caractersticas nuevas del sistema de propiedades es el concepto de propiedades asociadas.
Los elementos de WPF se basan en el principio de composicin y reutilizacin de componentes. Con frecuencia,
un elemento contenedor (como un elemento de diseo Grid) necesita datos adicionales sobre los elementos
secundarios para controlar su comportamiento (como la informacin de Fila/Columna). En lugar de asociar
todas estas propiedades a cada elemento, cualquier objeto puede proporcionar las definiciones de las
propiedades para cualquier otro objeto. Esto es similar a las caractersticas "expando" de JavaScript.
System.Windows.Media.Visual
Con un sistema ya definido, el paso siguiente consiste en conseguir que se dibujen los pxeles en la pantalla. La
clase Visual permite generar un rbol de objetos visuales, cada uno de los cuales puede contener instrucciones
de dibujo y metadatos sobre cmo representar esas instrucciones (recorte, transformacin, etc.). Visual est
diseado para ser sumamente ligero y flexible, por lo que la mayora de las caractersticas no tienen ninguna
exposicin en la API pblica y dependen casi exclusivamente de funciones de devolucin de llamada protegidas.
En realidad, Visual es el punto de entrada al sistema de composicin de WPF. Visual es el punto de conexin
entre estos dos subsistemas, la API administrada y el milcore no administrado.
WPF muestra los datos recorriendo las estructuras de datos no administradas de cuya administracin se
encarga milcore. Estas estructuras, denominadas nodos de composicin, representan un rbol de presentacin
jerrquica con instrucciones de representacin en cada nodo. Slo se puede tener acceso a este rbol,
mostrado en el lado derecho de la ilustracin siguiente, a travs de un protocolo de mensajera.
Al programar WPF, se crean los elementos Visual, as como los tipos derivados, que se comunican internamente
con el rbol de composicin a travs de este protocolo de mensajera. Cada elemento Visual de WPF puede
crear uno, ninguno o varios nodos de composicin.

MCT: Luis Dueas

Pag 212 de 445

Manual de Windows Presentation Foundation


Conviene observar aqu un detalle arquitectnico muy importante, y es que el rbol completo de objetos
visuales e instrucciones de dibujo se guarda en la memoria cach. Usando terminologa de grficos, WPF utiliza
un sistema de representacin retenido. Esto permite al sistema volver a dibujar con frecuencias de
actualizacin altas sin que el sistema de composicin bloquee las devoluciones de llamada al cdigo del usuario.
Esto ayuda a evitar la sensacin de que la aplicacin no responde.
Otro detalle importante que no es muy evidente en el diagrama es la forma en la que el sistema realiza
realmente la composicin.
En User32 y GDI, el sistema se basa en un mtodo de recorte de modo inmediato. Cuando es necesario
representar un componente, el sistema establece un lmite de recorte en cuyo exterior no permite al
componente tocar los pxeles y, a continuacin, solicita a ste que pinte los pxeles en ese cuadro. Este mtodo
funciona muy bien en sistemas con restricciones de memoria, ya que cuando algo cambia slo se debe
modificar el componente afectado; nunca hay dos componentes que afecten al color de un mismo pxel.
WPF utiliza un modelo de representacin "algoritmo de pintor". Esto significa que, en lugar de recortar cada
componente, se solicita a ste que efecte la representacin desde la parte trasera hacia la parte delantera de
la imagen. Esto permite a cada componente pintar sobre la imagen generada por el componente anterior. La
ventaja de este modelo es que permite tener formas complejas parcialmente transparentes. Con el moderno
hardware grfico actual, este modelo es relativamente rpido (lo que no ocurra cuando se crearon User32/
GDI).
Como se ha mencionado previamente, la filosofa bsica de WPF es adoptar un modelo de programacin ms
declarativo y centrado en las propiedades. En el sistema visual, esto se pone de manifiesto en un par de
lugares interesantes.
En primer lugar, si piensa en el sistema de grficos de modo retenido, ste se est alejando de un modelo de
tipo DrawLine/DrawLine imperativo hacia un modelo orientado a datos, new Line()/new Line(). Esta migracin
hacia la representacin controlada por datos permite expresar operaciones complejas en las instrucciones de
dibujo mediante propiedades. Los tipos que se derivan de Drawing son el modelo de objetos para la
representacin.
En segundo lugar, si evala el sistema de animacin, ver que es declarativo casi por completo. En lugar de
exigir al programador que calcule la ubicacin o el color siguiente, las animaciones pueden expresarse como un
conjunto de propiedades en un objeto de animacin. Estas animaciones permitirn expresar la intencin del
programador o del diseador (mueva este botn de aqu a all en 5 segundos) y el sistema podr determinar la
manera ms eficaz de lograrlo.
System.Windows.UIElement
UIElement define los subsistemas bsicos: diseo, entrada y eventos.
El diseo es un concepto bsico en WPF. Son muchos los sistemas en los que, o existe un conjunto fijo de
modelos de diseo (HTML admite tres modelos de diseo; flujo, absoluto y tablas), o no existe ningn modelo
de diseo (en realidad, User32 slo admite el posicionamiento absoluto). WPF se concibi dando por sentado
que los programadores y diseadores deseaban un modelo de diseo flexible y extensible, que pudiera ser
controlado por valores de propiedades en lugar de por lgica imperativa. El contrato bsico para el diseo se
introduce en el nivel UIElement, un modelo de dos fases con una pasada Measure y otra Arrange.
La fase Measure permite a un componente determinar el tamao que le gustara tener. Se trata de una fase
independiente de Arrange, ya que hay muchas situaciones en las que un elemento primario solicitar a un
elemento secundario que se "mida" varias veces para determinar su posicin y tamao ptimos. El hecho de
que los elementos primarios soliciten a los elementos secundarios que se midan demuestra otra filosofa clave
de WPF, el ajuste al contenido. Todos los controles de WPF admiten la capacidad de ajustarse al tamao natural

MCT: Luis Dueas

Pag 213 de 445

Manual de Windows Presentation Foundation


de su contenido. Esto facilita enormemente la localizacin y permite un diseo dinmico de los elementos
cuando los objetos cambian de tamao. La fase Arrange permite a un elemento primario colocar y determinar
el tamao final de cada elemento secundario.
A menudo, se habla mucho sobre la salida de WPF. Visual y los objetos relacionados. Sin embargo, tambin hay
una gran cantidad de innovaciones en cuanto a la entrada. Probablemente el cambio ms importante en el
modelo de entrada para WPF es el modelo coherente mediante el cual los eventos de entrada se enrutan a
travs del sistema.
La entrada se origina en forma de seal en un controlador de dispositivo de modo kernel y se vuelve a enrutar
al proceso y subproceso correctos a travs de un intrincado procedimiento que implica el kernel de Windows y
User32. Una vez que el mensaje de User32 correspondiente a la entrada se ha enrutado a WPF, se convierte en
un mensaje de entrada sin formato de WPF y se enva al distribuidor. WPF permite convertir los eventos de
entrada sin formato en varios eventos reales, lo que permite la implementacin de caractersticas como
"MouseEnter" en un nivel bajo del sistema con entrega garantizada.
Cada evento de entrada se convierte en al menos dos eventos, un evento de "vista previa" y el evento real.
Todos los eventos de WPF tienen informacin de enrutamiento a travs del rbol de elementos. Se dice que los
eventos "se traspasan" si van subiendo por el rbol desde un destino hasta la raz, y se dice que " tunelizan " si
se inician en la raz y pasan a un destino situado ms abajo. Los eventos de vista previa de entrada tunelizan,
lo que ofrece a cualquiera de los elementos del rbol una oportunidad para filtrar o realizar acciones cuando se
produce un evento. Los eventos normales (sin vista previa) se traspasan a continuacin desde el destino hasta
la raz.
Esta diferencia entre la fase de tnel y de traspaso permite que la implementacin de caractersticas como los
aceleradores de teclado funcione de forma coherente en un universo compuesto. En User32, la implementacin
de los aceleradores de teclado se realizara teniendo una tabla global nica con todos los aceleradores
admitidos

(Ctrl+N

asignado

"Nuevo").

En

el

distribuidor

de

la

aplicacin

se

llamara

TranslateAccelerator, que examinara los mensajes de entrada en User32 y determinara si alguno de ellos
coincide con un acelerador registrado. En WPF esto no funcionara, ya que el sistema es totalmente "ajustable",
es decir, que cualquier elemento puede controlar y utilizar cualquier acelerador de teclado. Tener este modelo
de dos fases para la entrada permite a los componentes implementar su propio "TranslateAccelerator".
Para ir incluso un poco ms lejos, UIElement introduce tambin el concepto de CommandBindings. El sistema
de comandos de WPF permite a los programadores definir la funcionalidad en funcin de un punto final de
comando, algo que implementa ICommand. Los enlaces de comandos permiten a un elemento definir una
asignacin entre un movimiento de entrada (Ctrl+N) y un comando (Nuevo). Tanto los movimientos de entrada
como las definiciones de comandos son extensibles, y pueden conectarse en el momento de su uso. Esto hace
que resulte trivial, por ejemplo, permitir que un usuario final personalice los enlaces de teclado que desea
utilizar dentro de una aplicacin.
Hasta ahora, este tema se ha centrado en las caractersticas "bsicas" de WPF, es decir, las caractersticas
implementadas en el ensamblado PresentationCore. Al concebir WPF, el resultado deseado era una separacin
limpia entre las partes fundamentales (como el contrato para el diseo con Measure y Arrange) y las partes
del marco de trabajo (como la implementacin de un diseo concreto como Grid). El objetivo era proporcionar
un punto de extensibilidad en la zona inferior de la pila que permitira a los programadores externos crear sus
propios marcos de trabajo en caso necesario.
System.Windows.FrameworkElement
FrameworkElement se puede examinar de dos maneras diferentes. Introduce un conjunto de directivas y
personalizaciones en los subsistemas incluidos en las capas inferiores de WPF. Tambin introduce un conjunto
de nuevos subsistemas.

MCT: Luis Dueas

Pag 214 de 445

Manual de Windows Presentation Foundation


La

directiva

primaria

introducida

por

FrameworkElement

trata

sobre

el

diseo

de

la

aplicacin.

FrameworkElement se basa en el contrato del diseo bsico introducido por UIElement y agrega el concepto de
una "ranura" de diseo que facilita a los autores del diseo la disponibilidad de un conjunto coherente de
elementos de semntica del diseo orientados a propiedades. Propiedades como HorizontalAlignment,
VerticalAlignment, MinWidth y Margin (por nombrar algunas) proporcionan a todos los componentes derivados
de FrameworkElement un comportamiento coherente dentro de los contenedores de diseo.
FrameworkElement tambin facilita la exposicin de la API a muchas caractersticas situadas en las capas
bsicas de WPF. Por ejemplo, FrameworkElement proporciona acceso directo a la animacin a travs del
mtodo BeginStoryboard. Un objeto Storyboard proporciona una manera de crear scripts para varias
animaciones con un conjunto de propiedades.
Las dos caractersticas ms importantes introducidas por FrameworkElement son el enlace de datos y los
estilos.
El subsistema de enlace de datos de WPF debera resultarle relativamente familiar a cualquiera que haya
utilizado formularios Windows Forms o ASP.NET para crear la interfaz de usuario (UI) de una aplicacin. En
cada uno de estos sistemas, hay una manera sencilla de expresar que se desea enlazar una o varias
propiedades de un elemento determinado a un fragmento de datos. WPF ofrece compatibilidad total para el
enlace de propiedades, la transformacin y el enlace de listas.
Una de las caractersticas ms interesantes del enlace de datos en WPF es la introduccin de plantillas de datos.
Las plantillas de datos le permiten especificar mediante declaracin cmo se debera visualizar un fragmento de
datos. En lugar de crear una interfaz de usuario personalizada que se puede enlazar a los datos, puede
solucionar el problema permitiendo que los datos determinen la presentacin que se va a crear.
La aplicacin de estilos es realmente una forma ligera de enlace de datos. El uso de estilos le permite enlazar
un conjunto de propiedades de una definicin compartida a una o varias instancias de un elemento. Los estilos
se aplican a un elemento, bien mediante una referencia explcita (estableciendo la propiedad Style) o bien de
forma implcita asociando un estilo al tipo CLR del elemento.
System.Windows.Controls.Control
La caracterstica ms significativa del control es la definicin de plantillas. Si piensa en el sistema de
composicin de WPF como en un sistema de representacin de modo retenido, la definicin de plantillas permite
a un control describir su representacin de una manera parametrizada y declarativa. En realidad,
ControlTemplate es simplemente un script que permite crear un conjunto de elementos secundarios, con
enlaces a las propiedades proporcionadas por el control.
Control proporciona un conjunto de propiedades estndar, como Foreground, Background y Padding, por citar
algunas, que los autores de las plantillas pueden utilizar para personalizar la presentacin de un control. La
implementacin de un control proporciona un modelo de datos y un modelo de interaccin. El modelo de
interaccin define un conjunto de comandos (como Cerrar para una ventana) y enlaces a movimientos de
entrada (como hacer clic en la X roja situada en la esquina superior de la ventana). El modelo de datos
proporciona un conjunto de propiedades para personalizar el modelo de interaccin o la presentacin
(determinado por la plantilla).
Esta diferencia entre el modelo de datos (propiedades), el modelo de interaccin (comandos y eventos) y el
modelo de presentacin (plantillas) permite una total personalizacin de la apariencia y el comportamiento de
un control.
Un aspecto comn del modelo de datos de los controles es el modelo de contenido. Si examina un control como
Button, ver que tiene una propiedad denominada "Content" de tipo Object. En formularios Windows Forms y
ASP.NET, esta propiedad sera normalmente una cadena; sin embargo, esto limita el tipo de contenido que

MCT: Luis Dueas

Pag 215 de 445

Manual de Windows Presentation Foundation


puede colocar en un botn. El contenido de un botn puede ser una cadena simple, un objeto de datos
complejo o un rbol de elementos completo. En el caso de un objeto de datos, la plantilla de datos se utiliza
para construir una presentacin.
Resumen
WPF est diseado para permitirle crear sistemas de presentacin dinmicos y controlados por datos. Cada
parte del sistema est diseada para crear objetos mediante conjuntos de propiedades que controlan el
comportamiento. El enlace de datos es una parte fundamental del sistema y est integrado en cada capa.
Las aplicaciones tradicionales crean una presentacin y, a continuacin, enlazan a algunos datos. En WPF, todo
lo concerniente al control, cada aspecto de la presentacin, est generado por algn tipo de enlace de datos. El
texto situado dentro de un botn se muestra creando un control compuesto dentro de ste y enlazando su
presentacin a la propiedad de contenido del botn.
Cuando comience a desarrollar aplicaciones basadas en WPF, encontrar un entorno muy familiar. Podr
establecer propiedades, utilizar objetos y enlazar datos de la misma manera que con formularios Windows
Forms o ASP.NET. Un examen ms profundo de la arquitectura de WPF le permitir descubrir que existe la
posibilidad de crear aplicaciones mucho ms ricas controladas fundamentalmente por los datos.

3.2. XAML
Lenguaje de marcado de aplicaciones extensible (XAML) es un lenguaje de marcado para la programacin de
aplicaciones declarativa. Windows Presentation Foundation (WPF) implementa un cargador Lenguaje de
marcado de aplicaciones extensible (XAML) y proporciona compatibilidad el lenguaje Lenguaje de marcado de
aplicaciones extensible (XAML) para los tipos de Windows Presentation Foundation (WPF), de tal forma que se
puede crear la mayor parte de la interfaz de usuario de la aplicacin en marcado Lenguaje de marcado de
aplicaciones extensible (XAML). Adems, el SDK incluye una herramienta de edicin Lenguaje de marcado de
aplicaciones extensible (XAML) denominada XAMLPad. Puede utilizar esta herramienta para realizar pruebas con
Lenguaje de marcado de aplicaciones extensible (XAML) en tiempo real.

3.2.1. Informacin General sobre XAML


En este tema se describen las caractersticas del lenguaje Lenguaje de marcado de aplicaciones extensible
(XAML) y se muestra cmo utilizar XAML para escribir aplicaciones Windows Presentation Foundation (WPF). En
este tema se describe especficamente XAML tal y como lo implementa Windows Presentation Foundation
(WPF). El propio XAML es un concepto de lenguaje ms amplio que Windows Presentation Foundation (WPF).
Un lenguaje declarativo compatible con el control de flujo
XAML simplifica la creacin de una interfaz de usuario para el modelo de programacin de .NET Framework.
Puede crear elementos de la interfaz de usuario visibles en el marcado XAML declarativo y, a continuacin,
separar la definicin de la interfaz de usuario de la lgica en tiempo de ejecucin utilizando archivos de cdigo
subyacente, que se unen al marcado mediante definiciones de clases parciales. La capacidad de combinar
cdigo con marcado en XAML es importante porque XML por s solo es declarativo, y no sugiere realmente un
modelo para el control de flujo. Un lenguaje declarativo basado en XML es muy intuitivo para crear interfaces
que van desde el prototipo a la produccin, sobre todo para las personas con entrenamiento en diseo y
tecnologas web. A diferencia de la mayora de los dems lenguajes de marcado, XAML representa directamente
la creacin de instancias de objetos administrados. Este principio de diseo general habilita el cdigo
simplificado y el acceso a la depuracin para los objetos que se crean en XAML.
Los archivos de XAML son archivos de XML que normalmente tienen la extensin .xaml.
El ejemplo de XAML siguiente muestra la pequea cantidad de marcado necesaria para crear un botn como
parte de una interfaz de usuario. El botn creado tiene una presentacin visual predeterminada procedente de
los estilos del tema y un comportamiento predeterminado procedente de su diseo de clase.

MCT: Luis Dueas

Pag 216 de 445

Manual de Windows Presentation Foundation


<StackPanel>
<Button Content="Click Me"/>
</StackPanel>
Elementos de objeto XAML
XAML tiene un conjunto de reglas que asignan elementos de objeto a clases o estructuras, atributos a
propiedades o eventos, y espacios de nombres de XML a espacios de nombres de CLR. Los elementos de XAML
se asignan a los tipos de Microsoft .NET tal y como se definen en los ensamblados a los que se hace referencia
y los atributos se asignan a los miembros de dichos tipos.
En el ejemplo anterior se han especificado dos elementos de objeto: <StackPanel> (con una etiqueta de cierre)
y <Button/> (que tambin tena varios atributos; stos se describen en una seccin posterior). Cada una de las
cadenas StackPanel y Button se asignan al nombre de una clase definida por WPF y que forma parte de los
ensamblados de WPF. Al especificar una etiqueta de elemento de objeto, se crea una instruccin para el
procesamiento de XAML que indica que se debe crear una nueva instancia de la clase con nombre al cargar la
pgina XAML. Cada instancia se crea llamando al constructor predeterminado de la clase subyacente o
estructura y almacenando el resultado. Para que se pueda utilizar como un elemento de objeto en XAML, dicha
clase o estructura debe exponer un constructor pblico predeterminado (sin parmetros).
Establecer propiedades
Las propiedades en XAML se establecen definiendo propiedades en un elemento de objeto utilizando alguna de
las sintaxis posibles. Las sintaxis que se pueden utilizar para una propiedad determinada variarn, dependiendo
de las caractersticas de la propiedad que se est estableciendo.
Para agregar caractersticas a los elementos de objeto, establezca los valores de las propiedades. El estado
inicial de la instancia de objeto subyacente para un elemento de objeto est basado en el comportamiento del
constructor predeterminado. Normalmente, la aplicacin utilizar algo distinto de una instancia completamente
predeterminada de cualquier objeto dado.
Sintaxis de atributo
En XAML, las propiedades se pueden expresar a menudo como atributos. La sintaxis de atributo es la sintaxis
de establecimiento de propiedades ms optimizada y ser la ms intuitiva para los programadores que han
utilizado lenguajes de marcado en el pasado. Por ejemplo, el marcado siguiente crea un botn que tiene texto
rojo y un fondo azul, y tambin muestra texto especificado como Content.
<Button Background="Blue" Foreground="Red" Content="This is a button"/>
Sintaxis de elementos de propiedad
En algunas propiedades de un elemento de objeto, no es posible usar la sintaxis de atributo, ya que el objeto o
la informacin necesaria para proporcionar el valor de la propiedad no se puede expresar correctamente como
una cadena simple. En estos casos, se puede utilizar otra sintaxis conocida como sintaxis de elementos de
propiedad. La sintaxis de elementos de propiedad establece la propiedad del elemento contenedor a la que se
hace referencia en el contenido de la etiqueta. Generalmente, el contenido es un objeto del tipo que la
propiedad toma como valor propio (con la instancia del valor normalmente especificada como otro elemento de
objeto). La sintaxis para el elemento de propiedad en s es <nombreDeTipo.Propiedad>. Despus de especificar
el contenido, se debe cerrar el elemento de propiedad con una etiqueta de cierre como cualquier otro elemento
(con la sintaxis </nombreDeTipo.Propiedad>). En las propiedades en las que se admite tanto la sintaxis de
atributo como la sintaxis de elementos de propiedad, ambas sintaxis tienen normalmente el mismo resultado,
aunque algunos detalles como el control del espacio en blanco pueden variar ligeramente entre ellas. Si es
posible utilizar una sintaxis de atributo, su uso es generalmente ms conveniente, ya que habilita un marcado
ms compacto, pero es simplemente una cuestin de estilo, no una limitacin tcnica. El ejemplo siguiente
muestra cmo se establecen las mismas propiedades que en el ejemplo anterior de sintaxis de atributo, pero
ahora utilizando la sintaxis de elementos de propiedad para todas las propiedades de Button.
<Button>
<Button.Background>
<SolidColorBrush Color="Blue"/>
</Button.Background>
<Button.Foreground>
<SolidColorBrush Color="Red"/>

MCT: Luis Dueas

Pag 217 de 445

Manual de Windows Presentation Foundation


</Button.Foreground>
<Button.Content>
This is a button
</Button.Content>
</Button>
La sintaxis de elementos de propiedad para XAML representa una variacin significativa de la interpretacin de
XML bsica del marcado. Para XML, <nombreDeTipo.Propiedad> representa otro elemento, sin ninguna relacin
necesariamente implcita con un elemento primario TypeName aparte del hecho de ser un elemento secundario.
En XAML, <nombreDeTipo.Property> implica directamente que Property es una propiedad de nombreDeTipo,
establecida por el contenido del elemento de propiedad, y nunca ser un elemento con nombre similar sino un
elemento independiente con un punto en el nombre.
Propiedades y herencia de clases
Las propiedades tal y como aparecen como atributos XAML en un elemento de WPF se heredan a menudo de las
clases base. Por ejemplo, en el ejemplo anterior, la propiedad Background no es una propiedad declarada
inmediatamente en la clase Button, si se examina la definicin de clase, los resultados de la reflexin o la
documentacin. En su lugar, Background se hereda de la clase Control base.
El comportamiento de la herencia de clases de los elementos XAML de WPF es otra desviacin significativa de la
interpretacin de XML bsica del marcado. La herencia de clases (especialmente cuando las clases base
intermedias son abstractas) es una de las razones por las que el conjunto de elementos de XAML y sus
atributos permitidos son casi imposibles de representar correcta y completamente utilizando los tipos de
esquema que se usan normalmente para la programacin en XML, como los formatos DTD o XSD. Asimismo, la
"X" de XAML corresponde a "extensible" y la extensibilidad descarta la integridad de cualquier representacin
dada de "qu es XAML para WPF" (aunque mantener definiciones xmlns independientes puede ayudar a
resolver este problema; xmlns se describe en una seccin posterior).
Valores de referencia y extensiones de marcado
Las extensiones de marcado son un concepto de XAML. En la sintaxis de atributo, las llaves ({ y }) indican un
uso de la extensin de marcado. Este uso hace que el procesamiento de XAML se aparte del tratamiento
general de valores de atributo como una cadena literal o un valor directamente convertible en cadena.
Cuando las propiedades toman un valor de tipo de referencia, requerirn a menudo una sintaxis de elementos
de propiedad (lo que crea siempre una nueva instancia) o una referencia de objeto mediante una extensin de
marcado. El uso de una extensin de marcado puede devolver una instancia existente, por lo que puede ser
ms verstil o incurrir en una menor sobrecarga de objetos.
Cuando se utiliza una extensin de marcado para proporcionar un valor de atributo, ste debera ser
proporcionado por la lgica de la clase de respaldo para la extensin de marcado pertinente. Las extensiones de
marcado ms comunes utilizadas en la programacin de aplicaciones de WPF son Binding, utilizada para las
expresiones de enlace de datos, y las referencias de recursos StaticResource y DynamicResource. Las
extensiones de marcado permiten utilizar la sintaxis de atributo para proporcionar valores de referencia para
las propiedades, aun cuando dichas propiedades no admitan una sintaxis de atributo para la creacin de
instancias de objeto directas, o permiten habilitar un comportamiento concreto que difiera del comportamiento
general que requiere que las propiedades de XAML se rellenen con valores del tipo de la propiedad.
Por ejemplo, en el ejemplo siguiente se establece el valor de la propiedad Style utilizando la sintaxis de
atributo. La propiedad Style toma una instancia de la clase Style, un tipo de referencia que de forma
predeterminada no se poda especificar dentro de una cadena de sintaxis de atributo. Pero en este caso, el
atributo hace referencia a una extensin de marcado determinada, StaticResource. Cuando se procesa dicha
extensin de marcado, devuelve una referencia a un estilo del que ya se han creado instancias como un recurso
con clave en un diccionario de recursos.
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
...

MCT: Luis Dueas

Pag 218 de 445

Manual de Windows Presentation Foundation


</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
...
</Border>
</StackPanel>
Los recursos son simplemente un uso de las extensiones de marcado habilitado por WPF o XAML.
Valores de atributo habilitados para el convertidor de tipos
En la seccin Sintaxis de atributo, se ha dicho que el valor de atributo debe poder establecerlo una cadena. El
control nativo bsico de cmo se convierten las cadenas en otros tipos de objetos o valores primitivos est
basado en el propio tipo String. Pero muchos tipos de WPF o miembros de esos tipos extienden el
comportamiento bsico del procesamiento de atributos de cadena, de tal forma que se pueden especificar
instancias de tipos de objeto ms complejos como valores de atributo mediante una cadena. En el nivel de
cdigo, este procesamiento se logra especificando un convertidor de tipos CLR que procesa el valor de atributo
de cadena. El tipo de estructura Thickness, utilizado normalmente para indicar mediciones de una rea
rectangular, como una propiedad Margin, es un ejemplo de tipo que tiene una sintaxis de atributo especial
habilitada para el convertidor de tipos expuesta para todas las propiedades que toman dicho tipo, con objeto de
proporcionar facilidad de uso en el marcado XAML. En el ejemplo siguiente se utiliza una sintaxis de atributo
habilitada para el convertidor de tipos con objeto de proporcionar un valor a la propiedad Margin:
<Button Margin="10,20,10,30" Content="Click me"/>
El ejemplo de sintaxis de atributo anterior es equivalente al ejemplo de sintaxis siguiente ms detallado, donde
la propiedad Margin se establece mediante la sintaxis de elementos de propiedad que contiene un elemento de
objeto Thickness, y se establecen cuatro propiedades clave de Thickness como atributos en la nueva instancia:
<Button Content="Click me">
<Button.Margin>
<Thickness Left="10" Top="20" Right="10" Bottom="30"/>
</Button.Margin>
</Button>
Aunque el uso de la sintaxis habilitada para el convertidor de tipos o de una sintaxis equivalente ms detallada
es generalmente una opcin de estilo de codificacin, la primera permite obtener un marcado ms optimizado.
(Sin embargo, hay un nmero limitado de objetos en los que el convertidor de tipos es la nica manera de
establecer una propiedad en ese tipo, debido a que el propio objeto de tipo no tiene un constructor
predeterminado. Un ejemplo sera Cursor.)
Tipos de coleccin y propiedades de la coleccin XAML
XAML especifica una caracterstica del lenguaje por la que el elemento de objeto que representa un tipo de
coleccin se puede omitir deliberadamente en el marcado. Cuando un procesador de XAML controla una
propiedad que toma un tipo de coleccin, se crea implcitamente una instancia del tipo de coleccin adecuado,
aun cuando el elemento de objeto para dicha coleccin no est presente en el marcado. En las pginas de
referencia del SDK para los tipos de coleccin, en las secciones de sintaxis de XAML se hace referencia de forma
ocasional a esta sintaxis, con la omisin deliberada del elemento de objeto, como sintaxis de coleccin implcita.
La sintaxis de coleccin implcita est disponible para los tipos que implementan IList o IDictionary, o para las
matrices.
Ya ha visto un ejemplo de una sintaxis de coleccin implcita sin que se llame a sta, en el ejemplo de recursos
de XAML:
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
...
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
...
</Border>
</StackPanel>
Con la excepcin del elemento raz, cada elemento de objeto de una pgina que est anidado como elemento
secundario de otro elemento es realmente un elemento que tiene una de las caractersticas siguientes o ambas:

MCT: Luis Dueas

Pag 219 de 445

Manual de Windows Presentation Foundation


es un miembro de una propiedad de coleccin implcita de su elemento primario o un elemento que especifica el
valor de la propiedad de contenido XAML para el elemento primario (las propiedades de contenido XAML se
describirn en una seccin posterior). En otras palabras, la relacin entre elementos primarios y secundarios en
una pgina de marcado es realmente un objeto nico en la raz, y cada elemento de objeto que est debajo de
la raz es una instancia nica que proporciona un valor de propiedad del elemento primario o uno de los
elementos dentro de una coleccin que es tambin un valor de propiedad de tipo de coleccin del elemento
primario. En el caso del ejemplo de los recursos, la propiedad Resources toma un objeto de tipo
ResourceDictionary. En el ejemplo siguiente se muestra la sintaxis equivalente con el elemento de objeto para
el valor ResourceDictionary especificado explcitamente.
<Page.Resources>
<ResourceDictionary>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
...
</ResourceDictionary>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
...
</Border>
</StackPanel>
</Page>
La coleccin Resources es un ejemplo de una propiedad de coleccin que est presente en muchos elementos
comunes del nivel de marco de trabajo de WPF. Para establecer esta propiedad en XAML es necesaria la sintaxis
de elementos de propiedad. Cada elemento de objeto incluido dentro del elemento de propiedad se convierte en
un elemento de la coleccin (una implementacin de IDictionary). Aunque el propio tipo de coleccin tiene
normalmente una propiedad o indizador que contiene los elementos, esa propiedad no se puede especificar en
el marcado; es totalmente implcita. Para el objeto ResourceDictionary, la propiedad es el indizador Item.
Propiedades del contenido XAML
XAML especifica una caracterstica del lenguaje por la que cualquier clase que se puede utilizar como un
elemento de objeto de XAML puede designar exactamente una de sus propiedades como la propiedad de
contenido XAML para las instancias de la clase. Cuando un procesador de XAML controla un elemento de objeto
que tiene una propiedad de contenido XAML, los elementos secundarios de XML de dicho elemento de objeto se
procesan como si estuvieran contenidos en una etiqueta de elemento de propiedad implcita que representa esa
propiedad de contenido. Dentro del marcado, se puede omitir la sintaxis de elementos de propiedad para la
propiedad de contenido XAML. Cualquier elemento secundario especificado en el marcado se convertir en el
valor de la propiedad de contenido XAML.
Ya ha visto un ejemplo de una propiedad de contenido XAML sin que se llame a sta: el primer ejemplo de este
tema.
<StackPanel>
<Button Content="Click Me"/>
</StackPanel>
Aqu, Button es un elemento secundario de StackPanel. ste es un marcado optimizado e intuitivo que omite
dos etiquetas por dos razones diferentes.

Elemento de propiedad StackPanel.Children omitido: StackPanel se deriva de Panel. Panel define


Children como su propiedad de contenido XAML. Por lo tanto, todas las clases derivadas de Panel
tienen esa propiedad de contenido XAML y se puede omitir el elemento de propiedad para Children.

Elemento

de

objeto

UIElementCollection

omitido:

La

propiedad

Children

toma

el

tipo

UIElementCollection, que implementa IList. Por consiguiente, se puede omitir la etiqueta de elemento
de objeto UIElementCollection, basndose en las reglas de XAML definidas para las colecciones. En
este caso, no se pueden crear instancias de UIElementCollection como elementos de objeto. Ni siquiera
se tiene la opcin de declarar explcitamente ese objeto de coleccin. Esto se debe a que
UIElementCollection no expone un constructor predeterminado. Otros tipos de coleccin de WPF

MCT: Luis Dueas

Pag 220 de 445

Manual de Windows Presentation Foundation


tampoco exponen los constructores para el uso de elementos de objeto, porque el control de la sintaxis
de la coleccin de XAML todava les permite trabajar implcitamente en XAML. sta es la razn por la
que el elemento de objeto UIElementCollection se muestra con comentarios en el ejemplo; sin ellos, el
ejemplo no se compilara.
<StackPanel>
<StackPanel.Children>
<!--<UIElementCollection>-->
<Button>
<Button.Content>
Click Me
</Button.Content>
</Button>
<!--</UIElementCollection>-->
</StackPanel.Children>
</StackPanel>
Texto interno y propiedades del contenido XAML
El ejemplo StackPanel / Button todava tiene otra variante.
<StackPanel>
<Button>Click Me</Button>
</StackPanel>
Observe el cambio en la forma en la que se especifica el texto de la presentacin para Button. La propiedad
Content se especific anteriormente en la sintaxis de atributo; esta vez, la cadena de la presentacin es el
texto interno que est dentro de un elemento de objeto Button. Esta sintaxis funciona porque Content es la
propiedad de contenido XAML de la clase base ContentControl de Button. La cadena incluida en el elemento se
evala basndose en el tipo de propiedad de la propiedad Content, que es Object. Object no intenta ninguna
conversin de tipos de cadenas, por lo que el valor de la propiedad Content se convierte en el valor de cadena
literal. Alternativamente, el contenido incluido dentro de Button podra haber sido cualquier Object nico. Los
controles como Button generalmente definen la propiedad de contenido XAML para la clase de manera que la
propiedad de contenido XAML se puede utilizar para la interfaz de usuario y el texto de la presentacin, para la
composicin de controles o para ambos.
La capacidad de colocar las cadenas dentro del elemento como contenido para generar marcado que se parece
a otros lenguajes de marcado comunes es de especial importancia para el modelo de documento dinmico.
Los valores de las propiedades de contenido XAML deben ser contiguos
El valor de una propiedad de contenido XAML se debe proporcionar exclusivamente antes o exclusivamente
despus

de

cualquier

otro

elemento

de

propiedad

en

ese

elemento

de

objeto.

Esto

es

cierto

independientemente de si el valor de una propiedad de contenido XAML se especifica como una cadena o como
uno o varios objetos. Por ejemplo, el marcado siguiente no se puede compilar:
<Button>I am a
<Button.Background>Blue</Button.Background>
blue button
</Button>
Esto no es vlido bsicamente porque si esta sintaxis fuera explcita utilizando la sintaxis de elementos de
propiedad para la propiedad de contenido, sta se establecera dos veces:
<Button>
<Button.Content>I am a </Button.Content>
<Button.Background>Blue</Button.Background>
<Button.Content> blue button</Button.Content>
</Button>
Un ejemplo similar que tampoco es vlido se da cuando la propiedad de contenido es una coleccin y los
elementos secundarios estn intercalados con los elementos de propiedad:
<StackPanel>
<Button>This example</Button>
<StackPanel.Resources>
<SolidColorBrush x:Key="BlueBrush" Color="Blue"/>
</StackPanel.Resources>
<Button>... is illegal XAML</Button>
</StackPanel>
Modelos de contenido
Una clase podra admitir su uso como un elemento XAML en lo referente a la sintaxis, pero dicho elemento slo
funcionar correctamente en una aplicacin o pgina si se coloca en una posicin esperada de un modelo de
contenido o rbol de elementos general. Por ejemplo, un elemento MenuItem se debera colocar normalmente
slo como un elemento secundario de una clase derivada de MenuBase, como Menu. Los modelos de contenido

MCT: Luis Dueas

Pag 221 de 445

Manual de Windows Presentation Foundation


para elementos concretos se documentan como parte de los comentarios en las pginas de la clase para los
controles y otras clases de WPF que se pueden utilizar como elementos XAML. Para algunos controles que
tienen modelos de contenido ms complejos, el modelo de contenido se documenta como un tema conceptual
independiente.
El uso de maysculas y minsculas y del espacio en blanco en XAML
XAML distingue entre maysculas y minsculas. Los elementos de objeto, los elementos de propiedad y los
nombres de atributo se deben especificar utilizando la grafa apropiada cuando se comparan por nombre con el
tipo subyacente en el ensamblado, o con un miembro de un tipo. Los valores para los atributos no siempre
distinguen entre maysculas y minsculas. La distincin entre maysculas y minsculas para los valores
depender del comportamiento del convertidor de tipos asociado a la propiedad que toma el valor o del tipo de
valor de propiedad. Por ejemplo, las propiedades que toma el tipo Boolean pueden tomar true o True como
valores equivalentes, pero slo porque la conversin de tipos de cadena predeterminada para Boolean ya los
permite como equivalentes.
Los procesadores y serializadores de XAML omiten o quitan todos los espacios en blanco no significativos y
normalizan cualquier espacio en blanco significativo. Este comportamiento generalmente slo tiene importancia
si se especifican cadenas dentro de las propiedades de contenido XAML. Es decir, XAML convierte los caracteres
de espacio, avance de lnea y tabulacin en espacios y, a continuacin, conserva un espacio si lo encuentra en
cualquier extremo de una cadena contigua. La explicacin completa del control de espacios en blanco de XAML
no se aborda en este tema.
Ms informacin sobre la sintaxis XAML
La sintaxis de coleccin implcita y las propiedades de contenido XAML son caractersticas del lenguaje XAML
que habilitan la omisin de ciertas etiquetas deducidas. El objetivo de estas caractersticas es conseguir que las
relaciones entre los elementos primarios-secundarios de una pgina sean ms claras al crear o examinar el
marcado.
Para obtener ms informacin sobre la sintaxis de atributo y la sintaxis de elementos de propiedad, as como
sobre otros trminos utilizados al describir la sintaxis XAML a lo largo de la documentacin del SDK. El tema
Terminologa de la sintaxis de XAML tambin es un buen lugar para comenzar si est considerando los usos de
XAML que desea habilitar al crear una clase personalizada.
Elementos raz de XAML y xmlns
Para que un archivo XAML pueda ser tanto un archivo XML con un formato correcto como un archivo XAML
vlido, slo debe tener un elemento raz. Normalmente, se debe elegir un elemento que forme parte del modelo
de aplicacin (por ejemplo, Window o Page para una pgina, ResourceDictionary para un diccionario externo o
Application para la raz de la definicin de la aplicacin). En el ejemplo siguiente se muestra el elemento raz de
un archivo XAML tpico para una pgina WPF, con el elemento raz Page.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
...
</Page>
El elemento raz tambin contiene los atributos xmlns y xmlns:x. Estos atributos indican a un procesador de
XAML los espacios de nombres que contienen las definiciones de los elementos a los que el marcado har
referencia. El atributo xmlns indica especficamente el espacio de nombres xmlns predeterminado. Dentro este
espacio de nombres, los elementos de objeto en el marcado se pueden especificar sin un prefijo. Para la
mayora de los escenarios de aplicaciones WPF y para casi todos los ejemplos ofrecidos en las secciones de WPF
del SDK, el espacio de nombres xmlns predeterminado est asignado al espacio de nombres de WPF
http://schemas.microsoft.com/winfx/2006/xaml/presentation. El atributo xmlns:x indica un espacio de nombres
xmlns

adicional,

que

asigna

el

espacio

de

nombres

del

lenguaje

XAML

http://schemas.microsoft.com/winfx/2006/xaml. Los componentes del lenguaje necesarios definidos por la


especificacin XAML tienen el prefijo x: cuando se hace referencia a ellos en el marcado de un archivo con esta

MCT: Luis Dueas

Pag 222 de 445

Manual de Windows Presentation Foundation


asignacin. Este uso de xmlns para definir un mbito de uso y asignacin es coherente con la especificacin
XML 1.0. Tenga en cuenta que los atributos xmlns slo son estrictamente necesarios en el elemento raz de
cada pgina y en la definicin de aplicacin si se proporciona sta en el marcado. Las definiciones xmlns se
aplicarn a todos los elementos secundarios de la raz (este comportamiento sigue siendo coherente con la
especificacin XML 1.0 para xmlns). Los atributos xmlns tambin se permiten en otros elementos por debajo de
la raz y se aplicaran a los elementos secundarios del elemento que los define. Sin embargo, ste no es un uso
tpico, porque una definicin o redefinicin frecuente de los espacios de nombres xmlns puede dar lugar a un
estilo de marcado XAML que resulte difcil de leer.
Los ensamblados de WPF se sabe que contienen los tipos que admiten las asignaciones de WPF al xmlns
predeterminado debido a la configuracin que forma parte del archivo de compilacin del proyecto. Los
ensamblados tambin se asignan en los archivos .targets. Por lo tanto, nicamente es necesario asignar el
xmlns para poder hacer referencia a los elementos de XAML que vienen de los ensamblados de WPF. Para sus
propios ensamblados personalizados o para los ensamblados fuera de WPF, puede especificar el ensamblado
como parte de la asignacin xmlns. Normalmente, se elige un prefijo diferente, pero tambin es posible elegir
un xmlns diferente como valor predeterminado y, a continuacin, asignar WPF a un prefijo. Para obtener ms
informacin sobre la relacin existente entre los espacios de nombres xmlns y los espacios de nombres del
cdigo de respaldo en los ensamblados.
El prefijo x:
En el ejemplo de elemento raz anterior, se utiliz el prefijo x: para asignar el xmlns de XAML
http://schemas.microsoft.com/winfx/2006/xaml. Este prefijo x: se utiliza para asignar el xmlns de XAML en las
plantillas de los proyectos, en los ejemplos y en la documentacin de este SDK. El prefijo x: o xmlns de XAML
contiene varias construcciones de programacin que utilizar con frecuencia en el XAML. A continuacin se
muestra una lista de las construcciones de programacin prefijo x: o xmlns de XAML ms comunes que
utilizar:

x:Key: establece una clave nica para cada recurso de un elemento ResourceDictionary. x:Key
representar probablemente el 90% de los usos de x: que ver en el marcado de su aplicacin.

x:Class: especifica el espacio de nombres de CLR y el nombre de clase para la clase que proporciona
cdigo subyacente para una pgina XAML. Debe disponer de esta clase para admitir el cdigo
subyacente; por esto casi siempre ver x: asignado, aun cuando no haya ningn recurso.

x:Name: especifica un nombre de objeto en tiempo de ejecucin para la instancia que existe en el
cdigo en tiempo de ejecucin una vez procesado un elemento de objeto. Utilice x:Name para aquellos
casos de asignacin de nombres a elementos en los que no se admite la propiedad de nivel de marco
de trabajo de WPF Name equivalente. Esto sucede en ciertos escenarios de animacin.

x:Static: habilita una referencia de valor que obtiene un valor esttico que de lo contrario no sera una
propiedad XAML que se pudiese establecer.

x:Type: construye una referencia Type basada en un nombre de tipo. Esto se utiliza para especificar
atributos que toman valores Type, como Style.TargetType, aunque en muchos casos la propiedad
dispone de una conversin de cadena a Type nativa y el uso de x:Type es opcional.

Hay construcciones de programacin adicionales en la estructura prefijo x: o xmlns de XAML que no son tan
habituales.
Eventos y el cdigo XAML subyacente
La mayora de las aplicaciones de WPF constan de marcado y cdigo subyacente. Dentro de un proyecto, el
cdigo XAML se escribe como un archivo .xaml y se utiliza un lenguaje de CLR, como Microsoft Visual Basic
.NET o C#, para escribir un archivo de cdigo subyacente. Cuando se compila un archivo XAML, la ubicacin del

MCT: Luis Dueas

Pag 223 de 445

Manual de Windows Presentation Foundation


archivo de cdigo XAML subyacente para cada pgina XAML se identifica especificando un espacio de nombres y
una clase como atributo x:Class del elemento raz de la pgina XAML.
En los ejemplos presentados hasta ahora se incluan varios botones, pero ninguno de ellos tena todava ningn
comportamiento lgico asociado. El mecanismo primario en el nivel de la aplicacin para agregar un
comportamiento a un elemento de objeto consiste en utilizar un evento existente de la clase de elemento y
escribir un controlador especfico para dicho evento que se invocar cuando se provoque ste en tiempo de
ejecucin. El nombre del evento y el nombre del controlador que se van a utilizar se especifican en el marcado,
mientras que el cdigo que implementa el controlador se define en el cdigo subyacente.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyNamespace.MyPageCode">
<Button Click="ClickHandler" >Click Me!</Button>
</Page>
namespace MyNamespace
{
public partial class MyPageCode
{
void ClickHandler(object sender, RoutedEventArgs e)
{
Button b = e.Source as Button;
b.Background = Brushes.Red;
}
}
}
Tenga en cuenta que el archivo de cdigo subyacente utiliza el espacio de nombres MyNamespace y declara
MyPageCode como una clase parcial dentro de dicho espacio de nombres. Esto es similar al valor de atributo
x:Class de MyNamespace.MyPageCode que se ha proporcionado en la raz del marcado. El compilador crear
automticamente una clase parcial para cualquier pgina de XAML compilada, derivando una clase del tipo de
elemento raz. Al proporcionar cdigo subyacente que tambin define la misma clase parcial, el cdigo
resultante se combina dentro del mismo espacio de nombres y la clase de la aplicacin compilada.
Si no desea crear un archivo de cdigo subyacente independiente, tambin puede insertar el cdigo dentro de
un archivo XAML. Sin embargo, el cdigo insertado es una tcnica menos verstil que tiene importantes
limitaciones.
Sintaxis de atributo de evento
Al especificar el comportamiento mediante eventos en el marcado, se utiliza normalmente la sintaxis de
atributo para asociar los controladores. El elemento de objeto donde se especifica el atributo de evento se
convierte en la instancia que escucha el evento y llama al controlador. El nombre del evento concreto que
desea controlar es el nombre del atributo. El valor del atributo es el nombre de mtodo del controlador que se
definir. A continuacin, debe proporcionar la implementacin del controlador en el cdigo subyacente,
controlador que estar basado en el delegado para ese evento. El controlador se escribe en cdigo subyacente
en un lenguaje de programacin como Microsoft Visual Basic .NET o C#.
Cada evento de WPF proporcionar datos de evento cuando ste se produzca. Los controladores de eventos
pueden tener acceso a estos datos de evento. En el ejemplo anterior, el controlador obtiene el origen de evento
del que se informa a travs de los datos de evento y, a continuacin, establece las propiedades en dicho origen.
Eventos enrutados
Una caracterstica especial de los eventos determinada que es nica y fundamental para WPF es un evento
enrutado. Los eventos enrutados permiten a un elemento controlar un evento producido por otro elemento
diferente, siempre que dichos elementos se relacionen entre s a travs de un rbol de elementos. Al especificar
el control de eventos con un atributo XAML, se puede escuchar y controlar el evento enrutado en cualquier
elemento, incluidos los elementos que no contienen ese evento en particular en la tabla de miembros de clase.
Esto se consigue calificando el atributo de nombre de evento con el nombre de la clase propietaria. Por
ejemplo, el elemento primario StackPanel en el ejemplo de StackPanel / Button actual podra registrar un

MCT: Luis Dueas

Pag 224 de 445

Manual de Windows Presentation Foundation


controlador para el evento de botn Click del elemento secundario especificando el atributo Button.Click en el
elemento de objeto StackPanel, con el nombre del controlador como valor de atributo.
x:Name
De forma predeterminada, la instancia de objeto que se crea al procesar un elemento de objeto no posee un
identificador nico o una referencia de objeto inherente que se pueda utilizar en el cdigo. Si se llama a un
constructor en el cdigo, casi siempre se utiliza el resultado del constructor para establecer una variable en la
instancia creada con objeto de que se pueda hacer referencia a dicha instancia posteriormente en el cdigo.
Para proporcionar acceso normalizado a los objetos creados mediante una definicin de marcado, XAML define
el atributo x:Name. Es posible establecer el valor del atributo x:Name en cualquier elemento de objeto. En el
cdigo subyacente, el identificador elegido es equivalente a una variable de instancia que hace referencia a la
instancia creada. Los elementos con nombre funcionan en todos los sentidos como si fueran instancias de
objeto (el nombre hace referencia a la instancia) y el cdigo subyacente puede hacer referencia a dichos
elementos para controlar las interacciones en tiempo de ejecucin dentro de la aplicacin.
Los elementos del nivel de marco de trabajo de WPF XAML heredan una propiedad Name, que es equivalente al
atributo x:Name definido en XAML. Otros tipos de clases tambin proporcionan equivalentes en el nivel de
propiedad para x:Name, que en general tambin suele definirse como una propiedad Name. En general, si no
puede localizar una propiedad Name en la tabla de miembros del elemento elegido, utilice en su lugar x:Name.
En el ejemplo siguiente se establece Name en un elemento StackPanel. A continuacin, un controlador en un
elemento Button dentro de StackPanel hace referencia al objeto StackPanel mediante su referencia de instancia
buttonContainer tal y como lo establece Name.
<StackPanel Name="buttonContainer">
...
<Button Click="RemoveThis">Click to remove this button</Button>
</StackPanel>
void RemoveThis(object sender, RoutedEventArgs e)
{
FrameworkElement fe = e.Source as FrameworkElement;
if (buttonContainer.Children.Contains(fe))
{
buttonContainer.Children.Remove(fe);
}
}
Al igual que una variable, el nombre de una instancia est regido por un concepto de mbito con objeto de
aplicar los nombres de forma que sean nicos dentro de un cierto mbito predecible. El marcado primario que
define una pgina indica un mbito de nombres nico, siendo el lmite de dicho mbito el elemento raz de
dicha pgina. Sin embargo, otros orgenes de marcado pueden interactuar con una pgina en tiempo de
ejecucin, como los estilos o las plantillas incluidas dentro de los estilos, y dichos orgenes tienen a menudo su
propio mbito de nombres que no tiene por qu estar conectado necesariamente con el de la pgina. Para
obtener ms informacin sobre x:Name y los mbitos de nombres.
Propiedades y eventos asociados
XAML incluye una caracterstica de lenguaje que permite especificar ciertas propiedades o eventos en cualquier
elemento, independientemente de si la propiedad o el elemento existe en la tabla de miembros para el
elemento en el que se establece. La versin de esta caracterstica para las propiedades se denomina propiedad
asociada y la versin para los eventos se denomina evento asociado. Conceptualmente, las propiedades y los
eventos asociados se pueden considerar como miembros globales que se pueden establecer en cualquier
elemento o clase, independientemente de su jerarqua de clases.
Las propiedades asociadas en XAML se utilizan normalmente mediante la sintaxis de atributo. En la sintaxis de
atributo, una propiedad asociada se especifica en la forma tipoDePropietario.nombreDePropiedad. A primera
vista, esto se parece al uso de un elemento de propiedad, pero en este caso el tipoDePropietario que se
especifica es siempre un tipo distinto del elemento de objeto en el que se establece la propiedad asociada.
tipoDePropietario es el tipo que proporciona los mtodos de descriptor de acceso que un procesador de XAML
requiere para poder obtener o establecer el valor de la propiedad asociada. El escenario ms comn para las

MCT: Luis Dueas

Pag 225 de 445

Manual de Windows Presentation Foundation


propiedades asociadas es permitir a los elementos secundarios enviar un valor de propiedad a su elemento
primario.
En el ejemplo siguiente se muestra la propiedad asociada Dock. La clase DockPanel define los descriptores de
acceso para DockPanel.Dock y, por lo tanto, es la propietaria de la propiedad asociada. La clase DockPanel
tambin incluye la lgica que recorre en iteracin sus elementos secundarios y busca en cada uno de ellos un
valor establecido de Dock. Si se encuentra dicho valor, ste se utiliza durante el diseo para colocar los
elementos secundarios. El uso de la propiedad asociada Dock y esta funcin de posicin constituyen de hecho el
escenario de motivacin para la clase DockPanel.
<DockPanel>
<Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button>
<Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button>
</DockPanel>
En Windows Presentation Foundation (WPF), todas las propiedades asociadas se implementan tambin como
propiedades de dependencia.
Los eventos asociados utilizan una forma de sintaxis de atributo similar: tipoDePropietario.nombreDeEvento. Al
igual que en los eventos no asociados, el valor del atributo para un evento asociado en XAML especifica el
nombre del mtodo controlador que se invoca cuando se controla el evento en el elemento.
Un escenario en el que se utilizan eventos asociados lo constituyen los eventos de entrada de dispositivo que se
pueden controlar en cualquier elemento, como los botones del mouse. Un ejemplo de este tipo de evento
asociado es MouseDown. Sin embargo, la mayora de los elementos del nivel de marco de trabajo de WPF
pueden utilizar este evento sin recurrir a un evento asociado. Esto es debido a que la clase del elemento base
UIElement crea un alias para el evento asociado MouseDown y expone dicho alias en la tabla de miembros
UIElement (como MouseDown). Como resultado, normalmente no es necesario especificar la sintaxis de
eventos asociados en una pgina XAML o en la programacin de aplicaciones de Windows Presentation
Foundation (WPF). La excepcin la constituye el uso de elementos personalizados o elementos de objeto que no
se derivan de UIElement, pero que aun as tienen una representacin visual (stos son poco frecuentes). En
WPF, todos los eventos asociados se implementan tambin como eventos enrutados. ContentElement tambin
expone los alias para los eventos de entrada, con objeto de que los utilice el modelo de documento dinmico.
Anatoma del elemento raz de una pgina XAML
La tabla siguiente muestra el tpico elemento raz de una pgina XAML desglosado; en ella se aprecian los
atributos concretos de un elemento raz identificados en este tema:

<Page

Elemento de objeto de apertura del


elemento raz

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

El espacio de nombres (WPF)


predeterminado

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

El espacio de nombres XAML

x:Class="MyNamespace.MyPageCode"

La declaracin de clase parcial que


conecta el marcado con cualquier cdigo
subyacente definido en esta misma clase
parcial

>

Fin del elemento de objeto para la raz,


que an no se ha cerrado porque la
pgina contiene elementos secundarios
Clases base y XAML

Debajo de XAML y sus esquemas existe una coleccin de clases que corresponden a los objetos de CLR, as
como elementos de marcado que se van a utilizar en XAML. Sin embargo, no todas las clases se pueden asignar
a elementos. Las clases abstractas, como ButtonBase, y ciertas clases base no abstractas se utilizan para la
herencia en el modelo de objetos CLR y no admiten las etiquetas de marcado XAML correspondientes. Las
clases base, incluso las abstractas, son importantes para el desarrollo en XAML porque cada uno de los

MCT: Luis Dueas

Pag 226 de 445

Manual de Windows Presentation Foundation


elementos de XAML concretos hereda miembros de alguna clase base en su jerarqua. A menudo, estos
miembros incluyen propiedades que se pueden establecer como atributos en el elemento o eventos que se
pueden controlar. FrameworkElement es la clase base concreta de la interfaz de usuario de WPF en el nivel de
marco WPF. Al disear la interfaz de usuario, se utilizarn varias clases de forma, de panel, de decorador o de
control, que se derivan de FrameworkElement. Una clase base relacionada, FrameworkContentElement, admite
elementos orientados a documentos que funcionan bien para una presentacin de diseo de flujo, utilizando API
que reflejan deliberadamente las API de FrameworkElement. La combinacin de atributos en el nivel de
elemento y un modelo de objetos CLR proporciona un conjunto de propiedades comunes que se pueden
establecer en la mayora de los elementos de XAML concretos, independientemente del tipo de elemento exacto
y su clase subyacente.
Seguridad XAML
XAML es un lenguaje de marcado que representa directamente la creacin de instancias y la ejecucin de
objetos. Por consiguiente, los elementos creados en XAML tienen la misma capacidad de interactuar con los
recursos del sistema (por ejemplo, el acceso a la red y la E/S del sistema de archivos) que el cdigo generado
equivalente.
WPF admite el marco de trabajo de seguridad Seguridad de acceso a cdigo (CAS) de .NET. Esto significa que el
contenido de WPF que se ejecuta en la zona de Internet tiene permisos de ejecucin reducidos. El "XAML
dinmico" (pginas de XAML no compilado interpretadas en el momento de la carga por un visor de XAML) y las
Aplicacin del explorador XAML (XBAP) se ejecutan normalmente en esta zona de Internet y utilizan el mismo
conjunto de permisos. Sin embargo, el XAML que se carga en una aplicacin de plena confianza tiene el mismo
acceso a los recursos del sistema que la aplicacin host.
Cargar XAML desde el cdigo
Se puede utilizar XAML para definir una interfaz de usuario completa, pero a veces tambin es conveniente
definir slo una parte de dicha interfaz en XAML. Esta funcin se podra utilizar para habilitar una
personalizacin parcial, para el almacenamiento local de informacin, utilizando XAML para proporcionar un
objeto comercial, o para diversos escenarios posibles. La clave para estos escenarios es la clase XamlReader y
su mtodo Load. La entrada es un archivo XAML y el resultado es un objeto que representa el rbol de objetos
en tiempo de ejecucin completo que se ha creado a partir de ese marcado. A continuacin, se puede insertar
el objeto como una propiedad de otro objeto que ya existe en la aplicacin. Siempre que la propiedad sea una
propiedad adecuada en el modelo de contenido que tiene funciones de presentacin y que notifique al motor de
ejecucin que se ha agregado el nuevo contenido a la aplicacin, es posible modificar con bastante facilidad el
contenido de una aplicacin en ejecucin cargando XAML. Tenga en cuenta que esta funcin normalmente slo
est disponible en las aplicaciones de plena confianza, debido a las implicaciones de seguridad obvias de la
carga de archivos en aplicaciones que se estn ejecutando.

3.2.2. Terminologa de la Sintaxis de XAML


En este tema se definen los trminos que se utilizan para describir los elementos de sintaxis de Lenguaje de
marcado de aplicaciones extensible (XAML). Estos trminos se utilizan con frecuencia en el resto del kit de
desarrollo de software (SDK). En este tema se desarrolla la terminologa bsica introducida en Informacin
general sobre XAML.
Origen de la terminologa de la sintaxis de XAML
La terminologa de la sintaxis de XAML definida aqu tambin se define o se hace referencia a ella dentro de la
especificacin del lenguaje XAML. XAML es un lenguaje basado en XML y sigue las reglas estructurales de XML.
Parte de esta terminologa la comparte con o est basada en la terminologa utilizada normalmente al describir
el lenguaje XML o el Modelo de objetos de documento (DOM) XML.
Sintaxis de elementos de objeto

MCT: Luis Dueas

Pag 227 de 445

Manual de Windows Presentation Foundation


La sintaxis de elementos de objeto es la sintaxis de marcado de XAML que crea instancias de una clase o
estructura common language runtime (CLR) declarando un elemento XML. Esta sintaxis se parece a la sintaxis
de elementos de otros lenguajes de marcado, como HTML. La sintaxis de elementos de objeto comienza con un
corchete angular izquierdo (<), seguido inmediatamente por el nombre de tipo de la clase o estructura cuyas
instancias se van a crear. Puede haber cero o ms espacios despus del nombre de tipo y se pueden declarar
cero o ms atributos en el elemento de objeto; cada pareja de nombre de atributo="valor" estar separada por
uno o ms espacios. Por ltimo, debe cumplirse una de las condiciones siguientes:

El elemento y la etiqueta deben cerrarse mediante una barra diagonal (/), seguida inmediatamente por
un corchete angular derecho (>).

La etiqueta de apertura debe completarse con un corchete angular derecho (>). Dicha etiqueta puede
ir seguida de otros elementos de objeto, de elementos de propiedad o de texto interno. El tipo exacto
de contenido que se puede incluir aqu viene determinado normalmente por el modelo de objetos del
elemento; vea la seccin Sintaxis de contenido en este mismo tema. Tambin debe existir la etiqueta
de cierre equivalente para el elemento de objeto, anidada y equilibrada correctamente con otras
parejas de etiquetas de apertura y cierre.

Por ejemplo, el ejemplo siguiente es una sintaxis de elementos de objeto que crea una nueva instancia de la
clase Button y tambin especifica un atributo Name y un valor para ese atributo:
<Button Name="CheckoutButton"/>
El ejemplo siguiente es una sintaxis de elementos de objeto que tambin incluye la sintaxis de propiedad de
contenido de Lenguaje de marcado de aplicaciones extensible (XAML). El texto interno incluido dentro se
utilizar para establecer la propiedad de contenido TextBox de Lenguaje de marcado de aplicaciones extensible
(XAML), Text.
<TextBox>This is a Text Box</TextBox>
Sintaxis de atributo
La sintaxis de atributo es la sintaxis de marcado de XAML que establece un valor para una propiedad o
denomina un controlador de eventos para un evento declarando un atributo en un elemento. El elemento
siempre se declara mediante la sintaxis de elementos de objeto. El nombre del atributo debe coincidir con el
nombre de miembro de CLR de una propiedad o un evento. El nombre del atributo va seguido de un operador
de asignacin (=). El valor de atributo debe ser una cadena encerrada entre comillas (").
Para que una propiedad se pueda establecer mediante la sintaxis de atributo, dicha propiedad debe ser pblica,
de lectura y escritura, y tener un tipo de valor de propiedad del que se puedan crear instancias o al que pueda
hacer referencia un procesador de XAML. Para los eventos, el evento debe ser pblico y tener un delegado
pblico. La propiedad o el evento debe ser un miembro de la clase o estructura de la que el elemento de objeto
contenedor crea una instancia.
El valor de atributo se rellena con uno de los valores siguientes, en el orden de procesamiento indicado a
continuacin:
1.

Si el procesador de XAML encuentra una llave, o un elemento de objeto que deriva de


MarkupExtension, se evala primero la extensin de marcado a la que se hace referencia en lugar de
procesarla como una cadena, y se utiliza el objeto devuelto por la extensin de marcado. En muchos
casos, el objeto devuelto por una extensin de marcado no ser un objeto nuevo, sino una referencia a
un objeto existente o una expresin que aplaza la evaluacin hasta el momento de la ejecucin.

2.

Si la propiedad se declara con un TypeConverter designado, o el tipo de valor de esa propiedad se


declara con un TypeConverter con atributos, el valor de cadena del atributo se enva al convertidor de
tipos como una entrada de conversin y el convertidor devolver una nueva instancia de objeto.

MCT: Luis Dueas

Pag 228 de 445

Manual de Windows Presentation Foundation


3.

Si no hay TypeConverter, se intenta una conversin directa al tipo de propiedad. Este nivel final es una
conversin directa entre tipos primitivos o una comprobacin de nombres en una enumeracin (que
devuelve los valores correspondientes).

Por ejemplo, utilizando el mismo marcado mostrado previamente, el ejemplo siguiente es la sintaxis de atributo
utilizada para asignar un valor de cadena a la propiedad Name:
<Button Name="CheckoutButton"/>
La propiedad Name es un miembro de la tabla de miembros para la clase Button. Button es una clase derivada
de la clase FrameworkElement que define Name.
Procesamiento de los valores de atributo
El valor de cadena incluido entre las comillas de apertura y cierre es procesado por un procesador de XAML. En
el caso de las propiedades, el comportamiento de procesamiento predeterminado est definido por el tipo de
propiedad de CLR subyacente. Si la propiedad es un tipo primitivo, el valor de atributo se asigna basndose en
la conversin implcita de la cadena al tipo primitivo pertinente. Si la propiedad es una enumeracin, la cadena
se trata como un nombre definido por dicha enumeracin y se devuelve el valor correspondiente de esta. Si la
propiedad no es un tipo primitivo ni una enumeracin, el valor de atributo se deber controlar mediante un
convertidor de tipos declarado en la misma propiedad o en el tipo de destino. El convertidor de tipos debe
proporcionar una conversin que acepte una cadena y debe producir una instancia del tipo de propiedad de CLR
subyacente. El paso de la conversin tambin se podra aplazar mediante una extensin de marcado.
Valores de atributo de enumeracin
Los valores de enumeracin en XAML son procesados intrnsecamente por los mtodos nativos de la estructura
Enum.
Para los valores de enumeracin sin marcadores, el comportamiento nativo consiste en procesar la cadena de
un valor de atributo y resolverlo como uno de los valores de enumeracin. La enumeracin no se especifica en
el formato Enumeracin.Valor, tal y como se hace en el cdigo. En su lugar, slo se especifica Valor, y
Enumeracin se deduce a partir del tipo de la propiedad que se est estableciendo. Si se especifica un atributo
en la forma Enumeracin.Valor, no se resolver correctamente.
Para las enumeraciones basadas en marcadores, el comportamiento est basado en el mtodo Enum.Parse. Se
pueden especificar varios valores para una enumeracin basada en marcadores separando cada valor con una
coma. Sin embargo, no es posible combinar valores de enumeracin que no estn basados en marcadores. Por
ejemplo, no se puede utilizar la sintaxis de comas para intentar crear un valor Trigger que acte en varias
condiciones de una enumeracin sin marcadores:
<!--This will not compile, because Visibility is not a flagwise enumeration.-->
...
<Trigger Property="Visibility" Value="Collapsed,Hidden">
<Setter ... />
</Trigger>
...
Las enumeraciones basadas en marcadores que admiten atributos que se pueden establecer en XAML no son
frecuentes en WPF. Sin embargo, una de estas enumeraciones es StyleSimulations. Por ejemplo, podra utilizar
la sintaxis de atributo basada en marcadores y separada por comas para modificar el ejemplo incluido en la
seccin Comentarios para la clase Glyphs; StyleSimulations = "BoldSimulation" podra convertirse en
StyleSimulations = "BoldSimulation,ItalicSimulation". KeyBinding.Modifiers es otra propiedad en la que se
pueden especificar varios valores de enumeracin. Sin embargo, esta propiedad es un caso especial, ya que la
enumeracin ModifierKeys admite su propio convertidor de tipos. El convertidor de tipos para los modificadores
utiliza un signo ms (+) como delimitador en lugar de una coma (,) con objeto de que se pueda utilizar en el
marcado la sintaxis ms tradicional para representar las combinaciones de teclas, como "Ctrl+Alt".
Referencias a nombres de miembros de evento y de propiedad
Al especificar un atributo, se puede hacer referencia a cualquier propiedad o evento que exista dentro de la
tabla de miembros del tipo CLR del que se ha creado una instancia para el elemento de objeto contenedor.

MCT: Luis Dueas

Pag 229 de 445

Manual de Windows Presentation Foundation


O bien, se puede hacer referencia a una propiedad o evento asociado, independiente del elemento de objeto
contenedor.
Asimismo, puede asignar un nombre a cualquier evento desde cualquier objeto que sea accesible a travs del
espacio de nombres predeterminado utilizando un nombre parcial nombreDeTipo.evento; esta sintaxis permite
asociar controladores para eventos enrutados en los que el controlador est diseado para controlar eventos
con enrutamiento desde elementos secundarios, pero donde el elemento primario no tiene ese evento en su
tabla de miembros. Esta sintaxis se parece a la sintaxis de eventos asociados, pero en este caso el evento no
es un verdadero evento asociado. En su lugar, se hace referencia a un evento con un nombre completo.
Los nombres de las propiedades se proporcionan a veces como el valor de un atributo, no como el nombre de
atributo, y dichos nombres tambin pueden incluir calificadores, como la propiedad especificada en la forma
tipoDePropietario.nombreDePropiedadDeDependencia. Este escenario es habitual al crear estilos o plantillas en
XAML. Las reglas de procesamiento para los nombres de propiedades proporcionados como un valor de atributo
son diferentes, y estn regidas por el tipo de propiedad que se va a establecer y por algunos factores del
contexto, como que un estilo o una plantilla tenga o no un tipo de destino.
Otro uso para los nombres de propiedades se da cuando un valor de atributo describe una relacin entre
propiedades. Esta caracterstica se utiliza para el enlace de datos y para los destinos de guin grfico, y est
habilitada por la clase PropertyPath y su convertidor de tipos.
Sintaxis de elementos de propiedad
La sintaxis de elementos de propiedad es una sintaxis que difiere ligeramente de la sintaxis XML bsica. En
XML, el valor de un atributo es de hecho una cadena y la nica variacin posible es el formato de codificacin
de cadenas distinto de UTF-8 que se utiliza. En XAML, puede asignar otros elementos de objeto como valores
de las propiedades. Esta funcin est habilitada por la sintaxis de elementos de propiedad. En lugar de
especificar la propiedad como un atributo dentro de la etiqueta de elemento, la propiedad se especifica
utilizando una etiqueta de elemento de apertura en la forma nombreDeTipoElemento.nombreDePropiedad, se
especifica el valor de la propiedad y, a continuacin, se cierra el elemento de propiedad.
Concretamente, la sintaxis comienza con un corchete angular izquierdo (<), seguido inmediatamente por el
nombre de tipo de la clase o estructura en la que est incluida la sintaxis de elementos de propiedad. Esta va
seguida inmediatamente de un punto (.), despus por el nombre de una propiedad que debe existir dentro de la
tabla de miembros del tipo especificado y, a continuacin, por un corchete angular derecho (>). El valor que se
va a asignar a la propiedad se incluye dentro del elemento de propiedad. Normalmente, el valor se proporciona
como uno o ms elementos de objeto, porque la especificacin de objetos como valores es el escenario que la
sintaxis de elementos de propiedad pretende resolver. Finalmente, se debe proporcionar una etiqueta de cierre
equivalente que especifique la misma combinacin nombreDeTipoElemento.nombreDePropiedad, anidada y
equilibrada correctamente con otras etiquetas de elemento. Por ejemplo, la sintaxis siguiente es la sintaxis de
elementos de propiedad para la propiedad ContextMenu de un objeto Button.
<Button>
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="1">First item</MenuItem>
<MenuItem Header="2">Second item</MenuItem>
</ContextMenu>
</Button.ContextMenu>
Right-click me!
</Button>
El valor tambin se puede proporcionar como texto interno, pero slo si el tipo de propiedad que se especifica
es un tipo de valor primitivo, como String, o una enumeracin en la que se especifica un nombre. Estos dos
usos no son habituales, porque cada uno de estos casos tambin admite la sintaxis de atributo. Un escenario
para rellenar un elemento de propiedad con una cadena es para las propiedades que no son la propiedad de
contenido XAML pero que se utilizan para la representacin de texto de la interfaz de usuario, en el que se
requiere que aparezcan elementos de espacio en blanco determinados, como avances de lnea. La sintaxis de

MCT: Luis Dueas

Pag 230 de 445

Manual de Windows Presentation Foundation


atributo no puede conservar los avances de lnea, pero la sintaxis de elementos de propiedad s, siempre que
est activa la conservacin de espacios en blanco significativos.
Un elemento de propiedad no forma parte del rbol lgico. Es nicamente una sintaxis determinada para
establecer una propiedad, y no es ningn elemento que tenga una instancia que lo respalde.
Sintaxis de elementos de propiedad para los tipos de coleccin
La especificacin XAML exige a las implementaciones de procesador de XAML que puedan identificar las
propiedades cuyo el tipo de valor sea una coleccin. La implementacin de WPF est basada en cdigo
administrado, y su procesador de XAML identifica los tipos de coleccin mediante uno de los mecanismos
siguientes:

Implementa IList.
Implementa IDictionary.
Deriva de Array.

Si el tipo de una propiedad es una coleccin, no es necesario especificar en el marcado el tipo de coleccin que
se deduce. En su lugar, los elementos que van a convertirse en elementos de la coleccin se especifican como
uno o ms elementos secundarios del elemento de propiedad del tipo de coleccin. Cada uno de estos
elementos se evala como un objeto durante la carga y se agrega a la coleccin llamando al mtodo Add de la
coleccin implcita. Por ejemplo, la propiedad Triggers de Style toma el tipo de coleccin especializado
TriggerCollection. Pero no es necesario crear instancias de un objeto TriggerCollection en el marcado. En su
lugar, especifique uno o varios elementos Trigger como elementos dentro del elemento de propiedad
Style.Triggers, donde Trigger (o una clase derivada) es el tipo que se espera como tipo de elemento para el
objeto TriggerCollection con establecimiento inflexible de tipos e implcito.
<Style x:Key="SpecialButton" TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="Button.IsMouseOver" Value="true">
<Setter Property = "Background" Value="Red"/>
</Trigger>
<Trigger Property="Button.IsPressed" Value="true">
<Setter Property = "Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
Una propiedad puede ser tanto un tipo de coleccin como la propiedad de contenido XAML para dicho tipo y los
tipos derivados.
Un elemento de coleccin implcito crea un miembro en el rbol lgico, aunque no aparece en el marcado como
un elemento. Normalmente, el constructor del tipo propietario realiza la creacin de instancias para la coleccin
que es una de sus propiedades, lo que permite agregar la coleccin al rbol.
Nota:
La lista genrica y las interfaces de diccionario (IList<(Of <(T>)>) y IDictionary<(Of <(TKey, TValue>)>))
no las admite el procesador WPFXAML para la deteccin de colecciones. Sin embargo, puede utilizar
List<(Of <(T>)>) como una clase base, ya que implementa directamente IList, o Dictionary<(Of <(TKey,
TValue>)>), ya que esta implementa directamente IDictionary.
Sintaxis de contenido XAML
La sintaxis de contenido XAML es una sintaxis que slo est habilitada en las clases que especifican
ContentPropertyAttribute como parte de su declaracin de clase. El objeto ContentPropertyAttribute requiere un
parmetro que especifique la propiedad por nombre definida para ser la propiedad de contenido de ese tipo de
elemento (incluyendo las clases derivadas). La propiedad as designada es la propiedad de contenido XAML de
un elemento. Cuando lo procesa un procesador de XAML, los elementos secundarios o el texto interno que se
encuentran entre las etiquetas de apertura y cierre del elemento se asignarn como el valor de esa propiedad
de contenido XAML. Las etiquetas de elemento de propiedad en un elemento no se asignan de esta manera; se
procesan primero y no se consideran como "contenido".

MCT: Luis Dueas

Pag 231 de 445

Manual de Windows Presentation Foundation


Al igual que cualquier otra propiedad, la propiedad de contenido XAML de un objeto ser de un tipo especfico.
ste puede ser el tipo Object. El tipo de esa propiedad de contenido ayuda a definir el modelo de contenido de
un objeto. Por ejemplo, un tipo de Object es dinmico en el sentido de que cualquier objeto puede convertirse
en el contenido, pero incluso esta asignacin de tipos dinmica implica que el contenido debe ser un objeto
nico. El objeto nico podra ser un objeto de coleccin, pero incluso en este caso slo puede haber un objeto
de coleccin de este tipo asignado como contenido.
Los modelos de contenido para tipos determinados se describen en las pginas de la clase para dichos tipos, o
se escriben como temas conceptuales independientes para familias de tipos y se vinculan desde cada referencia
de tipo pertinente.
Sintaxis de contenido para los tipos de coleccin
Para aceptar varios elementos de objeto (o texto interno) como contenido, el tipo de la propiedad de contenido
debe ser especficamente un tipo de coleccin. De forma similar a la sintaxis de elementos de propiedad para
los tipos de coleccin, un procesador de XAML debe identificar los tipos que son tipos de coleccin. Si un
elemento tiene una propiedad de contenido de XAML, el tipo de la propiedad de contenido de XAML es una
coleccin. No es necesario especificar el tipo de coleccin implcito en el marcado como un elemento de objeto,
as como tampoco es necesario especificar la propiedad de contenido de XAML como un elemento de propiedad.
Por consiguiente, el modelo de contenido aparente en el marcado puede tener ahora varios elementos
secundarios asignados como contenido. A continuacin se muestra la sintaxis de contenido para una subclase
Panel. Todas las clases derivadas de Panel establecen la propiedad de contenido de XAML para que sea
Children, lo que requiere un valor de tipo UIElementCollection.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</StackPanel>
</Page>
Observe que ni el elemento de propiedad para Children ni el elemento para UIElementCollection son necesarios
en el marcado. Esta es una caracterstica del diseo de XAML, de forma que los elementos incluidos
recursivamente que definen una interfaz de usuario se representan de forma ms intuitiva como un rbol de
elementos anidados con relaciones inmediatas entre los elementos primarios y secundarios, sin etiquetas de
elemento de propiedad u objetos de coleccin intermedios superfluos. De hecho, UIElementCollection no se
puede especificar en el marcado como un elemento de objeto, por razones de diseo. Dado que su nico uso
previsto es como una coleccin implcita, UIElementCollection no expone un constructor pblico predeterminado
y, por lo tanto, no se pueden crear instancias de l como un elemento de objeto.
Mezclar elementos de propiedad y elementos de objeto en un objeto con una propiedad de
contenido
La especificacin XAML declara que un procesador de XAML puede exigir que los elementos de objeto que se
utilizan para rellenar la propiedad de contenido de XAML dentro de un elemento de objeto sean contiguos y no
se mezclen. Esta restriccin contra la mezcla de elementos de propiedad y contenido la aplica el procesador de
WPFXAML.
Puede utilizar un elemento de objeto secundario como el primer marcado inmediato dentro de un elemento de
objeto. A continuacin, puede introducir elementos de propiedad. O bien, puede especificar uno o varios
elementos de propiedad, seguidos del contenido y, por ltimo, ms elementos de propiedad. Pero una vez que
un elemento de propiedad sigue al contenido, no se podr introducir ningn otro tipo de contenido, slo
elementos de propiedad adicionales.
Este requisito de orden de elemento de contenido/propiedad no se aplica al texto interno utilizado como
contenido. Sin embargo, mantener el texto interno contiguo es un buen estilo de marcado, ya que el espacio en

MCT: Luis Dueas

Pag 232 de 445

Manual de Windows Presentation Foundation


blanco significativo ser difcil de detectar visualmente en el marcado si los elementos de propiedad estn
intercalados en el texto interno.
Propiedades asociadas
Las propiedades asociadas son un concepto de programacin introducido en XAML segn el cual, un tipo puede
ser el propietario de las propiedades y definirlas, pero cualquier elemento puede establecerlas. El escenario
principal para el que estn pensadas las propiedades asociadas es aqul que permite a los elementos
secundarios de un rbol de elementos enviar informacin a un elemento primario sin necesidad de un modelo
de objetos compartido por todos los elementos. Y a la inversa, los elementos primarios pueden utilizar las
propiedades asociadas para enviar informacin a los elementos secundarios.
Las propiedades asociadas utilizan una sintaxis que a primera vista es similar a la de los elementos de
propiedad, ya que tambin se debe especificar una combinacin nombreDeTipo.nombreDePropiedad. Hay dos
diferencias importantes:

Puede utilizar la combinacin nombreDeTipo.nombreDePropiedad incluso al establecer una propiedad


asociada a travs de la sintaxis de atributo. Las propiedades asociadas son el nico caso en el que
certificar el nombre de la propiedad es un requisito en una sintaxis de atributo.

Tambin puede utilizar la sintaxis de elementos de propiedad para las propiedades asociadas. Sin
embargo, en la sintaxis de elementos de propiedad tpica, el nombreDeTipo especificado es el
elemento de objeto que contiene el elemento de propiedad. Si est haciendo referencia a una
propiedad asociada, el nombreDeTipo es la clase que define la propiedad asociada, no el elemento de
objeto contenedor.

Eventos asociados
Los eventos asociados son otro concepto de programacin introducido en XAML segn el cual, un tipo puede
definir los eventos, pero los controladores pueden estar asociados a cualquier objeto. A menudo, el tipo que
define un evento asociado es un tipo esttico que define un servicio, y algunas veces estos eventos asociados
estn expuestos por un alias de evento enrutado en los tipos que exponen el servicio. Los controladores para
los eventos asociados se especifican mediante la sintaxis de atributo. Al igual que sucede con los eventos
asociados, la sintaxis de atributo se expande para los eventos asociados con objeto de permitir el uso de
nombreDeTipo.nombreDeEvento, donde nombreDeTipo es la clase que proporciona descriptores de acceso de
controlador de eventos Add y Remove para la infraestructura de evento asociada, y nombreDeEvento es el
nombre del evento.
Espacios de nombres XML.
En ninguno de los ejemplos de sintaxis anteriores se especific un espacio de nombres distinto del
predeterminado. En las aplicaciones de WPF tpicas se especifica el espacio de nombres WPF como espacio de
nombres predeterminado. Puede especificar espacios de nombres distintos del predeterminado y seguir
utilizando prcticamente los mismos tipos de sintaxis, pero siempre que se mencione el nombre de una clase a
la que no se pueda tener acceso dentro del espacio de nombres predeterminado, dicho nombre debe ir
precedido por el prefijo del espacio de nombres de XML que se utiliz para asignar el espacio de nombres de
CLR correspondiente. Por ejemplo, <custom:MyElement/> es la sintaxis de elementos de objeto para crear una
instancia de la clase MyElement, donde el espacio de nombres de CLR que contiene dicha clase (y posiblemente
el ensamblado externo que contiene ese espacio de nombres) se asign previamente al prefijo custom.
Extensiones de marcado
XAML define una entidad de programacin de extensin de marcado que ofrece una va alternativa al control
habitual de atributos o elementos de objetos del procesador de XAML, y cede el procesamiento a una clase de
respaldo. La implementacin de WPF de un procesador de XAML utiliza la clase abstracta MarkupExtension
como base para todas las extensiones de marcado admitidas por WPF. El carcter que identifica una extensin

MCT: Luis Dueas

Pag 233 de 445

Manual de Windows Presentation Foundation


de marcado ante un procesador de XAML al utilizar la sintaxis de atributo es la llave de la apertura ({), seguida
por cualquier carcter distinto de una llave de cierre (}). La primera cadena que sigue a la llave de la apertura
debe hacer referencia a la clase que proporciona el comportamiento de la extensin en particular, donde la
referencia puede omitir la subcadena "Extensin" si dicha subcadena forma parte del nombre de clase
verdadero. A partir de ese momento, puede aparecer un solo espacio, y la implementacin de extensin utiliza
cada carcter subsiguiente como entrada, hasta que se encuentra la llave de cierre. Las extensiones de
marcado en WPF estn diseadas principalmente para proporcionar un medio de hacer referencia a otros
objetos ya existentes, o referencias diferidas a los objetos que se evaluarn en tiempo de ejecucin, mientras
se utiliza la sintaxis de atributo. Por ejemplo, un enlace de datos simple se consigue especificando la extensin
de marcado {Binding} en lugar del tipo de valor que tomara normalmente una propiedad determinada. Muchas
de las extensiones de marcado permiten la existencia de una sintaxis de atributo para propiedades en las que,
de lo contrario, no sera posible una sintaxis de atributo. Por ejemplo, un objeto Style es un tipo de referencia
relativamente complejo que contiene varias propiedades, cada una de las cuales tambin toma objetos byref y
no primitivas. Pero los estilos se crean normalmente como un recurso y, a continuacin, se hace referencia a
ellos mediante una de las dos extensiones de marcado que solicitan un recurso. La extensin cede la evaluacin
del valor de la propiedad a una bsqueda de recursos y habilita el ofrecer el valor de la propiedad Style,
tomando el tipo Style, en la sintaxis de atributo de la manera siguiente:
<Button Style="{StaticResource MyStyle}">My button</Button>
Aqu, StaticResource identifica la clase StaticResourceExtension que proporciona la implementacin de la
extensin de marcado. La cadena siguiente, MyStyle, se utiliza como la entrada para el constructor
StaticResourceExtension no predeterminado, donde el parmetro tal y como se toma de la cadena de extensin
declara el objeto ResourceKey solicitado. Se espera que MyStyle sea el valor x:Key (atributo) de un objeto
Style definido como recurso. El uso de Extensin de marcado StaticResource requiere que el recurso se utilice
para proporcionar el valor de la propiedad Style mediante una lgica de bsqueda de recursos estticos en el
momento de la carga.
Usos opcionales y no recomendados de XAML
Usos opcionales de los elementos de propiedad
Los usos opcionales de los elementos de propiedad incluyen ser especfico y "detallar" propiedades de contenido
de los elementos que el procesador de XAML considera implcitas. Por ejemplo, al declarar el contenido de un
objeto Menu, podra optar por declarar explcitamente la coleccin Items del objeto Menu como una etiqueta de
elemento de propiedad <Menu.Items>, y situar cada MenuItem dentro de <Menu.Items> en lugar de utilizar el
comportamiento implcito del procesador de XAML, en el que todos los elementos secundarios de un objeto
Menu deben ser valores MenuItem y se sitan en la coleccin Items. A veces los usos opcionales pueden ayudar
a clarificar visualmente la estructura del objeto tal y como se representa en el marcado. En otras ocasiones, el
uso explcito de un elemento de propiedad puede evitar un marcado que es tcnicamente funcional pero
visualmente confuso, como las extensiones de marcado anidadas dentro de un valor de atributo.
Atributos nombreDeTipo.nombreDeMiembro completos
La forma nombreDeTipo.nombreDeMiembro para un atributo en realidad funciona de forma ms universal que
en el caso de los eventos enrutados, pero en otras aplicaciones dicha forma es superflua y debera evitarse,
aunque slo sea por razones de estilo y legibilidad del marcado. En el ejemplo siguiente, cada una de las tres
referencias al atributo Background son completamente equivalentes:
<Button Background="Blue">Background</Button>
<Button Button.Background="Blue">Button.Background</Button>
<Button Control.Background="Blue">Control.Background</Button>
Button.Background funciona porque la bsqueda completa de esa propiedad en el objeto Button se realiza
correctamente (Background se ha heredado de Control) y Button es la clase del elemento de objeto o una clase
base. Control.Background funciona porque la clase Control define en realidad la propiedad Background y
Control es una clase base de Button.

MCT: Luis Dueas

Pag 234 de 445

Manual de Windows Presentation Foundation


Sin embargo, en el ejemplo siguiente la forma nombreDeTipo.nombreDeMiembro no funciona y, por tanto, se
muestra con formato de comentario:
<!--<Button Label.Background="Blue">Does not work</Button> -->
Label es otra clase derivada de Control, y si hubiese especificado Label.Background dentro de un elemento de
objeto Label, este uso habra funcionado. Sin embargo, debido a que Label no es la clase o la clase base de
Button, el comportamiento especificado del procesador de XAML es procesar Label.Background como una
propiedad asociada. Label.Background no es una propiedad asociada y se produce un error en este uso.
Elementos de propiedad nombreDeTipoBase.nombreDeMiembro
La sintaxis nombreDeTipoBase.nombreDeMiembro funciona para la sintaxis de elementos de propiedad de
manera anloga a como lo hace nombreDeTipo.nombreDeMiembro en la sintaxis de atributos. Por ejemplo, la
sintaxis siguiente funciona:
<Button>Control.Background PE
<Control.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</LinearGradientBrush>
</Control.Background>
</Button>
Aqu, el elemento de propiedad se ha proporcionado como Control.Background aunque dicho elemento estaba
incluido en Button. Pero al igual que la forma nombreDeTipo.nombreDeMiembro para los atributos,
nombreDeTipoBase.nombreDeMiembro denota un estilo pobre en el marcado y debera evitarlo.

3.2.3. Cdigo Subyacente y XAML


Cdigo subyacente es un trmino utilizado para describir el cdigo unido al cdigo creado por un procesador
XAML cuando se compila una pgina XAML en una aplicacin. En este tema se describen los requisitos para el
cdigo subyacente, as como un mecanismo de cdigo insertado alternativo para el cdigo en XAML.
Requisitos del cdigo subyacente, los controladores de eventos y las clases parciales

La clase parcial debe derivarse del tipo de clase utilizado como elemento raz. Puede dejar en blanco la
derivacin en la definicin de clase parcial del cdigo subyacente, pero en este caso en el resultado
compilado se supondr que la raz de la pgina es la clase base de la clase parcial aunque no se
especifique (porque la parte correspondiente al marcado de la clase parcial s especifica la raz de la
pgina como base).

Los controladores de eventos que se escriban deben ser mtodos de instancia definidos por la clase
parcial dentro del espacio de nombres identificado por x:Class. No se puede certificar el nombre de un
controlador de eventos para indicar a un procesador XAML que lo busque en otro mbito de clase.
Tampoco se pueden utilizar mtodos estticos como controladores de eventos.

El controlador de eventos debe coincidir con el delegado del evento apropiado.

En particular para el lenguaje Microsoft Visual Basic .NET, puede utilizar la palabra clave Handles
especfica del lenguaje para asociar los controladores a instancias y eventos en la declaracin del
controlador, en lugar de asociar los controladores a los atributos en XAML. Sin embargo, esta tcnica
tiene algunas limitaciones porque Handles no puede admitir todas las caractersticas especficas del
sistema de eventos de WPF, como algunos escenarios de eventos enrutados o asociados.

x:Code
x:Code es un elemento de directiva definido en XAML. Un elemento de directiva x:Code puede contener cdigo
de programacin insertado. El cdigo insertado que se define puede interactuar con XAML en la misma pgina.
En el siguiente ejemplo se ilustra el cdigo insertado C#. Observe que el cdigo est dentro del elemento
x:Code y que el cdigo debe estar entre <CDATA[...]]>, una secuencia de escape para el contenido en XML, de
manera que un procesador XAML (que interprete el esquema de XAML o el esquema de WPF) no intente
interpretar literalmente el contenido como XML.

MCT: Luis Dueas

Pag 235 de 445

Manual de Windows Presentation Foundation


<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MyNamespace.MyCanvasCodeInline" >
<Button Name="button1" Click="Clicked">Click Me!</Button>
<x:Code><![CDATA[
void Clicked(object sender, RoutedEventArgs e)
{
button1.Content = "Hello World";
}
]]></x:Code>
</Page>
Limitaciones del cdigo insertado
Debe estudiar la posibilidad de evitar o limitar el uso del cdigo insertado en aplicaciones basadas en XAML. Por
lo que se refiere a la arquitectura y la filosofa de codificacin, mantener una separacin entre el marcado y el
cdigo subyacentes permite diferenciar mucho mejor las funciones de programador y diseador. En un plano
ms tcnico, la escritura de cdigo para insertarlo puede resultar complicado, porque siempre se escribe en la
parte parcial generada de la pgina XAML, lo que permite utilizar nicamente las asignaciones de espacio de
nombres predeterminadas. Al no poder agregar instrucciones using, debe certificar totalmente muchas de las
llamadas a las API que se realizan. Las asignaciones de WPF predeterminadas incluyen la mayora de los
espacios de nombres CLR que se encuentran en los ensamblados WPF, pero no todos; esto le obligar a
certificar totalmente las llamadas a las API contenidas dentro de los dems espacios de nombres. En el cdigo
insertado tampoco puede definir varias clases. Adems, todas las entidades de cdigo deben existir como un
miembro o una variable dentro de la clase parcial generada. Tampoco estn disponibles otras caractersticas de
programacin especficas del lenguaje, tales como las macros o las #ifdef para variables globales o de
compilacin.

3.2.4. XAML y Clases Personalizadas


Lenguaje de marcado de aplicaciones extensible (XAML) admite la capacidad para definir una clase o estructura
personalizada en cualquier lenguaje de common language runtime (CLR) y, a continuacin, tener acceso a esa
clase utilizando marcado XAML, incluso utilizando una mezcla de etiquetas definidas en Windows Presentation
Foundation (WPF)- XAML y de la clase personalizada XAML dentro del mismo archivo de marcado. En este tema
se explican los requisitos que debe satisfacer una clase personalizada para ser utilizable como elemento XAML.
Clases personalizadas en aplicaciones o ensamblados
Las clases personalizadas que se utilizan en XAML se pueden definir de dos maneras distintas: dentro del
cdigo subyacente o de otro cdigo que genere la aplicacin Windows Presentation Foundation (WPF) primaria,
o como una clase en un ensamblado independiente, tal como una aplicacin ejecutable o una DLL utilizada
como biblioteca de clases. Cada uno de estos enfoques tiene ventajas y desventajas particulares.

La ventaja de crear una biblioteca de clases es que cualquiera de esas clases personalizadas puede
compartirse entre muchas posibles aplicaciones diferentes. Una biblioteca independiente tambin
facilita las tareas de control de versin de las aplicaciones y simplifica la creacin de una clase que se
desee utilizar como elemento raz en una pgina XAML.

La ventaja de definir las clases personalizadas en la aplicacin es que esta tcnica es relativamente
ligera, y minimiza los problemas de implementacin y pruebas que se encuentran al introducir
ensamblados independientes adems de la aplicacin ejecutable principal. Sin embargo, una
desventaja notable es que no se puede utilizar clases definidas en el mismo ensamblado como
elemento raz de una pgina XAML.

Ya estn definidas en el mismo ensamblado o en uno diferente, las clases personalizadas deben
asignarse entre el espacio de nombres CLR y el espacio de nombres XML para utilizarse en XAML como
elementos.

Requisitos para una clase personalizada como elemento XAML

MCT: Luis Dueas

Pag 236 de 445

Manual de Windows Presentation Foundation


Para permitir la creacin de instancias como elementos de objeto, la clase debe cumplir los requisitos
siguientes:

La clase personalizada debe ser pblica y admitir un constructor pblico predeterminado (sin
parmetros). (Las

estructuras

de

cdigo

administrado admiten implcitamente

este

tipo

de

constructor.)

La clase personalizada no debe ser una clase anidada (las clases anidadas y el "punto" en su sintaxis
interfieren con otras caractersticas de WPF tales como las propiedades asociadas).

Adems de permitir la sintaxis de elemento de objeto, tambin debe habilitar la sintaxis de elemento de
propiedad para cualquier otra propiedad pblica que admita el objeto como su tipo de valor. Esto se debe a que
ahora es posible crear instancias de un objeto como un elemento de objeto y a que el objeto puede rellenar el
valor de elemento de propiedad de tales propiedades.
Requisitos para las propiedades de una clase personalizada como atributos XAML
Las propiedades deben hacer referencia a un tipo por valor (tal como un tipo primitivo) o utilizar una clase para
tipo que tenga un constructor predeterminado o un convertidor de tipos dedicado en el nivel de clase.
Como alternativa, la propiedad puede hacer referencia a un tipo de clase abstracto o a una interfaz. Para las
clases abstractas o las interfaces, la expectativa en tiempo de ejecucin es que el valor de la propiedad deba
rellenarse con instancias de clase prcticas que implementen la interfaz, o con instancias de clase que deriven
de la clase abstracta.
Es posible declarar propiedades en una clase abstracta, pero solamente se pueden establecer en clases
prcticas que deriven de la clase abstracta, porque la creacin del elemento de objeto para la clase requiere un
constructor predeterminado vlido y una clase que permita crear instancias.
Sintaxis de atributo con convertidor de tipos
Si se proporciona un convertidor de tipos dedicado, con atributos, en el nivel de clase, la conversin de tipos
aplicada habilita la sintaxis de atributo para cualquier propiedad que necesita crear instancias de ese tipo. Un
convertidor de tipos no permite el uso de elemento de objeto del tipo; solamente la presencia de un constructor
predeterminado para ese tipo habilita el uso de elemento de objeto. Por consiguiente, las propiedades
habilitadas con convertidor de tipos, en general, no son utilizables en sintaxis de propiedad, a menos que el
propio tipo admita tambin la sintaxis de elemento de objeto. La excepcin consiste en que se puede especificar
una sintaxis de elemento de propiedad, pero el elemento de propiedad debe contener una cadena. Ese uso es
esencialmente el equivalente a un uso de sintaxis de atributo, realmente; este tipo de uso no es comn a
menos que se necesite una administracin ms slida del espacio en blanco en el valor del atributo. Por
ejemplo, lo siguiente es un uso de elemento de propiedad que toma una cadena y el uso de atributo
equivalente:
<Button>Hallo!
<Button.Language>
de-DE
</Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>
Ejemplos de propiedades donde se permite la sintaxis de atributo, pero se rechaza la sintaxis de elemento de
propiedad que contiene un elemento de objeto a travs de XAML, son varias propiedades que toman el tipo
Cursor. La clase Cursor tiene un objeto CursorConverter convertidor de tipos dedicado, pero no expone un
constructor predeterminado, por lo que la propiedad Cursor solamente se puede establecer mediante sintaxis
de atributo aunque el tipo Cursor real sea un tipo de referencia.
Convertidores de tipo por propiedad
La propia propiedad puede declarar tambin un convertidor de tipos en el nivel de propiedad. Esto habilita un
"minilenguaje" que crea instancias de objetos del tipo de la propiedad en el propio cdigo, procesando valores

MCT: Luis Dueas

Pag 237 de 445

Manual de Windows Presentation Foundation


de cadena de entrada del atributo como entrada para una operacin ConvertFrom basada en el tipo
correspondiente. Normalmente, esto se hace para proporcionar un descriptor de acceso adecuado y no como
nico medio para habilitar la configuracin de una propiedad en XAML. Sin embargo, tambin es posible utilizar
convertidores de tipos para atributos cuando se desee utilizar tipos CLR que no proporcionen un constructor
predeterminado ni un convertidor de tipos con atributos. Ejemplos de la API de WPF son ciertas propiedades
que toman el tipo CultureInfo. En este caso, WPF utilizaba el tipo Microsoft .NET Framework CultureInfo
existente para resolver mejor la compatibilidad y los escenarios de migracin utilizados en versiones anteriores
de los marcos de trabajo, pero el tipo CultureInfo no admita los constructores necesarios o la conversin de
tipos de nivel de tipo para ser directamente utilizable como un valor de propiedad XAML.
Siempre que exponga una propiedad que tenga un uso XAML, en particular si est creando controles, debera
considerar respaldar esa propiedad con una propiedad de dependencia. Esto es especialmente cierto si se utiliza
la implementacin Windows Presentation Foundation (WPF) existente del procesador de XAML, porque puede
mejorar el rendimiento utilizando el respaldo con DependencyProperty. Una propiedad de dependencia
expondr caractersticas del sistema de propiedades para la propiedad de modo que los usuarios esperen una
propiedad que permita el acceso mediante XAML. Esto incluye caractersticas tales como la animacin, el enlace
de datos y la compatibilidad con estilos.
Escribir y asignar atributos a un convertidor de tipos
Con frecuencia, necesitar escribir una clase personalizada derivada de TypeConverter para proporcionar
conversin de tipos a un tipo de propiedad.
Requisitos para la sintaxis de atributo del controlador de eventos XAML en los eventos de una clase
personalizada
Para ser utilizable como un evento CLR, el evento se debe exponer como un evento pblico en una clase que
admita un constructor predeterminado o en una clase abstracta donde se pueda tener acceso al evento en
clases derivadas. Para poder utilizarse cmodamente como un evento enrutado, el evento de CLR debe
implementar mtodos add y remove explcitos que agreguen y quiten controladores para la firma de evento
CLR y reenven esos controladores a los mtodos AddHandler y RemoveHandler. Estos mtodos agregan o
quitan controladores del almacn del controlador de eventos enrutados en la instancia a la que est asociado el
evento.
Nota:
Es posible registrar controladores directamente para eventos enrutados utilizando AddHandler, as como no
definir deliberadamente un evento CLR que exponga el evento enrutado. En general, esto no es
recomendable, porque el evento no habilitar la sintaxis de atributo XAML para asociar controladores y la
clase resultante ofrecer una vista XAML menos transparente del modelo de objetos de clase.
Escribir propiedades de coleccin
Las propiedades que toman un tipo de coleccin tienen una sintaxis XAML que permite especificar objetos que
se agregan a la coleccin. Esta sintaxis tiene dos caractersticas notables.

El objeto que es el objeto de coleccin no necesita especificarse en la sintaxis de elemento de objeto.


La presencia de ese tipo de coleccin es implcita siempre que se especifique una propiedad de XAML
que tome un tipo de coleccin.

Los elementos secundarios de la propiedad de coleccin se procesan para convertirse en miembros de


la coleccin. Normalmente, el acceso del cdigo a los miembros de una coleccin se realiza a travs de
mtodos de coleccin, tales como Add o mediante una propiedad indizadora de la coleccin. Sin
embargo, la sintaxis XAML no admite mtodos ni indizadores. Las colecciones son obviamente un
requisito muy comn para generar un rbol de elementos y se necesita alguna manera de rellenarlas
en XAML declarativo. Por consiguiente, los elementos secundarios de una propiedad de coleccin se
procesan agregndolos a la coleccin que es el valor de tipo de la propiedad de coleccin.

MCT: Luis Dueas

Pag 238 de 445

Manual de Windows Presentation Foundation


El procesador WPFXAML utiliza la definicin siguiente para lo que constituye una propiedad de coleccin. El tipo
de propiedad de la propiedad debe implementar una de las opciones siguientes:

Implementa IList.
Implementa IDictionary o el equivalente genrico (IDictionary<(Of <(TKey, TValue>)>)).
Deriva de Array.
Implementa IAddChild (una interfaz definida por WPF).

Cada uno de estos tipos tiene un mtodo Add, que es utilizado por el procesador de impresin XAML para
agregar elementos a la coleccin subyacente.
Nota:
Las interfaces genricas de lista y de diccionario (IList<(Of <(T>)>) y IDictionary<(Of <(TKey,
TValue>)>)) no se admiten para la deteccin de colecciones por el procesador WPFXAML. Sin embargo,
puede utilizar List<(Of <(T>)>) como una clase base, ya que implementa directamente IList o
Dictionary<(Of <(TKey, TValue>)>), ya que sta implementa directamente IDictionary.
Al declarar una propiedad que toma una coleccin, tenga cuidado con el modo en el que se inicializa ese valor
de propiedad en las nuevas instancias del tipo. Si no est implementando la propiedad como una propiedad de
dependencia, es aconsejable hacer que la propiedad utilice un campo de respaldo que llame al constructor del
tipo de coleccin. Si la propiedad es una propiedad de dependencia, quiz necesite inicializar la propiedad de
coleccin como parte del constructor de tipo predeterminado. Esto se debe a que una propiedad de
dependencia toma su valor predeterminado de los metadatos y, habitualmente, no se desea que el valor inicial
de una propiedad de coleccin sea una coleccin esttica y compartida (debe haber una instancia de coleccin
por cada instancia del tipo contenedor).
Puede implementar un tipo de coleccin personalizado para la propiedad de coleccin. Debido al tratamiento de
propiedad de coleccin implcito, no es necesario que el tipo de coleccin personalizado proporcione un
constructor predeterminado utilizar implcitamente el tipo en XAML. Sin embargo, puede proporcionar un
constructor predeterminado para el tipo de coleccin. Puede que valga la pena hacerlo as porque, a menos que
proporcione un constructor predeterminado, no podr declarar explcitamente la coleccin como un elemento de
objeto. Es posible que algunos autores de marcado prefieran considerar la coleccin explcita como una cuestin
de estilo de marcado. Adems, un constructor predeterminado puede simplificar los requisitos de inicializacin
al crear nuevos objetos que utilicen el tipo de coleccin como un valor de propiedad.
Declarar propiedades de contenido XAML
El lenguaje XAML define el concepto de una propiedad de contenido XAML. Cada clase utilizable en sintaxis de
objeto puede tener exactamente una propiedad de contenido XAML. Para declarar una propiedad para que sea
la propiedad de contenido XAML para la clase, aplique ContentPropertyAttribute como parte de la definicin de
clase. Especifique el nombre de la propiedad de contenido XAML que desee como Name en el atributo.
Puede especificar una propiedad de coleccin como propiedad de contenido XAML. El resultado es un uso para
esa propiedad mediante la cual el elemento de objeto puede tener uno o ms elementos secundarios, sin
elementos de objeto de coleccin intermedios ni etiquetas de elemento de propiedad. Estos elementos se tratan
entonces como el valor para la propiedad de contenido XAML y se agregan a la instancia de respaldo de la
coleccin.
Algunas propiedades XAML de WPF existentes utilizan el tipo de propiedad de Object. Esto permite que una
propiedad de contenido XAML pueda tomar valores primitivos tales como String as como un valor de objeto de
referencia nico. Si sigue este modelo, el tipo ser responsable de la determinacin de tipo, as como del
control de los tipos posibles. La razn tpica para un modelo de tipo Object es admitir tanto un medio simple
para agregar contenido de objetos en forma de cadena (que recibe un tratamiento de presentacin
predeterminado) como un medio avanzado de agregar contenido de objetos que especifique una presentacin
no predeterminada.

MCT: Luis Dueas

Pag 239 de 445

Manual de Windows Presentation Foundation


Serializar XAML
Para determinados escenarios, tales como la creacin de controles, quiz desee asegurarse de que toda
representacin de objetos para la que se pueda crear instancias en XAML pueda serializarse tambin en XAML
equivalente. Los requisitos de serializacin no se describen en este tema.

3.2.5. Extensiones de Marcado y XAML


En este tema se presenta el concepto de extensiones de marcado para Lenguaje de marcado de aplicaciones
extensible (XAML), incluidas sus reglas de sintaxis, propsito y modelo de objetos de clase subyacente.
Procesadores de XAML y extensiones de marcado
Un procesador de XAML se define como cualquier programa que pueda aceptar XAML como lenguaje segn sus
especificaciones (compilando o interpretando) y generar las clases subyacentes resultantes para su uso por un
modelo de objetos en tiempo de ejecucin (tambin segn las especificaciones de XAML ). De forma
predeterminada, tal procesador interpretar un valor de atributo como una cadena literal o la convertir en un
objeto basndose en el tipo de atributo o en los convertidores de tipos especficos de ese atributo. No obstante,
en ocasiones hay escenarios donde se requiere un comportamiento diferente. Por ejemplo, se puede indicar a
un procesador de XAML que un valor de un atributo debe ser en su lugar una referencia a un objeto ya
construido o a un objeto esttico. O bien, se puede indicar a un procesador de XAML que utilice una sintaxis
que proporcione argumentos no predeterminados al constructor de un objeto, que es una aberracin del
comportamiento del procesador de XAML especificado de manera predeterminada.
Sintaxis bsica de extensin de marcado
Se puede implementar una extensin de marcado para que proporcione valores para las propiedades de un uso
de atributo, las propiedades de un uso de elemento de propiedad o ambas.
Cuando se utiliza para proporcionar un valor de atributo, la sintaxis que distingue una extensin de marcado
para un procesador de impresin de XAML es la presencia de llaves de cierre y apertura ({ y }). El token de
cadena que sigue inmediatamente a la llave de apertura identifica el tipo de extensin de marcado.
Cuando se utiliza en sintaxis de elemento de propiedad, una extensin de marcado es visualmente igual que
cualquier otro elemento utilizado para proporcionar un valor de elemento de propiedad: una declaracin de
elemento XAML que hace referencia a la clase de extensin de marcado como un elemento, delimitada por
corchetes angulares (< >).
Extensiones de marcado especficas de WPF
Las extensiones de marcado ms comunes utilizadas en la programacin de WPF son las que admiten
referencias de recursos (StaticResource y DynamicResource) y las que admiten el enlace de datos (Binding).
StaticResource proporciona un valor para una propiedad XAML sustituyendo el valor de un recurso ya definido.
DynamicResource proporciona un valor para una propiedad XAML aplazando ese valor para que sea una
referencia a un recurso en tiempo de ejecucin. Una referencia de recurso dinmica fuerza una nueva bsqueda
cada vez que se tiene acceso a este tipo de recurso.
Binding proporciona un valor enlazado a datos para una propiedad, segn el contexto de datos que se aplique
al

elemento.

Esta

extensin

de

marcado

es

relativamente

compleja,

porque

habilita

una

sintaxis

fundamentalmente incluida en el propio cdigo para especificar un enlace de datos.


RelativeSource proporciona informacin de origen para un objeto Binding que puede navegar por varias
posibles relaciones en el rbol de elementos en tiempo de ejecucin. Esto proporciona una fuente especializada
para los enlaces que se crean en plantillas de uso mltiple o se crean en cdigo sin conocimiento completo del
rbol de elemento circundante.

MCT: Luis Dueas

Pag 240 de 445

Manual de Windows Presentation Foundation


TemplateBinding permite que una plantilla de control utilice valores para propiedades con plantilla procedentes
de propiedades definidas por el modelo de objetos de la clase que utilizar la plantilla.
Extensiones de marcado definidas por XAML
Existen varias extensiones de marcado existen que no son especficas la aplicacin WPF de XAML sino que, en
su lugar, forman parte de la especificacin y el espacio de nombres de XAML como lenguaje. Son tpicamente
identificables por el prefijo x: en la sintaxis, como se ve en el uso comn. La implementacin de WPF para ellas
utiliza la misma clase base MarkupExtension para proporcionar la implementacin.
Nota:
El prefijo x: se utiliza para la asignacin tpica del espacio de nombres XAML, en el elemento raz de una
aplicacin o documento XAML. Por ejemplo, las plantillas Microsoft Visual Studio 2005 inician un archivo
XAML mediante esta asignacin x:. Podra elegir un token de prefijo diferente en su propia asignacin
xmlns, pero esta documentacin asumir la asignacin x: predeterminada como medio de identificar esas
entidades que forman una parte definida del espacio de nombres XAML, para diferenciarlas del espacio de
nombres WPF u otros espacios de nombres arbitrarios.
x:Type proporciona el objeto Type para el tipo nombrado. Esto se utiliza con ms frecuencia la mayora en
estilos y plantillas.
x:Static genera valores estticos a partir de entidades de cdigo de tipo valor que no son directamente el tipo
del valor de una propiedad, pero se pueden evaluar como ese tipo.
x:Null especifica null como valor para una propiedad XAML.
x:Array proporciona compatibilidad para la creacin de matrices generales en la sintaxis de XAML, para aquellos
casos donde el soporte de coleccin proporcionado por los elementos base y los modelos de control no se
utilicen deliberadamente.
Ms sobre la sintaxis de extensin de marcado
Clases *Extension
El comportamiento de cada extensin de marcado se identifica para un procesador de XAML a travs de una
clase *Extension que deriva de MarkupExtension y proporciona una implementacin del mtodo ProvideValue.
Este mtodo define en cada extensin qu objeto se devuelve una vez que se evala la extensin de marcado.
Lo habitual es que las instancias del objeto devuelto se creen o se establezcan usando los diversos token de
cadena pasados a la extensin de marcado.
Por ejemplo, la clase StaticResourceExtension proporciona la implementacin de superficie de la bsqueda real
de recursos, de modo que su implementacin ProvideValue devuelva el objeto que se solicita, siendo la entrada
de esa implementacin en particular una cadena que se utiliza para buscar el recurso por su x:Key. Gran parte
de este detalle de implementacin es irrelevante si se est utilizando una extensin de marcado existente.
Interpretacin de la clase de extensin de los token de cadena siguientes
Los token de cadena que siguen al identificador de extensin de marcado y continan estando dentro de las
llaves los interpreta un procesador de XAML de una de las siguientes maneras:

Una coma siempre representa el separador o el delimitador de token individuales. Por consiguiente una
coma literal no se puede pasar a una extensin de marcado.

Si los token separados individuales no contienen ningn signo igual, cada token se trata como un
argumento de constructor. Cada parmetro de constructor se debe proporcionar como el tipo esperado
por esa firma y en el orden apropiado esperado por esa firma.
Nota:
Un procesador de XAML debe llamar al constructor que coincida con el recuento de argumentos del
nmero de pares. Por esta razn, si est implementando una extensin de marcado personalizada,

MCT: Luis Dueas

Pag 241 de 445

Manual de Windows Presentation Foundation

no proporcione el mismo recuento de argumentos a varios parmetros; lo que ocurre si hay ms


de un constructor de extensin de marcado con el mismo recuento de parmetros no est definido.

Si los token separados individuales contienen signos igual, un procesador de XAML llama primero al
constructor predeterminado para la extensin de marcado. A continuacin, cada par nombre=valor se
interpreta como un nombre de propiedad que existe en la extensin de marcado y un valor que
asignar a esa propiedad.

Si hay un resultado paralelo entre el comportamiento del constructor y el comportamiento de


configuracin de propiedad en una extensin de marcado, no importa qu comportamiento utilice. Es
ms comn utilizar los pares propiedad=valor para extensiones de marcado que tengan ms de una
propiedad configurable, aunque solamente sea porque hace que el marcado sea ms calculado y que
sea menos probable transponer accidentalmente parmetros de constructor (al especificar los pares
propiedad=valor, esas propiedades pueden estar en cualquier orden). Adems, no hay ninguna
garanta de que una extensin de marcado proporcione un parmetro de constructor que establezca
todas sus propiedades configurables. Por ejemplo, Binding es una extensin de marcado, con muchas
propiedades que se pueden configurar a travs de la extensin en la forma propiedad=valor, pero
Binding solamente admite dos constructores: un constructor predeterminado y uno que establece una
ruta de acceso inicial.

Escapar de llaves literales


El control de atributos en un procesador de XAML utiliza las llaves como indicadores de una extensin de
marcado. Tambin es posible producir un valor de atributo de carcter de llave literal si es necesario,
escribiendo una secuencia de escape con un par de llaves vaco seguido por la llave literal.
Anidar la sintaxis de extensin
Se permite anidar varias extensiones de marcado; en primer lugar se evala cada extensin de marcado ms
profunda, por ejemplo:
<Setter Property="Background"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
Ms sobre las extensiones de marcado y la sintaxis de elementos de propiedad
Cuando se utiliza como un elemento de objeto que rellena un valor de elemento de propiedad, una clase de
extensin de marcado es visualmente indistinguible de un elemento ordinario que se puede utilizar en XAML. La
diferencia prctica entre un elemento ordinario y una extensin de marcado en esta circunstancia es que la
extensin de marcado se evala como un valor con tipo o se aplaza como una expresin y, por consiguiente,
los mecanismos para cualquier posible error de tipo de los valores de la propiedad sern diferentes, de forma
similar a como se trata una propiedad enlazada en tiempo de ejecucin en otros modelos de programacin. Se
evaluar el tipo de los elementos ordinario frente a la propiedad que estn estableciendo inmediatamente en la
compilacin.
La mayora de las extensiones de marcado, cuando se utilizan en la sintaxis de elemento de objeto para rellenar
un elemento de propiedad, no tendran ningn contenido ni ninguna otra sintaxis de elemento de propiedad y,
por lo tanto, se cerrara la etiqueta de elemento del objeto y no se proporcionara ningn elemento derivado.
Siempre que un procesador de XAML encuentra un elemento de objeto, se llama al constructor de esa clase
para crear una instancia del objeto creado a partir del elemento analizado. Una clase de extensin de marcado
no es diferente; por consiguiente, si se desea que la extensin de marcado sea utilizable en sintaxis de
elemento de objeto, se debe proporcionar un constructor predeterminado. Algunas extensiones de marcado
existentes tienen por lo menos un valor de propiedad necesario que debe especificarse para la inicializacin
efectiva y, en ese caso, ese valor de propiedad suele proporcionarse como un atributo de propiedad en el
elemento de objeto. En las pginas de referencia Caractersticas de lenguaje (x:) de espacios de nombres XAML
y Extensiones de XAML de espacio de nombres de WPF se indicarn las extensiones de marcado que tienen
propiedades obligatorias (y los nombres de las propiedades obligatorias). Las pginas de referencia tambin

MCT: Luis Dueas

Pag 242 de 445

Manual de Windows Presentation Foundation


indican si se deniega la sintaxis de elemento de objeto o la sintaxis de atributo para extensiones de marcado
determinadas. Un caso notable es Extensin de marcado x:Array, que no admite la sintaxis de atributo porque
se debe especificar el contenido de esa matriz. El contenido de la matriz se administra como objetos generales;
por consiguiente, no hay ningn convertidor de tipos predeterminado factible para el atributo. Adems,
Extensin de marcado x:Array requiere un parmetro Type.

3.2.6. Espacios de Nombres y Asignacin de Espacios de Nombres de XAML


En este tema se explica con mayor detalle la presencia y el propsito de las dos asignaciones de espacio de
nombres que se encuentran en la etiqueta raz de cada archivo Lenguaje de marcado de aplicaciones extensible
(XAML). Tambin se describe cmo generar asignaciones similares para utilizar elementos definidos en su
propio cdigo y/o dentro de ensamblados independientes.
Declaraciones de espacios de nombres en XAML y WPF
Dentro de las declaraciones de espacios de nombres de la etiqueta raz de muchos archivos Lenguaje de
marcado de aplicaciones extensible (XAML), observar que hay dos declaraciones de xmlns. La primera
declaracin asigna el espacio de nombres de Windows Presentation Foundation (WPF) global como
predeterminado:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
La segunda declaracin asigna un espacio de nombres Lenguaje de marcado de aplicaciones extensible (XAML)
independiente (normalmente) al prefijo x:.
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
La relacin entre estas declaraciones es que, en realidad, XAML es un estndar de lenguaje, y WPF es una
implementacin que utiliza XAML como un lenguaje. El lenguaje XAML especifica algunos elementos de lenguaje
que se da por hecho que estn implementados para ofrecer compatibilidad y que cada uno de ellos debe estar
accesible a travs de implementaciones del procesador XAML que funcionan con el espacio de nombres XAML.
La implementacin de WPF reserva el espacio de nombres predeterminado para sus propias API y utiliza un
prefijo asignado independiente para la sintaxis de marcado esperada en XAML. Por convencin, ese prefijo es
x:, que es la misma convencin de x: que respetan las plantillas de proyecto, los ejemplos de cdigo y la
documentacin de las caractersticas del lenguaje de este SDK. El espacio de nombres XAML define muchas de
las caractersticas utilizadas normalmente que son necesarias incluso para las aplicaciones bsicas de WPF. Por
ejemplo, para combinar cualquier cdigo subyacente con un archivo XAML a travs de una clase parcial, debe
denominar esa clase como el atributo x:Class del elemento raz del archivo XAML pertinente. Por otra parte,
cualquier elemento definido en una pgina XAML al que desee obtener acceso como recurso con clave debe
tener el atributo x:Key establecido en el elemento en cuestin.
Asignar a clases y ensamblados personalizados
Puede asignar espacios de nombres a ensamblados utilizando una serie de tokens dentro de una declaracin de
prefijo de xmlns, de manera parecida al modo en que se asignan a prefijos los espacios de nombres de WPF y
XAML estndar.
La sintaxis acepta los siguientes tokens con nombre posibles y valores:
clr-namespace: Espacio de nombres common language runtime (CLR) declarado dentro del ensamblado que
contiene los tipos pblicos que se exponen como elementos.
assembly= El ensamblado que contiene la totalidad o parte del espacio de nombres CLR al que se hace
referencia. Este valor suele ser solamente el nombre del ensamblado, no su ruta de acceso. La ruta de acceso a
ese ensamblado se debe establecer como una referencia de proyecto en el archivo de proyecto que genera el
XAML compilado. Opcionalmente, para incorporar la administracin de versiones y la firma de nombre seguro,
el valor puede ser una cadena de acuerdo con lo definido por AssemblyName.

MCT: Luis Dueas

Pag 243 de 445

Manual de Windows Presentation Foundation


Observe que el carcter que separa el token clr-namespace de su valor es un signo de dos puntos (:), mientras
que el carcter que separa el token assembly de su valor es un signo igual (=). El carcter que se utiliza entre
estos dos tokens es un punto y coma. Por ejemplo:
xmlns:custom="clr-namespace:SDKSample;assembly=SDKSampleLibrary"
Asignar a ensamblados actuales
Se pueden omitir assembly si el clr-namespace al que se hace referencia se define dentro del mismo
ensamblado que el cdigo de aplicacin que hace referencia a las clases personalizadas. Otra sintaxis
equivalente para este caso consiste en especificar assembly=, sin ningn token de cadena tras el signo igual.
Las clases personalizadas no se pueden utilizar como elemento raz de una pgina si se definen en el mismo
ensamblado. No es necesario asignar las clases parciales; nicamente es preciso asignar las clases que no son
la clase parcial de una pgina de la aplicacin si piensa hacer referencia a ellas como elementos en XAML.
Asignar espacios de nombres CLR a espacios de nombres XML en un ensamblado
WPF define un atributo CLR que utilizan los procesadores XAML para asignar varios espacios de nombres CLR a
un mismo espacio de nombres XML. Este atributo, XmlnsDefinitionAttribute, se coloca en el nivel de
ensamblado en el cdigo fuente que genera el ensamblado. El cdigo fuente del ensamblado de WPF utiliza este
atributo

para

asignar

los

distintos

espacios

de

nombres

comunes,

como

System.Windows

System.Windows.Controls, al espacio de nombres:


http://schemas.microsoft.com/winfx/2006/xaml/presentation.
XmlnsDefinitionAttribute toma dos parmetros: el nombre del espacio de nombres XML y el nombre del espacio
de nombres CLR. Puede haber ms de un XmlnsDefinitionAttribute para asignar varios espacios de nombres
CLR al mismo espacio de nombres XML. Una vez asignados, si se desea se puede hacer referencia tambin a los
miembros de esos espacios de nombres aunque no estn completos, proporcionando la instruccin using
adecuada en la pgina de cdigo subyacente de la clase parcial.

3.2.7. Ambitos de Nombres de WPF


Los mbitos de nombres son al mismo tiempo un concepto y objetos de programacin que almacenan
relaciones entre los nombres de los objetos definidos en XAML y sus equivalentes de instancia. Los mbitos de
nombres del cdigo administrado de WPF se crean al cargar las pginas para una aplicacin XAML. La interfaz
INameScope define los mbitos de nombres como objetos de programacin. Tambin los implementa la clase
prctica NameScope.
mbitos de nombres en aplicaciones de XAML cargado
Los mbitos de nombres se crean en el elemento raz de una pgina XAML al procesarla. Cada nombre
especificado dentro de la pgina se agrega al mbito de nombres pertinente. Los elementos que son elementos
raz comunes (como Page y Window) siempre controlan un mbito de nombres. Si un elemento, como
FrameworkElement o FrameworkContentElement, es el elemento raz de la pgina en el marcado, un
procesador XAML agrega implcitamente una raz de Page para que Page pueda proporcionar un mbito de
nombres. Se crea un mbito de nombres aunque no se hay definido ningn atributo Name o x:Name
inicialmente en XAML.
Si intenta utilizar dos veces el mismo nombre en un mbito de nombres, se inicia una excepcin. Para el XAML
que tiene cdigo subyacente y forma parte de una aplicacin compilada, esa excepcin se inicia al crear la clase
generada para la pgina.
Agregar elementos a rboles de elementos analizados
Cualquier adicin al rbol de elementos despus de la carga y el procesamiento iniciales debe llamar a la
implementacin adecuada de RegisterName para la clase que define el mbito de nombres. De lo contrario, no
se podr hacer referencia al objeto agregado por su nombre mediante mtodos tales como FindName. No basta

MCT: Luis Dueas

Pag 244 de 445

Manual de Windows Presentation Foundation


con establecer una propiedad Name (o un Atributo x:Name) para registrar ese nombre en cualquier mbito de
nombres. Al agregar un elemento con nombre a un rbol de elementos que tiene un mbito de nombres
tampoco se registra el nombre en el mbito de nombres. Aunque los mbitos de nombres se pueden anidar, en
general los nombres se registran en el mbito de nombres que existe en el elemento raz, para que la ubicacin
del mbito de nombres creada por usted sea la misma que se habra creado en una pgina equivalente de
XAML cargado. El escenario ms comn para los programadores de aplicaciones consiste en utilizar
RegisterName para registrar los nombres en el mbito de nombres en la raz actual. RegisterName forma parte
de un escenario importante para buscar guiones grficos que se ejecutarn como animaciones. Si llama al
mtodo RegisterName para un elemento distinto del elemento raz en el mismo rbol lgico, el nombre se
registrar de todos modos en el elemento ms cercano la raz, como si hubiera llamado a RegisterName en el
elemento raz.
mbitos de nombres en cdigo
Para las aplicaciones que se crean mediante programacin y no a partir de XAML cargado, el elemento raz debe
implementar INameScope, o ser una clase derivada de FrameworkElement o de FrameworkContentElement,
para admitir un mbito de nombres.
Adems, para cualquier elemento que no se cargue y procese mediante un procesador XAML, el mbito de
nombres del objeto no se crea ni inicializa de manera predeterminada. Debe crear de manera explcita un
nuevo mbito de nombres para cualquier elemento en el que vaya a registrar nombres seguidamente. Para
crear un mbito de nombres para un elemento, se llama al mtodo SetNameScope esttico. Especifique el
elemento como el parmetro dependencyObject y una nueva llamada al constructor NameScope como el
parmetro value.
Si el objeto proporcionado como parmetro dependencyObject para el mtodo SetNameScope no es una
implementacin

de

INameScope,

FrameworkElement

FrameworkContentElement,

entonces

llamar

RegisterName en cualquier elemento secundario no surtir ningn efecto. Si no crea explcitamente el nuevo
mbito de nombres, al llamar a RegisterName se iniciar una excepcin.
mbitos de nombres en estilos y plantillas
Los estilos y las plantillas de WPF proporcionan la capacidad de reutilizar y aplicar de nuevo el contenido de una
manera sencilla, pero los estilos y las plantillas tambin pueden incluir elementos con nombres definidos en el
nivel de plantilla. Esta misma plantilla se puede utilizar varias veces en una pgina. Por este motivo, los estilos
y las plantillas definen sus propios mbitos de nombres, independientes de la pgina contenedora donde se
aplican dichos estilos y plantillas.
Considere el ejemplo siguiente:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Page.Resources>
<ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
<Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Page.Resources>
<StackPanel>
<Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
<Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
</StackPanel>
</Page>
Aqu, se aplica la misma plantilla a dos botones diferentes. Si las plantillas no tuvieran el mbitos de nombres
discretos, el nombre TheBorder utilizado en la plantilla provocara un conflicto de nombres. Cada instancia que
se crea de la plantilla tiene su propio mbito de nombres, por lo que en este ejemplo el mbito de nombres de
cada instancia de la plantilla contendr exactamente un nombre.
Los estilos tambin obtienen su propio mbito de nombres, principalmente para permitir la asignacin de
nombres concretos a los distintos componentes del guin. Estos nombres habilitan comportamientos concretos

MCT: Luis Dueas

Pag 245 de 445

Manual de Windows Presentation Foundation


destinados a elementos de ese nombre, aunque se vuelva a definir la plantilla como parte de la personalizacin
de un control.
A causa de los mbitos de nombres independientes, buscar elementos con nombre en una plantilla resulta ms
complicado que hacerlo en un elemento sin plantilla de una pgina. En primer lugar, debe determinar cul es la
plantilla aplicada, obteniendo el valor de la propiedad Template del control donde se aplica la plantilla. A
continuacin, se llama a la versin de plantilla de FindName, y se pasa el control donde se aplic la plantilla
como segundo parmetro.
Si usted es el autor de un control y genera una convencin donde un elemento con nombre determinado de una
plantilla aplicada es el destino para un comportamiento definido por el propio control, puede utilizar el mtodo
GetTemplateChild del cdigo de implementacin del control. El mtodo GetTemplateChild se protege, de tal
forma que nicamente su autor tiene acceso a l.
Si trabaja desde dentro de una plantilla y necesita obtener el espacio de nombres donde se aplica la plantilla,
obtenga TemplatedParent y, a continuacin, llame a FindName desde all. Un ejemplo de trabajo dentro de la
plantilla sera escribir la implementacin del controlador de eventos donde el evento se provocar desde un
elemento de una plantilla aplicada.
mbitos de nombres y API relacionadas con nombres
FrameworkElement tiene los mtodos FindName, RegisterName y UnregisterName. Si el elemento para el que
llama a estos mtodos posee un mbito de nombres, los mtodos del elemento se limitan a llamar a los
mtodos del mbito de nombres. De lo contrario, se comprueba el elemento primario por si posee un mbito de
nombres, y este proceso contina de forma recursiva hasta que se encuentra un mbito de nombres (debido al
comportamiento del procesador XAML, es seguro que hay un mbito de nombres en la raz).
FrameworkContentElement

tiene

FrameworkContentElement

poseer

comportamientos
jams

un

anlogos,

mbito

de

con

la

excepcin

nombres.

Los

de

mtodos

que

ningn

existen

en

FrameworkContentElement para que las llamadas se puedan reenviar, en caso necesario, a un elemento
primario FrameworkElement.
SetNameScope se utiliza para asignar un nuevo mbito de nombres a un objeto existente. Puede llamar ms de
una vez a SetNameScope a fin de restablecer o borrar el mbito de nombres, pero no suele hacerse.
GetNameScope tampoco se suele utilizar mediante cdigo.
Implementaciones de mbitos de nombres
Las clases siguientes implementan INameScope directamente:

NameScope
Style
ResourceDictionary
FrameworkTemplate

ResourceDictionary no utiliza mbitos de nombres, sino claves, porque es una implementacin de diccionariotabla hash. La nica razn por la que ResourceDictionary implementa INameScope es para poder iniciar
excepciones en el cdigo de usuario que ayuden a aclarar la distincin entre un mbito de nombres verdadero y
la manera de administrar las claves por parte de ResourceDictionary, adems de asegurarse, en particular, de
que ningn elemento primario aplique mbitos de nombres a ResourceDictionary.
FrameworkTemplate y Style implementan INameScope mediante definiciones de interfaz explcitas. Las
implementaciones explcitas permiten que estos mbitos de nombres se comporten de un modo convencional
cuando se tiene acceso a ellos a travs de la interfaz INameScope, que es el modo que los procesos internos de
WPF utilizan para comunicar los mbitos de nombres. No obstante, las definiciones de interfaz explcitas no

MCT: Luis Dueas

Pag 246 de 445

Manual de Windows Presentation Foundation


forman parte del espacio de nombres convencional de FrameworkTemplate y Style, porque casi nunca se
necesita llamar directamente a los mtodos INameScope en FrameworkTemplate y Style.
Las clases siguientes definen su propio mbito de nombres, utilizando la clase de aplicacin auxiliar
System.Windows.NameScope y conectndose a su implementacin de mbito de nombres a travs de la
propiedad asociada NameScope:

FrameworkElement
FrameworkContentElement

3.2.8. Estilos y Plantillas Insertados


Windows Presentation Foundation (WPF) proporciona objetos Style y objetos de plantilla (subclases de
FrameworkTemplate) como una manera de definir el aspecto visual de un elemento en los recursos, para poder
utilizarlos varias veces. Por esta razn, los atributos de XAML que aceptan los tipos Style y FrameworkTemplate
casi siempre realizan referencias de recursos a estilos y plantillas existentes, en lugar de definir otros nuevos
insertados.
Limitaciones de los estilos y las plantillas insertados
En Lenguaje de marcado de aplicaciones extensible (XAML), las propiedades de estilos y plantillas se pueden
establecer tcnicamente de dos maneras. Puede utilizar la sintaxis de atributo para hacer referencia a un estilo
definido dentro de un recurso, por ejemplo, <object Style="{StaticResource myResourceKey}" .../>. O bien,
puede utilizar la sintaxis de elementos de propiedad para definir un estilo insertado, por ejemplo:
< object >
< object .Style>
< Style .../>
</ object .Style>
</ object >
El uso de atributos es mucho ms comn. Un estilo que se define insertado y no se define en los recursos
necesariamente queda limitado al mbito del elemento contenedor y no se puede reutilizar con facilidad porque
carece de clave de recurso. En general, un estilo definido como recurso es ms verstil y til, y est ms en
lnea con el principio general del modelo de programacin de Windows Presentation Foundation (WPF),
consistente en separar la lgica de programacin, en el cdigo, de la de diseo, en el marcado.
Normalmente, no hay ninguna razn para establecer un estilo o una plantilla insertados, aunque nicamente se
pretendan utilizar en esa ubicacin. La mayora de los elementos que pueden tomar un estilo o una plantilla
tambin admiten una propiedad de contenido y un modelo de contenido. Aunque vaya a usar el rbol lgico que
cree mediante estilos o plantillas una sola vez, resultara incluso ms fcil rellenar esa propiedad de contenido
con los elementos secundarios equivalentes en el marcado directo. De este modo se omitiran totalmente los
mecanismos de plantillas y estilos.
Tambin son posibles para los estilos y las plantillas otras sintaxis habilitadas por las extensiones de marcado
que devuelven un objeto. Dos de estas extensiones con escenarios posibles son TemplateBinding y Binding.

3.2.9. Procesamiento de Espacios en Blanco en XAML


Lenguaje de marcado de aplicaciones extensible (XAML) tiene reglas de lenguaje que especifican cmo se
procesar el espacio en blanco significativo en una implementacin de procesador Lenguaje de marcado de
aplicaciones extensible (XAML). En este tema se documentan estas reglas del lenguaje, as como la
administracin del espacio en blanco adicional definida por la implementacin de Windows Presentation
Foundation (WPF) del procesador XAML y el sistema de escritura XAML para la serializacin.
Procesamiento del espacio en blanco
Definicin del espacio en blanco

MCT: Luis Dueas

Pag 247 de 445

Manual de Windows Presentation Foundation


De modo coherente con XML, los caracteres de espacio en blanco de XAML son el espacio, el avance de lnea y
la tabulacin. Corresponden a los valores 0020, 000A y 0009 de Unicode, respectivamente.
Normalizacin del espacio en blanco
De manera predeterminada, la normalizacin del espacio en blanco siguiente se produce cuando un procesador
XAML procesa un archivo XAML:
1.

Se quitan los caracteres de avance de lnea entre los caracteres del este asitico. Vea la seccin
Caracteres del este asitico ms adelante en este mismo tema para obtener una definicin del trmino
"caracteres del este asitico".

2.

Todos los caracteres de espacio en blanco (espacio, avance de lnea, tabulacin) se convierten en
espacios.

3.

Todos los espacios consecutivos se eliminan y reemplazan por un solo espacio.

4.

Se eliminan los un espacios que siguen inmediatamente a la etiqueta inicial.

5.

Se eliminan los espacios situados inmediatamente antes de la etiqueta de cierre.

El "valor predeterminado" corresponde al estado indicado por el valor predeterminado de Control de xml:space
en XAML.
Espacio en blanco en texto interno y primitivas de cadena
Las reglas de la normalizacin anteriores se aplican al texto interno situado dentro de los elementos XAML.
Despus de la normalizacin, un procesador XAML convertir cualquier texto interno en un tipo adecuado, como
se indica a continuacin:

Si el tipo de la propiedad no es una coleccin, pero no es directamente un tipo Object, el procesador


XAML intenta convertir en ese tipo utilizando su convertidor de tipos. Si se produce un error al
convertir en este punto, dar lugar a un error en tiempo de compilacin.

Si el tipo de la propiedad es una coleccin, y el texto interno es contiguo (sin etiquetas de elementos
intermedias), el texto interno se analiza como una sola cadena (String). Si el tipo de coleccin no
puede aceptar String, esto tambin da lugar a un error en tiempo de compilacin.

Si el tipo de la propiedad es Object, el texto interno se analiza como una sola cadena (String). Si hay
etiquetas de elemento intermedias, dar lugar a un error en tiempo de compilacin, porque el tipo
Object implica que hay un objeto nico (de tipo String u otro).

Si el tipo de la propiedad es una coleccin, y el texto interno no es contiguo, la primera subcadena se


convierte en String y se agrega como un elemento de coleccin, el elemento intermedio se agrega
como un elemento de coleccin y, por ltimo, la subcadena final (si la hay) se agrega a la coleccin
como un tercer elemento de tipo String.

Espacio en blanco y modelos del contenido de texto


En la prctica, conservar el espacio en blanco slo afecta a un subconjunto de todos los posibles modelos de
contenido. Ese subconjunto est compuesto de modelos de contenido que pueden aceptar alguna forma del tipo
String singleton, una coleccin String dedicada o una mezcla de String y otros tipos en una coleccin IList o
ICollection<(Of <(T>)>).
Incluso para los modelos de contenido que pueden aceptar cadenas, el comportamiento predeterminado dentro
de estos modelos de contenido consiste en no tratar como significativo el espacio en blanco restante. Por
ejemplo, ListBox toma IList, pero el espacio en blanco (como los avances de lnea entre los ListBoxItem) no se
conservan ni representan. De hecho, intentar utilizar avances de lnea como separadores entre las cadenas para

MCT: Luis Dueas

Pag 248 de 445

Manual de Windows Presentation Foundation


los elementos ListBoxItem no funciona en absoluto; las cadenas separadas por los avances de lnea se tratan
como una cadena y un elemento.
Aquellas colecciones que s tratan el espacio en blanco como significativo suelen formar parte del modelo de
documentos dinmicos. La coleccin principal que admite el comportamiento de preservacin de espacio en
blanco es InlineCollection. Esta clase de coleccin se declara con WhitespaceSignificantCollectionAttribute;
cuando se encuentra este atributo, el procesador XAML tratar el espacio en blanco de la coleccin como
significativo. La combinacin de xml:space="preserve" y de espacio en blanco dentro de una coleccin indicada
mediante WhitespaceSignificantCollectionAttribute da lugar a que TODO el espacio en blanco se conserva y
representa.

La

combinacin

de

xml:space="default"

de

espacio

en

blanco

dentro

de

WhitespaceSignificantCollectionAttribute dar lugar a la normalizacin del espacio en blanco inicial descrita


anteriormente, que dejar un espacio en blanco en ciertas posiciones, y esos espacios en blanco se conservan y
representan. El comportamiento deseable depende del programador, por lo que debe utilizar xml:space
selectivamente para habilitar el comportamiento que desee.
Asimismo, algunos elementos insertados que incluyen un avance de lnea en un modelo de documentos
dinmicos no deben introducir deliberadamente un espacio adicional ni siquiera en una coleccin con espacio en
blanco significativo. Por ejemplo, el elemento LineBreak tiene el mismo propsito que la etiqueta <BR/> de
HTML. Para mejorar la legibilidad en el marcado, LineBreak suele separarse del texto subsiguiente mediante un
avance de lnea creado. Ese avance de lnea no se debe normalizar para convertirlo en un espacio inicial en la
lnea subsiguiente. Para habilitar ese comportamiento, la definicin de clase del elemento LineBreak aplica
TrimSurroundingWhitespaceAttribute, que el procesador XAML interpreta como una indicacin de que siempre
se recorta el espacio en blanco que rodea a LineBreak.
Conservar el espacio en blanco
Hay varias tcnicas para conservar el espacio en blanco en el origen XAML para la presentacin, en su caso, a
las que no afecta la normalizacin del espacio en blanco del procesador XAML.
xml:space="preserve": especifique este atributo en el nivel del elemento donde desee conservar el espacio en
blanco. Tenga en cuenta que se conservar todo el espacio en blanco, incluso los espacios que puedan agregar
las aplicaciones de edicin de cdigo para alinear los elementos "para impresin" en una anidacin visualmente
intuitiva. Sin embargo, la representacin o no de estos espacios depende, una vez ms, del modelo de
contenido del elemento contenedor. Especificar xml:space="preserve" en el nivel raz no se recomienda,
porque, sea como fuere, la mayora de los modelos de objetos no considera significativo el espacio en blanco.
Es ms recomendable limitarse a establecer el atributo especficamente en el nivel de los elementos que
representan el espacio en blanco contenido en las cadenas o que son colecciones con espacio en blanco
significativo.
Entidades y espacios de no separacin: XAML permite colocar cualquier entidad Unicode dentro de un modelo
del objetos de texto. Puede utilizar entidades dedicadas, como el espacio de no separacin (&#160; en la
codificacin UTF-8). Tambin puede utilizar controles de texto enriquecido que admiten caracteres de espacio
de no separacin. Extreme las precauciones al utilizar entidades para simular caractersticas de diseo, como la
sangra, porque el resultado en tiempo de ejecucin de las entidades vara en funcin de un nmero de factores
mayor que en las utilidades de diseo generales, como el uso apropiado de paneles y mrgenes. Por ejemplo,
las entidades se asignan a fuentes y pueden cambiar de tamao en respuesta a la seleccin de fuente del
usuario.

3.2.10. Clases TypeConverter y XAML


La clase TypeConverter tiene una finalidad concreta como parte de la implementacin para una clase
personalizada administrada que se puede utilizar como un valor de propiedad en el uso de atributos Lenguaje
de marcado de aplicaciones extensible (XAML). Si escribe una clase personalizada, y desea que las instancias
de su clase se puedan utilizar como valores de atributos Lenguaje de marcado de aplicaciones extensible

MCT: Luis Dueas

Pag 249 de 445

Manual de Windows Presentation Foundation


(XAML) que se pueden establecer, podra necesitar aplicar TypeConverterAttribute a su clase, escribir una clase
TypeConverter personalizada, o ambas cosas.
XAML y valores de cadena
Al establecer un valor de atributo en XAML, el tipo inicial de ese valor es String. Incluso otros tipos primitivos,
como Double, son cadenas inicialmente en un procesador XAML, aunque la conversin a otros valores primitivos
no de cadena o a partir de valores con nombre de una enumeracin resulta relativamente sencilla gracias a las
conversiones de tipos integradas.
Un procesador XAML necesita dos fragmentos de informacin para procesar un valor de atributo. El primer
fragmento es el tipo de valor de la propiedad que se establece. Cualquier cadena que define un valor de
atributo y que se procesa en XAML se debe convertir o resolver finalmente a un valor de ese tipo. Si el valor es
un tipo primitivo, se intenta una conversin directa de la cadena. Si el valor es una enumeracin, la cadena se
utiliza para comprobar una coincidencia de nombre en esa enumeracin. Si el valor no es primitivo ni una
enumeracin, el tipo en cuestin debe poder proporcionar una instancia del tipo, o un valor, basado en una
cadena convertida.
Un caso especial es una extensin de marcado. Los usos de las extensiones de marcado deben administrarse en
un procesador XAML antes de comprobar el tipo de propiedad y otras consideraciones. El propsito de una
extensin de marcado es procesar una cadena y devolver un objeto. Si el objeto devuelto es una coincidencia
de tipo para la propiedad, la extensin de marcado proporciona un valor para una propiedad de tal forma que
evita cualquier conversin de tipos que tenga lugar fuera del cdigo de implementacin de la extensin de
marcado. Una situacin comn en que se necesita una extensin de marcado es la realizacin de una referencia
a un objeto que ya existe (en el mejor de los casos, un convertidor de tipos sin estado nicamente podra
generar una nueva instancia, lo que podra no ser deseable).
TypeConverter
Si el valor no es ningn tipo primitivo ni una enumeracin, y no hay ningn uso de extensin de marcado,
entonces debe haber algn medio para convertir String en el valor adecuado o en una nueva instancia al
procesar el XAML. sta es la funcin de la implementacin de TypeConverter. TypeConverter define cuatro
miembros que son pertinentes para convertir en cadenas y desde ellas a fin de procesar el XAML:

CanConvertTo
CanConvertFrom
ConvertTo
ConvertFrom

De ellos, el mtodo ms importante es ConvertFrom. Este mtodo convierte la cadena de entrada en el tipo de
objeto necesario.
El siguiente mtodo en importancia es ConvertTo. Si una aplicacin de WPF se convierte en una representacin
de marcado (por ejemplo, si se guarda en XAML), ConvertTo es responsable de generar una representacin de
marcado.
CanConvertTo y CanConvertFrom son mtodos de compatibilidad que se utilizan cuando un servicio consulta las
funciones de la implementacin de TypeConverter. Debe implementar estos mtodos para devolver true en
algunos casos, en particular para el tipo String.
Implementar un convertidor de tipos
Implementar ConvertFrom
Para poder utilizarlo como una implementacin de TypeConverter que admite XAML, el mtodo ConvertFrom
para ese convertidor debe aceptar una cadena como el parmetro value. Si el formato de la cadena es vlido y
la implementacin de TypeConverter la puede convertir, entonces el objeto devuelto debe ser convertible al tipo
esperado por la propiedad. De lo contrario, la implementacin de ConvertFrom debe devolver null.

MCT: Luis Dueas

Pag 250 de 445

Manual de Windows Presentation Foundation


Cada implementacin de TypeConverter puede tener su propia interpretacin de lo que constituye una cadena
vlida para una conversin y, adems, puede utilizar u omitir la descripcin de tipos o los contextos de
referencia cultural pasados como parmetros. Sin embargo, el procesamiento XAML de WPF podra no pasar
valores al contexto de descripcin de tipos en todos los casos, ni tampoco referencias culturales basadas en
xml-lang.
Nota:
No utilice los caracteres de llave, en particular {, como elementos posibles del formato de cadena. Estos
caracteres estn reservados como entrada y salida de una secuencia de extensin de marcado.
Implementar ConvertTo
ConvertTo ofrece compatibilidad con la serializacin. La compatibilidad con la serializacin para los tipos
personalizados no es un requisito absoluto. Sin embargo, si implementa un control, o utiliza la serializacin
como parte de las caractersticas o del diseo de la clase, debe implementar ConvertTo.
Para poder utilizarlo como una implementacin de TypeConverter que admite XAML, el mtodo ConvertTo para
ese convertidor debe aceptar una instancia del tipo (o un valor) admitido como parmetro value. Cuando el
parmetro destinationType es del tipo String, el objeto devuelto debe ser convertible a String. La cadena
devuelta debe representar un valor serializado de value. En la situacin ideal, el formato de serializacin elegido
deber ser capaz de generar el mismo valor si esa cadena se pasara a la implementacin de ConvertFrom del
mismo convertidor, sin ninguna prdida significativa de informacin.
Si el valor no se puede serializar, o si el convertidor no admite la serializacin, la implementacin de ConvertTo
debe devolver null, en cuyo caso se permite que inicie una excepcin.
Si el parmetro destinationType no es del tipo String, puede elegir su propia administracin de convertidor.
Normalmente, se revierte a la administracin de implementacin base.
Cada implementacin de TypeConverter puede tener su propia interpretacin de lo que constituye una cadena
vlida para una conversin y, adems, puede utilizar u omitir la descripcin de tipos o los contextos de
referencia cultural pasados como parmetros.
Nota:
No utilice los caracteres de llave, en particular {, como elementos posibles del formato de cadena. Estos
caracteres estn reservados como entrada y salida de una secuencia de extensin de marcado.
Implementar CanConvertTo
La implementacin de CanConvertTo debe devolver true para destinationType de tipo String y, de lo contrario,
diferir la evaluacin a la implementacin base.
Implementar CanConvertFrom
La implementacin de CanConvertFrom debe devolver true para sourceType de tipo String y, de lo contrario,
diferir la evaluacin a la implementacin base.
Aplicar TypeConverterAttribute
Para que el convertidor de tipos personalizado se utilice como convertidor de tipos activo para una clase
personalizada, debe aplicar el .atributo de .NET Framework TypeConverterAttribute a la definicin de clase. La
propiedad ConverterTypeName que se especifica a travs del atributo debe ser el nombre de tipo del
convertidor de tipos personalizado. Con este atributo aplicado, cuando un procesador XAML administra valores
cuyo tipo de propiedad utiliza el tipo de la clase personalizada, puede especificar cadenas y devolver instancias
de objeto.
Tambin puede proporcionar un convertidor de tipos para cada propiedad. En lugar de aplicar un .atributo de
.NET Framework TypeConverterAttribute a la definicin de clase, aplqueselo a una definicin de propiedad (a la
definicin principal, no a las implementaciones de get/set que contiene). El tipo de la propiedad debe coincidir
con el tipo procesado por el convertidor de tipos personalizado. Con este atributo aplicado, cuando un
procesador XAML administra valores de esa propiedad, puede procesar cadenas de entrada y devolver
instancias de objeto. La tcnica del convertidor de tipos para cada propiedad resulta especialmente til si

MCT: Luis Dueas

Pag 251 de 445

Manual de Windows Presentation Foundation


decide utilizar un tipo de propiedad de Microsoft .NET Framework o de alguna otra biblioteca donde no se puede
controlar la definicin de clase ni aplicar TypeConverterAttribute.

3.2.11. Entidades de Caracteres XML y XAML


Lenguaje de marcado de aplicaciones extensible (XAML) utiliza entidades de caracteres definidas en XML para
los caracteres especiales
Entidades de caracteres y problemas de escape nicos de XAML
En general, XAML utiliza las mismas entidades de caracteres y secuencias de escape que se definen en XML.
La excepcin principal es que las llaves ({ y }) son importantes en XAML porque estos caracteres informan al
procesador de XAML de que la secuencia de caracteres incluida entre ellas se debe interpretar como una
extensin de marcado.
Sin embargo, puede mostrar las llaves como caracteres literales utilizando una secuencia de escape especfica
de XAML y no de XML.
Tenga en cuenta que una barra diagonal inversa (\) no necesita marcarse con una secuencia de escape cuando
se administra como una cadena.
Entidades de caracteres XML
Como se ha mencionado previamente, la mayora de las entidades de caracteres y las secuencias de escape
que se utilizan al escribir el marcado XAML se definen mediante XML. En este tema no se proporciona la lista
completa de tales entidades; encontrar una referencia ms completa para ellas en la documentacin externa,
como las especificaciones de XML. Sin embargo, para mayor comodidad, en este tema se incluye una lista con
algunas de las entidades de caracteres especficas de XML que se utilizan normalmente para el marcado XAML.
Carcter

Entidad

Notas

& (carcter de Y
comercial)

&amp;

Se debe utilizar tanto para valores de atributo como para el


contenido de un elemento.

> (carcter
mayor que)

&lt;

Se debe utilizar para el valor de atributo, pero > es aceptable


como contenido de un elemento siempre que < no lo preceda.

< (carcter
menor que)

&lt;

Se debe utilizar para el valor de atributo, pero < es aceptable


como contenido de un elemento siempre que > no vaya tras
l.

" (carcter de
comillas dobles)

&quot;

Se debe utilizar para el valor de atributo, pero " es aceptable


como contenido de un elemento. Tenga en cuenta que los
valores de atributo se pueden incluir entre ' o "; el carcter
que aparece primero define los caracteres que enmarcan el
valor del atributo y la otra comilla alternativa se puede utilizar
como valor literal dentro del valor.

' (carcter de
comilla simple)

&apos;

Se debe utilizar para el valor de atributo, pero ' es aceptable


como contenido de un elemento. Tenga en cuenta que los
valores de atributo se pueden incluir entre ' o "; el carcter
que aparece primero define los caracteres que enmarcan el
valor del atributo y la otra comilla alternativa se puede utilizar
como valor literal dentro del valor.

(asignaciones
caracteres
numricos)

&#[entero]; o
&#x[hexadecimal];

XAML admite las asignaciones de caracteres numricos en la


codificacin que est activa.

(espacio de no
separacin)

&#160; (suponiendo
la codificacin UTF-8)

Para los elementos de documentos dinmicos o los elementos


que aceptan texto, como TextBox, los espacios de no
separacin no se normalizan fuera del marcado, ni siquiera
para xml:space="default".

MCT: Luis Dueas

Pag 252 de 445

Manual de Windows Presentation Foundation


Formato de los comentarios XML
XAML utiliza el formato de los comentarios de XML: el principio del comentario es <!--, el final del comentario
es -->, y la secuencia -- no debe producirse dentro del comentario.
Instrucciones de procesamiento de XML
XAML administra las instrucciones de procesamiento de XML de acuerdo con las especificaciones de XML, que
indican que se debe pasar a travs de las instrucciones. El procesamiento de WPFXAML no utiliza ninguna
instruccin de procesamiento.

3.2.12. Caractersticas de lenguaje (x:) de espacios de nombres XAML


3.2.12.1. Extensin de Marcado x:Array
Proporciona compatibilidad general para las matrices de objetos en XAML.
Uso de elementos de objeto XAML
<object>
<object.property>
<x:Array Type="typeName">
<arrayObject1/>
<arrayObject2/>
...
</x:Array>
</object.property>
<object>
Valores XAML
typeName

El nombre del tipo que x:Array contendr, que requiere a menudo un


prefijo. Vea Comentarios.

arrayObject1,arrayObject2,
etc.

Elementos de objeto que definen el contenido de la matriz. Vea


Comentarios.

Comentarios
Type es un atributo necesario para todos los elementos de objeto x:Array.
La clase ArrayExtension define el control para esta extensin de marcado en la implementacin del procesador
XAML de WPF. Esta clase no es de tipo sealed, y se puede utilizar como base para una implementacin de
extensin de marcado para un tipo de matriz personalizado.
x:Array est pensada ms concretamente para la extensibilidad de lenguaje general en XAML. No obstante,
x:Array tambin puede resultar til para rellenar algunas propiedades mediante XAML que aceptan interfaces o
clases de compatibilidad con colecciones generales como contenido de propiedad estructurado, como
IEnumerable, por ejemplo.
Los elementos de objeto que rellenan una matriz x:Array no suelen existir en el espacio de nombres xmlns de
WPF y requieren una asignacin de prefijo.
Por ejemplo, a continuacin se muestra una matriz simple de dos cadenas, con el prefijo sys (as como x)
definido en el nivel de la matriz:
<x:Array Type="sys:String" xmlns:x= http://schemas.microsoft.com/winfx/2006/xaml
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>Hello</sys:String>
<sys:String>World</sys:String>
</x:Array>
x:Array es una extensin de marcado. Las extensiones de marcado suelen implementarse cuando se necesita
utilizar valores de atributos que no sean valores literales o nombres de controladores, y se trata de un requisito
global que no se cubre con slo incluir convertidores de tipos en determinados tipos o propiedades. En cierto

MCT: Luis Dueas

Pag 253 de 445

Manual de Windows Presentation Foundation


modo, x:Array constituye una excepcin a esa regla general, porque en lugar de proporcionar administracin
alternativa de valores de atributos, x:Array proporciona la administracin alternativa de su contenido de texto
interno. Esto proporciona una compatibilidad que permite agrupar en una matriz clases de elementos que
podran no ser compatibles con ningn modelo de contenido existente, y hacer referencia a ellas
posteriormente en el cdigo subyacente teniendo acceso a la matriz con nombre y llamando a mtodos de
matriz para obtener los elementos individuales que la componen.
Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo, que es la
convencin que permite que un procesador XAML reconozca que el atributo se debe procesar mediante una
extensin de marcado.

3.2.12.2. Atributo x:Class


Configura la compilacin XAML para unir clases parciales entre el marcado y el cdigo subyacente. La clase
parcial de cdigo se define en un archivo de cdigo independiente en un lenguaje Common Language
Specification (CLS), mientras que la clase parcial de marcado se crea mediante CODEGEN durante la
compilacin XAML.
Uso de atributos XAML

<object x:Class="namespace.classname"...>
...
</object>
Valores XAML
namespace

Opcional. Especifica un espacio de nombres CLR que contiene la clase parcial identificada por
classname. Si se especifica namespace, se incluye un punto (.) para separar namespace y
classname.

classname

Necesario. Especifica el nombre CLR de la clase parcial que conecta el XAML cargado y el
cdigo subyacente de ese XAML.

Comentarios
x:Class se puede declarar como atributo para cualquier elemento que sea la raz de un rbol de elementos
Lenguaje de marcado de aplicaciones extensible (XAML) y que se genere (donde Lenguaje de marcado de
aplicaciones extensible (XAML) est incluido en un proyecto con la accin de compilacin Page), o bien para el
objeto Application raz de la definicin de una aplicacin generada. Si se declara x:Class en cualquier elemento
que no sea una raz de pgina o raz de aplicacin, y en cualquier circunstancia para un archivo Lenguaje de
marcado de aplicaciones extensible (XAML) que no est compilado, se producir un error en tiempo de
compilacin.
La clase utilizada como x:Class no puede ser una clase anidada.
x:Class es opcional en el sentido de que es totalmente vlido que una pgina XAML no tenga ningn cdigo
subyacente; sin embargo, si la pgina declara valores de atributos de control de eventos, o crea instancias de
elementos personalizados cuyas clases definidoras se encuentran en la clase de cdigo subyacente, entonces es
obligatorio proporcionar la referencia de x:Class (o x:Subclass) a la clase adecuada para el cdigo subyacente.
El valor del atributo x:Class debe ser una cadena que especifica el nombre completo de una clase. En las
aplicaciones simples, se puede omitir la informacin de espacio de nombres siempre que el cdigo subyacente
tambin est estructurado as (la definicin se inicia en el nivel de clases). El archivo de cdigo subyacente para
una definicin de pgina o de aplicacin debe estar dentro de un archivo de cdigo incluido como parte del
proyecto que genera una aplicacin compilada. Debe respetar las reglas de nombres de las clases CLR; para
obtener detalles, vea los detalles, vea Type Definitions. De manera predeterminada, la clase de cdigo
subyacente debe ser public, pero se puede definir con otro nivel de acceso mediante Atributo x:ClassModifier.

MCT: Luis Dueas

Pag 254 de 445

Manual de Windows Presentation Foundation


Observe que este significado del valor de atributo x:Class es especfico de la implementacin de XAML en WPF.
Puede que en implementaciones de XAML fuera de WPF no se utilice cdigo administrado y, por consiguiente,
podran utilizar una frmula de resolucin de clases diferente.

3.2.12.3. Atributo x:ClassModifier


Modifica el comportamiento de compilacin de XAML en los casos donde tambin se proporciona x:Class. En
concreto, en lugar de crear una clase parcial con un nivel del acceso pblico (el valor predeterminado), el
atributo x:Class proporcionado se crea con el valor de acceso NonPublic. Esto afecta al nivel de acceso de la
clase en los ensamblados generados.
Uso de atributos XAML
<object x:Class="namespace.classname" x:ClassModifier="NonPublic">
...
</object>
Valores XAML
NonPublic

La cadena exacta que se debe pasar para especificar el valor Public en lugar de NonPublic
vara, dependiendo del lenguaje de programacin subyacente que se utilice. Vea Comentarios.

Dependencias
x:Class tambin se debe proporcionar para el mismo elemento, que debe ser el elemento raz de una pgina.
Comentarios
El valor del atributo x:ClassModifier vara segn el lenguaje de programacin. La cadena que hay que utilizar
depende de cmo se implemente CodeDomProvider en el lenguaje, de los convertidores de tipos que se
devuelvan en cada lenguaje para definir los significados de TypeAttributes.Public y TypeAttributes.NonPublic, y
de si ese lenguaje distingue entre maysculas y minsculas o no.

Para C#, la cadena que se debe pasar para designar NonPublic es internal.
Para Microsoft Visual Basic .NET, la cadena que se debe pasar para designar NonPublic es Friend.
Para C++/CLI, en este momento los elementos de destino C++/CLI no admiten la compilacin de
XAML.

Tambin puede especificar Public (public en C#, Public en Microsoft Visual Basic .NET) pero no es frecuente,
porque el comportamiento Public ya es el valor predeterminado.
El valor para Private (private en C#) no es pertinente para x:ClassModifier, porque XAML no admite referencias
a clases anidadas, de modo que el modificador NonPublic tiene el mismo efecto.

3.2.12.4. Elemento de Directiva x:Code de XAML


Permite colocar cdigo dentro de una pgina XAML, para su compilacin por cualquier implementacin de
procesador XAML que compile XAML, en lugar de interpretarlo.
Uso de elementos de objeto XAML
<object>
<x:Code>
// code instructions, usually enclosed by CDATA...
</x:Code>
</object>
Dependencias
Atributo x:Class tambin se debe proporcionar en el elemento primario mostrado como object en la sintaxis, y
ese elemento debe ser el elemento raz de una pgina. El elemento de directiva x:Code debe ser un elemento
secundario inmediato del elemento raz object.
Comentarios
El cdigo incluido en el elemento de directiva x:Code de XAML se interpreta dentro de los espacios de nombres
XML proporcionados. Por consiguiente, suele ser necesario incluir tambin el cdigo de x:Code dentro de un
segmento CDATA.

MCT: Luis Dueas

Pag 255 de 445

Manual de Windows Presentation Foundation


x:Code no se permite para todos los mecanismos de implementacin posibles de un archivo XAML. El cdigo
para WPF se tiene que compilar, no se interpreta ni utiliza segn el principio Just-In-Time (JIT). Por ejemplo,
x:Code no se permite dentro de un documento XML Paper Specification (XPS), ni en XAML dinmico.
Los valores y destinos del proyecto contenedor que se utiliza para compilar la aplicacin determinan el
compilador del lenguaje correcto que se debe utilizar para el contenido de x:Code.
El cdigo declarado dentro de x:Code tiene varias limitaciones notables. La compilacin tratar el cdigo
colocado dentro de x:Code como si estuviera dentro del mbito de la clase parcial que ya se est creando para
esa pgina XAML. Por consiguiente, todo el cdigo que se defina deber estar constituido por miembros o
variables de esa clase parcial. No se pueden definir clases adicionales, excepto mediante anidacin de una clase
dentro de la clase parcial (aunque es vlido, no suele hacerse, porque en XAML no se puede hacer referencia a
las clases anidadas). No se pueden definir ni agregar otros espacios de nombres excepto el espacio de nombres
utilizado para la clase parcial existente. Las referencias a entidades de cdigo que se encuentren fuera del
espacio de nombres de la clase parcial deben ser siempre completas. Si los miembros que se declaran son
invalidaciones de miembros invalidables de la clase parcial, esto se debe especificar mediante la palabra clave
de invalidacin especfica del lenguaje. Si existen miembros que estn en conflicto con miembros de la clase
parcial creados fuera de la pgina XAML, de tal forma que el compilador lo notifica, el archivo XAML no se
cargar ni compilar.

3.2.12.5. Atributo x:FieldModifier


Modifica el comportamiento de compilacin de XAML, de tal forma que los campos correspondientes a las
referencias de objetos con nombre se definen con el acceso NonPublic, en lugar de con el comportamiento
Public predeterminado.
Uso de atributos XAML
<object x:FieldModifier="Public".../>
Valores XAML
Public

La cadena exacta que se debe pasar para especificar el valor Public en lugar de NonPublic vara,
dependiendo del lenguaje de programacin subyacente que se utilice. Vea Comentarios.

Dependencies
x:Name tambin se debe proporcionar en el mismo elemento.
Comentarios
El valor del atributo x:FieldModifier vara segn el lenguaje de programacin. La cadena que hay que utilizar
depende de cmo se implemente CodeDomProvider en el lenguaje, de los convertidores de tipos que se
devuelvan en cada lenguaje para definir los significados de TypeAttributes.Public y TypeAttributes.NonPublic, y
de si ese lenguaje distingue entre maysculas y minsculas o no.

Para C#, la cadena que se debe pasar para designar Public es public.
Para Microsoft Visual Basic .NET, la cadena que se debe pasar para designar Public es Public.
Para C++/CLI, en este momento los elementos de destino C++/CLI no admiten la compilacin de
XAML.

Tambin puede especificar NonPublic (internal en C#, Friend en Microsoft Visual Basic .NET) pero no es
frecuente, porque el comportamiento NonPublic ya es el valor predeterminado.
NonPublic es el valor predeterminado porque es infrecuente que el cdigo externo al ensamblado que ha
compilado el marcado XAML necesite tener acceso a un elemento creado mediante XAML. En la arquitectura de
seguridad de WPF se toma la decisin consciente de no hacer pblicos los campos que almacenan instancias de
elementos a no ser que se establezca especficamente el atributo x:FieldModifier.

MCT: Luis Dueas

Pag 256 de 445

Manual de Windows Presentation Foundation


x:FieldModifier slo es pertinente para los elementos que tambin tienen Atributo x:Name, porque ese nombre
se utiliza para hacer referencia al campo cuando es pblico.
La clase parcial del elemento raz es pblica de manera predeterminada, pero puede hacerse no pblica
mediante Atributo x:ClassModifier. Atributo x:ClassModifier tambin afecta al nivel de acceso de la instancia de
la clase del elemento raz. Puede incluir x:Name y x:FieldModifier en el elemento raz, pero lo nico que se
consigue es una copia de campo pblico del elemento raz, pero el nivel de acceso real de la clase del elemento
raz sigue estando controlado por Atributo x:ClassModifier.

3.2.12.6. Atributo x:Key


Identifica singularmente elementos que se crean y a los que se hace referencia como recursos, y que existen
dentro de un ResourceDictionary.
Uso de atributos XAML
<object.Resources>
<object x:Key="stringKeyValue".../>
</object.Resources>
Valores XAML
stringKeyValue

Cadena real utilizada como clave, que debe cumplir la Gramtica de XamlName.
O bien,
Extensin de marcado que proporciona un tipo de objeto alternativo que acta como
clave. Vea Comentarios.

Comentarios
En general, los elementos secundarios de un elemento primario que es una implementacin de IDictionary,
como ResourceDictionary, deben incluir un atributo x:Key que especifica un valor de clave nica dentro de ese
diccionario. Las excepciones son Style con la propiedad TargetType o DataTemplate con la propiedad DataType,
ya que ambas tienen su propia clave implcita. La aplicacin de esta singularidad de las claves en el momento
de la carga corre a cargo de la implementacin del procesador XAML de WPF. Los valores de x:Key ausentes o
que no sean nicos producirn errores en tiempo de carga.
El valor de atributo de x:Key puede ser cualquier cadena definida en Gramtica de XamlName, o bien un objeto
evaluado

mediante

una

extensin

de

marcado.

Por

ejemplo,

el

valor

de

x:Key

puede

ser

ComponentResourceKey. Este escenario se utiliza cuando algunos controles exponen una clave de estilo que se
puede utilizar para crear un recurso de estilo personalizado que influye en la apariencia y el funcionamiento de
ese control sin reemplazar el estilo completamente. Un ejemplo de este tipo de clave es ButtonStyleKey.
Observe que, en la sintaxis mostrada, el objeto ResourceDictionary est implcito en la manera en que el
procesador XAML genera una coleccin para rellenar una coleccin Resources, y no se suele proporcionar
explcitamente como un elemento en el marcado, aunque se puede hacer si se desea para aportar mayor
claridad (sera un elemento de objeto de coleccin entre el elemento de propiedad Resources y los elementos
que contiene incluidos en el diccionario).
La clase abstracta ResourceKey define el control para esta extensin de marcado en la implementacin del
procesador XAML de WPF. Sin embargo, el procesador XAML de WPF genera tipos de extensin subyacentes
diferentes para las claves, segn su uso. Por ejemplo, la clave de un objeto DataTemplate o sus clases
derivadas se administra por separado y genera un objeto DataTemplateKey diferenciado.
Las claves y los nombres no son conceptos idnticos y, en realidad, son mutuamente excluyentes segn la
definicin de WPF de estos conceptos.
El equivalente en cdigo de especificar x:Key es la clave usada en cualquier operacin que utiliza una clave con
la interfaz IDictionary subyacente. Por ejemplo, una clave x:Key aplicada en el marcado de un recurso equivale
al valor del parmetro key de ResourceDictionary.Add cuando se agrega el recurso a ResourceDictionary.

MCT: Luis Dueas

Pag 257 de 445

Manual de Windows Presentation Foundation


(x:Key es una caracterstica del lenguaje XAML y no est diseada exclusivamente para ResourceDictionary,
aunque sta es la aplicacin ms frecuente de x:Key en la implementacin de XAML en WPF.)

3.2.12.7. Atributo x:Name


Identifica singularmente los elementos de objeto para el acceso al elemento con instancias del cdigo
subyacente o general. Una vez aplicado a un modelo de programacin de respaldo, x:Name se puede
considerar equivalente a la variable que contiene una referencia de objeto, devuelta por un constructor.
Uso de atributos XAML
<object x:Name="XAMLNameValue".../>
Valores XAML
XAMLNameValue

Cadena que cumple a las restricciones de Gramtica de XamlName.

Comentarios
El atributo x:Name especificado se convierte en el nombre de un campo creado en el cdigo subyacente al
procesar XAML, y ese campo contiene una referencia al objeto.
De manera predeterminada, el campo creado es interno. Puede cambiar el acceso al campo especificando el
atributo x:FieldModifier.
Para una aplicacin que utiliza destinos de Microsoft Visual Basic .NET e incluye archivos XAML, se crea una
propiedad de referencia independiente durante la compilacin que agrega la palabra clave WithEvents a todos
los elementos que tienen un atributo x:Name, a fin de admitir la sintaxis de Handles para los delegados de
controladores de eventos. Esta propiedad siempre es pblica
x:Name debe ser nico dentro de un mbito de nombres. En los casos de XAML ms comunes, el mbito de
nombres principal se define mediante esos elementos contenidos en una misma pgina XAML. Los mbitos de
nombres adicionales los define cualquier plantilla que tambin est definida en esa pgina.
Un procesador XAML utiliza x:Name para registrar un nombre en un mbito de nombres, incluso en aquellos
casos en que la pgina no est compilada (por ejemplo, XAML dinmico). Esto se debe a que x:Name se
necesita potencialmente para el enlace de ElementName.
x:Name no se puede aplicar en algunos mbitos. Por ejemplo, los elementos de un objeto ResourceDictionary
no pueden tener nombres, porque ya tienen el x:Key (atributo) como su identificador nico.
Las reglas para permitir x:Name, as como la singularidad de los mbitos, se definen en la implementacin del
marco de trabajo subyacente de Windows Presentation Foundation (WPF), que divide los distintos elementos de
marcado en intervalos de NameScope independientes, tales como diccionarios de recursos, el rbol de
elementos lgico, etc.
Algunas aplicaciones del marco de trabajo de WPF podran ser capaces de evitar cualquier uso del atributo
x:Name, porque la propiedad de dependencia Name especificada dentro del espacio de nombres de WPF para
algunas de las clases base importantes (como FrameworkElement/FrameworkContentElement) ya satisface este
mismo propsito. Existen algunos escenarios de XAML y de marco de trabajo comunes donde es necesario tener
acceso mediante cdigo a un elemento que no tiene una propiedad Name, en particular en algunas clases de
respaldo de animaciones y guiones grficos. Por ejemplo, debe especificar x:Name en las escalas de tiempo y
transformaciones creadas en XAML, si piensa hacer referencia a ellas desde el cdigo.
Si Name se define como una propiedad de un elemento, Name y x:Name se pueden utilizar de forma
intercambiable, pero se producir un error si ambos se especifican en el mismo elemento.

MCT: Luis Dueas

Pag 258 de 445

Manual de Windows Presentation Foundation


Para los elementos personalizados, la propiedad (puede ser una propiedad CLR o una propiedad de
dependencia) que se asigna a x:Name para cualquier objeto determinado se puede establecer o cambiar
designando esa propiedad con el RuntimeNamePropertyAttribute en el cdigo de la declaracin de propiedad.
Name se puede establecer mediante la sintaxis de atributo XAML, mediante la sintaxis de elementos de
propiedad XAML, o mediante cdigo usando el mtodo SetValue; no obstante, tenga en cuenta que, en algunas
circunstancias, al establecer la propiedad Name en cdigo no se crea la referencia de campo representativa
dentro del mbito de nombres. . x:Name no se puede establecer en la sintaxis de elementos de propiedad
XAML ni mediante cdigo usando SetValue; slo se puede establecer utilizando la sintaxis de atributo en
elementos. En su lugar, utilice mtodos de NameScope desde el cdigo, para el mbito de nombres adecuado.

3.2.12.8. Extensin de Marcado x:Null


Especifica null como un valor para una propiedad XAML.
Uso de atributos XAML
<object property="{x:Null}" .../>
Uso de elementos de objeto XAML
<object>
<object.property>
<x:Null/>
</object.property>
</object>
Comentarios
null es la palabra clave para una referencia null en C# y C++. La palabra clave en Microsoft Visual Basic .NET
para una referencia null es Nothing.
La extensin de marcado x:Null no tiene ninguna propiedad que se pueda establecer.
Observe que null no es necesariamente el valor no establecido para una propiedad de dependencia de tipo de
referencia. El valor predeterminado inicial puede variar para cada propiedad de dependencia. Muchas
propiedades de dependencia no aceptan el valor null, mediante marcado ni mediante cdigo, debido a sus
implementaciones de devolucin de llamada de validacin.
x:Null es una extensin de marcado. Todas las extensiones de marcado de XAML utilizan los caracteres { y }
reconocidos por las implementaciones del procesador XAML, a fin de permitir mediante secuencias de escape el
control de valores de atributos que no sean literales o referencias del controlador. La sintaxis de atributo es la
sintaxis ms comn utilizada con esta extensin de marcado. x:Null tambin se puede utilizar en la sintaxis de
elementos de propiedad.
La clase NullExtension define la administracin para esta extensin de marcado en la implementacin del
procesador XAML de WPF.

3.2.12.9. Atributo x:Shared


Cuando se establece en false, modifica el comportamiento de recuperacin de recursos de Windows
Presentation Foundation (WPF), de suerte que las solicitudes de un recurso crearn una nueva instancia por
cada solicitud, en lugar de compartir la misma instancia para todas las solicitudes.
Uso de atributos XAML
<ResourceDictionary>
<object x:Shared="false".../>
</ResourceDictionary>
Comentarios
La condicin de x:Shared predeterminada para los recursos es true. Esta condicin significa que cualquier
solicitud de recurso devolver siempre la misma instancia. Al modificar un objeto devuelto a travs de una API
de recursos como FindResource, o al modificarlo directamente dentro de un ResourceDictionary, se cambia el

MCT: Luis Dueas

Pag 259 de 445

Manual de Windows Presentation Foundation


recurso original. Si las referencias a ese recurso eran dinmicas, los consumidores de ese recurso obtendrn el
recurso modificado. (Si las referencias al recurso eran estticas, los cambios que se produzcan en el recurso
despus del tiempo de procesamiento de XAML sern irrelevantes)
No se suele especificar x:Shared="true", porque ya es el valor predeterminado. No existe ningn cdigo
equivalente directo para x:Shared.
Un escenario para x:Shared="false" es aqul en que se define una clase derivada de FrameworkElement o de
FrameworkContentElement como recurso y se introduce el recurso de elemento en un modelo de contenido.
x:Shared="false" permite introducir un recurso de elemento varias veces en la misma coleccin (como
UIElementCollection, por ejemplo). Sin x:Shared="false", no sera vlido, porque la coleccin exige la unicidad
en su contenido. Sin embargo, el comportamiento de x:Shared="false" crea otra instancia idntica del recurso,
en lugar de devolver la misma.
Otro escenario para x:Shared="false" es el uso de un recurso Freezable para valores de animacin, pero desea
modificarlo para cada animacin.
La administracin de cadena de "false" no distingue maysculas de minsculas.
x:Shared nicamente es vlido en las condiciones siguientes:

El objeto ResourceDictionary que contiene los elementos con x:Shared se debe compilar. El objeto
ResourceDictionary no puede estar dentro de XAML dinmico ni se puede utilizar para temas.

El

objeto

ResourceDictionary

que

contiene

los

elementos

no

se

puede

anidar

en

otro

ResourceDictionary. Por ejemplo, no puede utilizar x:Shared para los elementos de un objeto
ResourceDictionary que est dentro de un Style que ya es un elemento de un ResourceDictionary.

3.2.12.10. Extensiones de Marcado x:Static


Hace referencia a cualquier entidad de cdigo esttica por valor definida conforme a Common Language
Specification (CLS). La propiedad a la que se hace referencia se evala antes de cargar el resto de la pgina
XAML y se puede utilizar para proporcionar el valor de una propiedad en XAML.
Uso de atributos XAML
<object property="{x:Static prefix:typeName.staticMemberName}" .../>
Uso de elementos de objeto XAML
<object>
<object.property>
<x:Static Member="prefix:typeName.staticMemberName" .../>
</object.property>
</object>
Valores XAML
prefix

Opcional. Prefijo que asigna un espacio de nombres xmlns no predeterminado.

typeName

Necesario. Tipo que define el miembro esttico deseado.

staticMemberName

Necesario. Nombre del miembro de valor esttico deseado (una constante, una
propiedad esttica, un campo o un valor de enumeracin).

Comentarios
La entidad de cdigo a la que se hace referencia debe ser una de las siguientes:

constante
propiedad esttica
campo
valor de enumeracin

Si se especifica cualquier otra entidad de cdigo, como una propiedad no esttica, da lugar a un error en
tiempo de compilacin.

MCT: Luis Dueas

Pag 260 de 445

Manual de Windows Presentation Foundation


x:Static puede hacer referencia a campos estticos o propiedades que no pertenezcan al espacio de nombres
xmlns predeterminado, pero para ello se requiere una asignacin de prefijo. El espacio de nombres xmlns
predeterminado se define para cualquier elemento XAML concreto como un atributo. Por lo general, esto se
define en el elemento raz para que xmlns se aplique a todos los elementos que se encuentren por debajo de la
raz. El espacio de nombres xmlns predeterminado que se utiliza para la programacin en Windows Presentation
Foundation (WPF) suele ser el espacio de nombres XAML de WPF. Debe asignar un prefijo si se cumple una de
las condiciones siguientes:

Se hace referencia a un tipo que existe en Microsoft .NET Framework pero que no forma parte del
espacio de nombres xmlns de WPF. ste es un escenario relativamente comn para utilizar x:Static.
Por ejemplo, puede utilizar una referencia x:Static con un prefijo que se asigna al espacio de nombres
System a fin de hacer referencia a las propiedades estticas de la clase Environment.

Se hace referencia a un tipo de un ensamblado personalizado.

Se hace referencia a un tipo que existe en un ensamblado de WPF, pero ese tipo se encuentra dentro
de un espacio de nombres CLR que no se ha asignado con xmlns de manera que forme parte de la
definicin de xmlns de WPF. La asignacin se lleva a cabo mediante definiciones en ese
ensamblado. Los espacios de nombres CLR sin asignar son tpicos para los espacios de nombres CLR
de WPF que no suelen estar pensados para XAML, como System.Windows.Threading.

Puede utilizar referencias de x:Static que no sean directamente el tipo de valor de una propiedad, pero que se
puedan evaluar como ese tipo. Por ejemplo, puede utilizar una referencia de x:Static esttica para obtener un
valor de una enumeracin, o bien fuera de una propiedad esttica como los distintos colores y pinceles
definidos por SystemColors. Las referencias de x:Static se pueden utilizar para establecer cualquier propiedad
en la sintaxis XAML, incluso aqullas que se basen en una propiedad con un tipo de referencia, porque la
administracin real del valor de x:Static una vez evaluado puede variar, segn los comportamientos de los
convertidores de tipos de la propiedad donde se aplica el valor esttico.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. El token de cadena que
se proporciona despus de la cadena de identificador x:Static se asigna como valor de Member de la clase de
extensin StaticExtension subyacente.
x:Static se puede utilizar en la sintaxis de elementos de objeto. En este caso, es preciso especificar el valor de
la propiedad Member.
x:Static tambin se puede utilizar en un uso de atributos detallado que especifica la propiedad Member como
un par propiedad=valor:
<object property="{x:Static Member=prefix:typeName.staticMemberName}" .../>
El uso detallado suele ser til para las extensiones que tienen ms de una propiedad que se puede configurar, o
en aquellos casos en que algunas propiedades son opcionales. Dado que x:Static tiene una sola propiedad
configurable, que es obligatoria, este uso detallado no es habitual.
En la implementacin del procesador XAML de WPF, el control para esta extensin de marcado se define
mediante la clase StaticExtension.
x:Static es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se necesita
que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este requisito
es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o propiedades.
Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo, que es la
convencin que permite que un procesador XAML reconozca que el atributo se debe procesar mediante una
extensin de marcado.

3.2.12.11. Atributo x:Subclass


MCT: Luis Dueas

Pag 261 de 445

Manual de Windows Presentation Foundation


Modifica el comportamiento de compilacin de XAML en los casos donde tambin se proporciona x:Class. En
concreto, en lugar de crear una clase parcial basada en la clase de pgina, el atributo x:Class proporcionado se
crea como una clase intermedia, por lo que se espera que la clase derivada proporcionada se base en x:Class.
Uso de atributos XAML
<object x:Class="namespace.classname" x:Subclass="subclassNamespace.subclassName">
...
</object>
Valores XAML
namespace

Opcional. Especifica un espacio de nombres CLR que contiene classname. Si se


especifica namespace, se incluye un punto (.) para separar namespace y classname.

classname

Necesario. Especifica el nombre CLR de la clase parcial que conecta el XAML cargado
y el cdigo subyacente de ese XAML. Vea Comentarios.

subclassNamespace

Opcional. Puede ser diferente de namespace, siempre que cada espacio de nombres
pueda resolver el otro. Especifica un espacio de nombres CLR que contiene
subclassName. Si se especifica subclassName, se incluye un punto (.) para separar
subclassNamespace y subclassName.

subclassName

Necesario. Especifica el nombre CLR de la subclase.

Dependencias
Atributo x:Class tambin se debe proporcionar en el mismo elemento, que debe ser el elemento raz de una
pgina.
Comentarios
El uso de x:Subclass est destinado principalmente a los lenguajes que no admiten las declaraciones de clases
parciales.
x:Subclass se puede declarar para cualquier elemento que sea la raz de una pgina Lenguaje de marcado de
aplicaciones extensible (XAML), y/o para la raz de Application en la definicin de aplicacin, que ya tiene
x:Class. Si se declara x:Subclass en cualquier elemento que no sea la raz de una pgina o aplicacin, o se
especifica sin que exista x:Class, se producir un error en tiempo de compilacin.
La creacin de clases derivadas que funcionen correctamente para el escenario x:Subclass es una tarea
bastante compleja. Puede que sea necesario examinar los archivos intermedios (los archivos .g generados en la
carpeta obj del proyecto, con nombres que incorporan los nombres de los archivos .xaml). Estos archivos
intermedios pueden ayudarle a determinar el origen de algunas construcciones de programacin en las clases
parciales combinadas dentro de la aplicacin compilada.
La clase utilizada como x:Subclass no puede ser una clase anidada.
Los controladores de eventos de la clase derivada deben ser de tipo internal override (Friend Overrides en
Microsoft Visual Basic .NET), a fin de invalidar los cdigos auxiliares correspondientes a los controladores que se
crean en la clase intermedia durante la compilacin. De lo contrario, las implementaciones de la clase derivada
ocultaran la implementacin de clase intermedia (prevaleceran sobre ella) y no se invocaran los controladores
de clase intermedios.
Al definir x:Class y x:Subclass , no es preciso proporcionar ninguna implementacin de la clase a la que x:Class
hace referencia. nicamente hay que darle un nombre mediante el atributo x:Class, para que sirva de gua al
compilador en relacin con la clase que se crea en los archivos intermedios (el compilador no elige un nombre
predeterminado en este caso). Puede proporcionar una implementacin de la clase x:Class si lo desea, pero no
es lo habitual cuando se utiliza x:Class y x:Subclass.

3.2.12.12. Extensin de Marcado x:Type


Proporciona el objeto Type para el tipo proporcionado.

MCT: Luis Dueas

Pag 262 de 445

Manual de Windows Presentation Foundation


Uso de atributos XAML
<object property="{x:Type prefix:typeNameValue}" .../>
Uso de elementos de objeto XAML
<object>
<object.property>
<x:Type TypeName="prefix:typeNameValue"/>
</object.property>
</object>
Valores XAML
prefix

Opcional. Prefijo que asigna un xmlns no predeterminado. Con frecuencia no se necesita


especificar un prefijo, vea las Notas.

typeNameValue

Necesario. Nombre de tipo que se puede resolver para hallar el xmlns predeterminado
actual, o prefijo asignado especificado si se proporciona prefix.

Comentarios
x:Type se utiliza para proporcionar el valor de atributo de una propiedad que acepta Type. Sin embargo,
muchas propiedades que toman Type como valor pueden aceptar directamente el nombre del tipo (el valor de
cadena Type.Name); vea la documentacin de la propiedad concreta para obtener informacin detallada. En
esencia, x:Type es un equivalente de la extensin de marcado para el operador typeof() de C# o para el
operador GetType de Microsoft Visual Basic .NET.
El xmlns predeterminado se define para cualquier pgina XAML determinada como atributo en el elemento raz.
Generalmente, el xmlns predeterminado que se utiliza para la programacin en Windows Presentation
Foundation

(WPF)

es

el

xmlns

XAML

de

WPF.

El

identificador

de

ese

espacio

de

nombres

es

http://schemas.microsoft.com/winfx/2006/xaml/presentation. La inmensa mayora de tipos destinados a la


programacin de aplicaciones de WPF comunes pertenecen a este xmlns. Por consiguiente, en general no es
preciso asignar un prefijo para obtener un tipo cuando se utiliza x:Type. Puede que sea necesario asignar un
prefijo si se hace referencia a un tipo desde un ensamblado personalizado, o para los tipos que existen en un
ensamblado de WPF pero que estn dentro de un espacio de nombres CLR que no se ha asignado en xmlns
para formar parte de la definicin de xmlns de WPF en ese ensamblado.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. El token de cadena que
se proporciona despus de la cadena de identificador x:Type se asigna como valor de TypeName de la clase de
extensin TypeExtension subyacente. El valor de este atributo es Type.Name del tipo deseado.
x:Type se puede utilizar en sintaxis de elementos de objeto. En este caso, es obligatorio especificar el valor de
la propiedad TypeName para inicializar correctamente la extensin.
x:Type tambin se puede utilizar en un uso de atributos detallado que especifica la propiedad TypeName como
un par propiedad=valor:
<object property="{x:Type TypeName=typeNameValue}" .../>
El uso detallado suele ser til para las extensiones que tienen ms de una propiedad que se puede configurar, o
en aquellos casos en que algunas propiedades son opcionales. Dado que x:Type tiene una sola propiedad
configurable, que es obligatoria, este uso detallado no es habitual.
En la implementacin del procesador XAML de WPF, el control para esta extensin de marcado se define
mediante la clase TypeExtension.
x:Type es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se necesita
que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este requisito
es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o propiedades.
Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo, que es la
convencin que permite que un procesador XAML reconozca que el atributo se debe procesar mediante una
extensin de marcado.

MCT: Luis Dueas

Pag 263 de 445

Manual de Windows Presentation Foundation

3.2.12.13. Atributo x:TypeArguments


Pasa las restricciones necesarias al constructor para un tipo genrico.
Uso de atributos XAML
<object x:Class="namespace.classname" x:TypeArguments="{x:Type type1}[,
{x:Type type2},{x:Type type3,...}]">
...
</object>
Valores XAML
namespace

Opcional. Especifica un espacio de nombres CLR que contiene la clase parcial


identificada por classname. Si se especifica namespace, se incluye un punto (.)
para separar namespace y classname.

classname

Necesario. Especifica el nombre CLR de la clase parcial que conecta el XAML


cargado y el cdigo subyacente de ese XAML.

type1, type2, type3,


...

Nombre de los tipos utilizados para restringir la instancia genrica. Los caracteres [
y ] de la sintaxis no son literales, indican que es opcional pasar ms de un tipo a
x:TypeArguments. Si se pasa ms de un tipo, deben separarse entre s mediante
comas (,).

Dependencias
Atributo x:Class tambin se debe proporcionar en el mismo elemento, que debe ser el elemento raz de una
pgina.
Comentarios
Este atributo slo se puede utilizar para el elemento raz, especificando x:Class para ese tipo genrico, y
nicamente cuando ese elemento raz se asigna a un tipo genrico que tiene al menos un argumento de tipo.
Un ejemplo de ello sera PageFunction<(Of <(T>)>).
Si el tipo genrico tiene un solo argumento de tipo, el valor de atributo es una referencia a un solo tipo, el cual
se especifica como valor de atributo mediante la sintaxis de Extensin de marcado x:Type. Si el tipo genrico
tiene varios argumentos de tipo, las diversas referencias de tipo se separan mediante comas dentro del valor
del atributo.

3.2.12.14. Atributo x:Uid


Proporciona un identificador dentro de los elementos de marcado que se utiliza en los procesos y las
herramientas de localizacin.
Uso de atributos XAML
<object x:Uid="identifier"... />
-or<object>
<object.property x:Uid="identifier"... >
...
</object.property>
</object>
Valores XAML
identifier

Cadena creada manualmente o generada automticamente que debe ser nica dentro del
archivo cuando la interpretan los procesos o las herramientas de localizacin.

Comentarios
x:Uid es el nico caso excepcional de Lenguaje de marcado de aplicaciones extensible (XAML) en que se
permite que un atributo se encuentre en un elemento de propiedad. Todos los otros atributos no son vlidos en
un elemento de propiedad. Este uso es necesario porque un elemento de propiedad puede contener una
cadena, y la nica manera de marcar esa cadena como un recurso nico que es preciso localizar es colocar el
atributo x:Uid en el elemento de propiedad envolvente.

MCT: Luis Dueas

Pag 264 de 445

Manual de Windows Presentation Foundation


Los procesadores Lenguaje de marcado de aplicaciones extensible (XAML) personalizados no deben provocar un
error si encuentran x:Uid en un elemento de propiedad.
No se espera que los procesadores Lenguaje de marcado de aplicaciones extensible (XAML) en el sentido
genrico (aqullos que no forman parte necesariamente del proceso de localizacin) exijan que los valores de
x:Uid sean nicos. Esa responsabilidad recae sobre el autor de los valores y la expectativa de singularidad es
razonable para los consumidores de los valores, tales como los procesos o las herramientas de globalizacin
dedicados.

3.2.12.15. Elemento de Directiva x:XData de XAML


El elemento de directiva x:XDataXAML coloca las islas de datos XML dentro de una pgina XAML. Los elementos
XML de este elemento de directiva no se tratan como si formaran parte del espacio de nombres xmlns de WPF,
y pueden contener XML arbitrario bien formado.
Uso de elementos de objeto XAML
<XmlDataProvider ...>
<x:XData>
<elementDataRoot>
[elementData]
</elementDataRoot>...
</x:XData>
</XmlDataProvider>
Valores XAML
elementDataRoot

Necesario. El nico elemento raz de la isla de datos adjunta. Sin una raz nica,
x:XData no es vlido como origen de datos.

[elementData]

Opcional. XML que representa los datos. Cualquier nmero de elementos se puede
contener como datos de elementos, los elementos anidados se pueden contener en
otros elementos, etc., segn las reglas generales de XML.

Dependencias
El elemento x:XData se utiliza principalmente como elemento secundario de XmlDataProvider o bien, como
alternativa, como el elemento secundario de la propiedad XmlSerializer de la propiedad de XmlDataProvider
expresado en sintaxis de propiedades de objeto.
Comentarios
Los elementos XML incluidos en este elemento de directiva pueden volver a declarar todos los posibles espacios
de nombres y prefijos dentro de la isla de datos. Normalmente, los datos deberan volver a definir el xmlns
base dentro de la isla de datos de manera que sea el nuevo xmlns predeterminado (establecido en una cadena
vaca). Es lo ms fcil para las islas de datos simples, porque las expresiones XPath utilizadas para hacer
referencia y enlazar a los datos pueden evitar la inclusin de prefijos. En las islas de datos ms complejas
podran definirse varios prefijos para los datos y utilizarse un prefijo concreto para el xmlns de la raz. En este
caso, todas las referencias a las expresiones XPath debern incluir el prefijo adecuado asignado por el espacio
de nombres.
Tcnicamente, x:XData se pueden utilizar como contenido de cualquier propiedad de tipo IXmlSerializable. Sin
embargo, XmlDataProvider.XmlSerializer es la nica implementacin notable.

3.2.12.16. Gramtica de XamlName


De la especificacin XAML
XAML define la gramtica de XamlName para identificar el conjunto de identificadores simblicos vlidos
utilizados para los tipos y las propiedades.
Los valores de cadena que son del tipo XamlName deben respetar la gramtica siguiente:
XamlName ::= NameStartChar ( NameChar )*
NameStartChar ::= LetterCharacter | '_'

MCT: Luis Dueas

Pag 265 de 445

Manual de Windows Presentation Foundation


NameChar ::= NameStartChar | DecimalDigit | CombiningCharacter
LetterCharacter ::= UnicodeLu | UnicodeLl | UnicodeLo | UnicodeLt | UnicodeNl
DecimalDigit ::= UnicodeNd
CombiningCharacter ::= UnicodeMn | UnicodeMc
Que supone los valores de categora generales siguientes, tal y como estn definidos en la base de datos de
caracteres Unicode
Abrev.

Descripcin

Lu

Letra, mayscula

Ll

Letra, minscula

Lt

Letra, ttulo

Lm

Letra, modificador

Lo

Letra, otra

Mn

Marca, de no espaciado

Mc

Marca, espacio combinable

Nd

Nmero, decimal

Nl

Nmero, letra

XAML define una segunda gramtica, DottedXamlName, que se utiliza para las referencias completas a
propiedades y eventos, as como para los miembros asociados.
Los valores de cadena que son del tipo DottedXamlName deben respetar la gramtica siguiente:
DottedXamlName ::= XamlName '.' XamlName

3.2.12.17. Secuencia de Escape / Extensin de Marcado {}


Proporciona la secuencia de escape en XAML para los valores de atributo, a fin de permitir que los valores
subsiguientes del atributo se interpreten como un literal.
Uso de atributos XAML
<object ... property="{}literalValue" .../>
Uso de elementos de propiedad XAML
<object>
<object.property>
{}literalValue
</object.property>
</object>
Valores XAML
literalValue

La cadena literal a la que se aplica la secuencia de escape.

Comentarios
La secuencia de escape {} se utiliza para evitar el uso de { y } habitual para las extensiones de marcado en la
sintaxis de atributo. La propia secuencia de escape no es estrictamente una extensin de marcado y no est
respaldada por una clase. Todas las dems extensiones de marcado de XAML utilizan los caracteres { y }
reconocidos por las implementaciones del procesador XAML, a fin de permitir mediante una secuencia de
escape el control de valores de atributos que no sean literales o referencias del controlador. Slo el caso
especial de las dos llaves adyacentes se tratar como la secuencia de escape.
Esta secuencia de escape es til para establecer el carcter literal { como el primer carcter de un valor.

MCT: Luis Dueas

Pag 266 de 445

Manual de Windows Presentation Foundation


Observe que esta secuencia de escape no se puede aplicar al carcter de comillas ("). Si necesita establecer un
carcter de comillas como valor de una propiedad sin contenido, utilice la sintaxis de elementos de propiedad y
coloque las comillas como una cadena dentro del elemento de propiedad, o bien utilice una entidad de
caracteres XML. Para una propiedad de contenido, las comillas pueden constituir la totalidad del contenido.

3.2.12.18. Control de xml:lang en XAML


xml:lang es un atributo definido en XML que declara la informacin de idioma y referencia cultural de un
elemento de objeto.
Uso de atributos XAML
<object xml:lang="rfc3066lang" />
Valores XAML
rfc3066lang

Cadena derivada de la norma RFC 3066 que identifica un idioma o bien un idioma y su
regin, separados por un guin.

Comentarios
La definicin para el atributo xml:lang en XAML se deriva de xml:lang, definido como un "atributo especial" por
World Wide Web Consortium (W3C) para XML. Los elementos pueden procesar la informacin de idioma y
referencia cultural de maneras diferentes segn sus implementaciones, pero no existe ningn procesamiento
XAML predeterminado del atributo xml:lang.
El valor predeterminado del atributo xml:lang es una cadena vaca en el nivel de atributo.
El mbito de los efectos de atributo xml:lang y su valor se aplica a los elementos secundarios.
Para los elementos que son clases derivadas de FrameworkElement o FrameworkContentElement, puede utilizar
la propiedad de dependencia Language equivalente, en lugar del atributo xml:lang. La propiedad Language se
establece de manera predeterminada en "en-US" si no se establece de otro modo, ya sea mediante la
propiedad misma o bien procesando el atributo xml:lang.

3.2.12.19. Control de xml:space en XAML


xml:space es un atributo definido en XML que declara el comportamiento con respecto al espacio en blanco
significativo dentro de un elemento de objeto, para todo el contenido (texto interno) incluido en el elemento
donde se declara xml:space; su mbito abarca tambin los elementos secundarios.
Uso de atributos XAML
<object xml:space="preserve" />
O bien,
<object xml:space="default" />
Comentarios
La definicin para el atributo xml:space en XAML que incluye sus dos valores posibles se deriva de xml:space
definido como un "atributo especial" por World Wide Web Consortium (W3C) para XML.
El valor predeterminado del atributo xml:space es el valor literal "default". Cuando su valor es "default", o si no
se indica xml:space en absoluto, el comportamiento de anlisis del espacio en blanco significativo es la
administracin predeterminada.
Para conservar el espacio en blanco dentro del contenido de un elemento de objeto, especifique
xml:space="preserve" para ese elemento de objeto.
El mbito de los efectos de atributo xml:space y su valor se aplica a los elementos secundarios.

3.2.13. Extensiones de XAML de Espacio de Nombres de WPF

MCT: Luis Dueas

Pag 267 de 445

Manual de Windows Presentation Foundation

3.2.13.1. Enlazar Extensin de Marcado


Difiere un valor de la propiedad que va a ser un valor enlazado a datos, creando un objeto de expresin
intermedio e interpretando el contexto de datos que se aplica al elemento en tiempo de ejecucin.
Uso de atributos XAML
<object property="{Binding}" .../>
O bien
<object property="{Binding
bindingPropertyName1=value,
bindingPropertyName2=value,
bindingPropertyNameN=value}" ...
/>
Uso de elementos de objeto XAML
<object>
<object.property>
<Binding/>
</object.property>
</object>
O bien
<object>
<object.property>
<Binding
bindingPropertyName1="value"
bindingPropertyName2="value"
bindingPropertyNameN="value"
/>
</object.property>
</object>
Cualquiera de las propiedades enumeradas a continuacin, que se estableceran como un par propiedad=valor
en la sintaxis de atributo del ejemplo, en lugar de ello se pueden establecer como atributos del elemento
Binding, como se define en la sintaxis de elementos de objeto.
Valores XAML
bindingPropertyName#

Propiedad Name de la propiedad de Binding que se va a establecer. No todas las


propiedades de Binding se pueden establecer con la extensin de enlace y
algunas de ellas nicamente se pueden establecer mediante extensiones de
marcado anidadas adicionales. Consulte la seccin "Propiedades de enlace que se
pueden establecer con la extensin de enlace".

value

Valor en que se establecer la propiedad. El control del valor de atributo es, en


definitiva, especfico del tipo y la lgica de bindingPropertyName que se
establece.

Propiedades de enlace que se pueden establecer con la extensin de enlace


En la sintaxis mostrada en este tema se utiliza la aproximacin genrica bindingPropertyName=value, porque
hay muchas propiedades de lectura y escritura de BindingBase o Binding que se pueden establecer mediante la
sintaxis de la extensin de marcado Binding. Se pueden establecer en cualquier orden. Bsicamente, puede
establecer cero o ms de las propiedades de la lista siguiente, mediante pares propiedad=valor separados por
comas.
Varios de estos valores de propiedad requieren tipos de objetos que no admiten una conversin de tipos nativa
y, en consecuencia, exigen establecer usos de extensin de marcado adicionales en XAML como valores de
atributo. Consulte la seccin Uso de atributos XAML de la referencia correspondiente a cada propiedad para
determinar la sintaxis de atributo apropiada.

BindsDirectlyToSource: tipo Boolean, puede ser true o false.


Converter: se puede establecer en XAML, pero para ello se requiere una referencia a un objeto, como
una Extensin de marcado StaticResource.

ConverterCulture: se puede establecer como un identificador basado en normas; consulte la referencia


correspondiente a ConverterCulture.

ConverterParameter: si se pasa un tipo por referencia, requiere una referencia a objeto, como una
Extensin de marcado StaticResource.

MCT: Luis Dueas

Pag 268 de 445

Manual de Windows Presentation Foundation

ElementName: mutuamente excluyente con respecto a RelativeSource, Source; cada una de estas
propiedades representa una metodologa de enlace determinada.

FallbackValue: si se pasa un tipo por referencia, requiere una referencia a objeto, como una Extensin
de marcado StaticResource.

Mode
NotifyOnSourceUpdated
NotifyOnTargetUpdated
NotifyOnValidationError
Path.
RelativeSource: mutuamente excluyente con respecto a ElementName, Source; cada una de estas
propiedades representa una metodologa de enlace determinada.

Source: mutuamente excluyente con respecto a RelativeSource, ElementName; cada una de estas
propiedades representa una metodologa de enlace determinada.

UpdateSourceTrigger
XPath

Las siguientes son propiedades de Binding que no se pueden establecer mediante la extensin de marcado
Binding.

UpdateSourceExceptionFilter
ValidationRules
XmlNamespaceManager

Comentarios
Los marcadores de posicin bindingPropertyName proporcionados aqu corresponden a los nombres de algunas
de las propiedades que se pueden establecer declaradas de la clase Binding y las cadenas de valor son
equivalentes a cmo se estableceran esos valores de propiedades como atributos XAML dentro de un objeto
Binding declarado como un elemento XAML.
La explicacin de sintaxis alternativas incluye cmo crear enlaces equivalentes en varias sintaxis posibles, tales
como las propiedades de atributo de un elemento de objeto Binding en XAML, la sintaxis de elementos de
propiedad de Binding, o la creacin mediante procedimiento de un enlace utilizando el mtodo SetBinding o el
constructor Binding.
Nota importante:
Por lo que se refiere a la prioridad de las propiedades de dependencia, una expresin Binding es
equivalente a un valor establecido localmente. Si establece un valor local para una propiedad que
previamente tena una expresin Binding, Binding se quita totalmente.
Nota:
MultiBinding y PriorityBinding no admiten la sintaxis de extensiones XAML (aunque comparten la misma
clase BindingBase, que en realidad implementa el comportamiento de XAML para Binding).
Binding es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se necesita
que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este requisito
es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o propiedades.
Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo, que es la
convencin que permite que un procesador XAML reconozca que el atributo se debe procesar mediante una
extensin de marcado. Para obtener ms informacin, consulte Extensiones de marcado y XAML. Binding es
una extensin de marcado inusual porque la clase Binding que implementa la funcionalidad de la extensin
tambin implementa otros mtodos y propiedades. Estos otros miembros no constituyen un requisito directo
para la funcionalidad de la extensin de marcado. Estos miembros estn dirigidos a aumentar la versatilidad y
autonoma de la clase Binding para que sea capaz de resolver numerosos escenarios de enlace de datos
adems de actuar como extensin de marcado XAML.

MCT: Luis Dueas

Pag 269 de 445

Manual de Windows Presentation Foundation

3.2.13.2. Extensin de Marcado ColorConvertedBitmap


Proporciona una manera de especificar un origen de mapa de bits que no tiene un perfil incrustado. Los
contextos y perfiles de los colores se especifican mediante URI, como el URI de origen de la imagen.
Uso de atributos XAML
<object property="{ColorConvertedBitmap imageSource sourceIIC destinationIIC}" .../>
Valores XAML
imageSource

URI del mapa de bits sin perfil.

sourceIIC

URI de la configuracin del perfil de origen.

destinationIIC

URI de la configuracin del perfil de destino

Comentarios
Esta extensin de marcado se ha diseado para rellenar un conjunto relacionado de valores de propiedades del
origen de la imagen, como UriSource.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. ColorConvertedBitmap
(o ColorConvertedBitmapExtension) no se puede utilizar en la sintaxis de elementos de propiedad, porque los
valores nicamente se pueden establecer como tales en el constructor inicial, que es la cadena que sigue al
identificador de la extensin.
ColorConvertedBitmap es una extensin de marcado. Las extensiones de marcado se suelen implementar
cuando se necesita que los valores de los atributos de escape no sean valores literales o nombres de
controladores, y este requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en
determinados tipos o propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en
su sintaxis de atributo, que es la convencin que permite que un procesador XAML reconozca que el atributo se
debe procesar mediante una extensin de marcado.

3.2.13.3. Extensin de Marcado ComponentResourceKey


Define claves para recursos que se cargan desde ensamblados externos, y hace referencia a ellas. Esto permite
especificar en una bsqueda de recursos un tipo de destino de un ensamblado, en lugar de un diccionario de
recursos explcito del ensamblado.
Uso de atributos XAML (clave de valor, sintaxis compacta)
<object x:Key="{ComponentResourceKey {x:Type targetTypeName}, targetID}" .../>
Uso de atributos XAML (clave de valor, sintaxis detallada)
<object x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type targetTypeName},
ResourceID=targetID}" .../>
Uso de atributos XAML (recurso de solicitud, sintaxis compacta)
<object property="{DynamicResource {ComponentResourceKey {x:Type targetTypeName},
targetID}}" .../>
Uso de atributos XAML (recurso de solicitud, sintaxis detallada)
<object property="{DynamicResource {ComponentResourceKey
TypeInTargetAssembly={x:Type targetTypeName}, ResourceID=targetID}}" .../>
Valores XAML
targetTypeName

Nombre del tipo common language runtime (CLR) pblico definido en el ensamblado de
recursos.

targetID

Clave del recurso. Al buscar los recursos, targetID ser anlogo al x:Key (atributo) del
recurso.

Comentarios
TypeInTargetAssembly identifica un tipo que existe como tal en el ensamblado de destino donde el recurso est
definido en realidad. ComponentResourceKey se puede definir y utilizar independientemente de si se sabe con

MCT: Luis Dueas

Pag 270 de 445

Manual de Windows Presentation Foundation


exactitud dnde est definida la propiedad TypeInTargetAssembly, pero en su caso deber resolverse el tipo a
travs de los ensamblados a los que se hace referencia.
Un uso comn de ComponentResourceKey consiste en definir claves que luego se exponen como miembros de
una clase. Para este uso, se utiliza el constructor de clase ComponentResourceKey, no la extensin de
marcado.
La sintaxis de atributo se suele utilizar para la extensin de marcado ComponentResourceKey. La sintaxis
compacta mostrada se basa en la firma del constructor ComponentResourceKey.ComponentResourceKey; es
importante el orden en el que se proporcionan targetTypeName y targetID. La sintaxis detallada se basa en el
constructor predeterminado ComponentResourceKey.ComponentResourceKey y, a continuacin, establece
TypeInTargetAssembly y ResourceId de manera anloga a una verdadera sintaxis de atributo en un elemento
de objeto. En la sintaxis detallada, el orden en que se establecen las propiedades carece de importancia. La
relacin y los mecanismos de estas dos alternativas (compacta y detallada) se describen con ms detalle en el
tema Extensiones de marcado y XAML.
ComponentResourceKey se puede utilizar en la sintaxis de elementos de objeto. En este caso, es necesario
especificar el valor de las propiedades TypeInTargetAssembly y ResourceId para inicializar correctamente la
extensin.
La clase ComponentResourceKey define el control para esta extensin de marcado en la implementacin del
lector XAML de WPF.
ComponentResourceKey es una extensin de marcado. Las extensiones de marcado se suelen implementar
cuando se necesita que los valores de los atributos de escape no sean valores literales o nombres de
controladores, y este requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en
determinados tipos o propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en
su sintaxis de atributo, que es la convencin que permite que un procesador XAML reconozca que el atributo se
debe procesar mediante una extensin de marcado.

3.2.13.4. Extensin de Marcado DynamicResource


Proporciona un valor para cualquier atributo de propiedad XAML difiriendo ese valor de modo que sea una
referencia a un recurso definido. El comportamiento de bsqueda de ese recurso es anlogo a la bsqueda en
tiempo de ejecucin.
Uso de atributos XAML
<object property="{DynamicResource key}" .../>
Uso de elementos de propiedad XAML
<object>
<object.property>
<DynamicResource ResourceKey="key" .../>
</object.property>
</object>
Valores XAML
key

Clave del recurso solicitado. Esta clave la asigna x:Key inicialmente si se ha creado un recurso en el
marcado, o bien se proporciona como parmetro key al llamar a ResourceDictionary.Add si el recurso
se ha creado mediante cdigo.

Comentarios
Un DynamicResource crear una expresin temporal durante la compilacin inicial y, de este modo, diferir la
consulta de recursos hasta que el valor de recurso solicitado se necesite realmente para construir un objeto.
Potencialmente, esto puede suceder una vez cargada la pgina XAML. El valor de recurso se buscar mediante
la bsqueda de clave en todos los diccionarios de recursos activos empezando por el mbito de la pgina
actual, y reemplazar la expresin utilizada como marcador de posicin en la compilacin.
Nota importante:

MCT: Luis Dueas

Pag 271 de 445

Manual de Windows Presentation Foundation

Por lo que se refiere a la prioridad de las propiedades de dependencia, una expresin DynamicResource es
equivalente a la posicin donde se aplica la referencia dinmica al recurso. Si establece un valor local para
una propiedad que previamente tena una expresin DynamicResource como su valor local,
DynamicResource se quita totalmente.
Algunos escenarios de acceso a recursos son particularmente adecuados para DynamicResource al contrario
que una Extensin de marcado StaticResource.
La propiedad ResourceKey especificada debe corresponder a un recurso existente determinado por x:Key
(atributo) en algn nivel de la pgina, la aplicacin, los temas de control disponibles y los recursos externos o
recursos del sistema, y la bsqueda de recursos se realizar en ese orden.
Una clave de recurso puede ser cualquier cadena definida en Gramtica de XamlName. Una clave de recurso
tambin puede ser otros tipos de objeto, como un Type. Una clave Type es fundamental para el modo de
aplicar estilos a los controles mediante temas.
Las API para la bsqueda de valores de recursos, como FindResource, siguen la misma lgica de bsqueda de
recursos que DynamicResource.
La manera declarativa alternativa de hacer referencia a un recurso es hacerlo como Extensin de marcado
StaticResource.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. El token de cadena que
se proporciona despus de la cadena de identificador DynamicResource se asigna como valor de ResourceKey
de la clase de extensin DynamicResourceExtension subyacente.
DynamicResource se puede utilizar en sintaxis de elementos de objeto. En este caso, es preciso especificar el
valor de la propiedad ResourceKey.
DynamicResource tambin se puede utilizar en un uso de atributos detallado que especifica la propiedad
ResourceKey como un par propiedad=valor:
<object property="{DynamicResource ResourceKey=key}" .../>
El uso detallado suele ser til para las extensiones que tienen ms de una propiedad que se puede configurar, o
en aquellos casos en que algunas propiedades son opcionales. Dado que DynamicResource tiene una sola
propiedad configurable, que es obligatoria, este uso detallado no es habitual.
La clase DynamicResourceExtension define el control para esta extensin de marcado en la implementacin del
procesador XAML de WPF.
DynamicResource es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se
necesita que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este
requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o
propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo,
que es la convencin que permite que un procesador XAML reconozca que el atributo se debe procesar
mediante una extensin de marcado.

3.2.13.5. Extensin de Marcado RelativeSource


Especifica las propiedades de un origen de enlace de RelativeSource, para su uso en una Enlazar extensin de
marcado, o al establecer la propiedad RelativeSource de un elemento Binding establecido en XAML.
Uso de atributos XAML
<Binding RelativeSource="{RelativeSource modeEnumValue}" .../>
Uso de atributos XAML (anidados en la extensin de enlace)
<object property="{Binding RelativeSource={RelativeSource modeEnumValue} ...}" .../>
Uso de elementos de objeto XAML
<Binding>

MCT: Luis Dueas

Pag 272 de 445

Manual de Windows Presentation Foundation


<Binding.RelativeSource>
<RelativeSource Mode="modeEnumValue"/>
</Binding.RelativeSource>
</Binding>
- or
<Binding>
<Binding.RelativeSource>
<RelativeSource
Mode="FindAncestor"
AncestorType="{x:Type typeName}"
AncestorLevel="intLevel"
/>
</Binding.RelativeSource>
</Binding>
Valores XAML
modeEnumValue

Una de las aplicaciones siguientes:

Token de cadena Self; corresponde a un objeto RelativeSource creado con su


propiedad Mode establecida en Self.

Token de cadena TemplatedParent; corresponde a un objeto RelativeSource


creado con su propiedad Mode establecida en TemplatedParent.

Token de cadena PreviousData; corresponde a un objeto RelativeSource creado


con su propiedad Mode establecida en PreviousData.

FindAncestor

Vea ms adelante la informacin sobre el modo FindAncestor.

Token de cadena FindAncestor. Al utilizar este token, se entra en un modo en que


RelativeSource especifica un tipo de antecesor y, opcionalmente, un nivel del antecesor.
Corresponde a un RelativeSource creado con su propiedad Mode establecida en
FindAncestor.

typeName

Necesario para el modo FindAncestor. El nombre de un tipo, que rellena la propiedad


AncestorType.

intLevel

Opcional para el modo FindAncestor. Un nivel del antecesor (se evala en la direccin
del elemento primario en el rbol lgico).

Comentarios
En la sintaxis de elementos de objeto para el modo FindAncestor que se muestra anteriormente, la segunda
sintaxis de elementos de objeto se utiliza especficamente para el modo FindAncestor. El modo FindAncestor
requiere un valor de AncestorType. Debe establecer AncestorType como atributo utilizando una referencia de
Extensin de marcado x:Type al tipo de antecesor que se desea buscar. Se utiliza el valor AncestorType al
procesar la solicitud de enlace en tiempo de ejecucin.
Para el modo FindAncestor, la propiedad AncestorLevel opcional puede ayudar a eliminar la ambigedad en la
bsqueda del antecesor en aquellos casos en que sea posible que exista ms de un antecesor de ese tipo en el
rbol de elementos.
La clase RelativeSource define el control para esta extensin de marcado en la implementacin del procesador
XAML de WPF.
RelativeSource es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se
necesita que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este
requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o
propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo,
que es la convencin que permite que un procesador XAML reconozca que el atributo se debe procesar
mediante una extensin de marcado.

3.2.13.6. Extensin de Marcado StaticResource

MCT: Luis Dueas

Pag 273 de 445

Manual de Windows Presentation Foundation


Proporciona un valor para cualquier atributo de propiedad XAML buscando una referencia a un recurso ya
definido. El comportamiento de bsqueda de ese recurso es anlogo a la bsqueda en tiempo de carga, que
busca recursos que se cargaron previamente desde el marcado de la pgina XAML actual, as como desde otros
orgenes de la aplicacin, y genera ese valor de recurso como el valor de la propiedad de los objetos en tiempo
de ejecucin.
Uso de atributos XAML
<object property="{StaticResource key}" .../>
Uso de elementos de objeto XAML
<object>
<object.property>
<StaticResource ResourceKey="key" .../>
</object.property>
</object>
Valores XAML
key

Clave del recurso solicitado. Esta clave la asigna x:Key (atributo) inicialmente si se ha creado un
recurso en el marcado, o bien se proporciona como parmetro key al llamar a Add si el recurso se ha
creado mediante cdigo.

Comentarios
Nota importante:
StaticResource no debe intentar realizar una referencia adelantada a un recurso que se define lxicamente
en un punto posterior del archivo XAML. Esto no se admite, e incluso si una referencia de este tipo no da
lugar a ningn error, el intento de hacerla provocar una reduccin del rendimiento en tiempo de carga
cuando se busque en las tablas de hash internas que representan un objeto ResourceDictionary. Para
obtener los mejores resultados, ajuste la composicin de los diccionarios de recursos de modo que se
eviten las referencias adelantadas. Si no puede evitar una referencia adelantada, utilice la Extensin de
marcado DynamicResource en su lugar.
La propiedad ResourceKey especificada debe corresponder a un recurso existente, identificado con un x:Key
(atributo) en algn nivel de la pgina, la aplicacin, los temas de control disponibles y los recursos externos o
del sistema. La bsqueda de recursos se produce en ese orden.
Una clave de recurso puede ser cualquier cadena definida en Gramtica de XamlName. Una clave de recurso
tambin puede ser otros tipos de objeto, como un Type. Una clave Type es fundamental para determinar cmo
se pueden aplicar los estilos a los controles mediante temas, a travs de una clave de estilo implcita.
La manera declarativa alternativa de hacer referencia a un recurso es hacerlo como Extensin de marcado
DynamicResource.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. El token de cadena que
se proporciona despus de la cadena de identificador StaticResource se asigna como valor de ResourceKey de
la clase de extensin StaticResourceExtension subyacente.
StaticResource se puede utilizar en la sintaxis de elementos de objeto. En este caso, es preciso especificar el
valor de la propiedad ResourceKey.
StaticResource tambin se puede utilizar en un uso de atributos detallado que especifica la propiedad
ResourceKey como un par propiedad=valor:
<object property="{StaticResource ResourceKey=key}" .../>
El uso detallado suele ser til para las extensiones que tienen ms de una propiedad que se puede configurar, o
en aquellos casos en que algunas propiedades son opcionales. Dado que StaticResource tiene una sola
propiedad configurable, que es obligatoria, este uso detallado no es habitual.
La clase StaticResourceExtension define el control para esta extensin de marcado en la implementacin del
procesador XAML de WPF.

MCT: Luis Dueas

Pag 274 de 445

Manual de Windows Presentation Foundation


StaticResource es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se
necesita que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este
requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o
propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo,
que es la convencin que permite que un procesador XAML reconozca que el atributo se debe procesar
mediante una extensin de marcado.

3.2.13.7. Extensin de Marcado TemplateBinding


Vincula el valor de una propiedad de una plantilla de control para que sea el valor de alguna otra propiedad
expuesta en el control con plantilla.
Uso de atributos XAML
<object property="{TemplateBinding targetProperty}" .../>
Uso de atributos XAML (para la propiedad Setter de una plantilla o estilo)
<Setter Property="propertyName" Value="{TemplateBinding targetProperty}" .../>
Valores XAML
propertyName

Propiedad DependencyProperty.Name de la propiedad que se establece en la sintaxis del


establecedor.

targetProperty

Propiedad de dependencia que existe en el tipo con plantilla, especificada por el valor de
DependencyProperty.Name.
O bien,
Un nombre de propiedad "relacionada" que se define por un tipo diferente que el tipo de
destino de la plantilla. En realidad, se trata de un objeto PropertyPath.

Comentarios
TemplateBinding es una forma optimizada de enlace para los escenarios de plantilla, anlogo a la instruccin
Binding construida con {Binding RelativeSource={RelativeSource TemplatedParent}}.
RelativeSource es otra extensin de marcado que se utiliza a veces en combinacin con TemplateBinding o en
su lugar para realizar enlaces de propiedades relativos dentro de una plantilla.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. El token de cadena que
se proporciona despus de la cadena de identificador TemplateBinding se asigna como valor de Property de la
clase de extensin TemplateBindingExtension subyacente.
Podra argumentarse que la sintaxis de elementos de objeto es posible, pero no se muestra porque no tiene
ninguna aplicacin realista. TemplateBinding se utiliza para rellenar los valores dentro de los establecedores,
mediante expresiones evaluadas, y el uso de la sintaxis de elementos de objeto para que TemplateBinding
rellene la sintaxis de elementos de propiedad de <Setter.Property> aplica un grado de detalle innecesario.
TemplateBinding tambin se puede utilizar en el uso de atributos detallado que especifica la propiedad Property
como un par de propiedad=valor:
<object property="{TemplateBinding Property=targetProperty}" .../>
El uso detallado suele ser til para las extensiones que tienen ms de una propiedad que se puede configurar, o
en aquellos casos en que algunas propiedades son opcionales. Dado que TemplateBinding tiene una sola
propiedad configurable, que es obligatoria, este uso detallado no es habitual.
La clase TemplateBindingExtension define el control para esta extensin de marcado en la implementacin del
procesador XAML de WPF.
TemplateBinding es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se
necesita que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este
requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o
propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo,

MCT: Luis Dueas

Pag 275 de 445

Manual de Windows Presentation Foundation


que es la convencin que permite que un procesador XAML reconozca que el atributo se debe procesar
mediante una extensin de marcado.

3.2.13.8. Extensin de Marcado ThemeDictionary


Proporciona a los autores de controles personalizados o a las aplicaciones que integran controles de otros
fabricantes una manera de cargar los diccionarios de recursos especficos del tema para utilizarlos en la
aplicacin de estilos al control.
Uso de atributos XAML
<object property="{ThemeDictionary assemblyUri}" .../>
Uso de elementos de objeto XAML
<object>
<object.property>
<ThemeDictionary AssemblyName="assemblyUri"/>
<object.property>
<object>
Valores XAML
assemblyUri

identificador de recursos uniforme (URI) del ensamblado que contiene informacin del tema.
Normalmente, se trata de un pack URI que hace referencia a un ensamblado en el paquete
mayor. Los recursos de ensamblado y los pack URI simplifican los problemas de
implementacin.

Comentarios
Extensin

est

pensada

para

rellenar

un

solo

valor

de

propiedad

concreto:

un

valor

para

ResourceDictionary.Source.
Utilizando esta extensin, puede especificar un nico ensamblado slo de recursos que contenga algunos estilos
para utilizarlos solamente cuando se aplique el tema Aero de Windows al sistema del usuario, otros estilos
cuando est activo el tema Luna, y as sucesivamente. Utilizando esta extensin, se puede invalidar
automticamente y volver a cargar el contenido de un diccionario de recursos especfico del control de modo
que sea especfico de otro tema cuando se necesite.
La cadena assemblyUri (valor de la propiedad AssemblyName) constituye la base de una convencin de
nomenclatura que identifica qu diccionario se aplica para un tema concreto. La lgica de ProvideValue para
ThemeDictionary completa la convencin generando un identificador de recursos uniforme (URI) que seala a
una variante concreta del diccionario del tema, contenida dentro de un ensamblado de recursos precompilado.
En este artculo no se aborda plenamente la descripcin de esta convencin ni el concepto de las interacciones
de los temas con la aplicacin general de estilos, a controles o en el nivel de aplicacin o pgina. El escenario
bsico para utilizar ThemeDictionary es especificar la propiedad Source de un objeto ResourceDictionary
declarado en el nivel de la aplicacin. Cuando se proporciona un URI para el ensamblado mediante una
extensin de ThemeDictionary en lugar de utilizar un URI directo, la lgica de la extensin proporciona la lgica
de invalidacin que se aplica cada vez que cambia el tema del sistema.
La sintaxis de atributo es la que se usa ms a menudo con esta extensin de marcado. El token de cadena que
se proporciona despus de la cadena de identificador ThemeDictionary se asigna como valor de AssemblyName
de la clase de extensin ThemeDictionaryExtension subyacente.
ThemeDictionary tambin se puede utilizar en la sintaxis de elementos de objeto. En este caso, es preciso
especificar el valor de la propiedad AssemblyName.
ThemeDictionary tambin se puede utilizar en un uso de atributos detallado que especifica la propiedad Member
como un par propiedad=valor:
<object property="{ThemeDictionary AssemblyName=assemblyUri}" .../>
El uso detallado suele ser til para las extensiones que tienen ms de una propiedad que se puede configurar, o
en aquellos casos en que algunas propiedades son opcionales. Dado que ThemeDictionary tiene una sola
propiedad configurable, que es obligatoria, este uso detallado no es habitual.

MCT: Luis Dueas

Pag 276 de 445

Manual de Windows Presentation Foundation


En la implementacin del procesador XAML de WPF, el control para esta extensin de marcado se define
mediante la clase ThemeDictionaryExtension.
ThemeDictionary es una extensin de marcado. Las extensiones de marcado se suelen implementar cuando se
necesita que los valores de los atributos de escape no sean valores literales o nombres de controladores, y este
requisito es de ndole ms global que limitarse a colocar los convertidores de tipos en determinados tipos o
propiedades. Todas las extensiones de marcado de XAML utilizan los caracteres { y } en su sintaxis de atributo,
que es la convencin que permite que un procesador XAML reconozca que el atributo se debe procesar
mediante una extensin de marcado.

3.2.13.9. Sintaxis de PropertyPath de XAML


El objeto PropertyPath admite una sintaxis insertada XAML compleja para establecer varias propiedades que
toman el tipo PropertyPath como valor. En este tema se documenta la sintaxis de PropertyPath tal como se
aplica a las sintaxis de enlace y animacin.
Donde se utiliza PropertyPath
PropertyPath es un objeto comn que se utiliza en varias caractersticas de Windows Presentation Foundation
(WPF). Aunque se utilice el objeto comn PropertyPath para llevar informacin de la ruta de acceso de
propiedad, los usos para cada rea de caractersticas donde se utiliza PropertyPath como un tipo varan. Por
consiguiente, es ms prctico documentar las sintaxis caracterstica por caracterstica.
Principalmente, WPF utiliza PropertyPath para describir rutas de acceso del modelo de objetos para recorrer las
propiedades de un origen de datos de objeto y para describir rutas de acceso de destino para animaciones
concretas.
Algunas propiedades de estilo y de plantilla, tales como Setter.Property, aceptan un nombre de propiedad
completo similar, superficialmente, a un objeto PropertyPath. No obstante, no es un verdadero objeto
PropertyPath; sino que se trata de un uso de formato de cadena propietario.propiedad completo habilitado por
el procesador XAML en combinacin con el convertidor de tipos para DependencyProperty.
PropertyPath para objetos de enlace de datos
El enlace de datos es una caracterstica de WPF que permite enlazar al valor de destino de cualquier propiedad
de dependencia. Sin embargo, no es necesario que el origen de tal enlace de datos sea una propiedad de
dependencia; puede ser cualquier tipo de propiedad que reconozca el proveedor de datos correspondiente. Las
rutas de acceso de propiedad se utilizan particularmente para la clase ObjectDataProvider, que se utiliza para
obtener orgenes de enlace de objetos common language runtime (CLR) y de sus propiedades.
Observe que el enlace de datos a XML no utiliza PropertyPath, porque no utiliza Path en Binding. En su lugar,
utiliza XPath y especifica la sintaxis XPath vlida en el Modelo de objetos de documento (DOM) XML de los
datos. XPath tambin se especifica como una cadena.
Una clave para entender las rutas de acceso de propiedad en el enlace de datos es que es posible destinar el
enlace a un valor de propiedad individual o, en su lugar, enlazar a propiedades de destino que acepten listas o
colecciones. Si est enlazando colecciones, la ruta de acceso de propiedad debe hacer referencia a una
coleccin, no a elementos de coleccin individuales. El motor de enlace de datos relacionar las colecciones de
origen con el destino automticamente; el comportamiento resultante ser el rellenado de un control ListBox
con una matriz de elementos.
Propiedad nica en el objeto inmediato como contexto de datos
<Binding Path="propertyName" .../>
propertyName debe resolverse en el nombre de una propiedad que est en el DataContext actual para un uso
de Path. Si el enlace actualiza el origen, esa propiedad debe ser de lectura y escritura, y el objeto de origen
debe ser mutable.

MCT: Luis Dueas

Pag 277 de 445

Manual de Windows Presentation Foundation


Indizador nico en el objeto inmediato como contexto de datos
<Binding Path="[key]" .../>
key debe ser el ndice con tipo a un diccionario o tabla hash, o el ndice de tipo entero de una matriz. Adems,
el valor de la clave debe ser un tipo que se pueda enlazar directamente a la propiedad donde se aplica. Por
ejemplo, una tabla hash que contenga claves de cadena y valores de cadena se puede utilizar de este modo
para enlazar a Text para un objeto TextBox. O bien, si la clave apunta a una coleccin o un subndice, podra
utilizar esta sintaxis para enlazar a una propiedad de la coleccin de destino. De lo contrario, deber hacer
referencia a una propiedad concreta, mediante una sintaxis tal como <Binding Path="[key].propertyName"
.../>.
Puede especificar el tipo del ndice si es necesario.
Propiedad mltiple (destino de propiedad indirecto)
<Binding Path="propertyName.propertyName2" .../>
propertyName debe resolverse en el nombre de una propiedad que sea el objeto DataContextactual. Las
propiedades de ruta propertyName y propertyName2 pueden ser cualquier propiedad que exista en una
relacin, donde propertyName2 es una propiedad que existe en el tipo que es el valor de propertyName.
Propiedad nica, fuera del mbito de nombres de carga de XAML, reflexin en tiempo de ejecucin
<object property="ownerType.propertyName" .../>
Esta sintaxis es exclusivamente para la ruta de acceso de origen para un enlace de datos a una propiedad CLR
y solamente puede ser una ruta de acceso de paso nico en las propiedades. propertyName debe resolverse en
el nombre de una propiedad que exista en ownerType. Se espera que ownerType sea de algn tipo que pueda
encontrarse en funcin de la reflexin en tiempo real. Como tal, no es legal para certificar ownerType con un
prefijo xmlns, porque este tipo de prefijo no tiene ningn significado para la reflexin, solamente para el XAML
de tiempo de compilacin. Vea la seccin siguiente.
Propiedad nica, asociada o en espera del contexto mediante estilo o plantilla
<object property="(ownerType.propertyName)" .../>
Los parntesis indican que esta propiedad en un objeto PropertyPath se debe construir utilizando una
calificacin parcial. Puede utilizar un espacio de nombres xmlns para buscar el tipo. ownerType busca los tipos
a los que tiene acceso un procesador de XAML, mediante las declaraciones XmlnsDefinitionAttribute de cada
ensamblado. La mayora de las aplicaciones tienen el xmlns predeterminado asignado al espacio de nombres
http://schemas.microsoft.com/winfx/2006/xaml/presentation, por lo que solamente es necesario un prefijo,
habitualmente, para tipos personalizados o que estn fuera de ese espacio de nombres xmlns. propertyName
debe resolverse en el nombre de una propiedad que exista en ownerType. Esta sintaxis se utiliza generalmente
para uno de los casos siguientes:

La ruta de acceso se especifica en XAML, que est en un estilo o plantilla que no tiene un tipo de
destino especificado. Generalmente, un uso certificado no es vlido para otros casos distintos de ste,
porque en los casos sin estilo ni plantilla la propiedad existe en una instancia, no en un tipo.

La propiedad es una propiedad asociada.


Est enlazando a una propiedad esttica. En este caso, ownerType es realmente un tipo.

Para el uso como destino del guin grfico, la propiedad especificada como propertyName debe ser un objeto
DependencyProperty.
Exploracin transversal de origen (enlace a jerarquas de colecciones)
<object Path="propertyName/propertyNameX" .../>
El carcter / de esta sintaxis se utiliza para navegar dentro de un objeto de origen de datos jerrquico; se
admiten varios pasos en la jerarqua con caracteres / sucesivos. La exploracin transversal de origen tiene en
cuenta la posicin del puntero de registro actual, que se determina sincronizando los datos con la interfaz de
usuario de su vista.
Nota:
Superficialmente, esta sintaxis se parece a XPath. Una expresin XPath verdadera para enlazar a un origen
de datos XML no se utiliza como un valor Path y se debe utilizar en su lugar para la propiedad XPath
mutuamente excluyente.
Indizadores mltiples
<object Path="[index1,index2...]" .../>

MCT: Luis Dueas

Pag 278 de 445

Manual de Windows Presentation Foundation


or
<object Path="propertyName[index,index2...]" .../>
Si un objeto determinado admite varios indizadores, esos indizadores se pueden especificar en orden, de
manera similar a la sintaxis de referencia a una matriz. El objeto en cuestin puede ser el contexto actual o el
valor de una propiedad que contiene un objeto de ndice mltiple.
De forma predeterminada, los valores del indizador tienen tipos que utilizan las caractersticas del objeto
subyacente. Puede especificar el tipo del ndice si es necesario.
Sintaxis mixtas
Las sintaxis antes mostradas puede intercalarse. Por ejemplo, el siguiente es un ejemplo que crea una ruta de
acceso de propiedad al color en una posicin x, y determinada de una propiedad ColorGrid que contiene una
matriz de cuadrcula de pxeles de objetos SolidColorBrush:
<Rectangle Fill="{Binding ColorGrid[20,30].SolidColorBrushResult}" .../>
PropertyPath para destinos de animacin
La propiedad de destino de una animacin debe ser una propiedad de dependencia que admite un objeto
Freezable o un tipo primitivo. Sin embargo, la propiedad de destino de un tipo y la propiedad animada final
pueden existir en objetos diferentes. Para las animaciones, se utiliza una ruta de acceso de propiedad se utiliza
para definir la conexin entre la propiedad del objeto de destino de animacin con nombre y la propiedad de
animacin de destino deseada, explorando transversalmente relaciones de objeto-propiedad en los valores de la
propiedad.
Consideraciones generales sobre objeto-propiedad para animaciones
El tipo de valor de la propiedad que se est animando debe ser un tipo Freezable o uno primitivo. La propiedad
que inicia la ruta de acceso debe resolverse en el nombre de una propiedad de dependencia que existe en el
tipo TargetName especificado.
Para permitir la clonacin para animar un objeto Freezable que ya est inmovilizado, el objeto especificado por
TargetName debe ser de una clase derivada de FrameworkElement o FrameworkContentElement.
Propiedad nica en el objeto de destino
<animation Storyboard.TargetProperty="propertyName" .../>
propertyName debe resolverse en el nombre de una propiedad de dependencia que existe en el tipo
TargetName especificado.
Establecimiento indirecto de destinos de propiedad
<animation Storyboard.TargetProperty="propertyName.propertyName2" .../>
propertyName debe ser una propiedad que sea un tipo de valor Freezable o un tipo primitivo, que exista en el
tipo TargetName especificado.
propertyName2 debe ser el nombre de una propiedad de dependencia que exista en el objeto que es el valor de
propertyName. En otras palabras, propertyName2 debe existir como una propiedad de dependencia en el tipo
que es propertyName PropertyType.
La asignacin indirecta de destino de animaciones es necesaria debido a los estilos y plantillas aplicados. Para
usar como destino una animacin, se necesita una propiedad TargetName en un objeto de destino; x:Name o
Name establecen ese nombre. Aunque los elementos de plantilla y estilo tambin pueden tener nombres, esos
nombres solamente son vlidos dentro del mbito de nombres del estilo y de la plantilla. (Si las plantillas y los
estilos compartieran mbitos de nombres con el marcado de la aplicacin, los nombres no podran ser nicos.
Los estilos y las plantillas se comparten literalmente entre las instancias y perpetuaran nombres duplicados.)
As, si las propiedades individuales de un elemento que quiz desee animar proceden de un estilo o de una
plantilla, deber empezar con una instancia de elemento con nombre que no proceda de una plantilla de estilo
y, a continuacin, dirigirse al rbol visual de estilos o de plantillas para llegar a la propiedad que desea animar.
Por ejemplo, la propiedad Background de un objeto Panel es un objeto Brush completo (realmente, un objeto
SolidColorBrush) procedente de una plantilla de tema. Para animar completamente un objeto Brush, debera
haber un tipo BrushAnimation (probablemente uno para cada tipo de Brush ) y tal tipo no existe. Para animar
un objeto Brush, en su lugar se animan las propiedades de un tipo Brush determinado. Necesita ir de un objeto

MCT: Luis Dueas

Pag 279 de 445

Manual de Windows Presentation Foundation


SolidColorBrush a su propiedad Color para aplicar all un objeto ColorAnimation. La ruta de acceso de propiedad
para este ejemplo sera Background.Color.
Propiedades asociadas
<animation Storyboard.TargetProperty="(ownerType.propertyName)" .../>
Los parntesis indican que esta propiedad en un objeto PropertyPath se debe construir utilizando una
calificacin parcial. Puede utilizar un espacio de nombres xmlns para buscar el tipo. ownerType busca los tipos
a los que tiene acceso un procesador de XAML, mediante las declaraciones XmlnsDefinitionAttribute de cada
ensamblado. La mayora de las aplicaciones tienen el xmlns predeterminado asignado al espacio de nombres
http://schemas.microsoft.com/winfx/2006/xaml/presentation, por lo que solamente es necesario un prefijo,
habitualmente, para tipos personalizados o que estn fuera de ese espacio de nombres xmlns. propertyName
debe resolverse en el nombre de una propiedad que exista en ownerType. La propiedad especificada como
propertyName debe ser un objeto DependencyProperty. (Todas las propiedades asociadas a WPF se
implementan como propiedades de dependencia, por lo que este problema slo afecta a las propiedades
asociadas personalizadas.)
Indizadores
<animation Storyboard.TargetProperty="propertyName.propertyName2[index].
propertyName3" .../>
La mayora de las propiedades de dependencia y de los tipos Freezable no admiten un indizador. Por
consiguiente, el nico uso para un indizador en una ruta de acceso de animacin est en una posicin
intermedia entre la propiedad que inicia la cadena en el destino con nombre y la propiedad animada final. En la
sintaxis que se proporciona, eso corresponde a propertyName2. Por ejemplo, podra ser necesario el uso del
indizador si la propiedad intermedia es una coleccin como TransformGroup, en una ruta de acceso de
propiedad como RenderTransform.Children[1].Angle.
PropertyPath en cdigo
El uso de cdigo para PropertyPath, incluido cmo construir un objeto PropertyPath, se documenta en el tema
de referencia para PropertyPath.
En general, PropertyPath se ha diseado para utilizar dos constructores diferentes, uno para los usos de enlace
y los usos de animacin ms simples, y otro para los usos de animacin complejos. Utilice la firma
PropertyPath(Object)

para

los

usos

de

enlace,

donde

el

objeto

es

una

cadena.

Utilice

la

firma

PropertyPath(Object) para rutas de acceso de animacin de un paso, donde el objeto es un objeto


DependencyProperty.

Utilice

la

firma

PropertyPath(String,

array<Object>[]()[])

para

las

animaciones

complejas. Este ltimo constructor utiliza una cadena de token para el primer parmetro y una matriz de
objetos que rellenan posiciones en la cadena de token para definir una relacin de ruta de acceso de propiedad.

3.2.13.10. Atributo PresentationOptions:Freeze


Establece el estado de IsFrozen en true para el elemento Freezable contenedor. El comportamiento
predeterminado de un elemento Freezable cuyo atributo PresentationOptions:Freeze no se especifica que el
valor de IsFrozen es false en tiempo de carga y depende del comportamiento de Freezable general en tiempo
de ejecucin.
Uso de atributos XAML
<object
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions">
<freezableElement PresentationOptions:Freeze="true"/>
</object>
Valores XAML
PresentationOptions

Un prefijo de xmlns, que puede ser cualquier cadena del prefijo vlida, conforme con
la especificacin XML 1.0. El prefijo PresentationOptions se utiliza con fines de
identificacin en esta documentacin.

freezableElement

MCT: Luis Dueas

Un elemento que crea una instancia de cualquier clase derivada de Freezable.

Pag 280 de 445

Manual de Windows Presentation Foundation


Comentarios
El atributo Freeze es el nico atributo o elemento de programacin definido en el espacio de nombres
http://schemas.microsoft.com/winfx/2006/xaml/presentation/options. El atributo Freeze existe especficamente
en este espacio de nombres especial para que se pueda designar como omitible, utilizando Atributo
mc:Ignorable como parte de las declaraciones del elemento raz. El motivo por el que Freeze debe ser omitible
es que no todas las implementaciones de procesador XAML pueden inmovilizar un elemento Freezable en
tiempo de carga; esta funcin no forma parte de la especificacin XAML.
La capacidad de procesar el atributo Freeze se integra de manera especfica en el procesador XAML que procesa
XAML para las aplicaciones compiladas. No todas las clases admiten el atributo, cuya sintaxis no es extensible
ni modificable. Si est implementando su propio procesador XAML, puede optar por imitar el comportamiento
de inmovilizacin del procesador XAML de WPF al procesar el atributo Freeze de los elementos Freezable en
tiempo de carga.
Cualquier valor del atributo Freeze que no sea true (sin distincin de maysculas y minsculas) genera un error
en tiempo de carga. (Especificar el atributo Freeze como false no es un error, pero ste ya es el valor
predeterminado, de manera que establecerlo en false no surte ningn efecto.)

3.2.14. Caractersticas del Lenguaje de Compatibilidad de Marcado (mc:)


3.2.14.1. Atributo mc:Ignorable
Especifica qu prefijos de espacios de nombres XML de un archivo de marcado puede omitir un procesador
XAML. El atributo mc:Ignorable admite la compatibilidad de marcado para la asignacin de espacios de
nombres personalizados y para el control de versiones XAML.
Uso de atributos XAML (un solo prefijo)
<object
xmlns:ignorablePrefix="ignorableUri"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="ignorablePrefix"...>
<ignorablePrefix1:ThisElementCanBeIgnored/>
</object>
Uso de atributos XAML (dos prefijos)
<object
xmlns:ignorablePrefix1="ignorableUri"
xmlns:ignorablePrefix2="ignorableUri2"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="ignorablePrefix1 ignorablePrefix2"...>
<ignorablePrefix1:ThisElementCanBeIgnored/>
</object>
Valores XAML
ignorablePrefix,
ignorablePrefix1, etc.

Cualquier cadena de prefijo vlida, de acuerdo con la especificacin de


XML 1.0.

ignorableUri

Cualquier URI vlido para designar un espacio de nombres, de acuerdo


con la especificacin de XML 1.0.

ThisElementCanBeIgnored

Un elemento que las implementaciones del procesador Lenguaje de


marcado de aplicaciones extensible (XAML) pueden omitir si no se puede
resolver el tipo subyacente.

Comentarios
El prefijo de espacio de nombres mc de XML es la convencin de prefijo recomendada para su uso al asignar el
espacio

de

nombres

de

compatibilidad

con

XAML,

http://schemas.openxmlformats.org/markup-

compatibility/2006.
Los elementos o atributos cuya parte del prefijo del nombre de elemento se identifique como mc:Ignorable no
provocarn errores al procesarlos en un procesador XAML. Si ese atributo no se pudo resolver como un tipo
subyacente o una construccin de programacin, el elemento se omite. Sin embargo, tenga en cuenta que los

MCT: Luis Dueas

Pag 281 de 445

Manual de Windows Presentation Foundation


elementos omitidos pueden generar errores de anlisis adicionales correspondientes a otros requisitos del
elemento; estos errores son los efectos secundarios por el hecho de no procesar el elemento. Por ejemplo,
puede que el modelo de contenido de un elemento determinado requiera exactamente un elemento secundario,
pero si el elemento secundario especificado se encuentra en un prefijo mc:Ignorable, y adems no se puede
resolver como un tipo, entonces el procesador XAML puede provocar un error.
mc:Ignorable slo se aplica a las asignaciones de espacio de nombres a cadenas de identificador. mc:Ignorable
no se aplica a las asignaciones de espacio de nombres a ensamblados, en las que se especifica un espacio de
nombres CLR y un ensamblado (o cuyo valor predeterminado de ensamblado es la aplicacin ejecutable actual).
Si est implementando un procesador XAML, dicha implementacin no debe provocar errores de anlisis ni de
procesamiento al resolver los tipos de ningn elemento o atributo certificado por un prefijo identificado como
mc:Ignorable. No obstante, la implementacin del procesador s puede iniciar excepciones que sean el efecto
secundario del hecho de no cargar o procesar un elemento, como en el ejemplo anterior de un solo elemento
secundario.
De manera predeterminada, un procesador XAML omitir el contenido incluido en un elemento omitido. Sin
embargo, puede especificar un atributo adicional, mc:ProcessContent (Atributo), para exigir el procesamiento
continuado del contenido incluido en un elemento omitido por parte del siguiente elemento primario disponible.
Se pueden especificar varios prefijos en el atributo, utilizando uno o ms caracteres de espacio en blanco como
separadores, por ejemplo: mc:Ignorable="ignore1 ignore2".

3.2.14.2. Atributo mc:ProcessContent


Especifica los elementos XAML cuyo contenido deben procesar los elementos primarios pertinentes, aunque un
procesador XAML omita el elemento primario por tener especificado el Atributo mc:Ignorable. El atributo
mc:ProcessContent admite la compatibilidad de marcado para la asignacin de espacios de nombres
personalizados y para el control de versiones XAML.
Uso de atributos XAML
<object
xmlns:ignorablePrefix="ignorableUri"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="ignorablePrefix"...
mc:ProcessContent="ignorablePrefix:ThisElementCanBeIgnored">
<ignorablePrefix:ThisElementCanBeIgnored>
[content]
</ignorablePrefix:ThisElementCanBeIgnored>
</object>
Valores XAML
ignorablePrefix

Cualquier cadena de prefijo vlida, de acuerdo con la especificacin de XML


1.0.

ignorableUri

Cualquier URI vlido para designar un espacio de nombres, de acuerdo con la


especificacin de XML 1.0.

ThisElementCanBeIgnored

Un elemento que las implementaciones del procesador Lenguaje de marcado


de aplicaciones extensible (XAML) pueden omitir si no se puede resolver el
tipo subyacente.

[content]

ThisElementCanBeIgnored est marcado como omitible. Si el procesador de


impresin omite ese elemento, se procesa [content] mediante object.

3.3. Elementos Base


Cuatro clases clave, que son UIElement, ContentElement, FrameworkElement y FrameworkContentElement,
implementan un porcentaje importante de la funcionalidad comn de elementos disponible en la programacin
de WPF. En este SDK nos referimos a estas cuatro clases como las clases de elementos base.

MCT: Luis Dueas

Pag 282 de 445

Manual de Windows Presentation Foundation

3.3.1. Informacin General sobre Elementos Base


Un porcentaje elevado de clases de Windows Presentation Foundation (WPF) se derivan de cuatro clases a las
que se suele hacer referencia en la documentacin del SDK como clases de elementos base. Estas clases son
UIElement, FrameworkElement, ContentElement y FrameworkContentElement. La clase DependencyObject
tambin est relacionada, porque es una clase base comn de UIElement y de ContentElement
API de elementos base en las clases de WPF
Tanto UIElement como ContentElement se derivan de DependencyObject, aunque mediante rutas ligeramente
distintas. La diferencia en este nivel reside en el modo de utilizar los elementos UIElement o ContentElement en
una interfaz de usuario y en su finalidad dentro de una aplicacin. Adems, UIElement tiene Visual en su
jerarqua de clases, que es una clase que expone la compatibilidad con los grficos de bajo nivel que subyacen
en Windows Presentation Foundation (WPF). Visual proporciona un marco de trabajo de representacin para
definir zonas de la pantalla rectangulares independientes. En la prctica, UIElement es para elementos que
admitan un modelo de objetos mayor, se han diseado para representar y disear en zonas que pueden
describirse como zonas de la pantalla rectangulares y donde el modelo de contenido es deliberadamente ms
abierto, a fin de permitir diferentes combinaciones de elementos. ContentElement no se deriva de Visual; su
modelo consiste en que un elemento ContentElement sea consumido por otro elemento, como un lector o un
visor, que a su vez interpretarn los elementos y producirn el objeto Visual completo utilizado por Windows
Presentation Foundation (WPF). Algunas clases UIElement estn diseadas para ser hosts de contenido:
proporcionan hospedaje y representacin para una o ms clases ContentElement (DocumentViewer es un
ejemplo de una clase de este tipo). ContentElement se utiliza como clase base para elementos con modelos de
objetos algo ms reducidos, ms dirigidos a contenido de texto, informacin o documentos que puedan
hospedarse en un elemento UIElement.
Nivel del marco de trabajo y nivel bsico
UIElement acta como clase base para FrameworkElement, y ContentElement acta como clase base para
FrameworkContentElement. La razn de ser de este siguiente nivel de clases es la compatibilidad con el nivel
bsico de WPF, independiente del nivel de marco de trabajo de WPF; esta divisin tambin est presente en
cmo se dividen las API entre los ensamblados PresentationCore y PresentationFramework. El nivel de marco
de trabajo de WPF presenta una solucin ms completa para las necesidades de aplicaciones bsicas, que
incluye la implementacin del administrador de diseo para presentacin. El nivel bsico de WPF proporciona
una manera de utilizar gran parte de WPF sin la sobrecarga del ensamblado adicional. La distincin entre estos
niveles casi nunca es relevante en la mayora de los escenarios tpicos de programacin de aplicaciones y, en
general, es preferible pensar en las API de WPF en conjunto sin preocuparse por la diferencia entre el nivel de
marco de trabajo de WPF y el nivel bsico de WPF. Puede que necesite conocer estas distinciones de nivel si en
el diseo de una aplicacin se opta por reemplazar cantidades importantes de funcionalidades del nivel de
marco de trabajo de WPF; por ejemplo, si la solucin global ya tiene sus propias implementaciones de
composicin y diseo de interfaz de usuario (UI).
Elegir el elemento del que derivar una clase
La manera ms prctica de crear una clase personalizada que extienda WPF consiste en derivar de una de las
clases de WPF que permita obtener la mxima cantidad posible de la funcionalidad deseada a travs de la
jerarqua de clases existente. En esta seccin, se muestra una lista de funcionalidades suministradas con las
principales clases de elementos, a fin de ayudarle a decidir de qu clase se debe heredar.
Si est implementando un control, que es una de las razones ms comunes para derivar de una clase de WPF,
es probable que sea conveniente derivar de una clase que sea un control prctico, una clase base de una
familia de controles o, como mnimo, de la clase base Control.
Si no est creando un control y necesita derivar de una clase situada en un punto ms alto de la jerarqua, las
secciones siguientes le ofrecen informacin sobre las caractersticas definidas en cada clase de elementos base.

MCT: Luis Dueas

Pag 283 de 445

Manual de Windows Presentation Foundation


Si crea una clase que se deriva de DependencyObject, se hereda la funcionalidad siguiente:

Compatibilidad con GetValue y SetValue, as como con el sistema de propiedades general.


Capacidad para utilizar propiedades de dependencia y propiedades asociadas, que se implementan
como propiedades de dependencia.

Si crea una clase que se deriva de UIElement, adems de la funcionalidad proporcionada por DependencyObject
heredar la siguiente:

Compatibilidad bsica para valores de propiedades animadas.


Compatibilidad con eventos de entrada bsicos y compatibilidad con comandos.
Mtodos virtuales que se pueden invalidar para proporcionar informacin a un sistema de diseo.

Si crea una clase que se deriva de FrameworkElement, adems de la funcionalidad proporcionada por
UIElement heredar la siguiente:

Compatibilidad con la aplicacin de estilos y los guiones grficos.


Compatibilidad con enlaces de datos.
Compatibilidad con referencias de recurso dinmicas.
Compatibilidad con la herencia de valores de propiedades y otros marcadores de los metadatos que
ayudan a comunicar condiciones sobre las propiedades a los servicios del marco de trabajo, tales como
el enlace de datos, los estilos o la implementacin del diseo en el marco de trabajo.

El concepto de rbol lgico.


Compatibilidad con la implementacin prctica del nivel de marco de trabajo de WPF del sistema del
diseo, incluida una invalidacin del mtodo OnPropertyChanged capaz de detectar cambios en las
propiedades que influyen en el diseo.

Si crea una clase que se deriva de ContentElement, adems de la funcionalidad proporcionada por
DependencyObject heredar la siguiente:

Compatibilidad con las animaciones.


Compatibilidad con eventos de entrada bsicos y compatibilidad con comandos.

Si crea una clase que se deriva de FrameworkContentElement, adems de la funcionalidad proporcionada por
ContentElement obtendr la siguiente:

Compatibilidad con la aplicacin de estilos y los guiones grficos.


Compatibilidad con enlaces de datos.
Compatibilidad con referencias de recurso dinmicas.
Compatibilidad con la herencia de valores de propiedades y otros marcadores de los metadatos que
ayudan a comunicar condiciones sobre las propiedades a los servicios del marco de trabajo, tales como
el enlace de datos, los estilos o la implementacin del diseo en el marco de trabajo.

No se hereda el acceso a las modificaciones del sistema de diseo (como ArrangeOverride). Las
implementaciones del sistema de diseo nicamente estn disponibles en FrameworkElement. Sin
embargo, s heredar una invalidacin de OnPropertyChanged capaz de detectar los cambios de
propiedades que influyen en el diseo y comunicrselas a cualquier host de contenido.

Se documentan modelos de contenido para gran variedad de clases. El modelo de contenido de una clase es
uno de los factores posibles que deben tenerse en cuenta al buscar la clase adecuada para derivarla.
Otras clases base
DispatcherObject
DispatcherObject proporciona compatibilidad con el modelo de subprocesos de WPF y permite asociar todos los
objetos creados para aplicaciones de WPF a Dispatcher. Aunque no se derive de UIElement, DependencyObject
o de Visual, puede ser conveniente derivar de DispatcherObject para obtener esta compatibilidad con el modelo
de subprocesos.
Visual

MCT: Luis Dueas

Pag 284 de 445

Manual de Windows Presentation Foundation


Visual implementa el concepto de objeto 2D que, en general, requiere la presentacin visual en una zona con
una forma ms o menos rectangular. La representacin real de Visual tiene lugar en otras clases (no es
autnoma), pero la clase Visual proporciona un tipo conocido que los procesos de representacin utilizan en
varios niveles. Visual implementa las pruebas de posicionamiento, pero no expone eventos que comunican los
casos positivos de ello (stos se encuentran en UIElement).
Freezable
Freezable simula la inmutabilidad en un objeto mutable; para ello, proporciona un medio de generar copias del
mismo cuando se necesita o desea un objeto inmutable por motivos de rendimiento. El tipo Freezable
proporciona una base comn para algunos elementos de grficos, como geometras y pinceles, as como
animaciones. Cabe destacar que un objeto Freezable no es un objeto Visual; puede contener propiedades que
se convierten en subpropiedades al aplicar el objeto Freezable para rellenar el valor de una propiedad de otro
objeto, subpropiedades que pueden afectar a la representacin.
Animatable
Animatable es una clase derivada de Freezable que agrega de manera especfica la capa de control de
animacin y algunos miembros de utilidad, a fin de permitir que las propiedades actualmente animadas se
distingan de las propiedades no animadas.
Control
Control es la clase base dirigida al tipo de objeto que se denomina o bien control o bien componente,
dependiendo de la tecnologa. En general, las clases de controles de WPF son aqullas que representan
directamente un control de interfaz de usuario o que participan estrechamente en la composicin de controles.
La funcionalidad primaria habilitada por Control es la creacin de plantillas de controles.

3.3.2. Informacin General sobre Objetos Freezable


En este tema se describe cmo utilizar y crear con eficacia objetos Freezable, que proporcionan caractersticas
especiales que pueden ayudar a mejorar el rendimiento de la aplicacin. Algunos ejemplos de objetos Freezable
son los pinceles, los lpices, las transformaciones, las geometras y las animaciones.
Este tema contiene las siguientes secciones:
Qu es un objeto Freezable?
Un objeto Freezable es un tipo especial de objeto que tiene dos estados: no inmovilizado e inmovilizado.
Cuando no est inmovilizado, un objeto Freezable parece comportarse como cualquier otro objeto. Cuando est
inmovilizado, un objeto Freezable ya no se puede modificar.
Un objeto Freezable proporciona un evento Changed para notificar a los observadores todas las modificaciones
del objeto. Inmovilizar un objeto Freezable, puede mejorar su rendimiento, porque ya no es preciso dedicar
recursos a las notificaciones de cambio. Un objeto Freezable inmovilizado tambin se puede compartir entre
subprocesos, lo que no sucede si el objeto Freezable no est inmovilizado.
Aunque la clase Freezable tiene muchas aplicaciones, la mayora de los objetos Freezable de Windows
Presentation Foundation (WPF) estn relacionados con el subsistema de grficos.
La clase Freezable facilita el uso de algunos objetos del sistema de grficos y puede ayudar a mejorar el
rendimiento de la aplicacin. Algunos ejemplos de tipos que heredan de Freezable son las clases Brush,
Transform y Geometry. Dado que contienen recursos no administrados, el sistema debe supervisar estos
objetos por si se producen modificaciones y, a continuacin, actualizar sus recursos no administrados
correspondientes cuando se produce un cambio en el objeto original. Aunque no se modifique realmente un
objeto del sistema de grficos, el sistema debe dedicar parte de sus recursos a supervisarlo, por si acaso
cambia.

MCT: Luis Dueas

Pag 285 de 445

Manual de Windows Presentation Foundation


Por ejemplo, supongamos que se crea un pincel SolidColorBrush y se utiliza para pintar el fondo de un botn.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;
Al representar el botn, el subsistema de grficos de WPF utiliza la informacin que se proporciona para pintar
un grupo de pxeles y crear el aspecto de un botn. Aunque se ha utilizado un pincel de color slido para
describir cmo se debe pintar el botn, en realidad este pincel de color slido no es el que se encarga de pintar.
El sistema de grficos genera objetos rpidos de bajo nivel para el botn y el pincel, y son esos objetos los que
realmente aparecen en la pantalla.
Si modifica el pincel, ser preciso volver a generar estos objetos de bajo nivel. La clase Freezable es lo que
proporciona a un pincel la capacidad de buscar sus objetos generados de bajo nivel correspondientes y
actualizarlos cuando cambian. Cuando esta capacidad est habilitada, se dice que el pincel "no est
inmovilizado".
El mtodo Freeze de un objeto Freezable permite deshabilitar esta capacidad de actualizacin automtica.
Puede utilizar este mtodo para "inmovilizar" el pincel, es decir, para que no se pueda modificar.
Nota:
No todos los objetos Freezable se pueden inmovilizar. Para evitar que se inicie una excepcin
InvalidOperationException, compruebe el valor de la propiedad CanFreeze del objeto Freezable, a fin de
determinar si se puede inmovilizar antes de intentar inmovilizarlo.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
Cuando ya no es necesario modificar un objeto Freezable, inmovilizarlo aporta ventajas de rendimiento. Si en el
ejemplo anterior inmoviliza el pincel, el sistema de grficos ya no tendr que supervisarlo por si cambia.
Adems, el sistema de grficos puede realizar otras optimizaciones, porque sabe que el pincel no cambiar.
Nota:
Para mayor comodidad, los objetos Freezable permanecen no inmovilizados hasta que se inmovilizan de
manera explcita.
Utilizar Freezables
Utilizar un objeto Freezable no inmovilizado es igual que utilizar cualquier otro tipo de objeto. En el ejemplo
siguiente, se cambia el color de SolidColorBrush del amarillo al rojo despus de utilizarlo para pintar el fondo de
un botn. El sistema de grficos acta en segundo plano para cambiar automticamente el botn del amarillo al
rojo la prxima vez que se actualiza la pantalla.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
myButton.Background = myBrush;
// Changes the button's background to red.
myBrush.Color = Colors.Red;
Inmovilizar un objeto Freezable
Para impedir que un objeto Freezable, se pueda modificar, llame a su mtodo Freeze. Al inmovilizar un objeto
que contiene objetos Freezable, stos ltimos se inmovilizan tambin. Por ejemplo, si inmoviliza una
PathGeometry, las figuras y los segmentos que contiene tambin se inmovilizan.
No se puede inmovilizar un objeto Freezable en ninguna de las situaciones siguientes:

Tiene propiedades animadas o enlazadas a datos.


Tiene propiedades establecidas por un recurso dinmico.
Contiene subobjetos Freezable que no se pueden inmovilizar.

Si estas condiciones no se cumplen y tampoco tiene previsto modificar un objeto Freezable, entonces es
conveniente inmovilizarlo para obtener las ventajas de rendimiento descritas anteriormente.

MCT: Luis Dueas

Pag 286 de 445

Manual de Windows Presentation Foundation


Cuando se llama al mtodo Freeze de un objeto Freezable, ste ya no se puede modificar. Si intenta modificar
un objeto inmovilizado, se inicia una excepcin InvalidOperationException. Al ejecutar el cdigo siguiente se
inicia una excepcin, porque se intenta modificar el pincel despus de inmovilizarlo.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
try {
// Throws an InvalidOperationException, because the brush is frozen.
myBrush.Color = Colors.Red;
}catch(InvalidOperationException ex)
{
MessageBox.Show("Invalid operation: " + ex.ToString());
}
Para evitar que se inicie esta excepcin, puede utilizar el mtodo IsFrozen para determinar si un objeto
Freezable est inmovilizado.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
if (myBrush.IsFrozen) // Evaluates to true.
{
// If the brush is frozen, create a clone and
// modify the clone.
SolidColorBrush myBrushClone = myBrush.Clone();
myBrushClone.Color = Colors.Red;
myButton.Background = myBrushClone;
}
else
{
// If the brush is not frozen,
// it can be modified directly.
myBrush.Color = Colors.Red;
}
En el ejemplo de cdigo anterior, se ha realizado una copia modificable de un objeto inmovilizado mediante el
mtodo Clone. En la seccin siguiente se explica la clonacin con ms detalle.
Nota: puesto que los objetos Freezable inmovilizados no se pueden animar, el sistema de animacin crea
automticamente clones modificables de los objetos Freezable inmovilizados si intenta animarlos con
Storyboard. Para eliminar la sobrecarga de rendimiento causada por la clonacin, no inmovilice los objetos si
tiene previsto animarlos.
Inmovilizar mediante marcado
Para inmovilizar un objeto Freezable declarado en el marcado, se utiliza el atributo PresentationOptions:Freeze.
En el ejemplo siguiente, se declara SolidColorBrush como recurso de pgina y se inmoviliza. A continuacin, se
utiliza para establecer el fondo de un botn.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions">
<Page.Resources>
<!-- This resource is frozen. -->
<SolidColorBrush
x:Key="MyBrush"
PresentationOptions:Freeze="True"
Color="Red" />
</Page.Resources>
<StackPanel>
<Button Content="A Button"
Background="{StaticResource MyBrush}">
</Button>
</StackPanel>
</Page>

MCT: Luis Dueas

Pag 287 de 445

Manual de Windows Presentation Foundation


Para utilizar el atributo Freeze, debe efectuar la asignacin al espacio de nombres de opciones de presentacin:
http://schemas.microsoft.com/winfx/2006/xaml/presentation/options.

PresentationOptions

es

el

prefijo

recomendado para asignar este espacio de nombres:


xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
Dado que no todos los lectores de XAML reconocen este atributo, se recomienda utilizar Atributo mc:Ignorable
para marcar el atributo Presentation:Freeze como omitible:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="PresentationOptions"
"Liberar" un objeto Freezable
Una vez inmovilizado, un objeto Freezable nunca se puede modificar ni liberar; sin embargo, s puede crear un
clon no inmovilizado mediante el mtodo Clone o CloneCurrentValue.
En el ejemplo siguiente, se establece el fondo de un botn con un pincel y, a continuacin, se inmoviliza el
pincel. Se realiza una copia no inmovilizada del pincel mediante el mtodo Clone. El clon se modifica y se utiliza
para cambiar el fondo del botn del amarillo al rojo.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
// Freezing a Freezable before it provides
// performance improvements if you don't
// intend on modifying it.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
// If you need to modify a frozen brush,
// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();
// Changing myBrushClone does not change
// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;
// Replacing myBrush with myBrushClone
// makes the button change to red.
myButton.Background = myBrushClone;
Nota:
Sea cual sea el mtodo de clonacin que utilice, las animaciones nunca se copian en el nuevo objeto
Freezable.
Los mtodos Clone y CloneCurrentValue generan copias en profundidad del objeto Freezable. Si el objeto
Freezable contiene otros objetos Freezable inmovilizados, stos tambin se clonan y son modificables. Por
ejemplo, si clona un PathGeometry inmovilizado para poder modificarlo, las figuras y los segmentos que
contiene tambin se copian y se pueden modificar.
Crear su propia clase Freezable
Una clase que se deriva de Freezable incluye las siguientes caractersticas.

Estados especiales: estado de slo lectura (inmovilizado) y estado modificable.


Seguridad de subprocesos: un objeto Freezable inmovilizado se puede compartir entre subprocesos.
Notificacin de los cambios detallados: a diferencia de otros objetos DependencyObject, los objetos
Freezable proporcionan notificaciones de cambios cuando cambian los valores de la subpropiedad.

Clonacin fcil: la clase Freezable ya ha implementado varios mtodos que generan clones perfectos.

Un objeto Freezable es un tipo de DependencyObject y, por consiguiente, utiliza el sistema de propiedades de


dependencia. No es necesario que las propiedades de clase sean propiedades de dependencia, pero al utilizar
propiedades de dependencia se reduce la cantidad de cdigo que hay que escribir, porque la clase Freezable se
ha diseado teniendo en cuenta las propiedades de dependencia.
Cada subclase de Freezable debe invalidar el mtodo CreateInstanceCore. Si la clase utiliza propiedades de
dependencia para todos los datos, con esto basta.

MCT: Luis Dueas

Pag 288 de 445

Manual de Windows Presentation Foundation


Si la clase contiene miembros de datos de propiedades que no son de dependencia, tambin debe invalidar los
mtodos siguientes:

CloneCore
CloneCurrentValueCore
GetAsFrozenCoree
GetCurrentValueAsFrozenCore
FreezeCore

Tambin debe observar las reglas siguientes para obtener acceso a los miembros de datos que no son
propiedades de dependencia y escribir en ellos:

Al principio de cualquier API que lee miembros de datos de propiedades que no son de dependencia,
llame al mtodo ReadPreamble.

Al principio de cualquier API que escribe miembros de datos de propiedades que no son de
dependencia, llame al mtodo WritePreamble. (Despus de llamar al mtodo WritePreamble de una
API, ya no necesita realizar una llamada adicional a ReadPreamble si tambin va a leer miembros de
datos de propiedades que no son de dependencia.)

Llame al mtodo WritePostscript antes de salir de los mtodos que escriben en los miembros de datos
de propiedades que no son de dependencia.

Si la clase contiene miembros de datos de propiedades que no son de dependencia y que son objetos
DependencyObject, tambin debe llamar al mtodo OnFreezablePropertyChanged cada vez que cambie uno de
sus valores, aunque establezca el miembro en null.
Nota:
Es muy importante que comience cada mtodo de Freezable que invalide con una llamada a la
implementacin base.

3.3.3. Informacin General sobre Alineacin, Mrgenes y Relleno


La clase FrameworkElement expone varias propiedades que se utilizan para colocar los elementos secundarios
de forma precisa. En este tema se analizan cuatro de las propiedades ms importantes: HorizontalAlignment,
Margin, Padding y VerticalAlignment. Es importante comprender los efectos de estas propiedades, ya que
proporcionan la base para controlar la posicin de los elementos en las aplicaciones Windows Presentation
Foundation (WPF).
Introduccin al posicionamiento de los elementos
Hay numerosas maneras de colocar los elementos mediante WPF. Sin embargo, lograr el diseo ideal va ms
all de la simple eleccin del elemento Panel adecuado. El control preciso de la posicin requiere estar
familiarizado con las propiedades HorizontalAlignment, Margin, Padding y VerticalAlignment.
En la ilustracin siguiente se muestra un escenario de diseo que utiliza varias propiedades de posicin.

A primera vista, podra parecer que los elementos Button de esta ilustracin estn colocados de forma
aleatoria. Sin embargo, sus posiciones estn controladas precisamente por medio de una combinacin de
mrgenes, alineaciones y relleno.
En el ejemplo siguiente se describe cmo crear el diseo de la ilustracin anterior. Un elemento Border
encapsula un elemento StackPanel primario, con un valor Padding de 15 pxeles independientes del dispositivo.

MCT: Luis Dueas

Pag 289 de 445

Manual de Windows Presentation Foundation


Esto se debe a la banda LightBlue estrecha que rodea al elemento StackPanel secundario. Los elementos
secundarios de StackPanel se utilizan para mostrar cada una de las diversas propiedades de posicin que se
detallan en este tema. Se usan tres elementos Button para demostrar las propiedades Margin y
HorizontalAlignment.
WindowTitle = "Margins, Padding and Alignment Sample"
'Add a Border.
Dim myBorder As New Border()
myBorder.Background = Brushes.LightBlue
myBorder.BorderBrush = Brushes.Black
myBorder.Padding = New Thickness(15)
myBorder.BorderThickness = New Thickness(2)
Dim myStackPanel As New StackPanel()
myStackPanel.Background = Brushes.White
myStackPanel.HorizontalAlignment = Windows.HorizontalAlignment.Center
myStackPanel.VerticalAlignment = Windows.VerticalAlignment.Top
Dim myTextBlock As New TextBlock()
myTextBlock.Margin = New Thickness(5, 0, 5, 0)
myTextBlock.FontSize = 18
myTextBlock.HorizontalAlignment = Windows.HorizontalAlignment.Center
myTextBlock.Text = "Alignment, Margin and Padding Sample"
Dim myButton1 As New Button()
myButton1.HorizontalAlignment = Windows.HorizontalAlignment.Left
myButton1.Margin = New Thickness(20)
myButton1.Content = "Button 1"
Dim myButton2 As New Button()
myButton2.HorizontalAlignment = Windows.HorizontalAlignment.Right
myButton2.Margin = New Thickness(10)
myButton2.Content = "Button 2"
Dim myButton3 As New Button()
myButton3.HorizontalAlignment = Windows.HorizontalAlignment.Stretch
myButton3.Margin = New Thickness(0)
myButton3.Content = "Button 3"
'Add child elements to the parent StackPanel.
myStackPanel.Children.Add(myTextBlock)
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myStackPanel.Children.Add(myButton3)
'Add the StackPanel as the lone Child of the Border.
myBorder.Child = myStackPanel
' Add the Canvas as the lone Child of the Border
myBorder.Child = myStackPanel
Me.Content = myBorder
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="Margins, Padding and Alignment Sample">
<Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" Padding="15">
<StackPanel Background="White" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock Margin="5,0,5,0" FontSize="18" HorizontalAlignment="Center">
Alignment, Margin and Padding Sample</TextBlock>
<Button HorizontalAlignment="Left" Margin="20">Button 1</Button>
<Button HorizontalAlignment="Right" Margin="10">Button 2</Button>
<Button HorizontalAlignment="Stretch" Margin="0">Button 3</Button>
</StackPanel>
</Border>
</Page>
En el diagrama siguiente se proporciona una vista en primer plano de las distintas propiedades de posicin que
se utilizan en el ejemplo anterior. En las secciones siguientes de este tema se describe con mayor detalle cmo
utilizar cada propiedad de posicin.

Introduccin a las propiedades de alineacin


Las propiedades HorizontalAlignment y VerticalAlignment describen cmo debera colocarse un elemento
secundario dentro del espacio de diseo asignado del elemento primario. Al combinar estas propiedades, puede
colocar los elementos secundarios de forma precisa. Por ejemplo, los elementos secundarios de DockPanel
pueden especificar cuatro alineaciones horizontales diferentes: Left, Right, Center o Stretch para rellenar el
espacio disponible. Para la posicin vertical existen valores similares.

MCT: Luis Dueas

Pag 290 de 445

Manual de Windows Presentation Foundation

Nota:
Las propiedades Height y Width establecidas explcitamente en un elemento tienen prioridad sobre el valor
de propiedad Stretch. Al intentar establecer Height, Width y HorizontalAlignment en un valor de Stretch, la
solicitud de Stretch se pasa por alto.
Propiedad HorizontalAlignment
La propiedad HorizontalAlignment declara las caractersticas de alineacin horizontal que se aplican a los
elementos secundarios. En la tabla siguiente se muestra cada uno de los valores posibles de la propiedad
HorizontalAlignment.
Miembro

Descripcin

Left

Los elementos secundarios se alinean a la izquierda del espacio de diseo


asignado del elemento primario.

Center

Los elementos secundarios se alinean al centro del espacio de diseo asignado del
elemento primario.

Right

Los elementos secundarios se alinean a la derecha del espacio de diseo asignado


del elemento primario.

Stretch (valor
predeterminado)

Los elementos secundarios se expanden para rellenar el espacio de diseo


asignado del elemento primario. Los valores explcitos de las propiedades Width y
Height tienen prioridad.

En el ejemplo siguiente se muestra cmo aplicar la propiedad HorizontalAlignment a elementos Button. Se


muestra cada valor de atributo, para ilustrar mejor los distintos comportamientos de representacin.
Dim myButton1 As New Button()
myButton1.HorizontalAlignment = Windows.HorizontalAlignment.Left
myButton1.Margin = New Thickness(20)
myButton1.Content = "Button 1"
Dim myButton2 As New Button()
myButton2.HorizontalAlignment = Windows.HorizontalAlignment.Right
myButton2.Margin = New Thickness(10)
myButton2.Content = "Button 2"
Dim myButton3 As New Button()
myButton3.HorizontalAlignment = Windows.HorizontalAlignment.Center
myButton3.Margin = New Thickness(0)
myButton3.Content = "Button 3"
Dim myButton4 As New Button()
myButton4.HorizontalAlignment = Windows.HorizontalAlignment.Stretch
myButton4.Content = "Button 4 (Stretch)"
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowTitle="HorizontalAlignment Sample">
<Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" Padding="15">
<StackPanel Background="White" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock Margin="5,0,5,0" FontSize="18" HorizontalAlignment="Center">
HorizontalAlignment Sample</TextBlock>
<Button HorizontalAlignment="Left">Button 1 (Left)</Button>
<Button HorizontalAlignment="Right">Button 2 (Right)</Button>
<Button HorizontalAlignment="Center">Button 3 (Center)</Button>
<Button HorizontalAlignment="Stretch">Button 4 (Stretch)</Button>
</StackPanel>
</Border>
</Page>
El cdigo anterior produce un diseo similar a la imagen siguiente. Los efectos de posicionamiento de cada
valor de HorizontalAlignment se ven en la ilustracin.

Propiedad VerticalAlignment
La propiedad VerticalAlignment describe las caractersticas de alineacin vertical que se aplican a los elementos
secundarios. En la tabla siguiente se muestra cada uno de los valores posibles para la propiedad
VerticalAlignment.

MCT: Luis Dueas

Pag 291 de 445

Manual de Windows Presentation Foundation

Miembro

Descripcin

Top

Los elementos secundarios se alinean con la parte superior del espacio de diseo
asignado del elemento primario.

Center

Los elementos secundarios se alinean al centro del espacio de diseo asignado del
elemento primario.

Bottom

Los elementos secundarios se alinean con la parte inferior del espacio de diseo
asignado del elemento primario.

Stretch (valor
predeterminado)

Los elementos secundarios se expanden para rellenar el espacio de diseo


asignado del elemento primario. Los valores explcitos de las propiedades Width y
Height tienen prioridad.

En el ejemplo siguiente se muestra cmo aplicar la propiedad VerticalAlignment a elementos Button. Se


muestra cada valor de atributo, para ilustrar mejor los distintos comportamientos de representacin. En este
ejemplo, se usa como elemento primario un elemento Grid con lneas de cuadrcula visibles, para ilustrar mejor
el comportamiento de cada valor de propiedad en el diseo.
Dim myTextBlock As New TextBlock()
myTextBlock.FontSize = 18
myTextBlock.HorizontalAlignment = Windows.HorizontalAlignment.Center
myTextBlock.Text = "VerticalAlignment Sample"
Grid.SetRow(myTextBlock, 0)
Dim myButton1 As New Button()
myButton1.VerticalAlignment = Windows.VerticalAlignment.Top
myButton1.Content = "Button 1 (Top)"
Grid.SetRow(myButton1, 1)
Dim myButton2 As New Button()
myButton2.VerticalAlignment = Windows.VerticalAlignment.Bottom
myButton2.Content = "Button 2 (Bottom)"
Grid.SetRow(myButton2, 2)
Dim myButton3 As New Button()
myButton3.VerticalAlignment = Windows.VerticalAlignment.Center
myButton3.Content = "Button 3 (Center)"
Grid.SetRow(myButton3, 3)
Dim myButton4 As New Button()
myButton4.VerticalAlignment = Windows.VerticalAlignment.Stretch
myButton4.Content = "Button 4 (Stretch)"
Grid.SetRow(myButton4, 4)
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowTitle="VerticalAlignment Sample">
<Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" Padding="15">
<Grid Background="White" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" FontSize="18"
HorizontalAlignment="Center">VerticalAlignment Sample</TextBlock>
<Button Grid.Row="1" Grid.Column="0" VerticalAlignment="Top">Button 1
(Top)</Button>
<Button Grid.Row="2" Grid.Column="0" VerticalAlignment="Bottom">Button 2
(Bottom)</Button>
<Button Grid.Row="3" Grid.Column="0" VerticalAlignment="Center">Button 3
(Center)</Button>
<Button Grid.Row="4" Grid.Column="0" VerticalAlignment="Stretch">Button 4
(Stretch)</Button>
</Grid>
</Border>
</Page>
El cdigo anterior produce un diseo similar a la imagen siguiente. Los efectos de posicionamiento de cada
valor de VerticalAlignment se ven en la ilustracin.

MCT: Luis Dueas

Pag 292 de 445

Manual de Windows Presentation Foundation


Introduccin a las propiedades de margen
La propiedad Margin describe la distancia entre un elemento y su elemento secundario o del mismo nivel. Los
valores de Margin pueden ser uniformes, mediante el uso de sintaxis como Margin="20". Con esta sintaxis, se
aplicara al elemento un valor de Margin uniforme de 20 pxeles independientes del dispositivo. Los valores de
Margin tambin pueden adoptar la forma de cuatro valores distintos, cada uno de los cuales describira un
margen distinto para aplicar a la izquierda, a la parte superior, a la derecha y a la parte inferior (en ese orden),
como Margin="0,10,5,25". El uso apropiado de la propiedad Margin permite obtener un control muy preciso de la
posicin de representacin de un elemento y la posicin de representacin de sus elementos contiguos y
secundarios.
Nota:
Un margen distinto de cero aplica espacio fuera del ActualWidth y ActualHeight del elemento.
En el ejemplo siguiente se muestra cmo aplicar mrgenes uniformes alrededor de un grupo de elementos
Button. La separacin de los botones es uniforme, con un bfer de margen de diez pxeles en cada direccin.
Dim myButton7 As New Button
myButton7.Margin = New Thickness(10)
myButton7.Content = "Button 7"
Dim myButton8 As New Button
myButton8.Margin = New Thickness(10)
myButton8.Content = "Button 8"
Dim myButton9 As New Button
myButton9.Margin = New Thickness(10)
myButton9.Content = "Button 9"
<Button Margin="10">Button 7</Button>
<Button Margin="10">Button 8</Button>
<Button Margin="10">Button 9</Button>
En muchos casos no es apropiado un margen uniforme. Si es as, se puede aplicar un espacio no uniforme. En
el ejemplo siguiente se muestra cmo aplicar un espacio de margen no uniforme a los elementos secundarios.
Los mrgenes se describen por este orden: izquierdo, superior, derecho, inferior.
Dim myButton1 As New Button
myButton1.Margin = New Thickness(0, 10, 0, 10)
myButton1.Content = "Button 1"
Dim myButton2 As New Button
myButton2.Margin = New Thickness(0, 10, 0, 10)
myButton2.Content = "Button 2"
Dim myButton3 As New Button
myButton3.Margin = New Thickness(0, 10, 0, 10)
<Button Margin="0,10,0,10">Button 1</Button>
<Button Margin="0,10,0,10">Button 2</Button>
<Button Margin="0,10,0,10">Button 3</Button>
Introduccin a la propiedad de relleno
El relleno es similar a Margin en muchos aspectos. La propiedad Padding se expone slo en algunas clases,
principalmente por comodidad: Block, Border, Control y TextBlock son ejemplos de clases que exponen una
propiedad Padding. La propiedad Padding amplia el tamao eficaz de un elemento secundario segn el valor
Thickness especificado.
En el ejemplo siguiente se muestra cmo aplicar Padding a un elemento Border primario.
Dim myBorder As New Border
myBorder.Background = Brushes.LightBlue
myBorder.BorderBrush = Brushes.Black
myBorder.BorderThickness = New Thickness(2)
myBorder.CornerRadius = New CornerRadius(45)
myBorder.Padding = New Thickness(25)
<Border Background="LightBlue"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="45"
Padding="25">
Utilizar alineacin, mrgenes y relleno en una aplicacin
HorizontalAlignment, Margin, Padding y VerticalAlignment ofrecen el control de posicionamiento necesario para
crear una interfaz de usuario (UI) compleja. Puede utilizar los efectos de cada propiedad para cambiar la

MCT: Luis Dueas

Pag 293 de 445

Manual de Windows Presentation Foundation


posicin de los elementos secundarios, lo que proporciona flexibilidad para lograr aplicaciones y experiencias de
usuario dinmicas.
En el ejemplo siguiente se muestra cada uno de los conceptos que se detallan en este tema. Partiendo de la
infraestructura del primer ejemplo de este tema, en este ejemplo se agrega un elemento Grid como elemento
secundario del elemento Border que veamos en el primer ejemplo. Se aplica Padding al elemento Border
primario. Se usa Grid para dividir el espacio entre tres elementos StackPanel secundarios. Se vuelven a usar
elementos Button para mostrar los distintos efectos de Margin y HorizontalAlignment. Se agregan elementos
TextBlock a cada ColumnDefinition para mejorar la definicin de las distintas propiedades aplicadas a los
elementos Button en cada columna.
Dim myBorder As New Border
myBorder.Background = Brushes.LightBlue
myBorder.BorderBrush = Brushes.Black
myBorder.BorderThickness = New Thickness(2)
myBorder.CornerRadius = New CornerRadius(45)
myBorder.Padding = New Thickness(25)
'Define the Grid.
Dim myGrid As New Grid
myGrid.Background = Brushes.White
myGrid.ShowGridLines = True
'Define the Columns.
Dim myColDef1 As New ColumnDefinition
myColDef1.Width = New GridLength(1, GridUnitType.Auto)
Dim myColDef2 As New ColumnDefinition
myColDef2.Width = New GridLength(1, GridUnitType.Star)
Dim myColDef3 As New ColumnDefinition
myColDef3.Width = New GridLength(1, GridUnitType.Auto)
'Add the ColumnDefinitions to the Grid
myGrid.ColumnDefinitions.Add(myColDef1)
myGrid.ColumnDefinitions.Add(myColDef2)
myGrid.ColumnDefinitions.Add(myColDef3)
'Add the first child StackPanel.
Dim myStackPanel As New StackPanel
myStackPanel.HorizontalAlignment = System.Windows.HorizontalAlignment.Left
myStackPanel.VerticalAlignment = System.Windows.VerticalAlignment.Top
Grid.SetColumn(myStackPanel, 0)
Grid.SetRow(myStackPanel, 0)
Dim myTextBlock1 As New TextBlock
myTextBlock1.FontSize = 18
myTextBlock1.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock1.Margin = New Thickness(0, 0, 0, 15)
myTextBlock1.Text = "StackPanel 1"
Dim myButton1 As New Button
myButton1.Margin = New Thickness(0, 10, 0, 10)
myButton1.Content = "Button 1"
Dim myButton2 As New Button
myButton2.Margin = New Thickness(0, 10, 0, 10)
myButton2.Content = "Button 2"
Dim myButton3 As New Button
myButton3.Margin = New Thickness(0, 10, 0, 10)
Dim myTextBlock2 As New TextBlock
myTextBlock2.Text = "ColumnDefinition.Width = ""Auto"""
Dim myTextBlock3 As New TextBlock
myTextBlock3.Text = "StackPanel.HorizontalAlignment = ""Left"""
Dim myTextBlock4 As New TextBlock
myTextBlock4.Text = "StackPanel.VerticalAlignment = ""Top"""
Dim myTextBlock5 As New TextBlock
myTextBlock5.Text = "StackPanel.Orientation = ""Vertical"""
Dim myTextBlock6 As New TextBlock
myTextBlock6.Text = "Button.Margin = ""1,10,0,10"""
myStackPanel.Children.Add(myTextBlock1)
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myStackPanel.Children.Add(myButton3)
myStackPanel.Children.Add(myTextBlock2)
myStackPanel.Children.Add(myTextBlock3)
myStackPanel.Children.Add(myTextBlock4)
myStackPanel.Children.Add(myTextBlock5)
myStackPanel.Children.Add(myTextBlock6)
'Add the second child StackPanel.
Dim myStackPanel2 As New StackPanel
myStackPanel2.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch
myStackPanel2.VerticalAlignment = System.Windows.VerticalAlignment.Top
myStackPanel2.Orientation = Orientation.Vertical
Grid.SetColumn(myStackPanel2, 1)
Grid.SetRow(myStackPanel2, 0)
Dim myTextBlock7 As New TextBlock
myTextBlock7.FontSize = 18
myTextBlock7.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock7.Margin = New Thickness(0, 0, 0, 15)

MCT: Luis Dueas

Pag 294 de 445

Manual de Windows Presentation Foundation


myTextBlock7.Text = "StackPanel 2"
Dim myButton4 As New Button
myButton4.Margin = New Thickness(10, 0, 10, 0)
myButton4.Content = "Button 4"
Dim myButton5 As New Button
myButton5.Margin = New Thickness(10, 0, 10, 0)
myButton5.Content = "Button 5"
Dim myButton6 As New Button
myButton6.Margin = New Thickness(10, 0, 10, 0)
myButton6.Content = "Button 6"
Dim myTextBlock8 As New TextBlock
myTextBlock8.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock8.Text = "ColumnDefinition.Width = ""*"""
Dim myTextBlock9 As New TextBlock
myTextBlock9.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock9.Text = "StackPanel.HorizontalAlignment = ""Stretch"""
Dim myTextBlock10 As New TextBlock
myTextBlock10.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock10.Text = "StackPanel.VerticalAlignment = ""Top"""
Dim myTextBlock11 As New TextBlock
myTextBlock11.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock11.Text = "StackPanel.Orientation = ""Horizontal"""
Dim myTextBlock12 As New TextBlock
myTextBlock12.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock12.Text = "Button.Margin = ""10,0,10,0"""
myStackPanel2.Children.Add(myTextBlock7)
myStackPanel2.Children.Add(myButton4)
myStackPanel2.Children.Add(myButton5)
myStackPanel2.Children.Add(myButton6)
myStackPanel2.Children.Add(myTextBlock8)
myStackPanel2.Children.Add(myTextBlock9)
myStackPanel2.Children.Add(myTextBlock10)
myStackPanel2.Children.Add(myTextBlock11)
myStackPanel2.Children.Add(myTextBlock12)
'Add the final child StackPanel.
Dim myStackPanel3 As New StackPanel
myStackPanel3.HorizontalAlignment = System.Windows.HorizontalAlignment.Left
myStackPanel3.VerticalAlignment = System.Windows.VerticalAlignment.Top
Grid.SetColumn(myStackPanel3, 2)
Grid.SetRow(myStackPanel3, 0)
Dim myTextBlock13 As New TextBlock
myTextBlock13.FontSize = 18
myTextBlock13.HorizontalAlignment = System.Windows.HorizontalAlignment.Center
myTextBlock13.Margin = New Thickness(0, 0, 0, 15)
myTextBlock13.Text = "StackPanel 3"
Dim myButton7 As New Button
myButton7.Margin = New Thickness(10)
myButton7.Content = "Button 7"
Dim myButton8 As New Button
myButton8.Margin = New Thickness(10)
myButton8.Content = "Button 8"
Dim myButton9 As New Button
myButton9.Margin = New Thickness(10)
myButton9.Content = "Button 9"
Dim myTextBlock14 As New TextBlock
myTextBlock14.Text = "ColumnDefinition.Width = ""Auto"""
Dim myTextBlock15 As New TextBlock
myTextBlock15.Text = "StackPanel.HorizontalAlignment = ""Left"""
Dim myTextBlock16 As New TextBlock
myTextBlock16.Text = "StackPanel.VerticalAlignment = ""Top"""
Dim myTextBlock17 As New TextBlock
myTextBlock17.Text = "StackPanel.Orientation = ""Vertical"""
Dim myTextBlock18 As New TextBlock
myTextBlock18.Text = "Button.Margin = ""10"""
myStackPanel3.Children.Add(myTextBlock13)
myStackPanel3.Children.Add(myButton7)
myStackPanel3.Children.Add(myButton8)
myStackPanel3.Children.Add(myButton9)
myStackPanel3.Children.Add(myTextBlock14)
myStackPanel3.Children.Add(myTextBlock15)
myStackPanel3.Children.Add(myTextBlock16)
myStackPanel3.Children.Add(myTextBlock17)
myStackPanel3.Children.Add(myTextBlock18)
'Add child content to the parent Grid.
myGrid.Children.Add(myStackPanel)
myGrid.Children.Add(myStackPanel2)
myGrid.Children.Add(myStackPanel3)
'Add the Grid as the lone child of the Border.
myBorder.Child = myGrid
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="Margins,
Padding and Alignment Sample">
<Border Background="LightBlue"
BorderBrush="Black"
BorderThickness="2"
CornerRadius="45"
Padding="25">

MCT: Luis Dueas

Pag 295 de 445

Manual de Windows Presentation Foundation


<Grid Background="White" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Name="StackPanel1"
VerticalAlignment="Top">
<TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel1
</TextBlock>
<Button Margin="0,10,0,10">Button 1</Button>
<Button Margin="0,10,0,10">Button 2</Button>
<Button Margin="0,10,0,10">Button 3</Button>
<TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
<TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
<TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
<TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
<TextBlock>Button.Margin="0,10,0,10"</TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="0" HorizontalAlignment="Stretch" Name="StackPanel2"
VerticalAlignment="Top" Orientation="Vertical">
<TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel2
</TextBlock>
<Button Margin="10,0,10,0">Button 4</Button>
<Button Margin="10,0,10,0">Button 5</Button>
<Button Margin="10,0,10,0">Button 6</Button>
<TextBlock HorizontalAlignment="Center">ColumnDefinition.Width="*"</TextBlock>
<TextBlock HorizontalAlignment="Center">StackPanel.HorizontalAlignment="Stretch"
</TextBlock>
<TextBlock HorizontalAlignment="Center">StackPanel.VerticalAlignment="Top"</TextBlock>
<TextBlock HorizontalAlignment="Center">StackPanel.Orientation="Horizontal"</TextBlock>
<TextBlock HorizontalAlignment="Center">Button.Margin="10,0,10,0"</TextBlock>
</StackPanel>
<StackPanel Grid.Column="2" Grid.Row="0" HorizontalAlignment="Left" Name="StackPanel3"
VerticalAlignment="Top">
<TextBlock FontSize="18" HorizontalAlignment="Center" Margin="0,0,0,15">StackPanel3
</TextBlock>
<Button Margin="10">Button 7</Button>
<Button Margin="10">Button 8</Button>
<Button Margin="10">Button 9</Button>
<TextBlock>ColumnDefinition.Width="Auto"</TextBlock>
<TextBlock>StackPanel.HorizontalAlignment="Left"</TextBlock>
<TextBlock>StackPanel.VerticalAlignment="Top"</TextBlock>
<TextBlock>StackPanel.Orientation="Vertical"</TextBlock>
<TextBlock>Button.Margin="10"</TextBlock>
</StackPanel>
</Grid>
</Border>
</Page>
Cuando se compila, la aplicacin anterior produce una interfaz de usuario similar a la de la ilustracin siguiente.
Los efectos de los distintos valores de propiedad son evidentes en el espacio entre los elementos y los valores
de propiedad significativos para los elementos de cada columna se muestran dentro de TextBlocks.

Pasos adicionales
Las propiedades de posicin definidas por la clase FrameworkElement proporcionan un control preciso de la
posicin de los elementos en las aplicaciones WPF. Ahora dispone de varias tcnicas que puede utilizar para
colocar mejor los elementos mediante WPF.

3.3.4. Temas Cmo sobre Elementos Base


En los temas de esta seccin se describe cmo usar los cuatro elementos base de WPF: UIElement,
ContentElement, FrameworkElement y FrameworkContentElement.

3.3.4.1. Cmo: Hacer que un Elemento UIElement sea Transparente o


Semitransparente

MCT: Luis Dueas

Pag 296 de 445

Manual de Windows Presentation Foundation


En este ejemplo se muestra cmo hacer que un elemento UIElement sea transparente o semitransparente. Para
hacer que un elemento sea transparente o semitransparente, se establece su propiedad Opacity. Un valor de
0.0 hace que el elemento sea completamente transparente, mientras que un valor de 1.0 lo deja
completamente opaco. Un valor de 0.5 aplica al elemento una opacidad del 50%, y as sucesivamente. La
propiedad Opacity de un elemento se establece en 1.0 de manera predeterminada.
Ejemplo
En el ejemplo siguiente se establece la propiedad Opacity de un botn en 0.25, de modo que se aplica a l y a
su contenido (en este caso, el texto del botn) una opacidad del 25%.
<!-- Both the button and its text are made 25% opaque. -->
<Button Opacity="0.25">A Button</Button>
// Both the button and its text are made 25% opaque.
Button myTwentyFivePercentOpaqueButton = new Button();
myTwentyFivePercentOpaqueButton.Opacity = new Double();
myTwentyFivePercentOpaqueButton.Opacity = 0.25;
myTwentyFivePercentOpaqueButton.Content = "A Button";
Si el contenido de un elemento tiene sus propios valores de Opacity, stos se multiplican por el valor de la
propiedad Opacity del elemento contenedor.
En el ejemplo siguiente se establece la propiedad Opacity de un botn en 0.25 la propiedad Opacity de un
control Image contenido en el botn en 0.5. Como resultado, la opacidad resultante de la imagen es del 12,5%:
0,25 * 0,5 = 0,125.
<!-- The image contained within this button has an effective
opacity of 0.125 (0.25 * 0.5 = 0.125). -->
<Button Opacity="0.25">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Margin="10">A Button</TextBlock>
<Image Source="sampleImages\berries.jpg" Width="50" Height="50"
Opacity="0.5"/>
</StackPanel>
</Button>
// The image contained within this button has an
// effective opacity of 0.125 (0.25*0.5 = 0.125);
Button myImageButton = new Button();
myImageButton.Opacity = new Double();
myImageButton.Opacity = 0.25;
StackPanel myImageStackPanel = new StackPanel();
myImageStackPanel.Orientation = Orientation.Horizontal;
TextBlock myTextBlock = new TextBlock();
myTextBlock.VerticalAlignment = VerticalAlignment.Center;
myTextBlock.Margin = new Thickness(10);
myTextBlock.Text = "A Button";
myImageStackPanel.Children.Add(myTextBlock);
Image myImage = new Image();
BitmapImage myBitmapImage = new BitmapImage();
myBitmapImage.BeginInit();
myBitmapImage.UriSource = new Uri("sampleImages/berries.jpg",UriKind.Relative);
myBitmapImage.EndInit();
myImage.Source = myBitmapImage;
ImageBrush myImageBrush = new ImageBrush(myBitmapImage);
myImage.Width = 50;
myImage.Height = 50;
myImage.Opacity = 0.5;
myImageStackPanel.Children.Add(myImage);
myImageButton.Content = myImageStackPanel;
Otra manera de controlar la opacidad de un elemento es establecer la opacidad del objeto Brush que pinta el
elemento. Este enfoque permite modificar selectivamente la opacidad de algunas partes de un elemento y
proporciona ventajas de rendimiento con respecto al uso de la propiedad Opacity del elemento. En el ejemplo
siguiente se establece en 0.25 la propiedad Opacity de un objeto SolidColorBrush utilizado para pintar la
propiedad Background del botn. Como resultado, el fondo del pincel tiene una opacidad del 25%, pero la
opacidad de su contenido (el texto del botn) sigue siendo del 100%.
<!-- This button's background is made 25% opaque, but its
text remains 100% opaque. -->
<Button>
<Button.Background>
<SolidColorBrush Color="Gray" Opacity="0.25" />
</Button.Background>
A Button
</Button>
//

This button's background is made 25% opaque,

MCT: Luis Dueas

Pag 297 de 445

Manual de Windows Presentation Foundation


// but its text remains 100% opaque.
Button myOpaqueTextButton = new Button();
SolidColorBrush mySolidColorBrush = new SolidColorBrush(Colors.Gray);
mySolidColorBrush.Opacity = 0.25;
myOpaqueTextButton.Background = mySolidColorBrush;
myOpaqueTextButton.Content = "A Button";
Tambin puede controlar la opacidad de colores individuales dentro de un pincel.

3.3.4.2. Cmo: Animar el Tamao de un Elemento FrameworkElement


Para animar el tamao de un elemento FrameworkElement, puede animar sus propiedades Width y Height o
bien utilizar un objeto ScaleTransform animado.
En el ejemplo siguiente se anima el tamao de dos botones utilizando estos dos enfoques. El tamao de un
botn se cambia animando su propiedad Width y el tamao del otro se cambia animando un objeto
ScaleTransform aplicado a su propiedad RenderTransform. Cada botn contiene texto. Inicialmente, el texto
tiene el mismo aspecto en ambos botones, pero al cambiar el tamao de los botones, el texto del segundo
botn se distorsiona.
Ejemplo
<!-- AnimatingSizeExample.xaml
This example shows two ways of animating the size
of a framework element. -->
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Microsoft.Samples.Animation.AnimatingSizeExample"
WindowTitle="Animating Size Example">
<Canvas Width="650" Height="400">
<Button Name="AnimatedWidthButton"
Canvas.Left="20" Canvas.Top="20"
Width="200" Height="150"
BorderBrush="Red" BorderThickness="5">
Click Me
<Button.Triggers>
<!-- Animate the button's Width property. -->
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="AnimatedWidthButton"
Storyboard.TargetProperty="(Button.Width)"
To="500" Duration="0:0:10" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
<Button
Canvas.Left="20" Canvas.Top="200"
Width="200" Height="150"
BorderBrush="Black" BorderThickness="3">
Click Me
<Button.RenderTransform>
<ScaleTransform x:Name="MyAnimatedScaleTransform"
ScaleX="1" ScaleY="1" />
</Button.RenderTransform>
<Button.Triggers>
<!-- Animate the ScaleX property of a ScaleTransform
applied to the button. -->
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="MyAnimatedScaleTransform"
Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
To="3.0" Duration="0:0:10" AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
</Canvas>
</Page>
Al transformar un elemento, se transforma el elemento completo y su contenido. Al modificar directamente el
tamao de un elemento, como en el caso del primer botn, el contenido del elemento no cambia de tamao a
no ser que su tamao y posicin dependan del tamao de su elemento primario.

MCT: Luis Dueas

Pag 298 de 445

Manual de Windows Presentation Foundation


Al animar el tamao de un elemento aplicando una transformacin animada a su propiedad RenderTransform se
obtiene un rendimiento mejor que al animar sus propiedades Width y Height directamente, porque la propiedad
RenderTransform no activa un paso de diseo.

3.3.4.3. Cmo: Determinar si un Elemento Freezable est Inmovilizado


En este ejemplo se muestra cmo determinar si un objeto Freezable est inmovilizado. Si intenta modificar un
objeto Freezable inmovilizado, se inicia una excepcin InvalidOperationException. Para evitarlo, use la
propiedad IsFrozen del objeto Freezable para determinar si se encuentra inmovilizado.
Ejemplo
En el ejemplo siguiente se inmoviliza SolidColorBrush y, a continuacin, se comprueba mediante la propiedad
IsFrozen si se encuentra inmovilizado.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;
if (myBrush.IsFrozen) // Evaluates to true.
{
// If the brush is frozen, create a clone and
// modify the clone.
SolidColorBrush myBrushClone = myBrush.Clone();
myBrushClone.Color = Colors.Red;
myButton.Background = myBrushClone;
}
else
{
// If the brush is not frozen,
// it can be modified directly.
myBrush.Color = Colors.Red;
}

3.3.4.4. Cmo: Controlar un Evento Cargado


En este ejemplo se muestra cmo controlar el evento FrameworkElement.Loaded y se facilita un escenario
adecuado para ello. El controlador crea un control Button al cargarse la pgina.
Ejemplo
En el ejemplo siguiente se utiliza Lenguaje de marcado de aplicaciones extensible (XAML) junto con un archivo
de cdigo subyacente.
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.FELoaded"
Loaded="OnLoad"
Name="root">
</StackPanel>
Public Sub OnLoad(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim b1 As Button = New Button()
b1.Content = "New Button"
root.Children.Add(b1)
b1.Height = 25
b1.Width = 200
b1.HorizontalAlignment = HorizontalAlignment.Left
End Sub

3.3.4.5. Cmo: Definir Mrgenes de Elementos y Controles


En este ejemplo se describe cmo establecer la propiedad Margin, cambiando cualquier valor de la propiedad
existente para el margen en el cdigo subyacente. La propiedad Margin es una propiedad del elemento base
FrameworkElement, por lo que la heredan diversos controles y otros elementos.

MCT: Luis Dueas

Pag 299 de 445

Manual de Windows Presentation Foundation


Este ejemplo est escrito en Lenguaje de marcado de aplicaciones extensible (XAML), con un archivo de cdigo
subyacente al que hace referencia el marcado XAML. El subyacente se muestra en versin C# y en versin
Microsoft Visual Basic .NET.
Ejemplo
<Button Click="OnClick" Margin="10" Name="btn1">
Click To See Change!!</Button>
Public Sub OnClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Get the current value of the property.
Dim marginThickness As Thickness
marginThickness = btn1.Margin
' If the current leftlength value of margin is set to 10 then change it to a new
' value. Otherwise change it back to 10.
If marginThickness.Left = 10 Then
btn1.Margin = New Thickness(60)
Else
btn1.Margin = New Thickness(10)
End If
End Sub

3.3.4.6. Cmo: Hacer que un Elemento Freezable sea de Slo Lectura


En este ejemplo se muestra cmo convertir Freezable en un elemento de slo lectura mediante una llamada al
mtodo Freeze.
No se puede inmovilizar un objeto Freezable si alguna de las condiciones siguientes es true para el objeto:

Tiene propiedades animadas o enlazadas a datos.


Tiene propiedades que establece un recurso dinmico.
Contiene subobjetos Freezable que no se pueden inmovilizar.

Si estas condiciones son false para el objeto Freezable y no piensa modificarlo, puede inmovilizarlo para
obtener mejoras de rendimiento.
Ejemplo
En el ejemplo siguiente se inmoviliza un objeto SolidColorBrush, que es un tipo de objeto Freezable.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;

3.3.4.7. Cmo: Obtener una Copia Modificable de un Elemento Freezable de


Slo Lectura
En este ejemplo se muestra cmo utilizar el mtodo Clone para crear una copia para escritura de un objeto
Freezable de slo lectura.
Una vez que un objeto Freezable se marca como de slo lectura ("inmovilizado"), no es posible modificarlo. Sin
embargo, es posible utilizar el mtodo Clone para crear un clon modificable del objeto inmovilizado.
Ejemplo
En el ejemplo siguiente se crea un clon modificable de un objeto SolidColorBrush inmovilizado.
Button myButton = new Button();
SolidColorBrush myBrush = new SolidColorBrush(Colors.Yellow);
// Freezing a Freezable before it provides
// performance improvements if you don't
// intend on modifying it.
if (myBrush.CanFreeze)
{
// Makes the brush unmodifiable.
myBrush.Freeze();
}
myButton.Background = myBrush;

MCT: Luis Dueas

Pag 300 de 445

Manual de Windows Presentation Foundation


// If you need to modify a frozen brush,
// the Clone method can be used to
// create a modifiable copy.
SolidColorBrush myBrushClone = myBrush.Clone();
// Changing myBrushClone does not change
// the color of myButton, because its
// background is still set by myBrush.
myBrushClone.Color = Colors.Red;
// Replacing myBrush with myBrushClone
// makes the button change to red.
myButton.Background = myBrushClone;

3.3.4.8. Cmo: Voltear un Control UIElement Horizontal o Verticalmente


En este ejemplo se muestra cmo utilizar una transformacin ScaleTransform para voltear en sentido horizontal
o vertical un elemento UIElement. En este ejemplo, se voltea un control Button (un tipo de elemento
UIElement) aplicndole una transformacin ScaleTransform a su propiedad RenderTransform.
Ejemplo
En la ilustracin siguiente se muestra el botn que se va a voltear.
Elemento UIElement que se va a voltear

A continuacin se muestra el cdigo que crea el botn.


<Button Content="Flip me!" Padding="5">
</Button>
Para voltear horizontalmente el botn, cree una transformacin ScaleTransform y establezca su propiedad
ScaleX en -1. Aplique la transformacin ScaleTransform a la propiedad RenderTransform del botn.
<Button Content="Flip me!" Padding="5">
<Button.RenderTransform>
<ScaleTransform ScaleX="-1" />
</Button.RenderTransform>
</Button>
El botn despus de aplicar ScaleTransform

Como puede observar en la ilustracin anterior, el botn se ha volteado, pero tambin se ha movido. Esto se
debe a que se volte desde su esquina superior izquierda. Para voltear el botn en su lugar, se debe aplicar
ScaleTransform a su centro, no a su esquina. Una manera fcil de aplicar ScaleTransform al centro de los
botones es establecer la propiedad RenderTransformOrigin del botn en 0.5, 0.5.
<Button Content="Flip me!" Padding="5"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<ScaleTransform ScaleX="-1" />
</Button.RenderTransform>
</Button>
El botn con su propiedad RenderTransformOrigin establecida en 0.5, 0.5

MCT: Luis Dueas

Pag 301 de 445

Manual de Windows Presentation Foundation


Para voltear verticalmente el botn, establezca la propiedad ScaleY del objeto ScaleTransform en lugar de su
propiedad ScaleX.
<Button Content="Flip me!" Padding="5"
RenderTransformOrigin="0.5,0.5">
<Button.RenderTransform>
<ScaleTransform ScaleY="-1" />
</Button.RenderTransform>
</Button>
El botn volteado en sentido vertical

3.3.4.9. Cmo: Utilizar un Objeto ThicknessConverter


Ejemplo
En este ejemplo se muestra cmo crear una instancia de ThicknessConverter y usarla para cambiar el grosor de
un borde.
En el ejemplo se define un mtodo personalizado denominado changeThickness; este mtodo en primer lugar
convierte el contenido de ListBoxItem, tal como se encuentra definido en un archivo de Lenguaje de marcado
de aplicaciones extensible (XAML) independiente, en una instancia de Thickness y ms adelante convierte el
contenido en un objeto String. Este mtodo pasa ListBoxItem a un objeto ThicknessConverter, que convierte la
propiedad Content de un ListBoxItem en una instancia de Thickness. Este valor se vuelve a recuperar como el
valor de la propiedad BorderThickness de Border.
Public Sub changeThickness(ByVal sender As Object, ByVal args As
SelectionChangedEventArgs)
Dim li As ListBoxItem = CType(CType(sender, ListBox).SelectedItem, ListBoxItem)
Dim myThicknessConverter As System.Windows.ThicknessConverter = _
New System.Windows.ThicknessConverter()
Dim th1 As Thickness = _
CType(myThicknessConverter.ConvertFromString(li.Content.ToString()), Thickness)
border1.BorderThickness = th1
bThickness.Text = "Border.BorderThickness =" + li.Content.ToString()
End Sub

3.3.4.10. Cmo: Usar un Objeto LengthConverter


En este ejemplo se muestra cmo crear y usar una instancia del objeto LengthConverter. En este ejemplo, los
valores de ubicacin de Canvas se representan mediante la propiedad Content en un objeto ListBoxItem.
Content se convierte despus en una instancia de Double, que es un argumento obligatorio para la ubicacin. A
continuacin, el valor se vuelve a convertir en String mediante LengthConverter. El valor se muestra como
texto en un elemento TextBlock mediante el uso del mtodo GetLeft.
Ejemplo
En el ejemplo siguiente se muestra cmo crear y usar una instancia del objeto LengthConverter. Se define un
mtodo personalizado denominado ChangeLeft, que convierte el contenido de ListBoxItem (que se define en un
archivo de Lenguaje de marcado de aplicaciones extensible (XAML) aparte) en una instancia de Double, y
posteriormente en un objeto String. Este mtodo pasa ListBoxItem a un objeto LengthConverter, que convierte
Content de ListBoxItem en una instancia de Double. Observe que este valor ya se ha convertido en
String mediante el mtodo ToString. A continuacin, este valor se vuelve a pasar a los mtodos SetLeft y
GetLeft de Canvas para cambiar la posicin del objeto text1.
Public Sub ChangeLeft(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
Dim li As ListBoxItem = CType(CType(sender, ListBox).SelectedItem, ListBoxItem)
Dim myLengthConverter As New LengthConverter
Dim db1 As Double = _
CType(myLengthConverter.ConvertFromString(li.Content.ToString()), Double)
Canvas.SetLeft(text1, db1)
Dim st1 As String = CType(myLengthConverter.ConvertToString(Canvas.GetLeft(text1)),
String)

MCT: Luis Dueas

Pag 302 de 445

Manual de Windows Presentation Foundation


canvasLeft.Text = "Canvas.Left = " + st1
End Sub

3.3.4.11. Cmo: Controlar el Evento ContextMenuOpening


El evento ContextMenuOpening se puede controlar en una aplicacin para ajustar un men contextual existente
antes de su presentacin o para suprimir el men que se mostrara en situacin normal estableciendo la
propiedad Handled en true en los datos de evento. El motivo habitual para establecer Handled en true en los
datos de evento es reemplazar completamente el men con un nuevo objeto ContextMenu, lo que a veces
requiere cancelar la operacin e iniciar una nueva apertura. Si escribe controladores para el evento
ContextMenuOpening, debe tener en cuenta los problemas de control de tiempo entre un control ContextMenu
y el servicio que es responsables de abrir y colocar los mens contextuales para los controles en general. En
este tema se ilustran algunas de las tcnicas de cdigo para varios escenarios de apertura de mens
contextuales y se muestra un caso donde se hace patente el problema de control de tiempo.
Hay varios escenarios de control del evento ContextMenuOpening:

Ajustar los elementos de men antes de la presentacin.


Reemplazar el men completo antes de la presentacin.
Suprimir completamente cualquier men contextual existente y no mostrar ninguno.

Ejemplo
Ajustar los elementos de men antes de la presentacin
Ajustar los elementos de men existentes es bastante simple y, probablemente, es el escenario ms comn.
Puede hacerlo para agregar o quitar opciones en el men contextual en respuesta a la informacin de estado
actual de la aplicacin, o a la informacin de estado concreta disponible como una propiedad del objeto en que
se solicita el men contextual.
La tcnica general consiste en obtener el origen del evento, que es el control concreto donde que se hizo clic
con el botn secundario, y obtener la propiedad ContextMenu de l. Suele ser conveniente comprobar la
coleccin Items para ver qu elementos de men contextual existen ya en ella y, a continuacin, agregar o
quitar los elementos MenuItem nuevos en la coleccin.
void AddItemToCM(object sender, ContextMenuEventArgs e)
{
//check if Item4 is already there, this will probably run more than once
FrameworkElement fe = e.Source as FrameworkElement;
ContextMenu cm = fe.ContextMenu;
foreach (MenuItem mi in cm.Items)
{
if ((String)mi.Header == "Item4") return;
}
MenuItem mi4 = new MenuItem();
mi4.Header = "Item4";
fe.ContextMenu.Items.Add(mi4);
}
Reemplazar el men completo antes de la presentacin
Un escenario alternativo es aqul en que se desea reemplazar el men contextual completo. Por supuesto,
puede utilizar una variacin del cdigo anterior para quitar todos los elementos de un men contextual
existente y agregar otros nuevos partiendo del elemento cero. Pero el enfoque ms intuitivo para reemplazar
todos los elementos del men contextual es crear un nuevo ContextMenu, rellenarlo con elementos y, a
continuacin, establecer la propiedad ContextMenu de un control en el nuevo ContextMenu.
A continuacin, se muestra el cdigo de controlador simple para reemplazar un ContextMenu. En el cdigo se
hace referencia a un mtodo BuildMenu personalizado que est separado porque lo llaman ms de uno de los
controladores del ejemplo.
void HandlerForCMO(object sender, ContextMenuEventArgs e)
{
FrameworkElement fe = e.Source as FrameworkElement;
fe.ContextMenu = BuildMenu();
}
ContextMenu BuildMenu()
{

MCT: Luis Dueas

Pag 303 de 445

Manual de Windows Presentation Foundation


ContextMenu theMenu = new ContextMenu();
MenuItem mia = new MenuItem();
mia.Header = "Item1";
MenuItem mib = new MenuItem();
mib.Header = "Item2";
MenuItem mic = new MenuItem();
mic.Header = "Item3";
theMenu.Items.Add(mia);
theMenu.Items.Add(mib);
theMenu.Items.Add(mic);
return theMenu;

}
Sin embargo, si utiliza este estilo de controlador para un evento ContextMenuOpening, potencialmente puede
exponer un problema de control de tiempo si el objeto donde se establece el ContextMenu no tiene un men
contextual preexistente. Cuando un usuario hace clic con el botn secundario en un control, se provoca el
evento ContextMenuOpening aunque el objeto ContextMenu existente est vaco o sea null. Sin embargo, en
este caso, sea cual fuere el nuevo ContextMenu que se establezca en el elemento de origen llega demasiado
tarde para mostrarlo. Adems, si el usuario hace clic con el botn secundario por segunda vez, esta vez
aparece el nuevo ContextMenu, su valor no es null y el controlador se reemplaza correctamente y muestra el
men cuando el controlador se ejecuta por segunda vez. Esto sugiere dos posibles soluciones alternativas:
1.

Asegrese de que los controladores de ContextMenuOpening se ejecuten siempre en controles que


tengan como mnimo un ContextMenu marcador de posicin disponible, que se reemplazar por el cdigo
del controlador. En este caso, an as puede utilizar el controlador mostrado en el ejemplo anterior, pero

2.

normalmente suele ser conveniente asignar un ContextMenu marcador de posicin en el marcado inicial:
<StackPanel>
<Rectangle Fill="Yellow" Width="200" Height="100" ContextMenuOpening="HandlerForCMO">
<Rectangle.ContextMenu>
<ContextMenu>
<MenuItem>Initial menu; this will be replaced ...</MenuItem>
</ContextMenu>
</Rectangle.ContextMenu>
</Rectangle>
<TextBlock>Right-click the rectangle above, context menu gets replaced</TextBlock>
</StackPanel>
Supongamos que el valor de ContextMenu inicial sea null, segn alguna parte de la lgica preliminar.
Podra comprobar si ContextMenu es null o utilizar un marcador en el cdigo para comprobar si el
controlador se ha ejecutado al menos una vez. Dado que se supone que ContextMenu est a punto de
mostrarse, a continuacin el controlador establece Handled en true en los datos de evento. Para el
ContextMenuService responsable de la presentacin del men contextual, un valor true para Handled en
los datos de evento representa una solicitud de cancelar la presentacin correspondiente a la combinacin
de men contextual y control que provoc el evento.

Ahora que ha suprimido el men contextual que podra mostrarse, el paso siguiente es proporcionar uno nuevo
y mostrarlo. Establecer el nuevo es bsicamente igual que con el controlador anterior: se genera un nuevo
ContextMenu y se establece en l la propiedad ContextMenu del origen del control. La operacin adicional
consiste en forzar ahora la presentacin del men contextual, porque se ha suprimido el primer intento. Para
forzar la presentacin, se establece la propiedad Popup.IsOpen en true dentro del controlador. Extreme las
precauciones al hacerlo, porque al abrir el men contextual en el controlador se provoca de nuevo el evento
ContextMenuOpening. Si entra de nuevo en el controlador, se vuelve infinitamente recursivo. Por este motivo,
siempre hay que comprobar si existe el valor null o utilizar un marcador al abrir un men contextual desde el
interior de un controlador de eventos de ContextMenuOpening.
Suprimir cualquier men contextual existente y no mostrar ninguno
El ltimo escenario, escribir un controlador que suprime un men totalmente, es infrecuente. Si un control no
est pensado para mostrar un men contextual, es probable que existan maneras ms adecuadas de
asegurarse de ello que suprimir el men slo cuando un usuario lo solicita. Sin embargo, si desea utilizar el
controlador para suprimir un men contextual y no presentar nada, entonces el controlador debe limitarse a
establecer Handled en true en los datos de evento. El ContextMenuService responsable de mostrar un men
contextual comprobar los datos del evento que se provoc en el control. Si el evento est marcado como

MCT: Luis Dueas

Pag 304 de 445

Manual de Windows Presentation Foundation


Handled en cualquier punto de la ruta, se suprime la accin de apertura de men contextual que ha iniciado el
evento.
void HandlerForCMO2(object sender, ContextMenuEventArgs e)
{
if (!FlagForCustomContextMenu)
{
e.Handled = true; //need to suppress empty menu
FrameworkElement fe = e.Source as FrameworkElement;
fe.ContextMenu = BuildMenu();
FlagForCustomContextMenu = true;
fe.ContextMenu.IsOpen = true;
}
}
}

3.4. Arbol de Elementos y Serializacin


Los elementos de programacin de WPF existen a menudo con alguna forma de relacin recproca en el rbol.
Por ejemplo, una interfaz de usuario de aplicacin creada en XAML se puede conceptuar como un rbol de
elementos. El rbol de elementos puede estar dividido en dos rboles discretos pero, en ocasiones, paralelos: el
rbol lgico y el rbol visual. La serializacin en WPF implica guardar el estado de estos dos rboles as como el
estado de la aplicacin y escribirlo en un archivo, normalmente en XAML.

3.4.1. Arboles en WPF


En muchas tecnologas, los elementos y componentes se organizan en una estructura de rbol que los
programadores manipulan directamente para afectar a la representacin de una aplicacin. Windows
Presentation Foundation (WPF) tambin utiliza varias metforas de la estructura de rbol para definir las
relaciones entre los elementos de programacin.
Arboles en WPF
La estructura de rbol principal de WPF es el rbol de elementos. Si crea una pgina de aplicacin en XAML, se
crea la estructura de rbol basndose en las relaciones del anidamiento de los elementos en el marcado. Si crea
una aplicacin en cdigo, se crea la estructura de rbol basndose en cmo asigne los valores de las
propiedades que implementan el modelo de contenido para un elemento determinado. En Windows Presentation
Foundation (WPF), existen en realidad dos maneras de procesar y conceptualizar el rbol de elementos: como
el rbol lgico y como el rbol visual. Las distinciones entre rbol lgico y rbol visual no son siempre
importantes, pero en ocasiones pueden dar lugar a problemas con algunos subsistemas de WPF y afectar a las
opciones que se hacen en marcado o en cdigo.
Aunque no siempre se manipula el rbol lgico o el rbol visual directamente, entender los conceptos relativos
a cmo interactan ayuda a entender cmo funciona la herencia de propiedades y el enrutamiento de eventos
en WPF.
Arbol lgico
En WPF, se agrega contenido a los elementos utilizando las propiedades. Por ejemplo, se agregan elementos a
un control ListBox mediante su propiedad Items. Al hacerlo, est colocando elementos en la ItemCollection del
control ListBox. Para agregar elementos a un control DockPanel, se utiliza su propiedad Children. En este caso,
agrega elementos a la UIElementCollection de DockPanel.
En Lenguaje de marcado de aplicaciones extensible (XAML), al colocar los elementos de lista en ListBox, o
controles u otros elementos en DockPanel, tambin se utilizan las propiedades Items y Children, de manera
explcita o implcita, como en el ejemplo siguiente.
<DockPanel
Name="ParentElement"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<!--implicit: <DockPanel.Children>-->
<ListBox DockPanel.Dock="Top">
<!--implicit: <ListBox.Items>-->
<ListItem>
<Paragraph>Dog</Paragraph>

MCT: Luis Dueas

Pag 305 de 445

Manual de Windows Presentation Foundation


</ListItem>
<ListItem>
<Paragraph>Cat</Paragraph>
</ListItem>
<ListItem>
<Paragraph>Fish</Paragraph>
</ListItem>
<!--implicit: </ListBox.Items>-->
</ListBox>
<Button Height="20" Width="100" DockPanel.Dock="Top">Buy a Pet</Button>
<!--implicit: </DockPanel.Children>-->
</DockPanel>
Tenga en cuenta que las etiquetas de elemento de propiedad no se necesitan de forma explcita, porque el
lector XAML deduce los elementos de propiedad al crear los objetos que crean la representacin de objetos de
la aplicacin en tiempo de ejecucin del ejecutable. En el grfico siguiente se proporciona una vista conceptual
del rbol lgico que se construye en tiempo de ejecucin (la bifurcacin del botn se ha omitido).
Esquema del aspecto de un rbol lgico genrico

Finalidad del rbol lgico


El rbol lgico existe para que los modelos de contenido puedan recorrer con prontitud en iteracin sus posibles
elementos secundarios, y para que los modelos de contenido puedan ser extensibles. Asimismo, el rbol lgico
proporciona un marco de trabajo para algunas notificaciones, como cuando se han cargado todos los elementos
en l.
Adems, las referencias de recursos se resuelven buscando en sentido ascendente en el rbol lgico para
encontrar las colecciones Resources del elemento de solicitud inicial y, a continuacin, los elementos primarios.
El rbol lgico se utiliza para la bsqueda de recursos cuando tambin est presente el rbol visual.
Invalidar el rbol lgico
Los autores de controles avanzados pueden invalidar el rbol lgico; para ello, deben invalidar varias API que
definen cmo un objeto general o el modelo de contenido agrega o quita elementos en dicho rbol.
Herencia de valores de propiedad
La herencia de valores de propiedad funciona a travs de un rbol hbrido. Los metadatos reales que contienen
la propiedad Inherits que habilita la herencia de propiedades consisten en la clase FrameworkPropertyMetadata
de nivel de marco de trabajo de WPF. Por consiguiente, tanto el elemento primario que contiene el valor original
como el elemento secundario que hereda deben ser FrameworkElement o FrameworkContentElement, y formar
parte de un rbol lgico. Sin embargo, se permite que el rbol lgico de elementos primarios contra elementos
secundarios sea disjunto, de tal forma que la herencia de valores de propiedad se pueda perpetuar a travs de
un elemento visual intermedio que no se encuentre en un rbol lgico. Para que la herencia de valores de
propiedad funcione de forma coherente a travs de un lmite de este tipo, la propiedad que hereda debe
registrarse como propiedad asociada. El rbol exacto utilizado para la herencia de propiedad no se puede
prever completamente mediante un mtodo de utilidad de clase de aplicacin auxiliar, ni siquiera en tiempo de
ejecucin.
Arbol visual
Adems del concepto de rbol lgico, en WPF existe el concepto de rbol visual. El rbol visual describe la
estructura de objetos visuales representados por la clase base Visual. Cuando se escribe una plantilla para un
control, se define o vuelve a definir el rbol visual aplicable a ese control. El rbol visual tambin reviste inters
para los programadores que desean un control de bajo nivel sobre el dibujo por motivos de optimizacin y
rendimiento. Una exposicin del rbol visual como parte de la programacin de aplicaciones de WPF

MCT: Luis Dueas

Pag 306 de 445

Manual de Windows Presentation Foundation


convencional consiste en que las rutas de evento de un evento enrutado recorren en su mayora el rbol visual,
no el rbol lgico. Esta sutileza de comportamiento de los eventos enrutados puede no resultar patente de
forma inmediata salvo para los autores de controles. Enrutar a travs del rbol visual permite que los controles
que implementan la composicin en el nivel visual controlen eventos o creen establecedores de eventos.
Arboles, elementos de contenido y hosts de contenido
Los elementos de contenido (clases que se derivan de ContentElement) no forman parte del rbol visual; no
heredan de Visual ni tienen representacin visual. Para que aparezcan en la interfaz de usuario, un elemento
ContentElement se debe hospedar en un host de contenido que sea un objeto Visual y un elemento del rbol
lgico, normalmente un elemento FrameworkElement. Puede considerarse el host del contenido como una
especie de "explorador" para el contenido que decide cmo mostrar ese contenido dentro de la zona de la
pantalla que controla. Cuando se hospeda el contenido, ste puede participar en algunos procesos del rbol que
suelen asociarse al rbol visual. En general, la clase host FrameworkElement incluye cdigo de implementacin
que agrega cualquier ContentElement hospedado a la ruta del evento a travs de subnodos del rbol lgico de
contenido, aunque el contenido hospedado no forme parte del verdadero rbol visual. Esto es necesario para
que un ContentElement pueda originar un evento enrutado que se enruta a cualquier elemento que no sea l
mismo.
Exploracin transversal del rbol
La clase LogicalTreeHelper proporciona los mtodos GetChildren, GetParent y FindLogicalNode para la
exploracin transversal del rbol lgico. En la mayora de los casos, no debera tener que atravesar el rbol
lgico de los controles existentes, porque casi siempre exponen sus elementos secundarios lgicos como una
propiedad de coleccin dedicada que admite las API de coleccin, tales como Add, un indizador, etc. El
escenario de exploracin transversal del rbol se utiliza principalmente por autores de controles que optan por
no derivar de los patrones de control previstos, tales como ItemsControl o Panel donde ya estn definidas las
propiedades de coleccin, sino que desean proporcionar su propia compatibilidad con propiedades de coleccin.
El rbol visual tambin admite una clase de aplicacin auxiliar para su propia exploracin transversal,
VisualTreeHelper. El rbol visual no se expone de un modo tan cmodo a travs de las propiedades especficas
del control, por lo que la clase VisualTreeHelper es la manera recomendada de atravesar el rbol visual si fuera
necesario en un escenario de programacin.
Rutas para los eventos enrutados como un "rbol"
Como se ha mencionado antes, la ruta de un evento enrutado recorre el rbol de manera efectiva, en sentido
ascendente o descendente, segn se trate de un evento enrutado de tnel o de propagacin. El concepto de
ruta de evento no tiene ninguna clase de aplicacin auxiliar que lo respalde directamente y que se pueda
utilizar para "recorrer" la ruta de evento con independencia de que se provoque un evento que se enrute
realmente. Hay una clase que representa la ruta, EventRoute, pero los mtodos de esa clase suelen ser slo
para uso interno.
Recursos y rboles
La bsqueda de recursos atraviesa bsicamente el rbol lgico. Los objetos que no estn en el rbol lgico
pueden hacer referencia a recursos, pero la bsqueda se inicia en el punto donde ese objeto est conectado al
rbol lgico. nicamente los nodos de rbol lgico pueden tener una propiedad Resources que contiene
ResourceDictionary, de manera que atravesar el rbol visual en busca de recursos no reviste ninguna ventaja.
Sin embargo, la bsqueda de recursos tambin se puede extender ms all del rbol lgico inmediato. Para el
marcado de aplicacin, la bsqueda de recursos puede continuar para incluir los recursos de la aplicacin, la
compatibilidad con temas y los valores de sistema. Los propios temas tambin pueden hacer referencia a
valores del sistema situados fuera del rbol lgico del tema si referencias de recursos son dinmicas.

3.4.2. Limitaciones en la Serializacin de XamlWriter.Save

MCT: Luis Dueas

Pag 307 de 445

Manual de Windows Presentation Foundation


El mtodo API Save se puede utilizar para serializar el contenido de una aplicacin de Windows Presentation
Foundation (WPF) como un archivo Lenguaje de marcado de aplicaciones extensible (XAML). Sin embargo,
existen algunas limitaciones notables relativas a qu se serializa exactamente. En este tema se documentan
estas limitaciones y algunas consideraciones generales.
Representacin en tiempo de ejecucin, no en tiempo de diseo
La filosofa bsica de lo que se serializada mediante una llamada a Save es que el resultado ser una
representacin del objeto serializado en tiempo de ejecucin. Muchas propiedades en tiempo de diseo del
archivo XAML original pueden haberse optimizado o perdido para cuando el marcado XAML se carga como
objetos en memoria, y no se conservan cuando se llama a Save para realizar la serializacin. El resultado
serializado es una representacin efectiva del rbol lgico construido de la aplicacin, pero no necesariamente
del XAML original que lo gener. Estos problemas hace que sea sumamente difcil utilizar la serializacin de
Save como parte de una superficie de diseo XAML extensa.
Autonoma de la serializacin
El resultado serializado de Save es autnomo; todo lo que se serializa est contenido dentro de una sola pgina
XAML, con un elemento raz nico, sin referencia externa alguna a excepcin de los URIs. Por ejemplo, si en la
pgina se hace referencia a recursos de los recursos de la aplicacin, stos aparecern como si se tratara de un
componente de la pgina serializada.
Eliminacin de las referencias a extensiones
El proceso de serializacin eliminar las referencias comunes a los objetos realizadas por diversos formatos de
extensin de marcado, tales como StaticResource o Binding. Estas referencias ya se han eliminado al crear los
objetos en memoria en el tiempo de ejecucin de la aplicacin, y la lgica de Save no repite el XAML original
para restaurar estas referencias en el resultado serializado. Este hecho inmoviliza potencialmente todos los
valores obtenidos de los recursos o enlazados a datos en el ltimo valor utilizado por la representacin en
tiempo de ejecucin, y nicamente se dispone de una capacidad limitada o indirecta para distinguir este valor
de cualquier otro establecido localmente. Las imgenes tambin se serializan como referencias a objeto a las
imgenes tal cual existen en el proyecto, en lugar de cmo referencias originales del cdigo fuente, con lo que
se pierden los nombre de archivo y los URI a los que se hiciera referencia originalmente. Incluso los recursos
declarados dentro de la propia pgina aparecen serializados en el punto donde se hizo referencia a ellos, en
lugar de conservarse como una clave de una coleccin de recursos.
No se conserva el control de eventos
Cuando se serializan controladores de eventos que se agregan mediante XAML, stos no se conservan. El
marcado XAML sin cdigo subyacente (y sin el mecanismo relacionado x:Code) no dispone de ninguna manera
de serializar la lgica de procedimiento en tiempo de ejecucin. Dado que la serializacin es autnoma y se
limita al rbol lgico, no existe ningn medio para almacenar controladores de eventos. Como resultado, los
atributos de controladores de eventos, tanto el propio atributo como el valor de cadena que da nombre al
controlador, se quitan del XAML de salida.
Escenarios realistas para el uso de XAMLWriter.Save
Aunque las limitaciones que hemos enumerado son bastante importantes, existen varios escenarios en los que
es adecuado utilizar Save para la serializacin.

Salida vectorial o grfica: la salida del rea representada se puede utilizar para reproducir el mismo
vector o grfico al volver a cargarla.

Documentos de texto enriquecido y dinmicos: el texto, el formato de todos los elementos y la


contencin de elementos en su seno se conservan en la salida. Esto puede ser til para los
mecanismos afines a la funcionalidad del portapapeles.

Conservar datos de objetos comerciales: si ha almacenado datos en elementos personalizados, tales


como datos XML, los objetos comerciales se pueden perpetuar mediante la serializacin siempre que

MCT: Luis Dueas

Pag 308 de 445

Manual de Windows Presentation Foundation


sigan determinadas reglas bsicas de XAML, como proporcionar constructores personalizados y
conversin para valores de propiedades por referencia.

3.4.3. Inicializacin de Elementos de Objeto No Incluidos en un Arbol de


Elementos
Algunos aspectos de la inicializacin de Windows Presentation Foundation (WPF) se difieren a los procesos que
suelen basarse en que ese elemento est conectado al rbol lgico o al rbol visual. En este tema se describen
las operaciones que pueden ser necesarias para inicializar un elemento que no est conectado a ninguno de
estos rboles.
Elementos y el rbol lgico
Al crear una instancia de una clase Windows Presentation Foundation (WPF) en cdigo, debe tener en cuenta
que hay varios aspectos de la inicializacin de objetos para una clase de Windows Presentation Foundation
(WPF) que deliberadamente no forman parte del cdigo que se ejecuta al llamar al constructor de la clase.
Concretamente para una clase de control, el constructor no define la mayora de la representacin visual de ese
control. En cambio, la representacin visual la define la plantilla del control. La plantilla puede proceder de
varios orgenes, pero lo ms habitual es que se obtenga de los estilos de tema. En la prctica, el enlace de las
plantillas se efecta en tiempo de ejecucin; la plantilla necesaria no se asocia al control correspondiente hasta
que ste est para el diseo. Y el control no est listo para el diseo hasta que se asocia a un rbol lgico
conectado a una superficie de la representacin en la raz. Este elemento del nivel de la raz es el que inicia la
representacin de todos sus elementos secundarios definidos en el rbol lgico.
El rbol visual tambin participa en este proceso. Las instancias de los elementos que forman parte del rbol
visual a travs de las plantillas tampoco se crean totalmente hasta que se conectan.
Como consecuencia de este comportamiento, algunas operaciones que se basan en las caractersticas visuales
completadas de un elemento requieren operaciones adicionales. Un ejemplo de ello es el caso en que se intenta
obtener las caractersticas visuales de una clase que se construy pero todava no est asociada a un rbol. Por
ejemplo, si desea llamar a Render para RenderTargetBitmap y el objeto visual que se pasa es un elemento no
conectado a un rbol, ese elemento no estar completo visualmente hasta que se completen las operaciones de
inicializacin adicionales.
Utilizar BeginInit y EndInit para inicializar el elemento
Varias clases de WPF implementan la interfaz ISupportInitialize. Los mtodos BeginInit y EndInit de la interfaz
se utilizan para indicar una zona del cdigo que contiene las operaciones de inicializacin (tales como establecer
los valores de propiedad que afectan a la representacin). Una vez se llama a EndInit en la secuencia, el
sistema del diseo puede procesar el elemento y comenzar a buscar un estilo implcito.
Si el elemento cuyas propiedades se establecen es una clase derivada de FrameworkElement o de
FrameworkContentElement, entonces puede llamar a las versiones de las clases BeginInit y EndInit, en lugar de
efectuar una conversin a ISupportInitialize.
Cdigo de ejemplo
A continuacin se muestra un ejemplo de cdigo para una aplicacin de consola que utiliza API de
representacin y el mtodo Load(Stream) de un archivo XAML dinmico para mostrar la posicin correcta de
BeginInit y EndInit en torno a otras llamadas de API que ajustan las propiedades que afectan a la
representacin.
En el ejemplo slo se muestra la funcin principal. Las funciones Rasterize y Save (no mostradas) son funciones
de utilidad que se encargan del procesamiento de imgenes y de E/S.
[STAThread]
static void Main(string[] args)
{
UIElement e;

MCT: Luis Dueas

Pag 309 de 445

Manual de Windows Presentation Foundation

string file = Directory.GetCurrentDirectory() + "\\starting.xaml";


using (Stream stream = File.Open(file, FileMode.Open))
{
//loading files from current directory, project settings take care of copying the file
ParserContext pc = new ParserContext();
pc.BaseUri = new Uri(file, UriKind.Absolute);
e = (UIElement)XamlReader.Load(stream, pc);
}
Size paperSize = new Size(8.5 * 96, 11 * 96);
e.Measure(paperSize);
e.Arrange(new Rect(paperSize));
e.UpdateLayout();
// Render effect at normal dpi, indicator is the original RED rectangle
RenderTargetBitmap image1 = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96);
Save(image1, "render1.png");
Button b = new Button();
b.BeginInit();
b.Background = Brushes.Blue;
b.Width = b.Height = 200;
b.EndInit();
b.Measure(paperSize);
b.Arrange(new Rect(paperSize));
b.UpdateLayout();
// now render the altered version, with the element built up and initialized
RenderTargetBitmap image2 = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96);
Save(image2, "render2.png");

3.4.4. Temas Cmo sobre el Arbol de Elementos y la Serializacin


En los temas de esta seccin se describe cmo utilizar el rbol de elementos de WPF.

3.4.4.1. Cmo: Buscar un Elemento por su Nombre


En este ejemplo se describe cmo utilizar el mtodo FindName para buscar un elemento por su valor de Name.
Ejemplo
En este ejemplo, el mtodo para buscar un elemento determinado por su nombre se escribe como el
controlador de eventos de un botn. stackPanel es la propiedad Name del elemento FrameworkElement raz
donde se realiza la bsqueda; a continuacin, mtodo de ejemplo indica visualmente cul es el elemento
buscado convirtindolo en un TextBlock y cambiando una de las propiedades de interfaz de usuario visibles de
TextBlock.
void Find(object sender, RoutedEventArgs e)
{
object wantedNode = stackPanel.FindName("dog");
if (wantedNode is TextBlock)
{
// Following executed if Text element was found.
TextBlock wantedChild = wantedNode as TextBlock;
wantedChild.Foreground = Brushes.Blue;
}
}

3.4.4.2. Cmo: Invalidar el Arbol Lgico


Aunque no es necesario en la mayora de los casos, los autores de controles avanzados tienen la opcin de
invalidar el rbol lgico.
Ejemplo
En este ejemplo se describe cmo crear subclases de StackPanel para invalidar el rbol lgico, en este caso se
trata de exigir un comportamiento que slo puede tener el panel y que nicamente representar un solo
elemento secundario. No es un comportamiento necesariamente deseable desde el punto de vista prctico, pero
se muestra aqu a fin de ilustrar el escenario de invalidacin del rbol lgico normal de un elemento.
public class SingletonPanel : StackPanel
{
//private UIElementCollection _children;
private FrameworkElement _child;
public SingletonPanel()
{
}
public FrameworkElement SingleChild
{
get { return _child;}

MCT: Luis Dueas

Pag 310 de 445

Manual de Windows Presentation Foundation


set
{

if (value==null) {
RemoveLogicalChild(_child);
} else {
if (_child==null) {
_child = value;
} else {
// raise an exception?
MessageBox.Show("Needs to be a single element");
}
}

}
}
public void SetSingleChild(object child)
{
this.AddLogicalChild(child);
}
public new void AddLogicalChild(object child)
{
_child = (FrameworkElement)child;
if (this.Children.Count == 1)
{
this.RemoveLogicalChild(this.Children[0]);
this.Children.Add((UIElement)child);
}
else
{
this.Children.Add((UIElement)child);
}
}
public new void RemoveLogicalChild(object child)
{
_child = null;
this.Children.Clear();
}
protected override IEnumerator LogicalChildren
{
get {
// cheat, make a list with one member and return the enumerator
ArrayList _list = new ArrayList();
_list.Add(_child);
return (IEnumerator) _list.GetEnumerator();}
}

3.5. Propiedades
Windows Presentation Foundation (WPF) proporciona un conjunto de servicios que se pueden utilizar para
extender la funcionalidad de una propiedad de common language runtime (CLR). Colectivamente, estos
servicios se conocen como el sistema de propiedades de WPF. Una propiedad que est respaldada por el
sistema de propiedades de WPF se conoce como una propiedad de dependencia.

3.5.1. Informacin General sobre las Propiedades de Dependencia


Windows Presentation Foundation (WPF) proporciona un conjunto de servicios que se pueden utilizar para
extender la funcionalidad de una propiedad de common language runtime (CLR). Colectivamente, estos
servicios se conocen como el sistema de propiedades de WPF. Una propiedad que est respaldada por el
sistema de propiedades de WPF se conoce como una propiedad de dependencia. Esta informacin general
describe el sistema de propiedades de WPF y las funciones de una propiedad de dependencia. Esto incluye
cmo utilizar propiedades de dependencia existentes en Lenguaje de marcado de aplicaciones extensible
(XAML) y en cdigo. Esta informacin general tambin presenta aspectos especializados de las propiedades de
dependencia, tales como los metadatos de propiedades de dependencia y cmo crear una propiedad de
dependencia propia en una clase personalizada.
Propiedades de dependencia y propiedades de CLR
En WPF, las propiedades se exponen normalmente como propiedades common language runtime (CLR). En un
nivel bsico, podra interactuar directamente con estas propiedades y nunca sabra que se implementan como
una propiedad de dependencia. Sin embargo, es recomendable conocer algunas o todas las caractersticas del
sistema de propiedades de WPF, para poder aprovecha estas caractersticas.

MCT: Luis Dueas

Pag 311 de 445

Manual de Windows Presentation Foundation


El propsito de las propiedades de dependencia es proporcionar una manera de calcular el valor de una
propiedad en funcin del valor de otras entradas. Estas otras entradas pueden incluir propiedades del sistema
tales como temas y preferencias del usuario, mecanismos de determinacin de propiedad Just-In-Time tales
como el enlace de datos y las animaciones o guiones grficos, plantillas del uso mltiple tales como recursos y
estilos, o valores conocidos a travs de relaciones de elementos primarios-secundarios con otros elementos del
rbol de elementos. Adems, una propiedad de dependencia se puede implementar para que proporcione
validacin autnoma, valores predeterminados, devoluciones de llamada que supervisen los cambios de otras
propiedades y un sistema que pueda forzar valores de la propiedad en funcin de informacin que puede estar
disponible en tiempo de ejecucin. Las clases derivadas tambin pueden cambiar algunas caractersticas
concretas de una propiedad existente invalidando metadatos de propiedades de dependencia, en lugar de
reemplazar la implementacin real de propiedades existentes o crear propiedades nuevas.
En la referencia de SDK, puede identificar qu propiedad es una propiedad de dependencia por la presencia de
la seccin de Informacin de propiedad de dependencia en la pgina de referencia administrada para esa
propiedad. La seccin de Informacin de propiedad de dependencia incluye un vnculo al campo identificador de
DependencyProperty para esa propiedad de dependencia y tambin incluye una lista de las opciones de
metadatos establecidas para esa propiedad, informacin de invalidacin por clases y otros detalles.
Propiedades CLR de respaldo de propiedades de dependencia
Las propiedades de dependencia y el sistema de propiedades de WPF extienden la funcionalidad de propiedad
proporcionando un tipo que respalda una propiedad, como implementacin alternativa al modelo estndar de
respaldar la propiedad con un campo privado. El nombre de este tipo es DependencyProperty. El otro tipo
importante que define el sistema de propiedades de WPF es DependencyObject.DependencyObject define la
clase base que puede registrar y poseer una propiedad de dependencia.
A continuacin se ofrece un resumen de la terminologa que se utiliza en esta documentacin de kit de
desarrollo de software (SDK) cuando se tratan las propiedades de dependencia:

Propiedad de dependencia: una propiedad respaldada por un objeto DependencyProperty.


Identificador de propiedad de dependencia: una instancia de DependencyProperty, que se obtiene
como valor de retorno al registrar una propiedad de dependencia y, a continuacin, se almacena como
miembro de una clase. Este identificador se utiliza como parmetro en muchas de las API que
interactan con el sistema de propiedades de WPF.

Contenedor

CLR:

implementaciones

reales

de

lectura

escritura

de

la

propiedad.

Estas

implementaciones incorporan el identificador de propiedad de dependencia utilizndolo en las llamadas


a GetValue y SetValue, proporcionando as el respaldo para la propiedad utilizando el sistema de
propiedades de WPF.
En el ejemplo siguiente se muestra la propiedad propiedad de dependencia IsSpinning y se muestra la relacin
del identificador DependencyProperty con la propiedad a la que respalda.
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
...
);
public bool IsSpinning
{
get { return (bool)GetValue(IsSpinningProperty); }
set { SetValue(IsSpinningProperty, value); }
}
La convencin de nomenclatura de la propiedad y su campo de respaldo DependencyProperty es importante. El
nombre del campo siempre es el nombre de la propiedad, con el sufijo Property.
Establecer valores de propiedad
Puede establecer propiedades en cdigo o en XAML.
Establecer valores de propiedad en XAML

MCT: Luis Dueas

Pag 312 de 445

Manual de Windows Presentation Foundation


En el siguiente ejemplo de XAML se especifica como valor de fondo para un botn el rojo. En este ejemplo se
muestra un caso donde el valor de cadena simple para un atributo XAML convierte su tipo, mediante el
cargador XAML, en un tipo WPF (un Color, mediante un SolidColorBrush) en el cdigo generado .
<Button Background="Red" Content="Button!"/>
XAML admite diversas formas de sintaxis para establecer propiedades. La sintaxis a utilizar para una propiedad
determinada depender del tipo de valor que utilice una propiedad, as como de otros factores tales como la
presencia de un convertidor de tipos.
Como ejemplo de sintaxis sin atributos, en el siguiente ejemplo de XAML se muestra otro fondo de botn. Esta
vez, en lugar de establecer un color slido simple, el fondo se establece en una imagen, con un elemento que
representa esa imagen y el origen de la imagen especificado como un atributo del elemento anidado. ste es un
ejemplo de sintaxis de elemento de propiedad.
<Button Content="Button!">
<Button.Background>
<ImageBrush ImageSource="wavy.jpg"/>
</Button.Background>
</Button>
Establecer propiedades en cdigo
Establecer valores de propiedad de dependencia en cdigo suele consistir en una simple llamada a la
implementacin de escritura expuesta por el "contenedor" de CLR.
Button myButton = new Button();
myButton.Width = 200.0;
Obtener un valor de propiedad consiste tambin esencialmente en una llamada a la implementacin de lectura
del "contenedor":
double whatWidth;
whatWidth = myButton.Width;
Tambin puede llamar directamente a API GetValue y SetValue del sistema de propiedades. Habitualmente, no
es necesario si se est utilizando propiedades existentes (los contenedores son ms cmodos y ofrecen una
mejor exposicin de la propiedad para las herramientas de desarrollo), pero llamar directamente a API es lo
adecuado para ciertos escenarios.
Tambin se puede establecer propiedades en XAML y, a continuacin, obtener acceso ms tarde en el cdigo
mediante cdigo subyacente.
Funcionalidad de propiedad proporcionada por una propiedad de dependencia
Una propiedad de dependencia proporciona funcionalidad que extiende la funcionalidad de una propiedad, a
diferencia de una propiedad respaldada por un campo. A menudo, cada una de estas funcionalidades
representa o admite una caracterstica concreta del conjunto total de propiedades de WPF:
Resources
Puede establecerse un valor de propiedad de dependencia haciendo referencia a un recurso. Los recursos se
especifican normalmente como elementos secundarios de un elemento raz de la pgina o de la aplicacin
(estas ubicaciones permiten el acceso ms cmodo al recurso). En el ejemplo siguiente se muestra cmo definir
un recurso SolidColorBrush.
<DockPanel.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>
Una vez definido el recurso, puede hacer referencia al recurso y utilizarlo para proporcionar un valor de
propiedad:
<Button Background="{DynamicResource MyBrush}" Content="I am gold" />
Este recurso en particular se conoce como Extensin de marcado DynamicResource (en XAML, se puede utilizar
una referencia de recurso esttica o dinmica). Para utilizar una referencia de recurso dinmica debe estar
estableciendo una propiedad de dependencia, por lo que es especficamente el uso de la referencia de recurso
dinmica lo que habilita el sistema de propiedades de WPF.
Nota:
Los recursos se tratan como un valor local, lo que significa que si se establece otro valor local, se eliminar
la referencia de recurso.

MCT: Luis Dueas

Pag 313 de 445

Manual de Windows Presentation Foundation


Enlace de datos
Una propiedad de dependencia puede hacer referencia a un valor mediante enlace de datos. El enlace de datos
funciona mediante una sintaxis de extensin de marcado concreta en XAML o mediante el objeto Binding en
cdigo. Con el enlace de datos, la determinacin final del valor de la propiedad se aplaza hasta el tiempo de
ejecucin, momento en el que se obtiene el valor desde un origen de datos.
En el ejemplo siguiente se establece la propiedad Content de un control Button, utilizando un enlace en XAML.
El enlace usa un contexto de datos heredado y un origen de datos XmlDataProvider (que no se muestra). El
propio enlace especifica la propiedad de origen deseada por XPath dentro del origen de datos.
<Button Content="{Binding XPath=Team/@TeamName}"/>
Nota:
Los enlaces se tratan como un valor local, lo que significa que, si establece otro valor local, eliminar el
enlace.
Las

propiedades

de

dependencia

la

clase

DependencyObject

no

admiten

de

forma

nativa

NotifyPropertyChanged para generar notificaciones de cambios de valor de la propiedad de origen


DependencyObject en operaciones de enlace de datos.
Estilos
Los estilos y las plantillas son dos de los principales escenarios que invitan a usar propiedades de dependencia.
Los estilos son particularmente tiles para establecer propiedades que definen la interfaz de usuario (UI) de la
aplicacin. Los estilos se definen habitualmente como recursos en XAML. Los estilos interactan con el sistema
de propiedades porque contienen normalmente "establecedores" para determinadas propiedades, as como
"desencadenadores" que modifican el valor de la propiedad en funcin del valor en tiempo real de otra
propiedad.
En el ejemplo siguiente se crea un estilo muy simple (que se definira dentro de un diccionario Resources, que
no se muestra) y, a continuacin, se aplica directamente a la propiedad Style de un control Button. El
establecedor que hay dentro del estilo establece la propiedad Background de un control Button con estilo en el
color verde.
<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>
Animations
Las propiedades de dependencia se pueden animar. Cuando se aplica una animacin y se est ejecutando, el
valor animado funciona en una prioridad ms alta que cualquier valor (tal como un valor local) que pueda tener
la propiedad.
En el ejemplo siguiente se anima la propiedad Background de una propiedad Button (tcnicamente, la
propiedad Background se anima utilizando la sintaxis de elemento de propiedad para especificar un objeto
SolidColorBrush en blanco como Background; entonces, la propiedad Color de ese objeto SolidColorBrush es la
propiedad que se anima directamente).
<Button>I am animated
<Button.Background>
<SolidColorBrush x:Name="AnimBrush"/>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimBrush"
Storyboard.TargetProperty="(SolidColorBrush.Color)"
From="Red" To="Green" Duration="0:0:5"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>

MCT: Luis Dueas

Pag 314 de 445

Manual de Windows Presentation Foundation


Invalidaciones de metadatos
Puede cambiar ciertos comportamientos de una propiedad de dependencia invalidando los metadatos para esa
propiedad al derivar de la clase que registra originalmente la propiedad de dependencia. La invalidacin de
metadatos se apoya en el identificador DependencyProperty. La invalidacin de metadatos, no requiere
implementar de nuevo la propiedad. El sistema de propiedades administra nativamente el cambio de
metadatos; cada clase puede contener metadatos individuales para todas las propiedades heredadas de las
clases base, tipo por tipo.
En el ejemplo siguiente se invalidan los metadatos de una propiedad de dependencia DefaultStyleKey. Invalidar
los metadatos de esta propiedad de dependencia concreta forma parte de un modelo de implementacin que
crea controles que pueden utilizar estilos predeterminados de temas.
public class SpinnerControl : ItemsControl
{
static SpinnerControl()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(SpinnerControl),
new FrameworkPropertyMetadata(typeof(SpinnerControl))
);
}
}
Herencia de valores de propiedad
Un elemento puede heredar el valor de una propiedad de dependencia de su elemento primario en el rbol.
Nota:
El comportamiento de herencia del valor de la propiedad no est habilitado globalmente para todas las
propiedades de dependencia, porque el tiempo de clculo para la herencia tiene cierto impacto sobre el
rendimiento. La herencia del valor de la propiedad solamente est habilitada, normalmente, para las
propiedades donde un escenario determinado sugiera que resulta adecuada la herencia del valor de la
propiedad. Puede determinar si una propiedad de dependencia se hereda examinando la seccin
Informacin de propiedad de dependencia de esa propiedad de dependencia en la referencia del SDK.
En el ejemplo siguiente se muestra un enlace y se establece la propiedad DataContext que especifica el origen
del enlace, lo que no se mostraba en el ejemplo de enlace anterior. El valor de la propiedad DataContext se
hereda, por consiguiente los enlaces subsiguientes de los elementos secundarios no tendrn que respetar el
origen que se especifica como DataContext en el elemento StackPanel primario.
<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource
XmlTeamsSource}}">
<Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>
Integracin de WPF Designer
Un control personalizado con propiedades implementadas como propiedades de dependencia recibir la
compatibilidad con Windows Presentation Foundation (WPF) Designer for Visual Studio adecuada. Un ejemplo
es la capacidad de modificar propiedades de dependencia directas y asociadas con la ventana Propiedades.
Prioridad de los valores de propiedades de dependencia
Al obtener el valor de una propiedad de dependencia, se est obteniendo potencialmente un valor que se
estableci en esa propiedad mediante cualquiera de las dems entradas basadas en propiedad que participan
en el sistema de propiedades de WPF. La prioridad de valor de propiedad de dependencia existe para que
diversos escenarios de obtencin de valores para propiedades puedan interactuar de una manera predecible.
Considere el ejemplo siguiente. El ejemplo incluye un estilo que se aplica a todos los botones y sus propiedades
Background, pero tambin especifica un botn con un valor Background establecido localmente.
Nota:
La documentacin de SDK utiliza ocasionalmente los trminos "valor local" o valor "localmente establecido"
para explicar las propiedades de dependencia. Un valor localmente establecido es un valor de propiedad
que se establece directamente en una instancia de objeto en cdigo o como un atributo de un elemento en
XAML.
De hecho, para el primer botn, la propiedad se establece dos veces, pero solamente se aplica un valor: el que
tiene la prioridad superior. Un valor localmente establecido tiene la prioridad superior (excepto para una

MCT: Luis Dueas

Pag 315 de 445

Manual de Windows Presentation Foundation


animacin en ejecucin, pero no hay ninguna animacin en este ejemplo) y, as, se utiliza el valor establecido
localmente en lugar del valor del establecedor del estilo para el segundo plano del primer botn. El segundo
botn no tiene ningn valor local (y ningn otro valor con prioridad ms alta que un establecedor de estilo) y,
as, el fondo de ese botn procede del establecedor del estilo.
<StackPanel>
<StackPanel.Resources>
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red"/>
</Style>
</StackPanel.Resources>
<Button Background="Green">I am NOT red!</Button>
<Button>I am styled red</Button>
</StackPanel>
Por qu existe la prioridad de propiedad de dependencia?
Normalmente, no se desea que los estilos se apliquen siempre y oculten incluso un valor localmente establecido
de un elemento individual (de lo contrario, sera muy difcil utilizar estilos o elementos en general). Por
consiguiente, los valores que proceden de estilos funcionan con una prioridad ms baja que un valor
establecido localmente.
Nota:
Hay varias propiedades definidas en elementos de WPF que no son propiedades de dependencia.
Habitualmente, las propiedades se implementan como propiedades de dependencia solamente cuando es
necesario admitir por lo menos uno de los escenarios habilitados por el sistema de propiedades: enlace de
datos, estilos, animacin, compatibilidad con valor predeterminado, herencia, propiedades asociadas o
invalidacin.
Ms informacin sobre propiedades de dependencia

Una propiedad asociada es un tipo de propiedad que admite una sintaxis especializada en XAML. Una
propiedad asociada no suele tener una correspondencia 1:1 con una propiedad de common language
runtime (CLR) y no es necesariamente una propiedad de dependencia. El propsito tpico de una
propiedad asociada es permitir que los elementos secundarios informen de los valores de la propiedad
a un elemento primario, aunque el elemento primario y los elementos secundarios no posean esa
propiedad como parte de las listas de miembros de la clase. Un escenario primario consiste en permitir
que los elementos secundarios informen el elemento primario de cmo se deben presentar en interfaz
de usuario.

Los programadores de componentes y los desarrolladores de aplicaciones pueden desear crear


propiedades de dependencia propias para habilitar funciones tales como el enlace de datos o la
compatibilidad con estilos, o para la invalidacin y la coercin de valor.

Generalmente las propiedades de dependencia deben considerarse propiedades pblicas, accesibles o,


por lo menos, reconocibles por cualquier llamador que tenga acceso a una instancia.

3.5.2. Informacin General sobre Propiedades Asociadas


Una propiedad asociada es un concepto definido por Lenguaje de marcado de aplicaciones extensible (XAML).
Las propiedades asociadas estn destinadas a utilizarse como un tipo de propiedad global configurable en
cualquier objeto. En Windows Presentation Foundation (WPF), las propiedades asociadas se definen
habitualmente como una forma especializada de propiedad de dependencia que no tiene el "contenedor" de
propiedad convencional.
Por qu usar propiedades asociadas
Uno de los propsitos de una propiedad asociada es permitir que los diferentes elementos secundarios
especifiquen valores nicos para una propiedad que en realidad est definida en un elemento primario. Una
aplicacin concreta de este escenario es hacer que los elementos secundarios informen al elemento primario de
cmo se presentarn en la interfaz de usuario (UI). Un ejemplo es la propiedad DockPanel.Dock. La propiedad
Dock se crea como una propiedad asociada porque se ha diseado para establecerse en elementos contenidos
dentro de un objeto DockPanel, en lugar de en el propio objeto DockPanel. La clase DockPanel define el campo

MCT: Luis Dueas

Pag 316 de 445

Manual de Windows Presentation Foundation


esttico DependencyProperty denominado DockProperty y, a continuacin, proporciona los mtodos GetDock y
SetDock como descriptores de acceso pblicos para la propiedad asociada.
Propiedades asociadas en XAML
En XAML, las propiedades asociadas se establecen usando la sintaxis
ProveedorDePropiedadAsociada.PropertyName.
A continuacin, se muestra un ejemplo de cmo se puede establecer DockPanel.Dock en XAML:
<DockPanel>
<CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>
Observe que el uso es similar a una propiedad esttica; siempre se hace referencia al tipo DockPanel que posee
y registra la propiedad asociada, en lugar de hacer referencia a ninguna instancia especificada por nombre.
Adems, dado que una propiedad asociada en XAML es un atributo que se establece en el marcado, solamente
la operacin de establecimiento tiene alguna relevancia. No es posible obtener directamente una propiedad en
XAML, aunque hay algunos mecanismos indirectos para comparar valores, tales como desencadenadores en
estilos.
Implementacin de propiedad asociada en WPF
En Windows Presentation Foundation (WPF), la mayora de las propiedades asociadas que existen en tipos WPF
se implementan como propiedades de dependencia. Las propiedades asociadas son un concepto de XAML,
mientras que las propiedades de dependencia son un concepto de WPF. Dado que las propiedades asociadas de
WPF son propiedades de dependencia, admiten conceptos de las propiedades de dependencia tales como los
metadatos de propiedad y los valores predeterminados de esos metadatos de propiedad.
Cmo el tipo propietario utiliza las propiedades asociadas
Aunque las propiedades asociadas son configurables en cualquier objeto, eso no significa automticamente que
la configuracin de la propiedad vaya a producir un resultado tangible, o ni que el valor vaya a ser usado
alguna vez por otro objeto. Generalmente, las propiedades asociadas se conciben de modo que objetos
procedentes de una amplia variedad de posibles jerarquas de clases o relaciones lgicas puedan proporcionar
informacin comn, cada uno de ellos, al tipo propietario. El tipo que define la propiedad asociada sigue
normalmente uno de estos modelos:

El tipo que define la propiedad asociada se ha diseado de modo que pueda ser el elemento primario
de los elementos que establecern los valores de la propiedad asociada. El tipo recorre a continuacin
sus elementos secundarios mediante lgica interna, obtiene los valores y acta sobre esos valores de
alguna manera.

El tipo que define la propiedad asociada se utilizar como elemento secundario para una variedad de
posibles elementos principales y modelos de contenido.

El tipo que define la propiedad asociada representa un servicio. Otros tipos establecen valores para la
propiedad asociada. A continuacin, cuando el elemento que estableci la propiedad se evala en el
contexto del servicio, los valores de la propiedad asociada se obtienen a travs de lgica interna de la
clase de servicio.

Ejemplo de una propiedad asociada definida por el elemento primario


El escenario ms tpico donde WPF define una propiedad asociada es cuando un elemento primario admite una
coleccin de elementos secundarios, y tambin implementa un comportamiento donde los caractersticas del
comportamiento se indican individualmente para cada elemento secundario.
DockPanel define la propiedad Dock asociada y DockPanel tiene cdigo del nivel de clase como parte de su
lgica de representacin (especficamente, MeasureOverride y ArrangeOverride). Una instancia de DockPanel
siempre comprobar si cualquiera de sus elementos secundarios inmediatos ha establecido un valor para Dock.

MCT: Luis Dueas

Pag 317 de 445

Manual de Windows Presentation Foundation


En ese caso, esos valores se convierten en la entrada para la lgica de representacin que se aplica a ese
elemento secundario en particular. Las instancias anidadas de DockPanel se ocupan, cada una de ellas, se sus
propios elementos secundarios inmediatos, pero ese comportamiento es especfico de la implementacin. Es
tericamente posible tener propiedades asociadas que influyan sobre elementos ms all del elemento primario
inmediato. Si la propiedad asociada Dock se establece en un elemento que no tiene ningn elemento primario
DockPanel sobre el que actuar, no se produce ningn error ni ninguna excepcin. Esto significa simplemente
que se estableci un valor de propiedad global, pero que no hay ningn elemento primario DockPanel que
pueda utilizar la informacin.
Propiedades asociadas en cdigo
Las propiedades asociadas en WPF no tienen los mtodos "contenedores" tpicos de CLR para facilitar el acceso
se lectura o escritura. Esto se debe a que la propiedad asociada no forma parte necesariamente del espacio de
nombres CLR para las instancias donde se establece la propiedad. Sin embargo, un lector de XAML debe poder
establecer esos valores cuando se procesa XAML. Para que una propiedad asociada sea efectiva, el tipo
propietario de la propiedad asociada debe implementar mtodos de descriptor de acceso dedicados en la forma
PropertyName y Set PropertyName. Estos mtodos de descriptor de acceso dedicados son tambin el medio
para obtener o establecer la propiedad asociada en el cdigo. Desde la perspectiva del cdigo, una propiedad
asociada es similar a un campo de apoyo que tiene descriptores de acceso de mtodo en lugar de descriptores
de acceso de propiedad; ese campo de apoyo puede existir en cualquier objeto, en lugar de tener que definirse
especficamente.
El ejemplo siguiente muestra cmo puede establecer una propiedad asociada en cdigo. En este siguiente
ejemplo, myCheckBox es una instancia de la clase CheckBox.
DockPanel myDockPanel = new DockPanel();
CheckBox myCheckBox = new CheckBox();
myCheckBox.Content = "Hello";
myDockPanel.Children.Add(myCheckBox);
DockPanel.SetDock(myCheckBox, Dock.Top);
De forma similar al caso de XAML, si myCheckBox no se hubiera sido agregado an como un elemento
secundario de myDockPanel por la tercera lnea de cdigo, la cuarta lnea de cdigo no producira una
excepcin, pero el valor de la propiedad no interactuara con un elemento primario DockPanel y, por lo tanto,
no hara nada. Solamente un valor Dock establecido en un elemento secundario, combinado con la presencia de
un elemento primario DockPanel, producir un comportamiento efectivo en la aplicacin representada.
Metadatos de propiedad asociados
Al registrar la propiedad, FrameworkPropertyMetadata se establece para especificar caractersticas de la
propiedad como, por ejemplo, si la propiedad afecta a la representacin, a la medicin, etc. Los metadatos para
una propiedad asociada no son diferentes, en general, en una propiedad de dependencia. Si se especifica un
valor predeterminado en una invalidacin para metadatos de propiedad asociada, ese valor se convierte en el
valor predeterminado de la propiedad asociada implcita en instancias de la clase de reemplazo. El valor
predeterminado se indica, especficamente, si algn proceso consulta el valor de una propiedad asociada a
travs del descriptor de acceso de mtodo Get para esa propiedad, especificando una instancia de la clase
donde se especificaron los metadatos, y no se ha establecido de ninguna otra manera el valor de esa propiedad
asociada.
Si desea habilitar la herencia del valor de la propiedad en una propiedad, es recomendable que utilice
propiedades asociadas en lugar de propiedades de dependencia no asociadas.
Propiedades asociadas personalizadas
Cundo crear una propiedad asociada
Se puede crear una propiedad asociada cuando haya una razn para tener un mecanismo de configuracin de
propiedad disponible para clases distintas de la clase de la definicin. El escenario ms comn para ello es el
diseo. Ejemplos de propiedades de diseo existentes son DockPanel.Dock, Panel.ZIndex y Canvas.Top. El
escenario habilitado aqu es que los elementos que existen como elementos secundarios para los elementos que

MCT: Luis Dueas

Pag 318 de 445

Manual de Windows Presentation Foundation


controlan el diseo pueden expresar individualmente los requisitos de diseo para sus elementos principales de
diseo, cada uno de los cuales establece un valor de propiedad que el elemento primario ha definido como una
propiedad asociada.
Otro escenario para utilizar una propiedad asociada es cuando la clase representa un servicio y se desea que las
clases puedan integrar el servicio de forma ms transparente.
Hay otro escenario ms compatible con Visual Studio 2008WPF Designer, tal como la edicin de ventana
Propiedades.
Como ya se ha mencionado, se debe registrar como una propiedad asociada si se desea utilizar la herencia del
valor de la propiedad.
Cmo crear una propiedad asociada
Si la clase est definiendo la propiedad asociada estrictamente para el uso en otros tipos, no es necesario que
la clase derive de DependencyObject. No obstante, s deber derivar de DependencyObject si sigue el modelo
WPF general consistente en hacer que la propiedad asociada sea tambin una propiedad de dependencia.
Defina la propiedad asociada como una propiedad de dependencia declarando un campo publicstaticreadonly de
tipo DependencyProperty. Para definir este campo, utilice el valor devuelto del mtodo RegisterAttached. El
nombre de campo debe coincidir con el nombre de propiedad asociado, al que se anexa la cadena Property,
para seguir el modelo WPF establecido de denominar los campos identificadores segn las propiedades que
representan. El proveedor de la propiedad asociada tambin debe proporcionar los mtodos GetPropertyName y
SetPropertyName como descriptores de acceso para la propiedad asociada; si no lo hace, el sistema de
propiedades no podr utilizar la propiedad asociada.
El descriptor de acceso Get
La firma para el descriptor de acceso GetPropertyName debe ser:

public static object GetPropertyName(object target)

El objeto target se puede especificar como un tipo ms especfico en la implementacin. Por ejemplo,
el mtodo DockPanel.GetDock establece el tipo del parmetro como UIElement, porque la propiedad
asociada solamente est destinada a establecerse en instancias de UIElement.

El valor devuelto se puede especificar como un tipo ms especfico en la implementacin. Por ejemplo,
el mtodo GetDock define el tipo como Dock, porque el valor solamente se puede establecer en esa
enumeracin.

El descriptor de acceso Set


La firma para el descriptor de acceso SetPropertyName debe ser:
public static void SetPropertyName(object target, object value)

El objeto target se puede especificar como un tipo ms especfico en la implementacin. Por ejemplo,
el mtodo SetDock establece el tipo como UIElement, porque la propiedad asociada solamente est
destinada a establecerse en instancias de UIElement.

El objeto value se puede especificar como un tipo ms especfico en la implementacin. Por ejemplo, el
mtodo SetDock define el tipo como Dock, porque el valor solamente se puede establecer en esa
enumeracin. Recuerde que el valor para este mtodo es la entrada procedente del cargador de XAML
cuando encuentra la propiedad asociada en un uso de propiedad asociada en el marcado. Esa entrada
es el valor especificado como valor de atributo XAML en el marcado. Por consiguiente, debe haber
compatibilidad con conversin de tipos, serializador de valor o extensin de marcado para el tipo que
se utilice, de modo que se pueda crear el tipo adecuado a partir del valor del atributo (que, en ltima
instancia, no es nada ms que una cadena).

MCT: Luis Dueas

Pag 319 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente se muestra el registro de propiedades de dependencia (usando el mtodo
RegisterAttached), as como los descriptores de acceso GetPropertyName y SetPropertyName. En el ejemplo, el
nombre de la propiedad asociada es IsBubbleSource. Por consiguiente, los descriptores de acceso se deben
denominar GetIsBubbleSource y SetIsBubbleSource.
public static readonly DependencyProperty IsBubbleSourceProperty =
DependencyProperty.RegisterAttached(
"IsBubbleSource",
typeof(Boolean),
typeof(AquariumObject),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
return (Boolean)element.GetValue(IsBubbleSourceProperty);
}
Atributos de propiedad asociada
WPF define varios Atributos de .NET Framework destinados a proporcionar informacin sobre las propiedades
asociadas a los procesos de la reflexin, as como a usuarios tpicos de reflexin e informacin de propiedad
tales como los diseadores. Dado que las propiedades asociadas tienen un tipo de mbito ilimitado, los
diseadores necesitan una manera de evitar abrumar a los usuarios con una lista global de todas las
propiedades asociadas definidas en una determinada implementacin de la tecnologa que utilice XAML. Los
Atributos de .NET Framework que define WPF para las propiedades asociadas se pueden utilizar para definir el
mbito en aquellas situaciones en las que una propiedad asociada dada deba mostrarse en una ventana de
propiedades. Tambin se puede considerar la aplicacin de estos atributos para propiedades asociadas propias.

3.5.3. Devoluciones de Llamada y Validacin de las Propiedades de


Dependencia
En este tema se describe cmo crear propiedades de dependencia utilizando implementaciones personalizadas
alternativas para las caractersticas relacionadas con propiedades, tales como la determinacin de validacin,
las devoluciones de llamada que se invocan cada vez que cambia el valor efectivo de la propiedad, y la
invalidacin de posibles influencias externas para la determinacin del valor. En este tema tambin se explican
los escenarios donde es apropiado expandir los comportamientos del sistema de propiedades predeterminado
mediante estas tcnicas.
Devoluciones de llamada de validacin
Las devoluciones de llamada de validacin se pueden asignar a una propiedad de dependencia cuando se
registra por primera vez. La devolucin de llamada de validacin no forma parte de los metadatos de la
propiedad; es una entrada directa del mtodo Register. Por consiguiente, una vez creada una devolucin de
llamada de validacin para una propiedad de dependencia, no puede invalidarse mediante una nueva
implementacin.
Las devoluciones de llamada se implementan de modo que se les proporcione un valor de objeto. Devuelven
true si el valor proporcionado es vlido para la propiedad; de lo contrario, devuelven false. Se supone que la
propiedad es del tipo correcto con respecto al tipo registrado en el sistema de propiedades, por lo que
normalmente no se comprueba su tipo dentro de las devoluciones de llamada. El sistema de propiedades utiliza
las devoluciones de llamada en varias operaciones diferentes. Entre ellas, se incluyen la inicializacin de tipos
por valores predeterminados, el cambio mediante programacin invocando el mtodo SetValue, o los intentos
de invalidacin de metadatos con el nuevo valor predeterminado proporcionado. Si cualquiera de estas
operaciones invoca la devolucin de llamada de validacin, y devuelve false, entonces se inicia una excepcin.
El autor de la aplicacin debe estar preparado para administrar estas excepciones. Un uso comn de las
devoluciones de llamada de validacin es la validacin de valores de enumeracin, o la restriccin de valores de
tipo Integer o Double cuando la propiedad establece medidas que deben ser mayores o iguales que cero.

MCT: Luis Dueas

Pag 320 de 445

Manual de Windows Presentation Foundation


Las devoluciones de llamada de validacin estn diseadas especficamente como validadores de clase, no de
instancias. Los parmetros de la devolucin de llamada no comunican un objeto DependencyObject concreto
para el que se establecen las propiedades que se van a validar. Por consiguiente, las devoluciones de llamada
de validacin no resultan tiles para aplicar las posibles "dependencias" que podran influir en el valor de una
propiedad, donde el valor especfico de la instancia de una propiedad depende de factores tales como los
valores especficos de la instancia de otras propiedades, o el estado en tiempo de ejecucin.
A continuacin, se muestra un ejemplo de cdigo para un escenario de devolucin de llamada de validacin
muy simple: se valida que el valor de una propiedad cuyo tipo primitivo es Double no es PositiveInfinity ni
NegativeInfinity.
Devoluciones de llamada de forzado de valores y eventos de cambio de propiedad
Las devoluciones de llamada de forzado de valores pasan la instancia de DependencyObject especfica para las
propiedades, al igual que las implementaciones de PropertyChangedCallback que invoca el sistema de
propiedades cada vez que cambia el valor de una propiedad de dependencia. Mediante el uso combinado de
estas dos devoluciones de llamada, puede crear una serie de propiedades de elementos de tal forma que los
cambios de una propiedad fuercen una conversin o reevaluacin de otra propiedad.
Un escenario tpico en que se suele usar la vinculacin de propiedades de dependencia es aqul en que existe
una propiedad controlada por la interfaz de usuario donde el elemento contiene una propiedad para cada valor
mnimo y mximo, y una tercera propiedad para el valor real o actual. Aqu, si el mximo se ajustara de tal
modo que el valor actual superase el nuevo mximo, sera deseable forzar el valor actual de manera que no
fuese mayor que el nuevo mximo, con una relacin similar entre los valores mnimo y actual.
A continuacin, se muestra un ejemplo de cdigo muy breve con una sola de las tres propiedades de
dependencia que ilustran esta relacin. En el ejemplo se muestra cmo se registra la propiedad CurrentReading
de un conjunto Min/Max/Current de propiedades *Reading. Se utiliza la validacin como se indica en la seccin
anterior.
La devolucin de llamada de cambio de propiedad para el valor Current se utiliza para reenviar el cambio a
otras propiedades dependientes, invocando explcitamente las devoluciones de llamada de forzado de valores
registradas para esas otras propiedades:
La devolucin de llamada de forzado de valores comprueba los valores de las propiedades de las que depende
potencialmente la propiedad actual y fuerza el valor actual si es necesario:
Nota:
Los valores predeterminados de las propiedades no se fuerzan. Puede ocurrir que se produzca un valor de
propiedad igual al predeterminado si un valor de propiedad sigue teniendo su valor predeterminado inicial,
o si se borran otros valores con el mtodo ClearValue.
Las devoluciones de llamada de forzado de valores y de cambio de propiedad forman parte de los metadatos de
una propiedad. Por consiguiente, puede cambiar las devoluciones de llamada para una propiedad de
dependencia determinada cuando existe en un tipo que se deriva del tipo que posee la propiedad de
dependencia, invalidando los metadatos para esa propiedad en el tipo.
Escenarios avanzados de forzado y devolucin de llamada
Restricciones y valores deseados
El sistema de propiedades utiliza las devoluciones de llamada de CoerceValueCallback para forzar un valor de
conformidad con la lgica que se declara, pero un valor forzado de una propiedad establecida localmente
conservar internamente un "valor deseado". Si las restricciones se basan en otros valores de propiedad que
pueden cambiar dinmicamente en el transcurso de la duracin de la aplicacin, tambin se cambian
dinmicamente las restricciones de forzado, con lo que puede suceder que cambie el valor de la propiedad
restringida a fin de acercarse lo ms posible al valor deseado en virtud de esas nuevas restricciones. El valor se

MCT: Luis Dueas

Pag 321 de 445

Manual de Windows Presentation Foundation


convertir en el valor deseado si se retiran todas las restricciones. Potencialmente, es posible incluir algunos
escenarios de dependencia bastante complicados si tiene varias propiedades dependientes entre s de manera
circular. Por ejemplo, en el escenario Min/Max/Current (con tres valores: mnimo, mximo y actual), podra
permitir al usuario establecer el mnimo y el mximo. En este caso, podra ser necesario forzar el valor mximo
para que siempre sea mayor que el mnimo, y viceversa. Pero si ese forzado est activo, y el mximo se fuerza
al mnimo, dejar el valor actual en un estado que no permite establecerlo, porque depende de ambos valores y
est restringido al intervalo comprendido entre ellos, que es cero. A continuacin, si se ajustan el mximo y el
mnimo, el valor actual parecer "seguir" a uno de los valores, porque el valor deseado del valor actual sigue
estando almacenado e intenta alcanzar el valor deseado cuando se retiran las restricciones.
Tcnicamente, no hay nada de malo en establecer dependencias complejas, pero pueden provocar un ligero
deterioro del rendimiento si requieren grandes cantidades de reevaluaciones, adems de resultar confusas para
los usuarios si afectan directamente a la interfaz de usuario. Extreme las precauciones con las devoluciones de
llamada de cambio de propiedad y de forzado de valores: asegrese de que el forzado previsto se pueda tratar
del modo menos ambiguo posible y no cree un exceso de restriccin. En este SDK se incluye un ejemplo
(Ejemplo PropertyChanged and CoerceValue Callbacks) que ilustra de manera deliberada algo que no constituye
necesariamente un procedimiento recomendado para el forzado, con varias propiedades de dependencia
interrelacionadas y algunas presentaciones de la interfaz de usuario. Es conveniente experimentar con este
ejemplo a fin de ilustrar los problemas de restriccin, adems del concepto de valor deseado que hemos
explicado.
Utilizar valores de forzado para cancelar cambios de valor
El sistema de propiedades tratar cualquier CoerceValueCallback que devuelva el valor UnsetValue como un
caso especial. Este caso especial significa que el sistema de propiedades debe rechazar el cambio de propiedad
que ha dado lugar a la llamada a CoerceValueCallback, y que el sistema de propiedades debe comunicar, en su
lugar, el valor anterior que tena la propiedad. Este mecanismo puede ser til para comprobar si los cambios de
una propiedad iniciados de manera asincrnica siguen siendo vlidos para el estado actual del objeto y
suprimirlos en caso negativo. Otro escenario posible es la supresin selectiva de un valor dependiendo de qu
componente de la determinacin del valor de la propiedad sea responsable del valor comunicado. Para ello,
puede utilizar el objeto DependencyProperty pasado en la devolucin de llamada y el identificador de propiedad
como entrada para el mtodo GetValueSource y, a continuacin, procesar ValueSource.

3.5.4. Propiedades de Dependencia Personalizadas


En este tema se describen las razones por las que los desarrolladores de aplicaciones y los autores de
componentes de Windows Presentation Foundation (WPF) pueden desear crear una propiedad de dependencia
personalizada, y se describen los pasos de implementacin as como algunas opciones de implementacin que
pueden mejorar el rendimiento, la facilidad de uso o la versatilidad de la propiedad.
Qu es una propiedad de dependencia?
Puede habilitar lo que de otro modo sera una propiedad de common language runtime (CLR) para que admita
estilos, enlaces de datos, herencia, animaciones y valores predeterminados implementndola como una
propiedad de dependencia. Las propiedades de dependencia son propiedades que se registran con el sistema de
propiedades de WPF llamando al mtodo Register (o RegisterReadOnly) y que estn respaldadas por un campo
de identificador DependencyProperty. Las propiedades de dependencia slo pueden utilizarlas los tipos
DependencyObject, pero como DependencyObject se encuentra bastante arriba en la jerarqua de clases de
WPF, la mayora de las clases disponibles en WPF pueden admitir propiedades de dependencia.
Ejemplos de propiedades de dependencia
Como ejemplos de propiedades de dependencia que se implementan en clases de WPF pueden mencionarse la
propiedad Background, la propiedad Width y la propiedad Text, entre muchas otras. Cada propiedad de
dependencia

expuesta

por

una

clase

tiene

un

campo

esttico

pblico

correspondiente

de

tipo

DependencyProperty expuesto en esa misma clase. ste es el identificador de la propiedad de dependencia. Al

MCT: Luis Dueas

Pag 322 de 445

Manual de Windows Presentation Foundation


identificador se le asigna un nombre utilizando una convencin: el nombre de la propiedad de dependencia con
la cadena Property anexada. Por ejemplo, el campo de identificador DependencyProperty correspondiente a la
propiedad Background es BackgroundProperty. El identificador almacena la informacin sobre la propiedad de
dependencia en el momento de su registro y el identificador se utiliza despus para otras operaciones
relacionadas con la propiedad de dependencia, como llamar a SetValue.
Tal y como se indica en Informacin general sobre las propiedades de dependencia, todas las propiedades de
dependencia de WPF (salvo la mayora de las propiedades asociadas) tambin son propiedades de CLR debido a
la implementacin de "contenedores". Por lo tanto, puede obtener o establecer las propiedades de dependencia
desde el cdigo llamando a los descriptores de acceso de CLR, que definen los contenedores de la misma
manera que utilizara otras propiedades de CLR. Como consumidor de propiedades de dependencia
establecidas, lo normal es que no utilice los mtodos GetValue y SetValue de DependencyObject, que
constituyen el punto de conexin con el sistema de propiedades subyacente. En lugar de ello, lo habitual es que
la implementacin existente de las propiedades de CLR ya haya llamado a GetValue y SetValue dentro de las
implementaciones de contenedor get y set de la propiedad, utilizando apropiadamente el campo de
identificador. Si est implementando una propiedad de dependencia personalizada propia, estar definiendo el
contenedor de forma similar.
Cundo debe implementarse una propiedad de dependencia?
Al implementar una propiedad en una clase, siempre y cuando la clase se derive de DependencyObject, tiene la
opcin de respaldar su propiedad con un identificador DependencyProperty y, de este modo, convertirla en una
propiedad de dependencia. No siempre ser necesario o adecuado convertir una propiedad en una propiedad de
dependencia, sino que depender de las necesidades de su escenario. En ocasiones, ser adecuada la tcnica
tpica de respaldar una propiedad con un campo privado. Sin embargo, debera implementar su propiedad como
una propiedad de dependencia siempre que desee que su propiedad admita una o varias de las siguientes
funciones de WPF:

Desea que su propiedad pueda establecerse en un estilo.

Desea que su propiedad admita el enlace de datos.

Desea que su propiedad pueda establecerse con una referencia de recurso dinmico.

Desea heredar automticamente el valor de una propiedad de un elemento primario del rbol de
elementos. En este caso, efecte el registro con el mtodo RegisterAttached, incluso aunque tambin
cree un contenedor de propiedades para el acceso de CLR.

Desea que su propiedad pueda animarse.

Desea que el sistema de propiedades notifique el momento en el que cambie el valor anterior de la
propiedad mediante acciones realizadas por el sistema de propiedades, el entorno o el usuario, o
mediante la lectura y el uso de estilos. El uso de metadatos de propiedad permite que su propiedad
especifique un mtodo de devolucin de llamada que se invocar cada vez que el sistema de
propiedades determine que el valor de la propiedad ha cambiado definitivamente. Un concepto
relacionado esto ltimo es la conversin del valor de las propiedades.

Desea utilizar convenciones de metadatos establecidas que tambin se utilizan en los procesos de
WPF, como notificar si el cambio de valor de una propiedad debe exigir que el sistema de diseo
recomponga la representacin visual de un elemento. O bien, desea poder utilizar invalidaciones para
los metadatos de forma que las clases derivadas puedan modificar las caractersticas basadas en
metadatos, como el valor predeterminado.

Desea que las propiedades de un control personalizado sean compatibles con caractersticas de Visual
Studio 2008 WPF Designer, como la edicin en la ventana Propiedades.

MCT: Luis Dueas

Pag 323 de 445

Manual de Windows Presentation Foundation


Al examinar estos escenarios, tambin debe tener en cuenta si puede obtener su escenario invalidando los
metadatos de una propiedad de dependencia existente, en lugar de implementar una propiedad completamente
nueva. La invalidacin de los metadatos ser factible o no en funcin de su escenario y de la similitud de dicho
escenario con la implementacin de las clases y propiedades de dependencia de WPF.
Lista de comprobacin para definir una propiedad de dependencia
La definicin de una propiedad de dependencia consiste en cuatro conceptos distintos. Estos conceptos no son
necesariamente los pasos de un procedimiento estricto, ya que algunos de ellos acaban combinndose en una
sola lnea de cdigo en la implementacin:

(Opcional) Cree metadatos de propiedad para la propiedad de dependencia.


Registre el nombre de la propiedad con el sistema de propiedades, especificando un tipo de propietario
y el tipo de valor de la propiedad. Especifique tambin los metadatos de la propiedad, si se utilizan.

Defina un identificador DependencyProperty como un campo publicstaticreadonly en el tipo de


propietario.

Defina una propiedad de "contenedor" de CLR cuyo nombre coincida con el nombre de la propiedad de
dependencia. Implemente los descriptores de acceso get y set de la propiedad de "contenedor" de CLR
para conectarla con la propiedad de dependencia que la respalda.

Registrar la propiedad con el sistema de propiedades


Para que su propiedad sea una propiedad de dependencia, deber registrarla en una tabla que mantiene el
sistema de propiedades y asignarle un identificador nico que se utilice como certificador para las operaciones
posteriores del sistema de propiedades. Estas operaciones podran ser operaciones internas o su propio cdigo
llamando a las API del sistema de propiedades. Para registrar la propiedad, llame al mtodo Register dentro del
cuerpo de su clase (dentro de la clase, pero fuera de las definiciones de miembros). La llamada al mtodo
Register tambin proporciona el campo de identificador como valor devuelto. La razn por la que la llamada a
Register se realiza fuera de las dems definiciones de miembros es porque este valor devuelto se utiliza para
asignar y crear un campo public static readonly de tipo DependencyProperty como parte de la clase. Este
campo se convierte en el identificador para la propiedad de dependencia.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
Convenciones de nomenclatura de las propiedades de dependencia
Existen convenciones de nomenclatura establecidas para las propiedades de dependencia que debe cumplir
siempre salvo en circunstancias excepcionales.
La propiedad de dependencia propiamente dicha tendr un nombre bsico, como "AquariumGraphic" en este
ejemplo, que se proporciona como primer parmetro de Register. Este nombre debe ser nico para cada tipo de
registro. Se considera que las propiedades de dependencia heredadas a travs de los tipos base ya forman
parte del tipo de registro; los nombres de las propiedades heredadas no pueden volver a registrarse. No
obstante, existe una tcnica para agregar una clase como propietario de una propiedad de dependencia,
aunque dicha propiedad de dependencia no sea heredada.
Al crear el campo de identificador, asgnele el nombre de la propiedad tal y como lo registr, ms el sufijo
Property. Este campo es el identificador de la propiedad de dependencia y se utilizar despus como entrada
para las llamadas a SetValue y GetValue que se realizarn en los contenedores, por parte de cualquier otro
acceso de cdigo a la propiedad efectuado por su propio cdigo, por parte de cualquier acceso de cdigo
externo permitido, por parte del sistema de propiedades y, posiblemente, por parte de los procesadores de
XAML.

MCT: Luis Dueas

Pag 324 de 445

Manual de Windows Presentation Foundation

Nota:
La implementacin tpica consiste en definir la propiedad de dependencia en el cuerpo de la clase, pero
tambin es posible definir una propiedad de dependencia en el constructor esttico de la clase. Este
enfoque podra tener sentido es necesaria ms de una lnea de cdigo para inicializar la propiedad de
dependencia.
Implementar el "contenedor"
Su implementacin del contenedor debera llamar a GetValue en la implementacin de get y a SetValue en la
implementacin de set (el campo y la llamada de registro original tambin se muestran aqu para mayor
claridad).
Salvo en circunstancias excepcionales, sus implementaciones de contenedores slo deberan realizar las
acciones GetValue y SetValue, respectivamente. El motivo de ello se explica en el tema Carga de XAML y
propiedades de dependencia.
Todas las propiedades de dependencia pblicas existentes que se incluyen en las clases de WPF utilizan este
modelo de implementacin de contenedor simple; la mayor parte de la complejidad del funcionamiento de las
propiedades de dependencia es inherentemente un comportamiento del sistema de propiedades o se
implementa a travs de otros conceptos, como la conversin o las devoluciones de llamada de cambio de
propiedad a travs de los metadatos de las propiedades.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register("AquariumGraphic",typeof(Uri),typeof(AquariumObject),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}
De nuevo, por convencin, el nombre de la propiedad de contenedor debe coincidir con el nombre elegido y
usado como primer parmetro de la llamada a Register que registr la propiedad. Si su propiedad no cumple
esta convencin, no necesariamente se deshabilitan todos los usos posibles, pero encontrar varios problemas
importantes:

No funcionarn determinados aspectos de los estilos y las plantillas.


La mayora de las herramientas y los diseadores deben basarse en las convenciones de nomenclatura
para serializar correctamente el XAML o para proporcionar ayuda sobre cada propiedad en el entorno
de diseador.

La implementacin actual del cargador XAML de WPF omite los contenedores por completo y se basa
en la convencin de nomenclatura a la hora de procesar los valores de los atributos.

Metadatos de propiedad para una nueva propiedad de dependencia


Al registrar una propiedad de dependencia mediante el sistema de propiedades, se crea un objeto de metadatos
en el que se almacenan las caractersticas de la propiedad. Muchas de estas caractersticas presentan valores
predeterminados que se establecen si la propiedad se registra con las firmas simples de Register. Otras firmas
de Register le permiten especificar los metadatos que desea al registrar la propiedad. Los metadatos ms
comunes para las propiedades de dependencia consisten en asignarles un valor predeterminado que se aplica a
las nuevas instancias que utilizan la propiedad.
Si est creando una propiedad de dependencia que existe en una clase derivada de FrameworkElement, puede
utilizar la clase de metadatos FrameworkPropertyMetadata ms especializada en lugar de la clase
PropertyMetadata base. El constructor de la clase FrameworkPropertyMetadata presenta varias firmas en las
que puede especificar conjuntamente varias caractersticas de los metadatos. Si slo desea especificar el valor
predeterminado, utilice la firma que toma un nico parmetro de tipo Object. Pase dicho parmetro de objeto
como un valor predeterminado especfico del tipo para su propiedad (el valor predeterminado proporcionado
debe ser el tipo que proporcion como parmetro propertyType en la llamada a Register).

MCT: Luis Dueas

Pag 325 de 445

Manual de Windows Presentation Foundation


En el caso de FrameworkPropertyMetadata, tambin puede especificar marcadores de opciones de metadatos
para su propiedad. Estos marcadores se convierten en propiedades discretas en los metadatos de la propiedad
despus del registro y se utilizan para comunicar determinadas instrucciones condicionales a otros procesos,
como el motor de diseo.
Establecer marcadores de metadatos adecuados

Si su propiedad (o los cambios realizados en su valor) afecta a la interfaz de usuario (UI) y, en


especial, afecta al modo en que el sistema de diseo debe cambiar de tamao o representar su
elemento en una pgina, establezca uno o varios de los marcadores siguientes: AffectsMeasure,
AffectsArrange, AffectsRender.

AffectsMeasure indica que un cambio realizado en esta propiedad exige un cambio en la


representacin de la interfaz de usuario en el que el objeto contenedor puede necesitar ms o
menos espacio dentro del elemento primario. Por ejemplo, una propiedad "Width" debe tener
establecido este marcador.

AffectsArrange indica que un cambio realizado en esta propiedad exige un cambio en la


representacin de la interfaz de usuario que normalmente no requiere un cambio en el espacio
dedicado, sino que indica que ha cambiado la posicin dentro del espacio. Por ejemplo, una
propiedad "Alignment" debe tener establecido este marcador.

AffectsRender indica que se ha producido algn otro cambio que no afectar al diseo ni a las
medidas, pero que requiere actualizar la representacin. Un ejemplo sera una propiedad que
cambia un color de un elemento existente, como "Background".

Estos marcadores suelen utilizarse como un protocolo en los metadatos para sus propias
implementaciones de invalidacin del sistema de propiedades o devoluciones de llamada de
diseo. Por ejemplo, puede tener una devolucin de llamada OnPropertyChanged que llame a
InvalidateArrange si alguna de las propiedades de la instancia notifica un cambio de valor y tiene
la propiedad AffectsArrange establecida en true en sus metadatos.

Algunas propiedades pueden afectar a las caractersticas de representacin del elemento primario
contenedor de forma mucho ms drstica que los cambios de tamao necesarios mencionados
anteriormente. Un ejemplo es la propiedad MinOrphanLines que se utiliza en el modelo de documentos
dinmicos, cuyos cambios pueden afectar a la representacin global del documento dinmico que
contiene el prrafo. Utilice AffectsParentArrange o AffectsParentMeasure para identificar casos
similares en sus propias propiedades.

De forma predeterminada, las propiedades de dependencia admiten el enlace de datos. Puede


deshabilitarlo intencionadamente en casos en los que no haya ningn escenario realista para el enlace
de datos o en los que el rendimiento del enlace de datos para un objeto de gran tamao suponga un
problema.

De forma predeterminada, el Modo de enlace de datos para las propiedades de dependencia toma
como valor predeterminado OneWay. Siempre puede cambiar el enlace para que sea TwoWay por cada
instancia de enlace. Pero como autor de la propiedad de dependencia, puede hacer la que propiedad
utilice el modo de enlace TwoWay de forma predeterminada. Un ejemplo de una propiedad de
dependencia existente es MenuItem.IsSubmenuOpen; el escenario para esta propiedad es que la
lgica de establecimiento de IsSubmenuOpen y la composicin de MenuItem interacten con el estilo
del tema predeterminado. La lgica de la propiedad IsSubmenuOpen utiliza el enlace de datos de
forma nativa para mantener el estado de la propiedad de acuerdo con otras propiedades de estado y
llamadas a mtodos. Otra propiedad de ejemplo que enlaza TwoWay de forma predeterminada es
TextBox.Text.

Tambin puede habilitar la herencia de propiedades en una propiedad de dependencia personalizada


estableciendo el marcador Inherits. La herencia de propiedades resulta de gran utilidad en escenarios
donde los elementos primarios y secundarios tienen una propiedad en comn, y tiene sentido que el

MCT: Luis Dueas

Pag 326 de 445

Manual de Windows Presentation Foundation


valor de dicha propiedad para los elementos secundarios est establecido en el mismo valor que para
los elementos primarios. Un ejemplo de propiedad heredable es DataContext, que se utiliza para que
las operaciones de enlace habiliten el escenario de detalles principales que resulta tan importante para
la presentacin de datos. Haciendo que DataContext pueda heredarse, cualquier elemento secundario
tambin heredar ese contexto de datos. Debido a la herencia del valor de las propiedades, puede
especificar un contexto de datos en la raz de la pgina o aplicacin y no necesita volver a especificarlo
para los enlaces de todos los elementos secundarios posibles. DataContext tambin es un buen
ejemplo para ilustrar que la herencia invalida el valor predeterminado, pero siempre puede
establecerse localmente en cualquier elemento secundario determinado. La herencia del valor de las
propiedades supone un posible costo de rendimiento y, por lo tanto, debe utilizarse con moderacin.

Establezca el marcador Journal para indicar si los servicios d el diario de navegacin deben detectar o
utilizar su propiedad. Un ejemplo es la propiedad SelectedIndex; todos los elementos seleccionados en
un control de seleccin deben mantenerse cuando se navega por el historial del diario.

Propiedades de dependencia de slo lectura


Puede definir una propiedad de dependencia que sea de slo lectura. No obstante, los escenarios para los que
debe definirse una propiedad de slo lectura son algo distintos, as como el procedimiento utilizado para
registrarlos con el sistema de propiedades y exponer el identificador.
Propiedades de dependencia de tipo de coleccin
Las propiedades de dependencia de tipo coleccin plantean algunos problemas de implementacin adicionales
que hay tener en cuenta.
Consideraciones de seguridad de las propiedades de dependencia
Las propiedades de dependencia deben declararse como propiedades pblicas. Los campos de identificador de
las propiedades de dependencia deben declararse como campos estticos pblicos. Aunque intente declarar
otros niveles de acceso (como protegido), siempre se puede obtener acceso a una propiedad de dependencia a
travs del identificador en combinacin con las API del sistema de propiedades. Es posible incluso obtener
acceso a un campo de identificador protegido debido a las API de determinacin de valores o de notificacin de
metadatos que forman parte del sistema de propiedades, como LocalValueEnumerator.
Propiedades de dependencia y constructores de clases
Existe un principio general en programacin de cdigo administrado (que suelen aplicar las herramientas de
anlisis del cdigo como FxCop) segn el cual los constructores de clases no deben llamar a mtodos virtuales.
Esto se debe a que es posible llamar a constructores como inicializacin base de un constructor de clases
derivadas, y podra entrarse en el mtodo virtual a travs del constructor en un estado de inicializacin
incompleto de la instancia del objeto que se est construyendo. Al derivar de cualquier clase que ya se deriva
de DependencyObject, debe ser consciente de que el propio sistema de propiedades llama y expone
internamente los mtodos virtuales. Estos mtodos virtuales forman parte de los servicios del sistema de
propiedades de WPF. Al invalidar los mtodos se permite que las clases derivadas participen en la
determinacin de valores. Para evitar posibles problemas con la inicializacin en tiempo de ejecucin, no debe
establecer los valores de las propiedades de dependencia dentro de los constructores de clases, a menos que
siga un modelo de constructor muy concreto.

3.5.5. Metadatos de las Propiedades de Dependencia


El sistema de propiedades de Windows Presentation Foundation (WPF) incluye un sistema de informe de
metadatos que va ms all de lo que se puede informar de una propiedad mediante reflexin o caractersticas
generales de common language runtime (CLR). Los metadatos para una propiedad de dependencia pueden
asignarse tambin de forma nica mediante la clase que define una propiedad de dependencia, pueden
modificarse cuando la propiedad de dependencia se agrega a una clase diferente y pueden ser invalidados

MCT: Luis Dueas

Pag 327 de 445

Manual de Windows Presentation Foundation


especficamente por todas las clases derivadas que hereden la propiedad de dependencia de la clase base de la
definicin.
Cmo se utilizan los metadatos de propiedades de dependencia
Los metadatos de propiedad de dependencia existen como un objeto que se puede consultar para examinar las
caractersticas de una propiedad de dependencia. El sistema de propiedades tiene acceso tambin con
frecuencia a estos metadatos cuando procesa cualquier propiedad de dependencia determinada. El objeto de
metadatos para una propiedad de dependencia puede contener los tipos siguientes de informacin:

Valor predeterminado para la propiedad de dependencia, si no se puede determinar ningn otro valor
para la propiedad de dependencia por valor local, estilo, herencia, etc. Para ver una explicacin en
profundidad de cmo los valores predeterminados participan en la prioridad utilizada por el sistema de
propiedades al asignar valores para las propiedades de dependencia.

Referencias a las implementaciones de devolucin de llamada que afectan a comportamientos de


coercin o notificacin de cambios propietario por propietario. Tenga en cuenta que estas devoluciones
de llamada se definen a menudo con un nivel de acceso no pblico, as que en general no es posible
obtener las referencias reales de los metadatos a menos que estn dentro el mbito de acceso
permitido.

Si la propiedad de dependencia en cuestin se considera una propiedad del nivel de marco de trabajo
de WPF, los metadatos pueden contener caractersticas de propiedad del nivel de marco de trabajo de
WPF, que proporcionan informacin e indican el estado de servicios tales como el motor de diseo del
nivel de marco de trabajo de WPF y la lgica de herencia de propiedad.

API de metadatos
El tipo que informa de la mayor parte de la informacin de los metadatos utilizados por el sistema de propiedad
es la clase PropertyMetadata. Las instancias de metadatos se especifican opcionalmente cuando se registran
propiedades de dependencia con el sistema de propiedades y pueden especificarse de nuevo para tipos
adicionales que se agregan a s mismos como propietarios o invalidan los metadatos que heredan de la
definicin de propiedad de dependencia de la clase base. (Para los casos donde un registro de propiedad no
especifica metadatos, se crea un objeto PropertyMetadata predeterminado con valores predeterminados para
esa clase.) Los metadatos registrados se devuelven como PropertyMetadata al llamar a las diversas
sobrecargas de GetMetadata que obtienen metadatos de una propiedad de dependencia de una instancia de
DependencyObject.
Entonces se deriva la clase PropertyMetadata para proporcionar metadatos ms concretos para divisiones
arquitectnicas tales como las clases de nivel de marco de trabajo de WPF. UIPropertyMetadata agrega informe
de animacin y [ T:System.Windows.FrameworkPropertyMetadata] proporciona las propiedades de nivel de
marco de trabajo de WPF mencionadas en la seccin anterior. Cuando se registra propiedades de dependencia,
se puede registrarlas con estas clases derivadas de PropertyMetadata. Cuando se examina los metadatos, el
tipo PropertyMetadata base se puede convertir en las clases derivadas para poder examinar las propiedades
ms concretas.
Nota:
Las caractersticas de propiedad que se pueden especificar en FrameworkPropertyMetadata se citan a veces
en esta documentacin como "marcadores". Al crear nuevas instancias de metadatos para su uso en
registros de propiedad de dependencia o invalidaciones de metadatos, debe especificar estos valores
mediante la enumeracin basada en marcadores FrameworkPropertyMetadataOptions y, a continuacin,
proporcionar
valores
de
la
enumeracin
posiblemente
concatenados
al
constructor
FrameworkPropertyMetadata. Sin embargo, una vez construidas, estas caractersticas de opcin se exponen
dentro de un objeto FrameworkPropertyMetadata como una serie de propiedades booleanas en lugar del
valor de enumeracin de construccin. Las propiedades booleanas permiten comprobar cada condicional, en
lugar de exigir que se aplique una mscara a un valor de enumeracin basado en marcadores para obtener
la informacin de inters. El constructor utiliza la enumeracin FrameworkPropertyMetadataOptions

MCT: Luis Dueas

Pag 328 de 445

Manual de Windows Presentation Foundation

concatenada para mantener la longitud de la firma del constructor dentro de lo razonable, mientras que los
metadatos construidos reales exponen las propiedades discretas para hacer que la consulta de los
metadatos sea ms intuitiva.
Cundo invalidar metadatos, cundo derivar una clase
El sistema de propiedades de WPF ha establecido funciones para modificar algunas caractersticas de las
propiedades de dependencia sin necesidad de implementarlas de nuevo por completo. Esto se logra
construyendo una instancia diferente de los metadatos de propiedad para la propiedad de dependencia tal como
existe en un tipo determinado. Tenga en cuenta que la mayora de las propiedades de dependencia existentes
no son propiedades virtuales as que, en rigor, la "reimplantacin" de clases heredadas solamente podra
lograrse sombreando el miembro existente.
Si el escenario que est intentando habilitar para una propiedad de dependencia en un tipo no se puede lograr
modificando caractersticas de propiedades de dependencia existentes, puede que sea necesario crear una clase
derivada y, a continuacin, declarar una propiedad de dependencia personalizada en la clase derivada. Una
propiedad de dependencia personalizada se comporta de forma idntica a las propiedades de dependencia
definidas por las API de WPF.
Una caracterstica notable de una propiedad de dependencia que no se puede invalidar es su tipo de valor. Si
est heredando una propiedad de dependencia que tiene el comportamiento aproximado que necesita, pero
necesita que tenga un tipo diferente, tendr que implementar una propiedad de dependencia personalizada y,
quiz, vincular las propiedades mediante conversin de tipos u otra implementacin en la clase personalizada.
Adems, no es posible invalidar un objeto ValidateValueCallbackexistente, porque esta devolucin de llamada
existe en el propio campo de registro y no dentro de sus metadatos.
Escenarios para modificar metadatos existentes
Si est trabajando con metadatos de una propiedad de dependencia existente, un escenario comn para
modificar metadatos de propiedades de dependencia consiste en modificar el valor predeterminado. Cambiar o
agregar devoluciones de llamada del sistema de propiedades es un escenario ms avanzado. Quiz desee
hacerlo si la implementacin de una clase derivada tiene diferentes interrelaciones entre propiedades de
dependencia. Uno de los condicionantes de tener un modelo de programacin que admita tanto cdigo como el
uso declarativo es que las propiedades deben poder establecerse en cualquier orden. En consecuencia, las
propiedades dependientes deben establecerse en el momento, sin contexto, y no pueden apoyarse en el
conocimiento de un orden de configuracin, tal como el que podra encontrarse en un constructor. Observe que
las devoluciones de llamada de la validacin no forman parte de los metadatos; forman parte del identificador
de propiedad de dependencia. Por consiguiente, las devoluciones de llamada de validacin no se pueden
modificar reemplazando metadatos.
En algunos casos, quiz desee tambin modificar las opciones de metadatos de propiedad del nivel de marco de
trabajo de WPF en propiedades de dependencia existentes. Estas opciones comunican ciertos condicionales
conocidos sobre propiedades del nivel de marco de trabajo de WPF a otros procesos del nivel de marco de
trabajo de WPF tales como el sistema de diseo. La configuracin de opciones, en general, solamente se hace
cuando se registra una nueva propiedad de dependencia, pero tambin es posible cambiar los metadatos de la
propiedad de nivel de marco de trabajo de WPF como parte de una llamada a OverrideMetadata o a AddOwner.
Invalidar metadatos
El propsito de invalidar metadatos es, principalmente, ofrecer la oportunidad de modificar los diversos
comportamientos derivados de metadatos que se aplican a la propiedad de dependencia tal como existe en el
tipo. Las razones para ello se explican con ms detalle en la seccin Metadatos.
Los metadatos de propiedad se pueden proporcionar para una propiedad de dependencia durante la llamada de
registro (Register). Sin embargo, en muchos casos, quiz desee proporcionar metadatos especficos del tipo
para

la

clase

cuando

MCT: Luis Dueas

herede

esa

propiedad

de

dependencia.

Puede

hacerlo

llamando

al

mtodo

Pag 329 de 445

Manual de Windows Presentation Foundation


OverrideMetadata. Para ver un ejemplo de las API de WPF la clase FrameworkElement es el tipo que registra en
primer lugar la propiedad de dependencia Focusable. Sin embargo, la clase Control reemplaza los metadatos
para la propiedad de dependencia, para proporcionar su propio valor predeterminado inicial, cambindolo de
false a true; por lo dems, reutiliza la implementacin original de Focusable.
Cuando se reemplazan metadatos, las distintas caractersticas de los metadatos se combinan o se reemplazan.

PropertyChangedCallback se combina. Si agrega una nueva PropertyChangedCallback, esa devolucin


de llamada se almacena en los metadatos. Si no especifica una PropertyChangedCallback en la
invalidacin, el valor de PropertyChangedCallback se promueve como una referencia del antecesor ms
prximo que lo especifique en los metadatos.

El comportamiento real del sistema de propiedades para PropertyChangedCallback es que las


implementaciones correspondientes a todos los propietarios de metadatos de la jerarqua se retienen y
se agregan a una tabla, de tal forma que el orden de ejecucin en el sistema de propiedades consiste
en invocar primero las devoluciones de llamada de la clase ms derivada.

Se reemplaza DefaultValue. Si no especifica una PropertyChangedCallback en la invalidacin, el valor


de DefaultValue procede del antecesor ms prximo que lo especifique en los metadatos.

Se

reemplazan

las

implementaciones

de

CoerceValueCallback.

Si

agrega

una

nueva

CoerceValueCallback, esa devolucin de llamada se almacena en los metadatos. Si no especifica una


CoerceValueCallback en la invalidacin, el valor de CoerceValueCallback se promueve como una
referencia del antecesor ms prximo que lo especifique en los metadatos.

El comportamiento del sistema de propiedades consiste en invocar nicamente la CoerceValueCallback


de

los

metadatos

inmediatos. Se

retiene

ninguna referencia a otras

implementaciones

de

CoerceValueCallback en la jerarqua.
Este comportamiento se implementa mediante Merge y se puede invalidar en las clases de metadatos derivadas
Invalidar metadatos de propiedades asociadas
En WPF, las propiedades asociadas se implementan como propiedades de dependencia. Esto significa que
tambin tienen metadatos de propiedad, que las clases individuales pueden invalidar. Las consideraciones de
mbito para una propiedad asociada en WPF son generalmente que cualquier objeto DependencyObject puede
tener una propiedad asociada establecida. Por consiguiente, cualquier clase derivada de DependencyObject
puede invalidar los metadatos de cualquier propiedad asociada, pues podran establecerse en una instancia de
la clase. Puede invalidar valores predeterminados, devoluciones de llamada o propiedades de informe de
caractersticas de nivel de marco de trabajo de WPF. Si la propiedad asociada se establece en una instancia de
la clase, se aplicarn las caractersticas de los metadatos de la propiedad de reemplazo. Por ejemplo, puede
invalidar el valor predeterminado, de modo que se informe del valor de invalidacin como valor de la propiedad
asociada en las instancias de la clase, siempre que la propiedad no se establezca de otra manera.
Nota:
La propiedad Inherits no es relevante para propiedades asociadas.
Agregar una clase como propietaria de una propiedad de dependencia existente
Una clase se puede agregar a s misma como propietaria de una propiedad de dependencia que ya se haya
registrado, utilizando el mtodo AddOwner. Esto permite que la clase utilice una propiedad de dependencia
registrada originalmente para un tipo diferente. La clase que se agrega no es, normalmente, una clase derivada
del tipo que registr como propietario esa propiedad en primer lugar. En la prctica, esto permite que la clase y
sus clases derivadas "hereden" una implementacin de la propiedad de dependencia sin que la clase propietaria
original y la clase que se agrega estn en la misma jerarqua de clases real. Adems, la clase que se agrega (y

MCT: Luis Dueas

Pag 330 de 445

Manual de Windows Presentation Foundation


todas las clases derivadas tambin) pueden proporcionar metadatos especficos del tipo de propiedad para la
propiedad de dependencia original.
Adems de agregarse a s misma como propietaria mediante los mtodos accesorios del sistema de
propiedades, la clase que se agrega debe declarar miembros pblicos adicionales en s misma para convertir la
propiedad de dependencia en un participante completo en el sistema de propiedades, con exposicin tanto a
cdigo como a marcado. Una clase que agrega una propiedad de dependencia existente tiene las mismas
responsabilidades en cuanto a la exposicin del modelo de objetos para esa propiedad de dependencia como
una clase que defina una nueva propiedad de dependencia personalizada. El primer miembro que se debe
exponer es un campo identificador de la propiedad de dependencia. Este campo debe ser un campo public static
readonly de tipo DependencyProperty, que est asignado al valor que devuelve la llamada a AddOwner. El
segundo miembro a definir es la propiedad "contenedora" de common language runtime (CLR). El contenedor
hace que sea mucho ms cmo manipular la propiedad de dependencia en el cdigo (evita llamar cada vez a
SetValue realizando esa llamada una sola vez en el propio contenedor). El contenedor se implementa de forma
idntica a como se implementara si se estuviera registrando una propiedad de dependencia personalizada.
AddOwner y propiedades asociadas
Puede llamar a AddOwner para una propiedad de dependencia que la clase propietaria defina como propiedad
asociada. Generalmente, la razn para hacerlo es exponer la propiedad previamente asociada como una
propiedad de dependencia no asociada. A continuacin expondr el valor devuelto por AddOwner como un
campo public static readonly para su uso como identificador de la propiedad de dependencia y definir las
propiedades "contenedoras" adecuadas para que la propiedad aparezca en la tabla de miembros y admita un
uso de propiedad no asociado en la clase.

3.5.6. Metadatos de las Propiedades de Marco de Trabajo


Las opciones de metadatos de las propiedades de marco de trabajo se comunican para las propiedades de
elementos de objeto que se consideran presentes en el nivel de marco de trabajo de WPF en la arquitectura de
Windows Presentation Foundation (WPF). En general, la designacin de nivel de marco de trabajo de WPF
conlleva que determinadas caractersticas, tales como la representacin, los enlaces de datos y las matizaciones
del sistema de propiedades, las administren las API y los archivos ejecutables de presentacin de WPF. Estos
sistemas consultan los metadatos de las propiedades de marco de trabajo para determinar las particularidades
especficas de las caractersticas de las propiedades de determinados elementos.
Informacin comunicada por los metadatos de las propiedades de marco de trabajo
Los metadatos de las propiedades de marco de trabajo se pueden dividir en las categoras siguientes:

Comunicacin de propiedades de diseo que afectan a un elemento (AffectsArrange, AffectsMeasure,


AffectsRender). Puede establecer estos marcadores de los metadatos si la propiedad afecta a esos
aspectos respectivos, y si tambin implementa los mtodos MeasureOverride / ArrangeOverride de la
clase para proporcionar al sistema del diseo comportamiento e informacin de representacin
concretos. Normalmente, este tipo de implementacin comprobara las invalidaciones de propiedad en
las propiedades de dependencia para aquellos casos en que se cumpliese cualquiera de estas
propiedades de diseo en los metadatos de propiedad, y slo esas invalidaciones tendran que solicitar
un nuevo paso de diseo.

Comunicacin de propiedades de diseo que afectan al elemento primario de un elemento


(AffectsParentArrange,

AffectsParentMeasure).

Algunos

ejemplos

en

que

se

establecen

estos

marcadores de manera predeterminada son FixedPage.Left y Paragraph.KeepWithNext.

Inherits. De

manera predeterminada, las

propiedades de dependencia no

heredan valores.

OverridesInheritanceBehavior permite que la ruta de herencia tambin recorra un rbol visual, lo que
es necesario para algunos escenarios de composicin de controles.

MCT: Luis Dueas

Pag 331 de 445

Manual de Windows Presentation Foundation

Nota:
El trmino "heredar" en el contexto de los valores de propiedad tiene un significado concreto para
las propiedades de dependencia: significa que los elementos secundarios pueden heredar el valor
de la propiedad de dependencia real de los elementos primarios gracias a una funcin de nivel de
marco de trabajo de WPF del sistemas de propiedades de WPF. No tiene nada que ver directamente
con la herencia de miembros y tipos de cdigo administrado a travs de tipos derivados.

Comunicacin de caractersticas de enlace de datos (IsNotDataBindable, BindsTwoWayByDefault). De


manera predeterminada, las propiedades de dependencia del marco de trabajo admiten el enlace de
datos, con un comportamiento de enlace unidireccional. Puede deshabilitar el enlace de datos si no
existe ningn escenario para ello en absoluto (dado que se pretende que sean flexibles y extensibles,
no hay muchos ejemplos de este tipo de propiedades en las API predeterminadas de WPF). Puede
establecer el enlace de modo que su valor predeterminado sea bidireccional para las propiedades que
conectan entre s los comportamientos de un control entre los elementos que lo componen
(IsSubmenuOpen es un ejemplo de ello) o en aquellos casos en que el enlace bidireccional sea el
escenario comn esperado por los usuarios (Text es un ejemplo de ello). Cambiar los metadatos
relacionados con el enlace de datos afecta nicamente al valor predeterminado; este valor siempre se
puede modificar para cada enlace.

Comunicacin de si las aplicaciones o los servicios compatibles con el diario deben incluir en l las
propiedades (Journal). Para los elementos generales, la inclusin en el diario no est habilitada de
manera predeterminada, sino que se habilita de manera selectiva para algunos controles de datos
proporcionados por el usuario. Esta propiedad sirve para que la lean los servicios de diario, incluida la
implementacin del diario de WPF, y suele establecerse para controles de usuario tales como
selecciones del usuario en listas que deben conservarse en los pasos de navegacin subsiguientes.

Leer FrameworkPropertyMetadata
Cada

una

de

las

propiedades

vinculadas

anteriormente

son

propiedades

especficas

que

FrameworkPropertyMetadata agrega a su clase base UIPropertyMetadata inmediata. Cada una de estas


propiedades es false de manera predeterminada. Una solicitud de metadatos de una propiedad cuando es
importante conocer el valor de estas propiedades debe intentar convertir los metadatos devueltos en
FrameworkPropertyMetadata y, a continuacin, comprobar los valores de las propiedades individuales segn
sea necesario.
Especificar los metadatos
Cuando se crea una nueva instancia de metadatos a fin de aplicarlos a un nuevo registro de propiedad de
dependencia, puede elegir la clase de metadatos que desea utilizar: la clase base PropertyMetadata o alguna
clase derivada, como FrameworkPropertyMetadata. En general, debe utilizar FrameworkPropertyMetadata, en
especial si la propiedad tiene alguna interaccin con el sistema de propiedades y las funciones de WPF, como
las de diseo y el enlace de datos. Otra opcin para escenarios ms sofisticados consiste en derivar de
FrameworkPropertyMetadata a fin de crear su propia clase de comunicacin de metadatos cuyos miembros
contengan informacin adicional. O tambin puede utilizar PropertyMetadata o UIPropertyMetadata para
comunicar el grado de compatibilidad con las caractersticas de la implementacin.
Para las propiedades existentes (llamada a AddOwner o OverrideMetadata), debe invalidar siempre con el tipo
de metadatos utilizado por el registro original.
Si crea una instancia de FrameworkPropertyMetadata, hay dos maneras de rellenar esos metadatos con valores
correspondientes a las propiedades concretas que comunican las caractersticas de las propiedades de marco de
trabajo:
1.

Utilice la firma de constructor de FrameworkPropertyMetadata, que permite un parmetro flags. Este


parmetro debe rellenarse con todos los valores combinados deseados de los marcadores de enumeracin
de FrameworkPropertyMetadataOptions.

MCT: Luis Dueas

Pag 332 de 445

Manual de Windows Presentation Foundation


2.

Utilice una de las firmas sin un parmetro flags y, a continuacin, establezca la propiedad Boolean de
comunicacin de FrameworkPropertyMetadata en true para cada cambio de caracterstica deseado. Si lo
hace, debe establecer estas propiedades antes de construir cualquier elemento con esta propiedad de
dependencia; las propiedades Boolean son de lectura y escritura a fin de permitir este comportamiento
consistente en evitar el parmetro flags y, an as, rellenar los metadatos, pero los metadatos deben
quedar sellados de manera efectiva antes de utilizar la propiedad. As pues, si intenta establecer las
propiedades despus de solicitar los metadatos, la operacin no ser vlida.
Comportamiento de combinacin de metadatos de propiedades de marco de trabajo

Cuando se invalidan los metadatos de propiedades de marco de trabajo, las distintas caractersticas de los
metadatos se combinan o reemplazan.

PropertyChangedCallback se combina. Si agrega una nueva PropertyChangedCallback, esa devolucin


de llamada se almacena en los metadatos. Si no especifica una PropertyChangedCallback en la
invalidacin, el valor de PropertyChangedCallback se promueve como una referencia del antecesor ms
prximo que lo especifique en los metadatos.

El comportamiento del sistema de propiedades real para PropertyChangedCallback es que se retienen


las implementaciones correspondientes a todos los propietarios de metadatos de la jerarqua y se
agregan a una tabla, de tal forma que el orden de ejecucin en el sistema de propiedades consiste en
invocar primero las devoluciones de llamada de la clase derivada ms profundamente. Las
devoluciones de llamada heredadas slo se ejecutan una vez, y cuentan como propiedad de la clase
que las coloc en los metadatos.

Se reemplaza DefaultValue. Si no especifica una PropertyChangedCallback en la invalidacin, el valor


de DefaultValue procede del antecesor ms prximo que lo especifique en los metadatos.

Se

reemplazan

las

implementaciones

de

CoerceValueCallback.

Si

agrega

una

nueva

CoerceValueCallback, esa devolucin de llamada se almacena en los metadatos. Si no especifica una


CoerceValueCallback en la invalidacin, el valor de CoerceValueCallback se promueve como una
referencia del antecesor ms prximo que lo especifique en los metadatos.

El comportamiento del sistema de propiedades consiste en invocar nicamente la CoerceValueCallback


de

los

metadatos

inmediatos. Se

retiene

ninguna referencia a otras

implementaciones

de

CoerceValueCallback en la jerarqua.

Los marcadores de FrameworkPropertyMetadataOptions se combinan como una operacin bit a bit, en


vez

de

utilizar

los

diversos

valores

de

las

propiedad

Boolean

equivalentes

de

FrameworkPropertyMetadata de los metadatos heredados. IsAnimationProhibited se reemplaza por


cualquier nuevo valor o conserva el valor de los metadatos heredados.
Este comportamiento se implementa mediante Merge y se puede invalidar en las clases de metadatos derivadas

3.5.7. Prioridad de los Valores de Propiedades de Dependencia


En este tema se explica el modo en que los mecanismos del sistema de propiedades de Windows Presentation
Foundation (WPF) pueden afectar al valor de una propiedad de dependencia, y se describe la prioridad por la
que ciertos aspectos del sistema de propiedades se aplican al valor efectivo de una propiedad.
El sistema de animacin de propiedades de WPF
El sistema de propiedades de WPF proporciona una manera eficaz de determinar el valor de las propiedades de
dependencia mediante diversos factores, lo que posibilita caractersticas como la validacin de propiedades en
tiempo real, el enlace en tiempo de ejecucin y la notificacin a las propiedades relacionadas de los cambios en
los valores de otras propiedades. El orden y la lgica exactos que se utilizan para determinar los valores de las
propiedades de dependencia son relativamente complejos. Conocer este orden le ayudar a evitar establecer

MCT: Luis Dueas

Pag 333 de 445

Manual de Windows Presentation Foundation


propiedades sin necesidad y tambin podr eliminar la confusin sobre el motivo exacto por el cual algn
intento de influir o prever el valor de una propiedad de dependencia no produjo el valor esperado.
Las propiedades de dependencia se pueden "establecer" en varios lugares
A continuacin se muestra XAML de ejemplo en el que la misma propiedad (Background) tiene tres operaciones
"set" que podran influir en su valor.
<Button Background="Red">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Green"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Blue" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>Click
</Button>
Aqu, qu color espera que se aplique, rojo, verde o azul?
Con la excepcin de los valores animados y la conversin, los conjuntos de propiedades locales se establecen
con la mayor prioridad. Si establece un valor localmente, puede esperar que dicho valor tendr prioridad,
incluso sobre cualquier estilo o sobre las plantillas de los controles. En nuestro ejemplo, Background se
establece en el color rojo (Red) de forma local. Por consiguiente el estilo definido en este mbito, aunque se
trata de un estilo implcito que en otro caso se aplicara a todos los elementos de ese tipo en ese mbito, no
tiene la mxima prioridad para dar su valor a la propiedad Background. Si quitara el valor local Red de esa
instancia de Button, el estilo tendra prioridad y el botn obtendra el valor Background del estilo. Dentro del
estilo, los desencadenadores tienen prioridad, por lo que el botn ser azul si el mouse est encima, y verde en
caso contrario.
Lista de prioridad para el establecimiento de propiedades de dependencia
A continuacin se muestra el orden definitivo que utiliza el sistema de propiedades al asignar los valores de las
propiedades de dependencia en tiempo de ejecucin. En primer lugar se indican los que tienen mayor prioridad.
Esta lista desarrolla algunas de las generalizaciones realizadas en el tema Informacin general sobre las
propiedades de dependencia.
1.
2.

Conversin del sistema de propiedades. Para obtener detalles sobre la conversin.


Animaciones activas o animaciones con un comportamiento de bloqueo. Para tener cualquier efecto
prctico, una animacin de una propiedad debe poder tener prioridad sobre el valor base (inanimado),
incluso si dicho valor se estableci localmente.

3.

Valor local. Un valor local se podra establecer a travs de la comodidad de la propiedad de


"contenedor", que tambin equivale a establecer como un atributo o elemento de propiedad en XAML, o
mediante una llamada al mtodo SetValue API utilizando una propiedad de una instancia concreta. Si
establece un valor local utilizando un enlace o un recurso, cada uno de ellos acta con la misma prioridad
que si se estableciera un valor directo.

4.

Propiedades de plantilla TemplatedParent. Un elemento tiene la propiedad TemplatedParent si se cre


como parte de una plantilla (ControlTemplate o DataTemplate). Dentro de la plantilla, se aplica la
prioridad siguiente:
1.

Desencadenadores de la plantilla TemplatedParent.

2.

Conjuntos de propiedades (normalmente a travs de atributos XAML ) de la plantilla


TemplatedParent.

5.

Estilo implcito. Slo se aplica a la propiedad Style. La propiedad Style se llena con cualquier recurso
de estilo cuya clave coincida con el tipo de ese elemento. Ese recurso de estilo debe existir o en la pgina
o en la aplicacin; la bsqueda de un recurso de estilo implcito no contina en los temas.

MCT: Luis Dueas

Pag 334 de 445

Manual de Windows Presentation Foundation


6.

Desencadenadores de los estilos. Los desencadenadores incluidos en los estilos de la pgina o la


aplicacin (estos estilos

podran ser explcitos

implcitos, pero

no proceder de

los estilos

predeterminados, que tienen una prioridad ms baja).


7.

Desencadenadores de la plantilla. Cualquier desencadenador de una plantilla incluida en un estilo o de


una plantilla aplicada directamente.

8.

Establecedores de estilo. Valores procedentes de un elemento Setter procedente de la pgina o la


aplicacin.

9.

Estilo predeterminado (tema). Para obtener informacin ms detallada sobre cundo se aplica y cmo
se relacionan los estilos del tema con las plantillas incluidas en los estilos del tema. Dentro de un estilo
predeterminado se aplica el orden de prioridad siguiente:

10.

1.

Desencadenadores activos del estilo del tema.

2.

Establecedores del estilo del tema.

Herencia. Algunas propiedades de dependencia heredan sus valores del elemento primario a los
elementos secundarios, de forma que es necesario establecerlas especficamente en cada elemento de la
aplicacin.

11.

Valor predeterminado de los metadatos de la propiedad de dependencia. Cualquier propiedad de


dependencia determinada puede tener un valor predeterminado establecido por el registro del sistema de
propiedades de esa propiedad concreta. Asimismo, las clases derivadas que heredan una propiedad de
dependencia tienen la opcin de invalidar esos metadatos (incluso el valor predeterminado) para cada
tipo. Dado que la herencia se comprueba antes que el valor predeterminado, para una propiedad
heredada un valor predeterminado del elemento primario tiene prioridad sobre un elemento secundario.
Por consiguiente, si no se establece una propiedad heredable en ninguna parte, se utiliza el valor
predeterminado tal como se ha especificado en la raz o en el elemento primario en lugar del valor
predeterminado del elemento secundario.

TemplatedParent
TemplatedParent no se aplica como un elemento de prioridad a cualquier propiedad de un elemento que se
declara directamente en el marcado de la aplicacin estndar. El concepto de TemplatedParent slo existe para
los elementos secundarios dentro de un rbol visual que se generan al aplicar la plantilla. Cuando el sistema de
propiedades busca un valor en la plantilla TemplatedParent, est buscando en la plantilla que cre ese
elemento. Los valores de propiedades procedentes de la plantilla TemplatedParent generalmente se comportan
como si se hubieran establecido como un valor local en el elemento secundario, pero esta prioridad menor
frente a la del valor local existe porque es posible que las plantillas se compartan.
La propiedad Style.
El orden de bsqueda descrito anteriormente se aplica a todas las propiedades de dependencia posibles excepto
una: la propiedad Style. La propiedad Style es nica porque no se le pueden aplicar estilos, por lo que no le
aplican los elementos de prioridad del 5 al 8. Asimismo, no se recomienda animar o convertir Style (animar
Style requerira una clase de animacin personalizada). De este modo, quedan tres formas en las que se podra
establecer la propiedad Style:

Estilo explcito. El valor de la propiedad Style se establece directamente. En la mayora de los


escenarios, el estilo no se define en el propio cdigo, sino que se hace referencia a l como un recurso,
por clave explcita. En este caso, la propia propiedad Style se comporta como si fuera un valor local, es
decir, un elemento de prioridad 3.

Estilo implcito. El valor de la propiedad Style no se establece directamente. Sin embargo, Style existe
en algn nivel en la secuencia de bsqueda de recursos (pgina, aplicacin) y se le asigna una clave

MCT: Luis Dueas

Pag 335 de 445

Manual de Windows Presentation Foundation


utilizando una clave de recurso que coincide con el tipo al que debe aplicarse el estilo. En este caso, la
propia propiedad Style adquiere una prioridad identificada en la secuencia como elemento de nivel 5.
Esta condicin se puede detectar utilizando DependencyPropertyHelper con la propiedad Style y
buscando ImplicitStyleReference en los resultados.

Estilo predeterminado, tambin conocido como el estilo del tema. La propiedad Style no se establece
directamente y de hecho se leer como null hasta el tiempo de ejecucin. En este caso, el estilo
procede de la evaluacin del tema en tiempo de ejecucin que forma parte del motor de presentacin
de WPF.

Para los estilos implcitos que no pertenecen a los temas, el tipo debe coincidir exactamente: una clase
derivada de MyButtonButton no utilizar implcitamente un estilo para Button.
Estilos predeterminados (tema)
Cada control que se distribuye con WPF tiene un estilo predeterminado. Ese estilo predeterminado puede variar
para cada tema, motivo por el que a veces se le conoce como estilo del tema.
La informacin ms importante que se incluye en un estilo predeterminado para un control es su plantilla de
control, que existe en el estilo del tema como un establecedor para su propiedad Template. Si no hubiera
ninguna plantilla en los estilos predeterminados, un control sin una plantilla personalizada como parte de un
estilo personalizado no tendra ninguna apariencia visual. La plantilla del estilo predeterminado da una
estructura bsica a la apariencia visual de cada control y tambin define las conexiones entre las propiedades
definidas en el rbol visual de la plantilla y la clase de control correspondiente. Cada control expone un
conjunto de propiedades que pueden influir en la apariencia visual del control sin reemplazar la plantilla por
completo. Por ejemplo, considere la apariencia visual predeterminada de un control Thumb, que es un
componente de ScrollBar.
Un control Thumb tiene ciertas propiedades personalizables. La plantilla predeterminada de un control Thumb
crea una estructura bsica o rbol visual con varios componentes Border anidados para crear una apariencia de
tipo bisel. Si se va a exponer una propiedad que forma parte de la plantilla para que la personalice la clase
Thumb, dicha propiedad debe ser expuesta mediante TemplateBinding dentro de la plantilla. En el caso de
Thumb, varias propiedades de estos bordes comparten un enlace de plantilla a propiedades como Background o
BorderThickness. Pero algunas otras propiedades u organizaciones visuales estn incluidas en el cdigo de la
plantilla de control o se enlazan a valores que proceden directamente del tema y no se pueden cambiar salvo
reemplazando la plantilla completa. Generalmente, si una propiedad procede de un elemento primario con
plantilla y no se expone mediante un enlace de plantilla, no puede ajustarse mediante los estilos, porque no
hay ninguna manera sencilla de especificarla como destino. Pero la herencia de valores de propiedades de la
plantilla aplicada todava podra influir en esa propiedad, igual que podra hacerlo el valor predeterminado.
Los estilos del tema utilizan un tipo como clave en sus definiciones. Sin embargo, cuando se aplican temas a
una instancia determinada de un elemento, la bsqueda de los temas para este tipo se realiza comprobando la
propiedad DefaultStyleKey en un control. Esto contrasta con el uso del tipo literal, tal como hacen los estilos
implcitos. El valor de DefaultStyleKey se heredara a las clases derivadas incluso si el implementador no lo
cambiara (la forma prevista de cambiar la propiedad no es invalidarla en el nivel de propiedad, sino cambiar su
valor predeterminado en los metadatos de la propiedad). Este direccionamiento indirecto permite a las clases
base definir los estilos del tema para los elementos derivados que, de otra forma, no tendran ningn estilo (o,
lo que es ms importante, no tienen una plantilla dentro de ese estilo y, por ello, no tendran ningn tipo de
apariencia visual predeterminada). As, puede derivar MyButton de Button y aun as obtener la plantilla
predeterminada de Button. Si fuera el autor del control MyButton y deseara un comportamiento diferente,
podra invalidar los metadatos de la propiedad de dependencia para DefaultStyleKey en MyButton con objeto de
devolver una clave diferente y, a continuacin, definira los estilos del tema pertinentes, incluyendo la plantilla
para MyButton que debe empaquetar con su control MyButton.

MCT: Luis Dueas

Pag 336 de 445

Manual de Windows Presentation Foundation


Referencias de recursos dinmicos y los enlaces
Las referencias de recursos dinmicos y las operaciones de enlace se consideran como si estuvieran
estableciendo el valor al que se aplican. Por ejemplo, un recurso dinmico aplicado a un valor local adquiere
una prioridad como elemento 3, un enlace para un establecedor de propiedades dentro de un estilo del tema
adquiere una prioridad como elemento 9, etc. Dado que tanto las referencias de recursos dinmicos como los
enlaces deben poder obtener valores del estado de tiempo de ejecucin de la aplicacin, esto implica que el
proceso real de determinar la prioridad del valor de la propiedad para cualquier propiedad determinada tambin
se extiende al tiempo de ejecucin.
En sentido estricto, las referencias de recursos dinmicos no forman parte del sistema de propiedades, pero
tienen un orden de bsqueda propio que interacta con la secuencia citada anteriormente. Dicha prioridad
puede resumirse bsicamente en: elemento a raz de la pgina, aplicacin, tema, sistema.
Los recursos dinmicos y los enlaces no slo funcionan con la misma prioridad que un valor local, sino que en
realidad son un valor local, pero con un valor que se aplaza. Una consecuencia de esto es que si tiene un
recurso dinmico o un enlace para un valor de una propiedad, cualquier valor local que establezca
posteriormente reemplazar el recurso dinmico o el enlace por completo. Incluso si llama a ClearValue para
borrar el valor establecido localmente, no se restaurar el recurso dinmico o el enlace. De hecho, si llama a
ClearValue para una propiedad que tiene un recurso dinmico o un enlace (sin ningn valor local "literal"), la
llamada a ClearValue tambin los borra.
Conversin, animaciones y valor base
La conversin y las animaciones se aplican a un valor que se denomina "valor base" en este SDK. Por tanto, el
valor base es cualquier valor que se determina evaluando hacia arriba en los elementos hasta que se alcanza el
elemento 2.
Para una animacin, el valor base puede tener efecto en el valor animado, si esa animacin no especifica tanto
"From" como "To" para ciertos comportamientos o si la animacin recupera deliberadamente el valor base
cuando se completa. Para ver esto en la prctica, ejecute el Ejemplo From, To, and By Animation Target Values.
Pruebe a establecer los valores locales del alto del rectngulo en el ejemplo, de forma que el valor local inicial
difiera de cualquier "From" en la animacin. Observar que las animaciones se inician inmediatamente
utilizando los valores "From" y que reemplazan el valor base tras iniciarse. La animacin podra especificar que
se vuelva al valor hallado antes de la animacin una vez completada especificando el FillBehavior final. Despus
se utiliza la prioridad normal para la determinacin del valor base.
Es posible que se apliquen varias animaciones a una sola propiedad y que cada una de ellas se haya definido
desde puntos distintos en la prioridad de valores. Sin embargo, puede que estas animaciones compongan sus
valores, en lugar de aplicar simplemente la animacin que tenga la prioridad ms alta. Esto depende de cmo
se definen exactamente las animaciones y del tipo del valor que se anima.
La conversin se aplica en el nivel ms alto. Incluso una animacin que ya est ejecutndose est sujeta a la
conversin de valores. Ciertas propiedades de dependencia existentes en WPF tienen integrada la conversin.
Para una propiedad de dependencia personalizada, el comportamiento de la conversin se define escribiendo
una devolucin de llamada CoerceValueCallback y pasando la devolucin de llamada como parte de los
metadatos al crear la propiedad. Tambin puede invalidar el comportamiento de la conversin de las
propiedades existentes invalidando los metadatos de esa propiedad en una clase derivada. La conversin
interacta con el valor base de forma que se aplican restricciones en cuanto a la conversin siempre y cuando
existan en ese momento, pero el valor base se sigue conservando. Por consiguiente, si posteriormente se
levantan las restricciones en cuanto a conversin, sta devolver el valor ms cercano posible a ese valor base
y puede que la influencia de la conversin en una propiedad cese en cuanto se levanten todas las restricciones.
Comportamientos desencadenantes

MCT: Luis Dueas

Pag 337 de 445

Manual de Windows Presentation Foundation


Los controles suelen definir comportamientos desencadenantes como parte de su estilo predeterminado en los
temas. El establecimiento de propiedades locales en los controles podra evitar que los desencadenadores
fueran capaces de responder a los eventos controlados por el usuario, bien de forma visual o mediante su
comportamiento. El uso ms comn de un desencadenador de propiedades es para propiedades de control o de
estado como IsSelected. Por ejemplo, de forma predeterminada, cuando un control Button est deshabilitado
(el desencadenador para IsEnabled es false), el valor de Foreground en el estilo del tema es lo que hace que el
control aparezca "deshabilitado". Pero si ha establecido un valor local para Foreground, la prioridad de ese color
normal para el botn deshabilitado ser reemplazada por el conjunto de propiedades locales, incluso en este
escenario desencadenado por propiedades. Tenga cuidado al establecer valores para las propiedades que tienen
comportamientos de desencadenador en el nivel del tema y asegrese de que no est interfiriendo
excesivamente con la experiencia del usuario pensada por ese control.
ClearValue y la prioridad de los valores
El mtodo ClearValue proporciona un medio conveniente para borrar cualquier valor aplicado localmente de una
propiedad de dependencia establecida en un elemento. Sin embargo, llamar a ClearValue no garantiza que el
valor predeterminado establecido en los metadatos durante el registro de la propiedad sea el nuevo valor
efectivo. Todos los dems participantes en la prioridad de valores siguen estando activos. Slo se ha quitado de
la secuencia de prioridad el valor establecido localmente. Por ejemplo, si llama a ClearValue para una propiedad
que tambin se establece mediante un estilo del tema, se aplicar el valor del tema como nuevo valor en lugar
del valor predeterminado basado en los metadatos. Puede verlo ilustrado en Ejemplo Restoring Default Values,
aunque en este caso el estilo aplicado sea un estilo implcito definido en recursos en el nivel de la aplicacin. Si
desea sacar del proceso a todos los participantes del valor de la propiedad y establecer el valor en el valor
predeterminado de los metadatos registrados, puede obtener ese valor predeterminado definitivamente
consultando los metadatos de la propiedad de dependencia y, a continuacin, utilizar el valor predeterminado
para establecer localmente la propiedad con una llamada a SetValue.

3.5.8. Propiedades de Dependencia de Slo Lectura


En este tema se describen las propiedades de dependencia de slo lectura; se incluyen las ya existentes, as
como los escenarios y las tcnicas para crear una personalizada.
Propiedades de la dependencia de slo lectura existentes
Algunas de las propiedades de dependencia definidos en el marco de trabajo de Windows Presentation
Foundation (WPF) son de slo lectura. El motivo habitual tpica para especificar una propiedad de dependencia
de slo lectura es que se trata de propiedades deben utilizarse para determinar el estado en casos en que hay
muchos factores que afectan a este ltimo, pero en los que limitarse a establecer la propiedad en ese estado no
es deseable desde el punto de vista del diseo de la interfaz de usuario. Por ejemplo, la propiedad IsMouseOver
se limita, en realidad, a exponer el estado determinado por la entrada de mouse. Cualquier intento de
establecer este valor mediante programacin y eludir la entrada de mouse real sera imprevisible y dara lugar a
incoherencias.
Al no poder establecerse, las propiedades de dependencia de slo lectura no son adecuadas para muchos de los
escenarios en que las propiedades de dependencia suelen ofrecer una solucin (a saber: enlace de datos,
aplicacin de un estilo directo a un valor, validacin, animacin o herencia). A pesar de no poderse establecer,
las propiedades de dependencia de slo lectura conservan algunas de las funciones adicionales que admiten las
propiedades de dependencia en el sistema de propiedades. De stas, la ms importante es la capacidad de ser
utilizadas como desencadenador de propiedad en un estilo. Los desencadenadores no se pueden habilitar con
una propiedad common language runtime (CLR) normal; se necesita una propiedad de dependencia. La
propiedad IsMouseOver mencionada anteriormente es un ejemplo perfecto de un escenario donde podra
resultar de gran utilidad definir un estilo para un control, donde alguna propiedad visible, como el fondo, el
primero plano u otras propiedades similares de elementos compuestos dentro del control cambiar cuando el
usuario site un mouse sobre alguna zona definida del control. Los procesos de invalidacin inherentes al

MCT: Luis Dueas

Pag 338 de 445

Manual de Windows Presentation Foundation


sistema de propiedades pueden detectar y comunicar los cambios de una propiedad de dependencia de slo
lectura, lo que constituye la compatibilidad interna con la funcionalidad de desencadenador de propiedad.
Crear propiedades de dependencia de slo lectura personalizadas
Asegrese de leer la seccin anterior sobre los motivos por los que las propiedades de dependencia de slo
lectura no funcionan en muchos escenarios de propiedades de dependencia tpicos. Sin embargo, si el escenario
es el adecuado, puede ser conveniente crear su propia propiedad de dependencia de slo lectura.
Gran parte del proceso de creacin de una propiedad de dependencia de slo lectura es igual al descrito en los
temas Propiedades de dependencia personalizadas y Cmo: Implementar una propiedad de dependencia. Hay
tres diferencias importantes:

Al registrar la propiedad, llame al mtodo RegisterReadOnly en lugar de al mtodo Register normal


para el registro de propiedades.

Al implementar la propiedad de "contenedor" de CLR, asegrese de que tampoco el contenedor tenga


una implementacin de establecimiento, de tal forma que no haya ninguna incoherencia en el estado
de slo lectura para el contenedor pblico que se expone.

El objeto devuelto por el registro de slo lectura es DependencyPropertyKey en lugar de


DependencyProperty. Este campo debe almacenarse igualmente como miembro, pero no es habitual
convertirlo en un miembro pblico del tipo.

Por supuesto, el valor o campo privado que respalda la propiedad de dependencia de slo lectura puede ser de
lectura y escritura con la lgica que usted decida. Sin embargo, la manera ms sencilla de establecer la
propiedad, ya sea inicialmente o como parte de lgica de tiempo de ejecucin, es utilizar las API del sistema de
propiedades, en lugar de eludir el sistema de propiedades y establecer directamente el campo de respaldo
privado. En particular, existe una firma de SetValue que acepta un parmetro de tipo DependencyPropertyKey.
Cmo y dnde se establezca este valor mediante programacin dentro de la lgica de la aplicacin afectar a
cmo se establecer el acceso en la DependencyPropertyKey creada al registrar la propiedad de dependencia
por primera vez. Si toda esta lgica se administra dentro de la clase, puede hacerlo privado, pero si requiere
que se establezca desde otro componente del ensamblado, puede establecerlo como interno. Un enfoque
consiste en llamar a SetValue dentro de un controlador de eventos de clase de un evento pertinente que
comunique a una instancia de clase que es preciso cambiar el valor almacenado de la propiedad. Otro enfoque
consiste

en

vincular

las

propiedades

de

dependencia

entre

mediante

devoluciones

de

llamada

PropertyChangedCallback y CoerceValueCallback emparejadas como parte de los metadatos de esas


propiedades durante el registro.
Dado que DependencyPropertyKey es privada, y que el sistema de propiedades no la propaga fuera del cdigo,
una propiedad de dependencia de slo lectura aporta mayor seguridad de establecimiento que una propiedad
de dependencia de lectura y escritura. Para una propiedad de dependencia de lectura y escritura, el campo de
identificacin es pblico de manera explcita o implcita, con lo que la propiedad se puede establecer
ampliamente.

3.5.9. Herencia de Valores de Propiedad


La herencia de valores de propiedad es una caracterstica del sistema de propiedades de Windows Presentation
Foundation (WPF). La herencia de valores de propiedad permite que los elementos secundarios de un rbol de
elementos obtengan el valor de una propiedad concreta de sus elementos primarios, y lo hereden tal y como
est establecido en cualquier punto del elemento primario ms prximo. El elemento primario tambin podra
haber obtenido su valor a travs de la herencia de valores de propiedad, del tal forma que el sistema se repite
potencialmente hasta la raz de la pgina. La herencia de valores de propiedad no es el comportamiento
predeterminado del sistema de propiedades; una propiedad se debe establecer con un valor de metadatos
concreto para que sta inicie la herencia de valores de propiedad en los elementos secundarios.

MCT: Luis Dueas

Pag 339 de 445

Manual de Windows Presentation Foundation


La herencia de valores de propiedad es la herencia de contencin
El trmino "herencia" utilizado aqu no representa exactamente el mismo concepto que la herencia en el
contexto de los tipos y de la programacin orientada a objetos en general, donde las clases derivadas heredan
las definiciones de miembros de sus clases base. Ese significado de herencia tambin est activo en WPF: las
propiedades definidas en diversas clases base se exponen como atributos para las clases XAML derivadas
cuando se utilizan como elementos y se exponen como miembros para el cdigo. La herencia de valores de
propiedad se refiere, en particular, al modo en que valores de las propiedades se pueden heredar de un
elemento a otro basndose en las relaciones entre elementos primarios y secundarios dentro de un rbol de
elementos. Ese rbol de elementos queda visible directamente al anidar los elementos dentro de otros
elementos al definir aplicaciones en marcado XAML. Los rboles de objetos tambin se pueden crear mediante
programacin agregando objetos a colecciones designadas de otros objetos, en cuyo caso la herencia de
valores de propiedad funcionar de igual forma en el rbol terminado en tiempo de ejecucin.
Aplicaciones prcticas de la herencia de valores de propiedad
Las API de WPF incluyen varias propiedades que tienen habilitada la herencia de valores de propiedad. El
escenario tpico para ellas es aqul en que es apropiado que una propiedad se establezca una sola vez por
pgina, pero donde esa propiedad tambin es un miembro de una de las clases de elementos base y, en
consecuencia, tambin existir en la mayora de los elementos secundarios. Por ejemplo, la propiedad
FlowDirection controla en qu direccin se debe presentar y organizar en la pgina el contenido dinmico.
Normalmente, es conveniente administrar el concepto de flujo de texto de manera coherente en todos los
elementos secundarios. Si la direccin de flujo se restablece por cualquier motivo en algn nivel del rbol de
elementos, por accin del usuario o del entorno, lo normal es que haya que restablecerla en todo l. Cuando la
propiedad FlowDirection se establece para heredar, nicamente es preciso establecer o restablecer el valor una
vez en el nivel del rbol de elementos que abarca las necesidades de presentacin de cada pgina de la
aplicacin. Incluso el valor predeterminado inicial heredar de esta manera. A pesar de ello, el modelo de
herencia de valores de propiedad permite restablecer el valor en elementos individuales para los pocos casos en
que se desea expresamente mezclar las direcciones de flujo.
Hacer heredable una propiedad personalizada
Cambiando los metadatos de una propiedad personalizada, puede hacer que tambin sus propias propiedades
personalizadas sean heredables. No obstante, tenga en cuenta que hay algunas consideraciones de rendimiento
al designar una propiedad como heredable. En los casos en que esa propiedad no tiene un valor local
establecido, o un valor obtenido a travs de estilos, plantillas o enlaces de datos, una propiedad heredable
proporciona sus valores de propiedad asignados a todos los elementos secundarios del rbol lgico.
Para que una propiedad participe en la herencia de valores, cree una propiedad asociada personalizada, como
se

describe

en

Cmo:

Registrar

una

propiedad

asociada.

Registre

la

propiedad

con

metadatos

(FrameworkPropertyMetadata) y especifique la opcin "Inherits" en la configuracin de opciones de los


metadatos. Asegrese tambin de que la propiedad tenga un valor predeterminado establecido, porque ahora
ese valor heredar. Aunque registr la propiedad como asociada, tambin puede ser conveniente crear un
"contenedor" de propiedad para el acceso set/get para el tipo de propietario, como lo hara para una propiedad
de dependencia no asociada. A continuacin, la propiedad heredable se puede establecer mediante el
contenedor de propiedad directo del tipo de propietario o de los tipos derivados, o bien mediante la sintaxis de
propiedades asociadas de cualquier DependencyObject.
Las propiedades asociadas son conceptualmente similares a las propiedades globales; puede comprobar para el
valor en cualquier DependencyObject y obtener un resultado vlido. El escenario tpico para las propiedades
asociadas consiste en establecer los valores de propiedad en elementos secundarios. Este escenario es ms
efectivo si se trata de una propiedad asociada que siempre est presente implcitamente como tal en cada
elemento (DependencyObject) del rbol.
Nota:

MCT: Luis Dueas

Pag 340 de 445

Manual de Windows Presentation Foundation

Aunque puede que parezca que la herencia de valores de propiedad funciona para las propiedades de
dependencia no asociadas, no se ha definido el comportamiento de la herencia de una propiedad no
asociada a travs de algunos lmites de elementos del rbol en tiempo de ejecucin. Utilice siempre
RegisterAttached para registrar las propiedades en las que especifique Inherits en los metadatos.
Heredar valores de propiedad a travs de los lmites del rbol
La herencia de propiedades funciona atravesando un rbol de elementos. Este rbol suele ser paralelo al rbol
lgico. Sin embargo, cada vez que se incluye un objeto de nivel bsico de WPF en el marcado que define un
rbol de elementos, como un Brush, se crea un rbol lgico discontinuo. Un verdadero rbol lgico no se
extiende conceptualmente a travs de Brush, porque el rbol lgico es un concepto de nivel de marco de
trabajo de WPF. Puede observar esta situacin reflejada en los resultados cuando utilice los mtodos de
LogicalTreeHelper. Sin embargo, la herencia de valores de propiedad puede cerrar esta brecha del rbol lgico y
pasar a travs de ella los valores heredados, siempre que la propiedad heredable se haya registrado como
propiedad asociada y no se encuentre ningn lmite de bloqueo deliberado de la herencia (como un control
Frame).

3.5.10. Seguridad de las Propiedades de Dependencia


Generalmente se debe considerar que las propiedades de dependencia son propiedades pblicas. La naturaleza
del sistema de propiedades de Windows Presentation Foundation (WPF) impide la capacidad de realizar
garantas de seguridad sobre el valor de una propiedad de dependencia.
Acceso y seguridad de contenedores y propiedades de a dependencia
Las propiedades de dependencia se suelen implementar junto con propiedades common language runtime
(CLR) "contenedor" que simplifican la obtencin o el establecimiento de la propiedad desde una instancia. Sin
embargo, en realidad los contenedores no son ms que mtodos tiles que implementan las llamadas estticas
subyacentes a GetValue y SetValue utilizadas al interactuar con las propiedades de dependencia. Expresado de
otro modo, las propiedades se exponen como propiedades common language runtime (CLR) que resultan estar
respaldadas por una propiedad de dependencia en lugar de por un campo privado. Los mecanismos de
seguridad aplicados a los contenedores no imitan el comportamiento ni el acceso del sistema de propiedades de
la propiedad de dependencia subyacente. Efectuar una peticin de seguridad al contenedor nicamente
impedir el uso del mtodo til, pero no impedir las llamadas a GetValue o SetValue. De igual forma, poner un
nivel de acceso protegido o privado en los contenedores tampoco proporciona ninguna seguridad efectiva.
Si escribe sus propias propiedades de dependencia, debe declarar los contenedores y el campo de identificador
DependencyProperty como miembros pblicos, para que los llamadores no obtengan informacin engaosa
sobre el verdadero nivel de acceso de esa propiedad (por el hecho de que su almacn se implemente como una
propiedad de dependencia).
Para una propiedad de dependencia personalizada, puede registrar la propiedad como de dependencia y de slo
lectura, lo que s proporciona un medio efectivo de evitar que establezca la propiedad cualquier persona que no
posea una referencia a la DependencyPropertyKey de esa propiedad.
Nota:
No se prohbe declarar un campo de identificador DependencyProperty privado. Resultara plausible
utilizarlo para contribuir a reducir el espacio de nombres inmediatamente expuesto de una clase
personalizada, pero este tipo de propiedad no debe considerarse "privada" en el mismo sentido en que este
nivel de acceso se define en las definiciones del lenguaje common language runtime (CLR), por los motivos
descritos en la seccin siguiente.
Exposicin de sistema de propiedades de las propiedades de dependencia
En general, no resulta til y puede dar lugar a confusin, declarar DependencyProperty con cualquier nivel de
acceso que no sea pblico. Ese valor de nivel de acceso nicamente impedir que una persona pueda obtener
una referencia a la instancia desde la clase de declaracin. Sin embargo, hay varios aspectos del sistema de
propiedades que devolvern una DependencyProperty como manera de identificar una propiedad determinada
tal como existe en una instancia de una clase o una instancia de clase derivada, y este identificador se puede

MCT: Luis Dueas

Pag 341 de 445

Manual de Windows Presentation Foundation


utilizar en una llamada a SetValue aunque el identificador esttico original se haya declarado como no pblico.
Asimismo, los mtodos virtuales OnPropertyChanged reciben informacin de cualquier propiedad de
dependencia existente cuyo valor haya cambiado. Adems, el mtodo GetLocalValueEnumerator devuelve
identificadores de cualquier propiedad para las instancias con un valor establecido localmente.
Validacin y seguridad
Aplicar una peticin a una propiedad ValidateValueCallback y esperar el error de validacin si sta no se cursa
correctamente no es un mecanismo de seguridad adecuado para impedir que se establezca una propiedad. Un
llamador malintencionado que opere dentro del dominio de aplicacin tambin puede suprimir la invalidacin
del establecimiento de valores mediante ValidateValueCallback.

3.5.11. Modelos de Constructores Seguros para Objetos DependencyObject


En general, los constructores de clase no deben llamar a devoluciones de llamada como mtodos virtuales o
delegados, porque se puede llamar a los constructores como inicializacin base de constructores para una clase
derivada. Podra entrarse en el mtodo virtual en un estado de inicializacin incompleto de cualquier objeto
determinado. Sin embargo, el propio sistema de propiedades llama y expone internamente devoluciones de
llamada, como parte del sistema de propiedades de dependencia. Una operacin tan simple como establecer un
valor de propiedad de dependencia con una llamada a SetValue, incluye potencialmente una devolucin de
llamada en algn punto de la determinacin. Por esta razn, deben extremarse las precauciones al establecer
los valores de propiedades de dependencia dentro del cuerpo de un constructor, algo que puede resultar
problemtico si el tipo se utiliza como clase base. Existe un modelo concreto para implementar constructores
DependencyObject que evita los problemas concretos con los estados de las propiedades de dependencia y las
devoluciones de llamada inherentes, que se documenta aqu.
Mtodos virtuales del sistema de propiedades
Potencialmente, se llama a los mtodos virtuales o devoluciones de llamada siguientes durante los clculos de
la llamada a SetValue que establece un valor de propiedad de dependencia: ValidateValueCallback,
PropertyChangedCallback, CoerceValueCallback, OnPropertyChanged. Cada uno de estos mtodos virtuales o
devoluciones de llamada sirve para una finalidad concreta dirigida a expandir la versatilidad del sistema de
propiedades de Windows Presentation Foundation (WPF) y las propiedades de dependencia.
Aplicacin de las reglas de FXCop con respecto a los mtodos virtuales del sistema de propiedades
Si utiliza la herramienta FXCop de Microsoft como parte del proceso de compilacin, y deriva de algunas clases
del marco de trabajo de WPF llamando al constructor base o bien implementa sus propias propiedades de
dependencia en clases derivadas, podra producirse una infraccin de una regla de FXCop concreta. La cadena
de nombre de esta infraccin es: DoNotCallOverridableMethodsInConstructors
Se trata de una regla que forma parte del conjunto de reglas pblico predeterminado de FXCop. Posiblemente,
lo que comunica esta regla es la existencia de una traza a travs del sistema de propiedades de dependencia
que, llegado un punto, llama a un mtodo virtual de dicho sistema. Esta infraccin de la regla podra seguir
apareciendo aunque se sigan los modelos de constructor recomendados que se documentan en este tema, en
cuyo caso puede que sea necesario deshabilitar dicha regla en la configuracin del conjunto de reglas de
FXCop.
La mayora de los problemas proceden de derivar clases, no de usar las clases existentes
Los problemas que comunica esta regla se producen cuando se deriva de una clase que se implementa con
mtodos virtuales en su secuencia de construccin. Si sella la clase, o si sabe o exige de algn otro modo que
no se deriva de ella, las consideraciones que se explican aqu y los problemas que dan lugar a la regla de FXCop
no son de aplicacin en su caso. Sin embargo, si crea clases previstas para su uso como clases base, como
plantillas, o un conjunto ampliable de bibliotecas de controles, por ejemplo, entonces debe seguir los modelos
recomendados para los constructores.

MCT: Luis Dueas

Pag 342 de 445

Manual de Windows Presentation Foundation


Los constructores predeterminados deben inicializar todos los valores solicitados por las
devoluciones de llamada
Cualquier miembro de instancia que se utilice en las invalidaciones o devoluciones de llamada de la clase (las
devoluciones de llamada de la lista de la seccin Mtodos virtuales del sistema de propiedades) se deben
inicializar en el constructor predeterminado de la clase aunque algunos de esos valores se rellenen mediante
valores "reales" a travs de los parmetros de los constructores no predeterminados.
En el cdigo de ejemplo siguiente (y de los ejemplos subsiguientes) es un ejemplo de pseudocdigo en C# que
infringe esta regla y explica el problema:
public class MyClass : DependencyObject
{
public MyClass() {}
public MyClass(object toSetWobble)
: this()
{
Wobble = toSetWobble; //this is backed by a DependencyProperty
_myList = new ArrayList();
// this line should be in the default ctor
}
public static readonly DependencyProperty WobbleProperty =
DependencyProperty.Register("Wobble", typeof(object), typeof(MyClass));
public object Wobble
{
get { return GetValue(WobbleProperty); }
set { SetValue(WobbleProperty, value); }
}
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
int count = _myList.Count;
// null-reference exception
}
private ArrayList _myList;
}
Cuando el cdigo de aplicacin llama a new MyClass(objectvalue), se llama al constructor predeterminado y a
los constructores de clase base. A continuacin, se establece Property1 = object1, que llama al mtodo virtual
OnPropertyChanged del objeto DependencyObjectMyClass poseedor. La invalidacin hace referencia a _myList,
que no se ha inicializado todava.
Una manera de evitar estos problemas es asegurarse de que las devoluciones de llamada slo utilizan otras
propiedades de dependencia, y que cada una de stas ltimas tiene un valor predeterminado establecido como
parte de sus metadatos registrados.
Modelos de constructor seguros
Para evitar los riesgos de inicializacin incompleta si la clase se utiliza como clase base, siga estos modelos:
Constructores predeterminados que llaman a la inicializacin base
Implemente estos constructores llamando al valor predeterminado base:
public MyClass : SomeBaseClass
{
public MyClass() : base() {
// ALL class initialization, including initial defaults for
// possible values that other ctors specify or that callbacks need.
}
}
Constructores no predeterminados (tiles), que no coinciden con ninguna firma base
Si estos constructores utilizan los parmetros para establecer las propiedades de dependencia en la
inicializacin, llame primero al constructor predeterminado de su propia clase para la inicializacin y, a
continuacin, utilice los parmetros para establecer las propiedades de dependencia. Pueden ser propiedades
de dependencia definidas por la clase o bien heredadas de las clases base, pero debe utilizar el modelo
siguiente en cualquier caso:
public MyClass : SomeBaseClass
{
public MyClass(object toSetProperty1) : this() {
// Class initialization NOT done by default.
// Then, set properties to values as passed in ctor parameters.
Property1 = toSetProperty1;
}
}
Constructores no predeterminados (tiles), que coinciden con firmas base

MCT: Luis Dueas

Pag 343 de 445

Manual de Windows Presentation Foundation


En lugar de llamar al constructor base con la misma parametrizacin, llame de nuevo al constructor
predeterminado de su propia clase. No llame al inicializador base; en su lugar debe llamar a this(). A
continuacin, reproduzca el comportamiento del constructor original utilizando los parmetros pasados como
valores para establecer las propiedades pertinentes. Utilice la documentacin del constructor base original a fin
de obtener orientacin para determinar las propiedades que debe establecer cada parmetro concreto:
public MyClass : SomeBaseClass
{
public MyClass(object toSetProperty1) : this() {
// Class initialization NOT done by default.
// Then, set properties to values as passed in ctor parameters.
Property1 = toSetProperty1;
}
}
Debe hacer coincidir todas las firmas
Para aquellos caso en que el tipo base tiene varias firmas, debe hacer coincidir deliberadamente todas las
firmas posibles con una implementacin de constructor propia que utilice el modelo recomendado consistente
en llamar al constructor predeterminado de clase antes de establecer otras propiedades.
Establecer propiedades de dependencia con SetValue
Estos mismos modelos se aplican si establece una propiedad que no tiene un contenedor para facilitar el
establecimiento de propiedades, y establece los valores con SetValue. Las llamadas al mtodo SetValue que
atraviesa los parmetros del constructor tambin deben llamar al constructor predeterminado de la clase para
la inicializacin.

3.5.12. Propiedades de Dependencia de Tipo de Coleccin


En este se proporciona orientacin y sugerencias de modelos de implementacin de una propiedad de
dependencia cuyo tipo sea de coleccin.
Implementar una propiedad de dependencia de tipo de coleccin
Para las propiedades de dependencia en general, el modelo de implementacin que se sigue consiste en definir
un

contenedor

de

propiedad

CLR,

donde

esa

propiedad

est

respaldada

por

un

identificador

de

DependencyProperty, en lugar de por un campo u otra construccin. Este mismo modelo se sigue al
implementar una propiedad de tipo de coleccin. Sin embargo, una propiedad de tipo de coleccin presenta
cierta complejidad en el modelo cada vez el tipo contenido en la coleccin es, a su vez, una clase derivada de
DependencyObject o Freezable.
Inicializar la coleccin ms all del valor predeterminado
Al crear una propiedad de dependencia, no se especifica el valor predeterminado de la misma como el valor
inicial del campo. En su lugar, se especifica el valor predeterminado a travs de los metadatos de la propiedad
de dependencia. Si la propiedad es un tipo de referencia, el valor predeterminado especificado en sus
metadatos no es un valor predeterminado de una instancia individual, sino un valor predeterminado que se
aplica a todas las instancias del tipo. Por consiguiente, debe extremar las precauciones para no utilizar la
coleccin esttica singular definida por los metadatos de la propiedad de coleccin como el valor
predeterminado activo de las instancias recin creadas de su tipo. En vez de eso, debe asegurarse de
establecer de manera deliberada el valor de coleccin en una coleccin nica (instancia) como parte de la lgica
del constructor de clase. De lo contrario, habr creado involuntariamente una clase singleton.
Considere el ejemplo siguiente. En la seccin siguiente del ejemplo se muestra la definicin de una clase
Aquarium. La clase define la propiedad de dependencia de tipo de coleccin AquariumObjects, que utiliza el tipo
List<(Of <(T>)>) genrico con una restriccin de tipo FrameworkElement. En la llamada a Register(String,
Type, Type, PropertyMetadata) para la propiedad de dependencia, los metadatos establecen el valor
predeterminado en un nuevo objeto List<(Of <(T>)>) genrico.
public class Fish : FrameworkElement { }
public class Aquarium : DependencyObject
{
private static readonly DependencyPropertyKey AquariumContentsPropertyKey =
DependencyProperty.RegisterReadOnly(

MCT: Luis Dueas

Pag 344 de 445

Manual de Windows Presentation Foundation


"AquariumContents",
typeof(List<FrameworkElement>),
typeof(Aquarium),
new FrameworkPropertyMetadata(new List<FrameworkElement>())
);
public static readonly DependencyProperty AquariumContentsProperty =
AquariumContentsPropertyKey.DependencyProperty;
public List<FrameworkElement> AquariumContents
{
get { return (List<FrameworkElement>)GetValue(AquariumContentsProperty); }

...
}
Sin embargo, si se limita a dejar el cdigo tal y como se muestra, ese valor predeterminado nico de la lista se
compartir para todas las instancias de Aquarium. Si ejecutara el cdigo de pruebas siguiente, diseado para
mostrar cmo crear dos instancias independientes de Aquarium y agregar un tipo Fish nico diferente a cada
una de ellas, vera un resultado sorprendente:
Aquarium myAq1 = new Aquarium();
Aquarium myAq2 = new Aquarium();
Fish f1 = new Fish();
Fish f2 = new Fish();
myAq1.AquariumContents.Add(f1);
myAq2.AquariumContents.Add(f2);
MessageBox.Show("aq1 contains " + myAq1.AquariumContents.Count.ToString() + " things");
MessageBox.Show("aq2 contains " + myAq2.AquariumContents.Count.ToString() + " things");
En lugar de que el recuento de cada coleccin sea de uno, el recuento de cada coleccin es de dos! Esto se
debe a que cada Aquarium agreg Fish a la coleccin de valores predeterminados, resultante de una llamada de
constructor nica en los metadatos, con lo que se comparte entre todas las instancias. Esta situacin casi nunca
es deseable.
Para corregir este problema, debe restablecer el valor de la propiedad de dependencia de coleccin en una
instancia nica, como parte de la llamada al constructor de clase. Dado que la propiedad es de dependencia y
de slo lectura, se utiliza el mtodo SetValue(DependencyPropertyKey, Object) para establecerla, utilizando una
clave DependencyPropertyKey que slo est accesible dentro de la clase.
public Aquarium() : base()
{
SetValue(AquariumContentsPropertyKey, new List<FrameworkElement>());
}
Ahora, si ejecuta de nuevo el mismo cdigo de pruebas de antes, los resultados seran ms previsibles, ya que
Aquarium tiene su propia coleccin nica.
Habra una ligera variacin en el modelo si optase por hacer la propiedad de coleccin de lectura y escritura. En
ese caso, podra llamar al descriptor de acceso set pblico desde el constructor para llevar a cabo la
inicializacin, en la que igualmente se llamara a la firma sin clave de SetValue(DependencyProperty, Object)
dentro del contenedor set, utilizando un identificador de DependencyProperty pblico.
Comunicar los cambios de valores de enlace de propiedades de coleccin
Una propiedad de coleccin que tambin es de dependencia no comunica automticamente los cambios a sus
subpropiedades. Si crea enlaces en una coleccin, esto puede evitar que el enlace comunique los cambios, lo
que invalida algunos escenarios de enlace de datos. Sin embargo, si utiliza el tipo de coleccin
FreezableCollection<(Of <(T>)>), entonces s se comunican correctamente los cambios de las subpropiedades
a los elementos contenidos en la coleccin y el enlace funciona como est previsto.
Para habilitar el enlace de subpropiedades en una coleccin de objetos de dependencia, cree la propiedad de
coleccin como el tipo FreezableCollection<(Of <(T>)>), con una restriccin de tipo para esa coleccin a
cualquier clase derivada de DependencyObject.

3.5.13. Carga de XAML y Propiedades de Dependencia


Tener en cuenta las propiedades de dependencia es inherente a la implementacin actual en WPF del
procesador XAML. El procesador XAML de WPF utiliza mtodos del sistema de propiedades para las propiedades
de dependencia al cargar el XAML binario y al procesar atributos que son propiedades de dependencia. En la
prctica esto supone la omisin de los contenedores de propiedad. Al implementar propiedades de dependencia

MCT: Luis Dueas

Pag 345 de 445

Manual de Windows Presentation Foundation


personalizadas, debe tener en cuenta este comportamiento y evitar incluir en el contenedor de propiedad
ningn cdigo que no sean los mtodos del sistema de propiedades GetValue y SetValue.
Implementacin de cargador de XAML de WPF y rendimiento
Por motivos de implementacin, resulta menos costoso desde el punto de vista de la informtica identificar una
propiedad como de dependencia y tener acceso al mtodo SetValue del sistema de propiedades para
establecerla, en lugar de utilizar el contenedor de propiedad y su establecedor. Esto se debe a que un
procesador XAML debe deducir el modelo de objetos completo del cdigo de respaldo basndose nicamente en
las relaciones entre los miembros y los tipos que se indican en la estructura del marcado y en diversas cadenas.
El tipo se busca mediante una combinacin de xmlns y atributos de ensamblado, pero para identificar los
miembros, determinar cules admiten que se los establezca como atributos, y resolver qu tipos admiten las
propiedades, se requerira llevar a cabo una extensa reflexin mediante PropertyInfo. Dado que las propiedades
de dependencia de un tipo determinado estn accesibles como una tabla de almacenamiento a travs del
sistema de propiedades, la implementacin en WPF del procesador XAML utiliza esta tabla y deduce que
cualquier propiedad ABC determinada se puede establecer de un modo ms eficaz llamando al mtodo SetValue
del tipo derivado contenedor DependencyObject, para lo que se utiliza el identificador de propiedad de
dependencia ABCPropiedad.
Implicaciones para las propiedades de dependencia personalizadas
Dado que la implementacin actual en WPF del comportamiento del procesador XAML para establecer
propiedades omite completamente los contenedores, no se debe incluir ninguna lgica adicional en las
definiciones de set del contenedor para la propiedad de dependencia personalizada. Si incluye lgica de este
tipo en la definicin de set, entonces dicha lgica no se ejecutar cuando la propiedad se establezca en XAML
en lugar de mediante cdigo.
De igual forma, otros aspectos del procesador XAML que obtienen valores de propiedades del procesamiento
XAML tambin utilizan GetValue en lugar del contenedor. Por consiguiente, tambin se debe evitar cualquier
implementacin adicional en la definicin de get que no sea la llamada a GetValue.
El ejemplo siguiente es una definicin de propiedad de dependencia recomendada con contenedores, donde el
identificador de propiedad est almacenado como un campo publicstaticreadonly y las definiciones de set y get
no contienen ningn cdigo excepto los mtodos del sistema de propiedades necesarios que definen la lgica de
respaldo de las propiedades de dependencia.
public static readonly DependencyProperty AquariumGraphicProperty =
DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}

3.5.14. Temas Cmo sobre Propiedades


3.5.14.1. Cmo: Implementar una Propiedad de Dependencia
En este ejemplo se muestra cmo respaldar una propiedad common language runtime (CLR) con un campo
DependencyProperty, para definir as una propiedad de dependencia. Si define sus propias propiedades y desea
que admitan numerosos aspectos de la funcionalidad de Windows Presentation Foundation (WPF), incluidos los
estilos, el enlace de datos, la herencia, la animacin y los valores predeterminados, debe implementarlas como
propiedades de dependencia.

MCT: Luis Dueas

Pag 346 de 445

Manual de Windows Presentation Foundation


Ejemplo
En el ejemplo siguiente se registra en primer lugar una propiedad de dependencia llamando al mtodo Register.
El nombre del campo identificador que se utiliza para almacenar el nombre y las caractersticas de la propiedad
de dependencia debe ser el valor de Name que eligi para la propiedad de dependencia como la parte de la
llamada al mtodo Register, con la cadena literal Property anexada a dicho valor. Por ejemplo, si registra una
propiedad de dependencia cuyo valor de Name es Location, el campo identificador que defina para la propiedad
de dependencia deber denominarse LocationProperty.
En este ejemplo, el nombre de la propiedad de dependencia y su descriptor de acceso CLR es State; el campo
de identificador es StateProperty; el tipo de la propiedad es Boolean; y el tipo que registra la propiedad de
dependencia es MyStateControl.
Si no sigue este modelo de nombres, puede que los diseadores no informen correctamente sobre la propiedad
y es posible que algunos aspectos de la aplicacin de estilos del sistema a las propiedades no se comporten
como cabra esperar.
Tambin puede especificar metadatos predeterminados para una propiedad de dependencia. En este ejemplo se
registra que el valor predeterminado de la propiedad de dependenciaState es false.
public class MyStateControl : ButtonBase
{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

3.5.14.2. Cmo: Restaurar el Valor Predeterminado de una Propiedad de


Dependencia
En este ejemplo se muestra cmo utilizar el mtodo ClearValue para restablecer el valor de una propiedad de
dependencia en su valor predeterminado.
Ejemplo
En el ejemplo siguiente se borran los valores de propiedad establecidos localmente de varios tipos de elementos
Shape. El mtodo RestoreDefaultProperties definido por el usuario que se muestra en este ejemplo busca todas
las propiedades de dependencia de lectura y escritura establecidas localmente y borra todas ellas. Los valores
locales de las propiedades se han establecido (mediante la sintaxis de atributos de XAML) en una pgina de
XAML cargada (que no se muestra). Despus de ejecutar RestoreDefaultProperties, se determina el valor real
de cada propiedad mediante el valor de Setter contenido en el estilo correspondiente a ese tipo de elemento
Shape.
Observe que el valor predeterminado de una propiedad de dependencia no es necesariamente el valor de
DefaultValue establecido en los metadatos de esa propiedad. Existen, adems, otros factores activos que
pueden convertirse en el origen del valor efectivo de la propiedad una vez borrado el valor local.
Private Sub RestoreDefaultProperties(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim uic As UIElementCollection = Sandbox.Children
For Each uie As Shape In uic
Dim locallySetProperties As LocalValueEnumerator = uie.GetLocalValueEnumerator()
While locallySetProperties.MoveNext()
Dim propertyToClear As DependencyProperty = locallySetProperties.Current.Property
If Not propertyToClear.ReadOnly Then
uie.ClearValue(propertyToClear)
End If
End While
Next
End Sub
El ejemplo completo del que se deriva este ejemplo incluye los estilos implcitos para cada tipo de elemento
Shape. Cuando la llamada a ClearValue borra el valor local, el estilo de cada elemento Shape determina los

MCT: Luis Dueas

Pag 347 de 445

Manual de Windows Presentation Foundation


valores de propiedad correspondientes a las propiedades concretas que se han borrado. El valor de
DefaultValue basado en metadatos de esas propiedades utiliza una prioridad de determinacin de valor ms
baja que la de los estilos, por lo que no se utiliza DefaultValue ni siquiera una vez borrados los valores.

3.5.14.3. Cmo: Agregar un Tipo de Propietario para una Propiedad de


Dependencia
En este ejemplo se muestra cmo agregar una clase como un propietario de una propiedad de dependencia
registrada para un tipo diferente. Al hacerlo, el lector y el sistema de propiedades de XAML en WPF pueden
reconocer la clase como un propietario adicional de la propiedad. Al realizar la adicin como propietario, la clase
de adicin puede proporcionar metadatos especficos del tipo.
En el ejemplo siguiente, StateProperty es una propiedad registrada por la clase MyStateControl. La clase
UnrelatedStateControl se agrega como un propietario de StateProperty mediante el mtodo AddOwner,
utilizando en concreto la firma que permite utilizar nuevos metadatos para la propiedad de dependencia que
existen en el tipo de adicin. Observe que debe proporcionar descriptores de acceso common language runtime
(CLR) para la propiedad de modo similar al ejemplo mostrado en Cmo: Implementar una propiedad de
dependencia, as como volver a exponer el identificador de la propiedad de dependencia en la clase que se
agrega como propietario.
Sin contenedores, la propiedad de dependencia seguira funcionando desde la perspectiva de acceso mediante
programacin utilizando GetValue o SetValue. Sin embargo, suele ser conveniente imitar este comportamiento
del sistema de propiedades mediante los contenedores de propiedades CLR. Los contenedores facilitan el
establecimiento de la propiedad de dependencia mediante programacin y permiten establecer las propiedades
como atributos XAML.
Ejemplo
public class MyStateControl : ButtonBase
{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}
...
public class UnrelatedStateControl : Control
{
public UnrelatedStateControl() { }
public static readonly DependencyProperty StateProperty =
MyStateControl.StateProperty.AddOwner(typeof(UnrelatedStateControl), new
PropertyMetadata(true));
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
}

3.5.14.4. Cmo: Registrar una Propiedad Asociada


En este ejemplo se muestra cmo registrar una propiedad asociada y proporcionar descriptores de acceso
pblicos para que se pueda utilizar la propiedad en Lenguaje de marcado de aplicaciones extensible (XAML) y
en cdigo. Las propiedades asociadas son un concepto de sintaxis definido por Lenguaje de marcado de
aplicaciones extensible (XAML). La mayora de las propiedades asociadas para los tipos de WPF tambin se
implementan como propiedades de dependencia. Puede utilizar las propiedades de dependencia en cualquier
tipo DependencyObject.
Ejemplo

MCT: Luis Dueas

Pag 348 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente se muestra cmo registrar una propiedad asociada como una propiedad de
dependencia, utilizando el mtodo RegisterAttached. La clase de proveedor tiene la opcin de proporcionar los
metadatos predeterminados para la propiedad que son aplicables cuando la propiedad se utiliza en otra clase, a
menos que esa clase invalide los metadatos. En este ejemplo, el valor predeterminado de la propiedad
IsBubbleSource se establece en false.
La clase de proveedor para una propiedad asociada (aunque no se registre como propiedad de dependencia)
debe proporcionar descriptores de acceso estticos get y set que cumplan la convencin de nomenclatura
siguiente: Set[NombreDePropiedadAsociada] y Get[NombreDePropiedadAsociada]. Estos descriptores de acceso
se necesitan para que el lector XAML activo pueda reconocer las propiedades como atributos en XAML y
resolver los tipos pertinentes.
public static readonly DependencyProperty IsBubbleSourceProperty =
DependencyProperty.RegisterAttached("IsBubbleSource",typeof(Boolean),
typeof(AquariumObject), new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender));
public static void SetIsBubbleSource(UIElement element, Boolean value)
{
element.SetValue(IsBubbleSourceProperty, value);
}
public static Boolean GetIsBubbleSource(UIElement element)
{
return (Boolean)element.GetValue(IsBubbleSourceProperty);
}

3.5.14.5. Cmo: Invalidar Metadatos en una Propiedad de Dependencia


En este ejemplo se muestra cmo invalidar los metadatos de propiedad de dependencia predeterminados que
proceden de una clase heredada, llamando al mtodo OverrideMetadata y proporcionando metadatos
especficos del tipo.
Ejemplo
Mediante la definicin de PropertyMetadata, una clase puede definir los comportamientos de una propiedad de
dependencia, tales como su valor predeterminado las y devoluciones de llamada del sistema de propiedades.
Muchas clases de propiedades de dependencia ya tienen metadatos predeterminados establecidos como parte
de su proceso de registro. Esto incluye las propiedades de dependencia que forman parte de las API de WPF.
Una clase que hereda la propiedad de dependencia a travs de su herencia de clases puede invalidar los
metadatos originales de tal forma que las caractersticas de la propiedad que se pueden modificar mediante
metadatos coincidan con los requisitos especficos de la subclase.
La invalidacin de metadatos en una propiedad de dependencia se debe hacer antes de colocar esa propiedad
para su uso por el sistema de propiedades (esto equivale al momento en que se crean instancias especficas de
los objetos que registran la propiedad). Las llamadas a OverrideMetadata se deben realizar dentro de los
constructores estticos del tipo que se proporciona como parmetro forType de OverrideMetadata. Si se
intentan cambiar los metadatos despus de que existan instancias de tipo de propietario, no se iniciarn
excepciones, pero se provocarn comportamientos incoherentes en el sistema de propiedades. Asimismo, los
metadatos slo se pueden invalidar una vez para cada tipo. Cualquier intento subsiguiente de invalidar los
metadatos en el mismo tipo iniciar una excepcin.
En el ejemplo siguiente, la clase MyAdvancedStateControl personalizada invalida los metadatos proporcionados
para StateProperty mediante MyAdvancedStateControl con nuevos metadatos de propiedad. Ahora, por
ejemplo, el valor predeterminado de StateProperty es true cuando se consulta la propiedad en una instancia de
MyAdvancedStateControl recin construida.
public class MyStateControl : ButtonBase
{
public MyStateControl() : base() { }
public Boolean State
{
get { return (Boolean)this.GetValue(StateProperty); }
set { this.SetValue(StateProperty, value); }
}
public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
"State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

MCT: Luis Dueas

Pag 349 de 445

Manual de Windows Presentation Foundation


...
public class MyAdvancedStateControl : MyStateControl
{
public MyAdvancedStateControl() : base() { }
static MyAdvancedStateControl()
{
MyStateControl.StateProperty.OverrideMetadata(typeof(MyAdvancedStateControl), new
PropertyMetadata(true));
}
}

3.6. Eventos
Windows Presentation Foundation (WPF) introduce eventos enrutados que pueden invocar controladores que
existen en varios agentes de escucha en el rbol de elementos de una aplicacin.

3.6.1. Informacin General sobre Eventos Enrutados


En este tema se describe el concepto de eventos enrutados en Windows Presentation Foundation (WPF). En l
se define la terminologa de los eventos enrutados, se describe cmo se enrutan a travs de un rbol de
elementos, se resume cmo controlarlos y se explica cmo crear eventos enrutados personalizados.
Qu es un evento enrutado?
Puede considerar los eventos enrutados desde dos perspectivas: funcional y de implementacin. Aqu se
presentan ambas definiciones, ya que algunas personas encuentran que una es ms til que la otra.
Definicin funcional: un evento enrutado es un tipo de evento que puede invocar controladores o varios agentes
de escucha en un rbol de elementos, en lugar de simplemente en el objeto que lo desencaden.
Definicin de implementacin: Un evento enrutado es un evento CLR que est respaldado por una instancia de
la clase RoutedEvent y que es procesado por el sistema de eventos de Windows Presentation Foundation (WPF).
Una aplicacin tpica de WPF contiene muchos elementos. Tanto si se crean mediante cdigo como si se
declaran en XAML, estos elementos se relacionan entre s a travs de un rbol de elementos. En funcin de la
definicin del evento, la ruta de eventos puede viajar en cualquiera de las dos direcciones, pero generalmente
viaja partiendo del elemento de origen y, a continuacin, "se propaga" en sentido ascendente por el rbol de
elementos hasta que llega a la raz (normalmente una pgina o una ventana). Puede que le resulte familiar el
concepto de propagacin si ha trabajado previamente con el modelo de objetos de DHTML.
Considere el siguiente rbol de elementos simple:
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightGray" Orientation="Horizontal"
Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>
Este rbol de elementos genera algo parecido a lo siguiente:

En este rbol de elementos simplificado, el origen de un evento Click es uno de los elementos Button y el
elemento Button en el que se hizo clic es el primer elemento que tiene la oportunidad de controlar el evento.
Pero si ninguno de los controladores asociados a Button acta sobre el evento, este se propagar hacia arriba
hasta el elemento primario de Button en el rbol de elementos, que es StackPanel. Potencialmente, el evento
se propaga hasta Border y, a continuacin, contina hacia la raz de la pgina en el rbol de elementos (que no
se muestra).
En otras palabras, la ruta de eventos para este evento Click es:
Botn-->StackPanel-->Borde-->...

MCT: Luis Dueas

Pag 350 de 445

Manual de Windows Presentation Foundation


Escenarios de nivel superior para los eventos enrutados
A continuacin se muestra un breve resumen de los escenarios que motivaron el concepto de evento enrutado
y por qu un evento CLR tpico no resultaba adecuado para estos escenarios:
Encapsulacin y composicin de controles: existen diversos controles de WPF que tienen un modelo de
contenido enriquecido. Por ejemplo, puede colocar una imagen dentro de un control Button, lo que de hecho
extiende el rbol visual del botn. Sin embargo, la imagen agregada no debe interrumpir el comportamiento de
la prueba de posicionamiento que hace que un botn responda al evento Click de su contenido, aun cuando el
usuario haga clic en pxeles que tcnicamente forman parte de la imagen.
Puntos de asociacin de controladores nicos: en formularios Windows Forms, era necesario asociar varias
veces el mismo controlador para procesar eventos que podran desencadenarse desde varios elementos. Los
eventos enrutados le permiten asociar ese controlador una sola vez, tal como se mostr en el ejemplo anterior,
y utilizar la lgica del controlador para determinar el origen del evento si fuera necesario. Por ejemplo, este
podra ser el controlador para el XAML mostrado previamente:
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
switch (feSource.Name)
{
case "YesButton":
// do something here ...
break;
case "NoButton":
// do something ...
break;
case "CancelButton":
// do something ...
break;
}
e.Handled=true;
}
Control de clases: los eventos enrutados permiten un controlador esttico definido por la clase. Este controlador
de clase tiene la oportunidad de controlar un evento antes de que pueda hacerlo cualquiera de los
controladores de instancia asociados.
Referencia a un evento sin reflexin: algunas tcnicas de escritura de cdigo y de marcado requieren una
manera de identificar un evento concreto. Un evento enrutado crea un campo RoutedEvent como identificador,
lo que proporciona una slida tcnica de identificacin de eventos que no requiere la reflexin esttica o en
tiempo de ejecucin.
Cmo se implementan los eventos enrutados
Un evento enrutado es un evento CLR que est respaldado por una instancia de la clase RoutedEvent y
registrado en el sistema de eventos de WPF. La instancia de RoutedEvent obtenida del registro normalmente se
retiene como un miembro del campo publicstaticreadonly de la clase que registra y, por tanto, es la
"propietaria" del evento enrutado. La conexin con el evento CLR del mismo nombre (que a veces se denomina
el evento "contenedor") se logra reemplazando las implementaciones add y remove para el evento CLR. Lo
normal es que add y remove se dejen como un valor predeterminado implcito que utiliza la sintaxis de eventos
especfica del lenguaje adecuada para agregar y quitar controladores de ese evento. El mecanismo de conexin
y de respaldo de los eventos enrutados es conceptualmente similar al modo en que una propiedad de
dependencia es una propiedad CLR respaldada por la clase DependencyProperty y registrada en el sistema de
propiedades de WPF.
En el ejemplo siguiente se muestra la declaracin de un evento enrutado Tap personalizado y se incluye el
registro y la exposicin del campo identificador RoutedEvent y de las implementaciones add y remove para el
evento TapCLR.
Public Shared ReadOnly TapEvent As RoutedEvent = EventManager.RegisterRoutedEvent("Tap",
RoutingStrategy.Bubble, GetType(RoutedEventHandler), GetType(MyButtonSimple))
' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
AddHandler(ByVal value As RoutedEventHandler)
Me.AddHandler(TapEvent, value)

MCT: Luis Dueas

Pag 351 de 445

Manual de Windows Presentation Foundation


End AddHandler
RemoveHandler(ByVal value As RoutedEventHandler)
Me.RemoveHandler(TapEvent, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.RaiseEvent(e)
End RaiseEvent
End Event
Controladores de eventos enrutados y XAML
Para agregar un controlador para un evento utilizando XAML, declare el nombre del evento como un atributo en
el elemento que funciona como agente de escucha de eventos. El valor del atributo es el nombre de su mtodo
de controlador implementado, que debe existir en la clase parcial del archivo de cdigo subyacente.
<Button Click="b1SetColor">button</Button>
La sintaxis XAML para agregar controladores de eventos CLR estndar es la misma que la que se utiliza para
agregar controladores de eventos enrutados, porque realmente se estn agregando controladores al contenedor
de eventos CLR, que se basa en una implementacin de eventos enrutados.
Estrategias de enrutamiento
Los eventos enrutados utilizan una de estas tres estrategias de enrutamiento:

Propagacin: se invocan los controladores de eventos en el origen del evento. A continuacin, el


evento enrutado va pasando por los elementos primarios sucesivos hasta alcanzar la raz del rbol de
elementos. La mayora de los eventos enrutados utilizan la estrategia del enrutamiento de
propagacin. Los eventos con enrutamiento de propagacin generalmente se utilizan para informar
sobre cambios de entrada o de estado procedentes de controles distintos u otros elementos de la
interfaz de usuario.

Directo: slo el propio elemento de origen tiene la oportunidad de invocar controladores como
respuesta. Esto es anlogo al "enrutamiento" utilizado por formularios Windows Forms para los
eventos. Sin embargo, a diferencia de un evento CLR estndar, los eventos con enrutamiento directo
admiten el control de clases (el control de clases se explica en una seccin posterior) y pueden ser
utilizados por EventSetter y EventTrigger.

Tnel: inicialmente, se invocan los controladores de eventos en la raz de rbol de elementos. A


continuacin, el evento enrutado viaja a travs de los elementos secundarios sucesivos a lo largo de la
ruta, hacia el elemento del nodo que es el origen del evento enrutado (el elemento que desencaden
el evento enrutado). Los eventos con enrutamiento de tnel se suelen utilizar o controlar como parte
de la composicin de un control, de forma que los eventos de las partes compuestas se puedan
suprimir o reemplazar deliberadamente por eventos que son especficos del control completo. Los
eventos de entrada proporcionados en WPF suelen venir implementados como una pareja de tnelpropagacin. Los eventos de tnel tambin se conocen a veces como eventos Preview, debido a una
convencin de nomenclatura que se utiliza para los pares.

Por qu se deben utilizar los eventos enrutados?


Como desarrollador de aplicaciones, no siempre necesita saber ni preocuparse de si el evento que est
controlando se implementa como un evento enrutado. Los eventos enrutados tienen un comportamiento
especial, pero ese comportamiento es prcticamente invisible si est controlando un evento en el elemento
donde se desencadena.
Los eventos enrutados demuestran su eficacia cuando se utiliza cualquiera de los escenarios sugeridos: definir
los controladores comunes en una raz comn, componer un control personalizado o definir una clase de
controles personalizada.
Los agentes de escucha de los eventos enrutados y los orgenes de los eventos enrutados no necesitan
compartir un evento comn en su jerarqua. Cualquier UIElement o ContentElement puede ser un agente de

MCT: Luis Dueas

Pag 352 de 445

Manual de Windows Presentation Foundation


escucha de eventos para cualquier evento enrutado. Por consiguiente, puede utilizar todo el conjunto de
eventos enrutados disponibles a lo largo de la API activa como una "interfaz" conceptual en la que elementos
dispares de la aplicacin pueden intercambiar informacin sobre los eventos. Este concepto de "interfaz" para
los eventos enrutados es especialmente aplicable a los eventos de entrada.
Los eventos enrutados tambin se pueden utilizar para comunicar datos a travs del rbol de elementos,
porque los datos del evento para cada evento se perpetan a cada elemento de la ruta. Un elemento podra
cambiar algo en los datos del evento, y ese cambio estara disponible para el elemento siguiente de la ruta.
Aparte del aspecto del enrutamiento, hay otros dos motivos por los que cualquier evento de WPF se podra
implementar como un evento enrutado en lugar de un evento CLR estndar. Si est implementando sus propios
eventos, tambin podra tener en cuenta estos principios:

Algunas caractersticas del diseo de estilos y plantillas de WPF, como EventSetter y EventTrigger
requieren que el evento al que se hace referencia sea un evento enrutado. Este es el escenario del
identificador de eventos mencionado anteriormente.

Los eventos enrutados admiten un mecanismo de control de clases en el que la clase puede especificar
mtodos estticos que tienen la oportunidad de controlar eventos enrutados antes de que cualquier
controlador de instancias registrado tenga acceso a ellos. Esto es muy til en el diseo de controles,
porque una clase puede exigir comportamientos de clase orientados a eventos que no se pueden
suprimir accidentalmente controlando un evento en una instancia.

Cada una de las consideraciones anteriores se explica en una seccin independiente de este tema.
Agregar e implementar un controlador de eventos para un evento enrutado
Para agregar un controlador de eventos en XAML, basta con que agregue el nombre del evento a un elemento
como un atributo y establezca el valor del atributo en el nombre del controlador de eventos que implementa un
delegado adecuado, como en el ejemplo siguiente.
<Button Click="b1SetColor">button</Button>
b1SetColor es el nombre del controlador implementado que contiene el cdigo que controla el evento Click.
b1SetColor debe tener la misma firma que el delegado RoutedEventHandler, que es el delegado del controlador
de eventos para el evento Click. El primer parmetro de todos los delegados del controlador de eventos
enrutado especifica el elemento al que se agrega el controlador de eventos y el segundo parmetro especifica
los datos para el evento.
void b1SetColor(object sender, RoutedEventArgs args)
{
//logic to handle the Click event
...
}
RoutedEventHandler es el delegado del controlador de eventos enrutados bsico. Para los eventos enrutados
especializados para ciertos controles o escenarios, los delegados que deben usarse para los controladores de
eventos enrutados tambin podran volverse ms especializados, de forma que puedan transmitir datos de
evento especializados. Por ejemplo, en un escenario de entrada comn, podra controlar un evento enrutado
DragEnter. Su controlador debera implementar el delegado DragEventHandler. Utilizando el delegado ms
concreto, puede procesar DragEventArgs en el controlador y leer la propiedad Data, que contiene la carga del
portapapeles de la operacin de arrastrar.
Resulta sencillo agregar un controlador para un evento enrutado en una aplicacin que se crea mediante
cdigo. Los controladores de eventos enrutados siempre se pueden agregar a travs de un mtodo auxiliar
AddHandler (que es el mismo mtodo al que llama el respaldo existente para add). Sin embargo, los eventos
enrutados de WPF existentes generalmente tienen implementaciones de respaldo de lgica add y remove que
permiten agregar controladores para los eventos enrutados mediante una sintaxis de eventos especfica del
lenguaje, que una sintaxis ms intuitiva que el mtodo de aplicacin auxiliar. A continuacin se muestra un
ejemplo de uso del mtodo auxiliar:

MCT: Luis Dueas

Pag 353 de 445

Manual de Windows Presentation Foundation


void MakeButton()
{
Button b2 = new Button();
b2.AddHandler(Button.ClickEvent, new RoutedEventHandler(Onb2Click));
}
void Onb2Click(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}
En el ejemplo siguiente se muestra la sintaxis de operador de C# (Visual Basic tiene una sintaxis de operador
ligeramente diferente debido al modo en que controla la eliminacin de referencias):
void MakeButton2()
{
Button b2 = new Button();
b2.Click += new RoutedEventHandler(Onb2Click2);
}
void Onb2Click2(object sender, RoutedEventArgs e)
{
//logic to handle the Click event
}
Si est utilizando Visual Basic, tambin puede utilizar la palabra clave Handles para agregar controladores como
parte de las declaraciones de los controladores.
El concepto de controlado
Todos los eventos enrutados comparten una misma clase base para los datos de eventos, RoutedEventArgs.
RoutedEventArgs define la propiedad Handled, que tiene un valor booleano. El propsito de la propiedad
Handled es permitir que cualquier controlador de eventos a lo largo de la ruta marque el evento enrutado como
controlado, estableciendo el valor de Handled en true. Una vez procesados por el controlador de un elemento a
lo largo de la ruta, se informa de nuevo sobre los datos de evento compartidos a cada agente de escucha a lo
largo de la ruta.
El valor de Handled afecta al modo en que se procesa o se informa sobre un evento enrutado cuando viaja a lo
largo de la ruta. Si Handled es true en los datos de evento para un evento enrutado, los controladores que
realizan escuchas para detectar el evento enrutado en otros elementos ya no se suelen invocar para esa
instancia concreta del evento. Esto se cumple tanto para los controladores asociados en XAML como para los
controladores agregados mediante sintaxis de asociacin de controladores de eventos especficas del lenguaje
como += o Handles. Para la mayora de los escenarios de controladores comunes, al marcar un evento como
controlado estableciendo Handled en true se "detendr" el enrutamiento para una ruta de tnel o una ruta de
propagacin y tambin para cualquier evento que se controle en un punto de la ruta mediante un controlador
de clase.
No obstante, hay un mecanismo "handledEventsToo" mediante el cual los agentes de escucha pueden seguir
ejecutando controladores en respuesta a los eventos enrutados en cuyos datos de evento Handled sea true. Es
decir, la ruta de eventos no se detiene realmente al marcar como controlados los datos de evento. Slo puede
utilizar el mecanismo handledEventsToo en cdigo o en un elemento EventSetter:

En cdigo, en lugar de utilizar una sintaxis de eventos especfica del lenguaje que funciona para los
eventos CLR generales, llame al mtodo AddHandler(RoutedEvent, Delegate, Boolean) de WPF para
agregar su controlador. Especifique el valor de handledEventsToo como true.

En un elemento EventSetter, establezca el atributo HandledEventsToo en true.

Aparte del comportamiento que genera el estado Handled en los eventos enrutados, el concepto de Handled
tiene implicaciones para el modo en que se disea una aplicacin y se escribe el cdigo del controlador de
eventos. Puede conceptuar Handled como un protocolo simple que exponen los eventos enrutados. La forma
concreta en que utilice este protocolo depende de usted, pero el diseo conceptual de cmo se debe utilizar el
valor de Handled es el siguiente:

Si un evento enrutado est marcado como controlado, no es necesario que los dems elementos a lo
largo de esa ruta lo controlen de nuevo.

MCT: Luis Dueas

Pag 354 de 445

Manual de Windows Presentation Foundation

Si un evento enrutado no est marcado como controlado, significa que los dems agentes de escucha
situados anteriormente a lo largo de la ruta han decidido no registrar un controlador o que los
controladores que se registraron decidieron no manipular los datos de evento y establecer Handled en
true. Tambin es posible que el agente de escucha actual sea el primer punto de la ruta. Llegados a
este punto, los controladores del agente de escucha actual tienen tres posibles lneas de accin:

No realizar ninguna accin; el evento sigue estando sin controlar y se enruta al agente de
escucha siguiente.

Ejecutar cdigo en respuesta al evento, pero tomar la determinacin de que la accin


realizada no fue lo suficientemente sustancial como para marcar el evento como controlado. El
evento se enruta al agente de escucha siguiente.

Ejecutar cdigo en respuesta al evento. Marcar el evento como controlado en los datos de
evento pasados al controlador, porque la accin realizada se considera lo suficientemente
sustancial como para marcarlo como controlado. El evento se enruta al agente de escucha
siguiente, pero con Handled=true en sus datos de evento, de forma que slo los agentes de
escucha handledEventsToo tengan la oportunidad de invocar ms controladores.

El comportamiento de enrutamiento mencionado anteriormente refuerza este diseo conceptual: es ms difcil


(aunque todava posible mediante cdigo o estilos) asociar controladores a los eventos enrutados que se
invocan aun cuando un controlador anterior a lo largo de la ruta ya haya establecido Handled en true.
En las aplicaciones, es bastante habitual controlar un evento enrutado de propagacin solamente en el objeto
que lo desencaden, y no preocuparse en absoluto por las caractersticas de enrutado del evento. Sin embargo,
es una buena prctica marcar el evento enrutado como controlado en los datos de evento para evitar efectos
secundarios imprevistos en caso de que un elemento situado ms arriba en el rbol de elementos tambin
tenga un controlador asociado para ese mismo evento enrutado.
Controladores de clase
Si est definiendo una clase que deriva de alguna manera de DependencyObject, tambin puede definir y
asociar un controlador de clase para un evento enrutado que es un miembro de evento declarado o heredado
de su clase. Los controladores de clase se invocan antes que cualquier controlador de agente de escucha de
instancia que est asociado a una instancia de esa clase, cada vez que un evento enrutado alcanza una
instancia de elemento en su ruta.
Algunos controles de WPF tienen el control de clase inherente para ciertos eventos enrutados. En este caso,
podra dar la impresin de que el evento enrutado nunca se desencadena, pero en realidad est sujeto al
control de clase y sus controladores de instancia todava pueden controlar el evento enrutado si utiliza ciertas
tcnicas. Asimismo, muchas clases y controles base exponen mtodos virtuales que se pueden utilizar para
invalidar el comportamiento del control de clase.
Eventos asociados en WPF
El lenguaje XAML tambin define un tipo especial de evento denominado evento asociado. Un evento asociado
le permite agregar un controlador para un evento determinado a un elemento arbitrario. No es necesario que el
elemento que controla el evento defina o herede el evento asociado y ni el objeto que desencadena
potencialmente el evento ni la instancia que controla el destino deben definir o ser "propietarios" de ese evento
como miembro de clase.
El sistema de entrada de WPF utiliza mucho los eventos asociados. Sin embargo, casi todos estos eventos
asociados se reenvan a travs de los elementos base. Los eventos de entrada aparecen como eventos
enrutados no asociados equivalentes que son miembros de la clase de elemento base. Por ejemplo, el evento
asociado MouseDown subyacente se puede controlar ms fcilmente en cualquier UIElement determinado
utilizando MouseDown en ese UIElement en lugar de emplear sintaxis de eventos asociados en XAML o en
cdigo.

MCT: Luis Dueas

Pag 355 de 445

Manual de Windows Presentation Foundation


Nombres de evento completos en XAML
Otro uso de una sintaxis similar a la sintaxis de eventos asociados nombreDeTipo.nombreDeEvento pero que no
es en sentido estricto un uso de eventos asociados se produce al asociar controladores para eventos enrutados
que son desencadenados por elementos secundarios. Los controladores se asocian a un elemento primario
comn para aprovecharse del enrutamiento de eventos, aunque el evento enrutado pertinente no sea miembro
del elemento primario comn. Considere este ejemplo de nuevo:
<Border Height="50" Width="300" BorderBrush="Gray" BorderThickness="1">
<StackPanel Background="LightGray" Orientation="Horizontal"
Button.Click="CommonClickHandler">
<Button Name="YesButton" Width="Auto" >Yes</Button>
<Button Name="NoButton" Width="Auto" >No</Button>
<Button Name="CancelButton" Width="Auto" >Cancel</Button>
</StackPanel>
</Border>
Aqu, el agente de escucha del elemento primario donde se agrega el controlador es un StackPanel. Sin
embargo, est agregando un controlador para un evento enrutado que se declar y ser desencadenado por la
clase Button (en realidad, ButtonBase, pero disponible para Button a travs de la herencia). Button es el
"propietario" del evento, pero el sistema de eventos enrutados permite asociar los controladores para cualquier
evento enrutado a cualquier agente de escucha de instancias de UIElement o ContentElement que, de lo
contrario, podra asociar los agentes de escucha para un evento common language runtime (CLR). El espacio de
nombres xmlns predeterminado para estos nombres de atributo de evento completos es normalmente el
espacio de nombres xmlns de WPF predeterminado, pero tambin puede especificar espacios de nombres con
prefijos para los eventos enrutados personalizados.
Eventos de entrada de WPF
Dentro de la plataforma WPF, con frecuencia se emplean los eventos enrutados como eventos de entrada. En
WPF, a los nombres de los eventos con enrutamiento de tnel se les antepone la palabra "Preview" por
convencin. Los eventos de entrada suelen presentarse en parejas, donde uno es el evento de propagacin y el
otro es el evento de tnel. Por ejemplo, el evento KeyDown y el evento PreviewKeyDown tienen la misma
firma, pero el primero es el evento de entrada de propagacin y el segundo es el evento de entrada de tnel.
En ocasiones, los eventos de entrada slo tienen una versin de propagacin o quizs slo una versin
enrutada directa. En la documentacin, los temas sobre eventos enrutados contienen referencias cruzadas a los
temas relativos a los eventos enrutados similares con estrategias de enrutamiento alternativas, si existen
dichos eventos enrutados, y las secciones de las pginas de referencia administradas clarifican la estrategia de
enrutamiento de cada evento enrutado.
Los eventos de entrada de WPF que se presentan en parejas se implementan de forma que una nica accin del
usuario desde la entrada, como presionar un botn del mouse, desencadenar los dos eventos enrutados de la
pareja, uno detrs de otro. En primer lugar, se desencadena el evento de tnel y este viaja por su ruta. A
continuacin se desencadena el evento de propagacin y este viaja por su ruta. Los dos eventos comparten
literalmente la misma instancia de datos de evento, porque la llamada del mtodo RaiseEvent de la clase de
implementacin que desencadena el evento de propagacin est a la escucha de los datos de evento
procedentes del evento de tnel y los reutiliza en el nuevo evento desencadenado. Los agentes de escucha con
controladores para el evento de tnel tienen la primera oportunidad de marcar el evento enrutado como
controlado (en primer lugar los controladores de clase y despus los controladores de instancias). Si un
elemento a lo largo de la ruta de tnel marca el evento enrutado como controlado, los datos del evento
controlado se envan para el evento de propagacin y no se invocarn los controladores tpicos asociados para
los eventos de entrada de propagacin equivalentes. Externamente dar la impresin de que el evento de
propagacin controlado ni siquiera se ha desencadenado. Este comportamiento de los controles es til para la
composicin de controles, donde podra ser conveniente que fuera el control final y no sus partes compuestas el
que informara sobre todos los eventos de entrada basados en pruebas de posicionamiento o sobre los eventos
de entrada basados en el foco. El elemento del control final est ms cercano a la raz en la composicin y, por
tanto, tiene la oportunidad de controlar desde la clase el evento de tnel en primer lugar y posiblemente
"reemplazar" dicho evento enrutado por un evento ms especfico del control, como parte del cdigo que
respalda la clase del control.

MCT: Luis Dueas

Pag 356 de 445

Manual de Windows Presentation Foundation


Para ilustrar cmo funciona el procesamiento de eventos de entrada, observe el ejemplo de evento de entrada
siguiente. En la ilustracin del rbol siguiente, leaf element #2 es el origen de un evento PreviewMouseDown y, a
continuacin, de un evento MouseDown.
Eventos de entrada de propagacin y de tnel

El orden de procesamiento de los eventos es el siguiente:


1.

PreviewMouseDown (tnel) en el elemento raz.

2.

PreviewMouseDown (tnel) en el elemento intermedio n. 1.

3.

PreviewMouseDown (tnel) en el elemento de origen n. 2.

4.

MouseDown (propagacin) en el elemento de origen n. 2.

5.

MouseDown (propagacin) en el elemento intermedio n. 1.

6.

MouseDown (propagacin) en el elemento raz.

Un delegado de controlador de eventos enrutados proporciona referencias a dos objetos: el objeto que
desencaden el evento y el objeto en el que se invoc el controlador. El objeto en el que se invoc el
controlador es el objeto sobre el que informa el parmetro sender. La propiedad Source de los datos del evento
informa sobre el objeto en el que se desencaden el evento por primera vez. Un evento enrutado tambin
puede desencadenarlo y controlarlo el mismo objeto, en cuyo caso sender y Source son idnticos (esto es lo
que ocurre con los pasos 3 y 4 de la lista del ejemplo de procesamiento de eventos).
Debido a los mecanismos de tnel y de propagacin, los elementos principales reciben eventos de entrada en
los que Source es uno de sus elementos secundarios. Cuando es importante para conocer cul es el elemento
de origen, puede identificarlo teniendo acceso a la propiedad Source.
Normalmente, una vez que el evento de entrada se marca como Handled, ya no se invocan ms controladores.
Lo habitual es marcar los eventos de entrada como controlados en cuanto se invoca un controlador que se
ocupa del control lgico especfico de la aplicacin relacionado con el significado del evento de entrada.
La excepcin a estas directrices generales sobre el estado Handled es que los controladores del evento de
entrada que se registran para omitir deliberadamente el estado Handled de los datos de evento todava se
invocaran a lo largo de cualquiera de las rutas.
El modelo de datos de evento compartido entre los eventos de tnel y de propagacin, y el desencadenamiento
en primer lugar de los eventos de tnel y a continuacin de los de propagacin no es un concepto que se
cumpla

de

forma

general

para

todos

los

eventos

enrutados.

Ese

comportamiento

se

implementa

especficamente segn el modo en que los dispositivos de entrada de WPF deciden desencadenar y conectar los
pares de eventos de entrada. Implementar sus propios eventos de entrada es un escenario avanzado, pero
tambin podra decidir seguir ese modelo para sus propios eventos de entrada.
Ciertas clases eligen controlar ciertos eventos de entrada mediante clases, normalmente con la intencin de
volver a definir lo que significa un determinado evento de entrada controlado por el usuario dentro de ese
control y de desencadenar un nuevo evento.
EventSetters y EventTriggers

MCT: Luis Dueas

Pag 357 de 445

Manual de Windows Presentation Foundation


En los estilos, puede incluir en el marcado sintaxis de control de eventos XAML predeclarada utilizando un
EventSetter. Cuando se aplica el estilo, el controlador al que se hace referencia se agrega a la instancia que
recibe el estilo. Slo puede declarar un EventSetter para un evento enrutado. A continuacin se muestra un
ejemplo. Observe que el mtodo b1SetColor al que se hace referencia aqu est en un archivo de cdigo
subyacente.
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.EventOvw2"
Name="dpanel2"
Initialized="PrimeHandledToo">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<EventSetter Event="Click" Handler="b1SetColor"/>
</Style>
</StackPanel.Resources>
<Button>Click me</Button>
<Button Name="ThisButton" Click="HandleThis">
Raise event, handle it, use handled=true handler to get it anyway.
</Button>
</StackPanel>
La ventaja que se obtiene aqu es que es probable que el estilo contenga gran cantidad de informacin de otro
tipo que se podra aplicar a cualquier botn de la aplicacin, y si EventSetter forma parte de ese estilo se
promueve la reutilizacin de cdigo incluso en el nivel de marcado. Asimismo, un EventSetter resume los
nombres de los mtodos para los controladores un paso ms all de la aplicacin general y el marcado de la
pgina.
Otra sintaxis especializada que combina el evento enrutado con caractersticas de animacin de WPF es
EventTrigger. Como ocurre con el elemento EventSetter, para EventTrigger slo pueden utilizarse eventos
enrutados. Normalmente, un EventTrigger se declara como parte de un estilo, pero un EventTrigger tambin se
puede declarar en elementos de nivel de pgina como parte de la coleccin Triggers o en un elemento
ControlTemplate. Un EventTrigger le permite especificar un Storyboard que se ejecuta siempre que un evento
enrutado alcanza un elemento en su ruta que declara un EventTrigger para ese evento. La ventaja de un
EventTrigger sobre simplemente controlar el evento y hacer que inicie un guin grfico existente es que un
EventTrigger proporciona un mejor control sobre el guin grfico y su comportamiento de tiempo de ejecucin.
Ms informacin sobre los eventos enrutados
En este tema se explican principalmente los eventos enrutados desde la perspectiva de describir los conceptos
bsicos y proporcionar orientacin sobre cmo y cundo responder a los eventos enrutados que ya existen en
los distintos elementos y controles base. Sin embargo, puede crear sus propios eventos enrutados en su clase
personalizada junto con toda la compatibilidad necesaria, como clases y delegados de datos de evento
especializados. El propietario del evento enrutado puede ser cualquier clase, pero los eventos enrutados deben
desencadenarlos y controlarlos las clases derivadas UIElement o ContentElement para que sean tiles.

3.6.2. Informacin General sobre Eventos Asociados


Lenguaje de marcado de aplicaciones extensible (XAML) define un componente de lenguaje y un tipo de evento
denominado evento asociado. El concepto de evento asociado permite agregar un controlador correspondiente
a un evento determinado a un elemento arbitrario, en lugar de al elemento que realmente define o hereda el
evento. En este caso, ni el objeto que provoca potencialmente el evento ni la instancia de control de destino
definen ni "poseen" el evento de ningn modo.
Sintaxis de eventos asociados
Los eventos asociados tienen una sintaxis XAML y un modelo de codificacin que es preciso utilizar en el cdigo
de respaldo para admitir el uso de este tipo de eventos.
En la sintaxis XAML, el evento asociado no se especifica slo por su nombre de evento, sino por su tipo
poseedor y su nombre de evento, separados por un punto (.). Dado que el nombre de evento se certifica con el

MCT: Luis Dueas

Pag 358 de 445

Manual de Windows Presentation Foundation


nombre de su tipo poseedor, la sintaxis de eventos asociados permite asociar cualquier evento a cualquier
elemento del que se puedan crear instancias.
Por ejemplo, a continuacin se muestra la sintaxis XAML para asociar un controlador para un evento asociado
personalizado, NeedsCleaning:
<aqua:Aquarium Name="theAquarium" Height="600" Width="800"
aqua:AquariumFilter.NeedsCleaning="WashMe"/>
Observe el prefijo aqua:, que es necesario en este caso porque el evento asociado es un evento personalizado
que procede de un xmlns asignado personalizado.
Cmo se implementan los eventos asociados en WPF
En WPF, los eventos asociados estn respaldados por un campo RoutedEvent y se enrutan a travs del rbol
despus de provocarse. Normalmente, el origen del evento asociado (el objeto que provoca el evento) es un
origen del sistema o de servicio; en consecuencia, el objeto que ejecuta el cdigo que provoca el evento no
forma parte directa del rbol de elementos.
Escenarios para los eventos asociados
En WPF, los eventos asociados estn presentes en algunas reas de caractersticas donde existe la abstraccin
de nivel de servicio, por ejemplo, para los eventos habilitados por la clase Mouse esttica o por la clase
Validation. Las clases que interactan con el servicio o que lo utilizan pueden usar el evento en la sintaxis de
eventos asociados o bien exponer el evento asociado como evento enrutado que forma parte de la integracin
de la clase en las funciones del servicio.
Aunque WPF define varios eventos asociados, los escenarios donde los utilizar o controlar directamente son
muy limitados. En general, el evento asociado sirve para algn fin de la arquitectura, pero luego se reenva a
un evento enrutado no asociado (respaldado por un "contenedor" de evento CLR).
Por ejemplo, el evento asociado MouseDown subyacente se puede controlar ms fcilmente en cualquier
UIElement determinado utilizando MouseDown en ese UIElement en lugar de emplear sintaxis de eventos
asociados en XAML o en cdigo. El evento asociado sirve para fines de la arquitectura, porque permite la
expansin futura de los dispositivos de entrada. El dispositivo hipottico slo necesitara provocar MouseDown
para simular una entrada del mouse y no necesitara derivar de la clase Mouse para ello. Sin embargo, este
escenario implica el control de eventos mediante cdigo, y el control mediante XAML del evento asociado no es
pertinente a este escenario.
Administrar eventos asociados en WPF
El proceso de control de eventos asociados y el cdigo de controlador que se escribe son, bsicamente, iguales
que para un evento enrutado.
En general, un evento asociado de WPF no se diferencia mucho de un evento enrutado de WPF. Las diferencias
residen en cmo se origina el evento y en cmo lo expone como miembro una clase (lo que tambin afecta a la
sintaxis de controlador en XAML).
Sin embargo, como se indica anteriormente, los eventos asociados de WPF existentes no estn destinados en
particular al control en WPF. Casi siempre, la finalidad del evento es permitir que un elemento compuesto
informe de un estado a un elemento primario en la composicin de controles, en cuyo caso el evento se suele
provocar mediante cdigo y, adems, se basa en la administracin de clases de la clase primaria pertinente.
Por ejemplo, se espera que los elementos de Selector provoquen el evento asociado Selected, que es
administrado por la clase Selector; a continuacin, es posible que la clase Selector lo convierta en un evento
enrutado diferente, SelectionChanged.
Definir sus propios eventos asociados como eventos enrutados

MCT: Luis Dueas

Pag 359 de 445

Manual de Windows Presentation Foundation


Si deriva de las clases base comunes de WPF, puede implementar sus propios eventos asociados incluyendo
determinados mtodos de modelo en la clase y utilizando mtodos de utilidad que ya estn presentes en las
clases base.
El modelo es el siguiente:

Un mtodo Add*Handler con dos parmetros. El primer parmetro debe identificar el evento y el
evento identificado debe coincidir con nombres que tengan * en el nombre de mtodo. El segundo
parmetro es el controlador que se va a agregar. El mtodo debe ser pblico y esttico, sin ningn
valor devuelto.

Un mtodo Remove*Handler con dos parmetros. El primer parmetro debe identificar el evento y el
evento identificado debe coincidir con nombres que tengan * en el nombre de mtodo. El segundo
parmetro es el controlador que se va a quitar. El mtodo debe ser pblico y esttico, sin ningn valor
devuelto.

El mtodo de descriptor de acceso Add*Handler facilita el procesamiento XAML cuando se declaran atributos de
controlador de eventos asociados en un elemento. Los mtodos Add*Handler y Remove*Handler tambin
permiten el acceso mediante cdigo al almacn de controladores de eventos del evento asociado.
Este modelo general no es lo bastante preciso para la implementacin prctica en un marco de trabajo, porque
cada implementacin de lector de XAML podra tener esquemas diferentes para identificar los eventos
subyacentes en el lenguaje y la arquitectura de respaldo. sta es una de las razones por las que WPF
implementa los eventos asociados como eventos enrutados; el identificador que debe utilizarse para un evento
(RoutedEvent) ya est definido por el sistema de eventos de WPF. Asimismo, enrutar un evento constituye una
extensin natural de la implementacin en el concepto de nivel de lenguaje de XAML de un evento asociado.
La implementacin de Add*Handler para un evento asociado de WPF est compuesto de una llamada a
AddHandler con el evento enrutado y el controlador como argumentos.
En general, esta estrategia de implementacin y el sistema de eventos enrutados restringen el control de los
eventos asociados a las clases derivadas de UIElement o de ContentElement, porque slo ellas tienen
implementaciones de AddHandler.
Por ejemplo, en el cdigo siguiente se define el evento asociado NeedsCleaning de la clase propietaria
Aquarium; para ello se utiliza la estrategia de eventos asociados de WPF consistente en declarar el evento
asociado como evento enrutado.
<aqua:Aquarium Name="theAquarium" Height="600" Width="800"
aqua:AquariumFilter.NeedsCleaning="WashMe"/>
Observe que el mtodo utilizado para establecer el campo de identificador

del

evento

asociado,

RegisterRoutedEvent, es en realidad el mismo mtodo que se utiliza para registrar un evento enrutado no
asociado. Tanto los eventos asociados como los eventos enrutados se registran en un almacn interno
centralizado. Esta implementacin de almacn de eventos permite la consideracin conceptual de Uso de
eventos como interfaces.
Provocar un evento asociado de WPF
Normalmente, no es necesario provocar los eventos asociados existentes definidos en WPF mediante cdigo.
Estos eventos siguen el modelo conceptual general de "servicio", donde las responsables de provocar los
eventos son las clases de servicio, como InputManager.
Sin embargo, si define un evento asociado personalizado basado en el modelo de WPF consistente en basar los
eventos asociados en eventos enrutados (RoutedEvent), puede utilizar RaiseEvent para provocar un evento
asociado de cualquier objeto UIElement o ContentElement. Para provocar un evento enrutado (asociado o no)
es preciso declarar un elemento concreto del rbol de elementos como origen del evento; este origen se
comunica como llamador del mtodo RaiseEvent. Determinar qu elemento se comunica como origen en el
rbol es responsabilidad del servicio.

MCT: Luis Dueas

Pag 360 de 445

Manual de Windows Presentation Foundation

3.6.3. Eventos de Duracin de Objetos


En este tema se describen los eventos especficos de WPF que representan las fases de la duracin de un
objeto, a saber, creacin, uso y destruccin.
Eventos de duracin de objetos
Todos los objetos de cdigo administrado de Microsoft .NET Framework pasan por un conjunto similar de fases
de duracin: creacin, uso y destruccin. Adems, muchos objetos tienen una fase de finalizacin de su
duracin que tiene lugar como parte de la fase de destruccin. Los objetos de WPF, y ms concretamente los
objetos visuales que WPF identifica como elementos, tambin tienen un conjunto de fases comunes de duracin
de objeto. Los modelos de programacin y de aplicacin de WPF exponen estas fases como una serie de
eventos. Hay cuatro tipos principales de objetos en WPF con respecto a los eventos de duracin; los elementos
en general, los elementos de ventana, los hosts de navegacin y los objetos de aplicacin. Las ventanas y los
hosts de navegacin tambin pertenecen al grupo mayor de objetos visuales (elementos). En este tema se
describen los eventos de duracin comunes a todos los elementos y, a continuacin, se presentan los ms
concretos que se aplican a las definiciones de aplicacin, ventanas u hosts de navegacin.
Eventos de duracin comunes para elementos
Cualquier elemento de nivel de marco de trabajo de WPF (aquellos objetos que se derivan de
FrameworkElement o FrameworkContentElement) tiene tres eventos de duracin comunes: Initialized, Loaded y
Unloaded.
Initialized
Initialized se provoca primero y corresponde aproximadamente a la inicializacin del objeto mediante la llamada
a su constructor. Dado que el evento se produce en respuesta a la inicializacin, es seguro que se establecen
todas las propiedades del objeto. (Una excepcin de ello son los usos de expresiones del tipo de recursos
dinmicos o enlaces; estas expresiones no se evaluarn.) Como consecuencia del requisito de que se
establezcan todas las propiedades, la secuencia del elemento Initialized provocado por elementos anidados
definidos en marcado parece suceder por orden desde los elementos ms profundos del rbol de elementos
hasta los elementos primarios cercanos a la raz. Este orden se debe a que las relaciones entre elementos
primarios y secundarios y de contencin son propiedades, y por consiguiente el elemento primario no puede
comunicar la inicializacin hasta que se han inicializado completamente tambin los elementos secundarios que
rellenan la propiedad.
Cuando escriba controladores en respuesta al evento Initialized, debe tener en cuenta que no existe ninguna
garanta de que se hayan creado todos los dems elementos del rbol de elementos (rbol lgico o el rbol
visual) en torno al punto donde se asocie el controlador, en particular los elementos primarios. Puede que haya
variables de miembro que sean null, o que algunos orgenes de datos no se hayan rellenado an por el enlace
subyacente (incluso en el nivel de expresin).
Loaded
El evento Loaded se provoca a continuacin. El evento Loaded se provoca antes de la representacin final, pero
despus de que el sistema de diseo haya calculado todos los valores necesarios para representar. Loaded
implica que el rbol lgico en el que est contenido un elemento est completo, y se conecta a un origen de
presentacin que proporciona el HWND y la superficie de representacin. El enlace de datos estndar (enlaces a
orgenes locales, como otras propiedades u orgenes de datos definidos directamente) se habr producido antes
de Loaded. El enlace de datos asincrnico (orgenes externos o dinmicos) podra haberse producido, pero por
definicin de su naturaleza asincrnica no se puede garantizar que as sea.
El mecanismo por el que se provoca el evento Loaded es diferente que el de Initialized. El evento Initialized se
provoca de elemento en elemento, sin la coordinacin directa de un rbol de elementos completado. En cambio,
el evento Loaded se provoca como un esfuerzo coordinado en todo el rbol de elementos (en concreto, en el

MCT: Luis Dueas

Pag 361 de 445

Manual de Windows Presentation Foundation


rbol lgico). Cuando todos los elementos del rbol estn en un estado en que se consideran cargados, el
evento Loaded se provoca en primer lugar en el elemento raz. El evento Loaded se provoca a continuacin
consecutivamente en cada elemento secundario.
Nota:
A primera vista, este comportamiento podra parecerse a la propagacin de los eventos enrutados. Sin
embargo, no se lleva ninguna informacin de un evento a otro. Cada elemento siempre tiene la oportunidad
de controlar su evento Loaded, de manera que marcar los datos de evento como controlados no surte
ningn efecto ms all de ese elemento.
Unloaded
Unloaded se provoca en ltimo lugar y lo inicia el origen de presentacin o bien el elemento visual primario que
se quita. Al provocar y controlar el evento Unloaded, puede suceder que elemento primario de origen del
evento (segn lo determina la propiedad Parent) o cualquier elemento dado que se encuentre ms arriba en los
rboles lgico o visual, ya no est establecido, lo que significa que el enlace de datos, las referencias de
recursos y los estilos podran no estar establecidos en su valor normal o en su ltimo valor conocido en tiempo
de ejecucin.
Elementos de modelos de aplicacin de eventos de duracin
Los siguientes elementos de modelos de aplicacin se basan en los eventos de duracin comunes para los
elementos: Application, Window, Page, NavigationWindow y Frame. stos extienden los eventos de duracin
comunes con eventos adicionales que son pertinentes a su finalidad especfica.

3.6.4. Marcar Eventos Enrutados como Controlados y Control de Clases


Los controladores para un evento enrutado pueden marcar el evento como controlado dentro de los datos del
evento. Al controlar el evento, de hecho se acortar la ruta. El control de clases es un concepto de
programacin admitido por los eventos enrutados. Un controlador de clases tiene la oportunidad de controlar un
evento enrutado determinado en un nivel de clase con un controlador que se invoca antes que cualquier
controlador de instancias de cualquier instancia de la clase.
Cundo se deben marcar los eventos como controlados
El hecho de establecer el valor de la propiedad Handled en true en los datos de evento para un evento enrutado
se denomina "marcar el evento como controlado". No hay ninguna regla absoluta que determine cundo debe
marcar los eventos enrutados como controlados, ni como autor de una aplicacin ni como autor de un control
que responde a los eventos enrutados existentes o implementa nuevos eventos enrutados. En la mayora de los
casos, el concepto de "controlado" entendido como transportado en los datos de evento del evento enrutado se
debera utilizar como un protocolo limitado para las respuestas de su propia aplicacin a los distintos eventos
enrutados expuestos en las API de WPF, as como para cualquier evento enrutado personalizado. Otra manera
de abordar el problema "controlado" consiste en tener en cuenta que generalmente debera marcar un evento
enrutado como controlado si su cdigo respondi al evento enrutado de una manera significativa y
relativamente completa. Lo normal es que no sea necesario que haya ms de una respuesta significativa que
requiera implementaciones del controlador independientes para cada aparicin de un evento enrutado. Si se
necesitan ms respuestas, el cdigo necesario se debera implementar a travs de lgica de la aplicacin que se
encadena dentro de un nico controlador en lugar de utilizar el sistema de eventos enrutados para el reenvo.
El concepto de "significativo" tambin es subjetivo y depende de su aplicacin o su cdigo. Como orientacin
general, algunos ejemplos de "respuesta significativa" podran ser: establecer el foco, modificar el estado
pblico, establecer propiedades que afectan a la representacin visual y desencadenar otros eventos nuevos.
Como ejemplos de respuestas no significativas podramos mencionar: modificar el estado privado (sin impacto
visual o representacin de programacin), registrar eventos, o examinar los argumentos de un evento y decidir
no responder al mismo.
El comportamiento del sistema de eventos enrutados refuerza este modelo de "respuesta significativa" para
utilizar el estado controlado de un evento enrutado, porque los controladores agregados en XAML o la firma

MCT: Luis Dueas

Pag 362 de 445

Manual de Windows Presentation Foundation


comn de AddHandler no se invocan en respuesta a un evento enrutado cuyos datos de evento ya estn
marcados como controlados. Debe realizar el esfuerzo adicional de agregar un controlador con la versin de
parmetros de handledEventsToo (AddHandler(RoutedEvent, Delegate, Boolean)) para controlar eventos
enrutados que han sido marcados como controlados por participantes anteriores en la ruta de eventos.
En algunas circunstancias, son los propios controles quienes marcan ciertos eventos enrutados como
controlados. Un evento enrutado controlado representa una decisin de los autores de controles de WPF en el
sentido de que las acciones del control en respuesta al evento enrutado son significativas o completas como
parte de la implementacin del control, y el evento no necesita ninguna operacin de control adicional.
Normalmente esto se hace agregando un controlador de clases para un evento o reemplazando uno de los
elementos virtuales de controlador de clases que existe en una clase base. Todava puede evitar este control de
eventos si lo considera necesario.
Eventos "preview (tnel)" frente a eventos de propagacin y el control de eventos
Los eventos enrutados Preview son eventos que siguen una ruta de tnel a travs del rbol de elementos. El
prefijo "Preview" expresado en la convencin de nomenclatura es indicativo del principio general para los
eventos de entrada segn el cual los eventos enrutados Preview (de tnel) se desencadenan antes que el
evento enrutado de propagacin equivalente. Adems, los eventos enrutados de entrada que tienen una pareja
de tnel y de propagacin tienen una lgica de control distinta. Si un agente de escucha de eventos marca el
evento enrutado de tnel/preview como controlado, el evento enrutado de propagacin se marcar como
controlado incluso antes de que lo reciba cualquier agente de escucha del evento enrutado de propagacin.
Tcnicamente, los eventos enrutados de tnel y de propagacin son eventos independientes, pero comparten
deliberadamente la misma instancia de los datos de evento para permitir este comportamiento.
La conexin entre los eventos enrutados de tnel y de propagacin se realiza mediante la implementacin
interna de cmo cualquier clase de WPF desencadena sus propios eventos enrutados declarados, y esto se
cumple para los eventos enrutados de entrada emparejados. Pero a menos que exista esta implementacin en
el nivel de clase, no hay ninguna conexin entre un evento enrutado de tnel y un evento enrutado de
propagacin que comparten el mismo esquema de nomenclatura: sin tal implementacin, seran dos eventos
enrutados completamente independientes y no se desencadenaran uno tras otro ni compartiran los datos de
evento.
Controladores de clases y controladores de instancias
Los eventos enrutados consideran dos tipos distintos de agentes de escucha para el evento: los agentes de
escucha de clase y los agentes de escucha de instancia. Los agentes de escucha de clase existen porque los
tipos han llamado a una API de EventManager determinada, RegisterClassHandler, en su constructor esttico o
han reemplazado un mtodo virtual de controlador de clases de una clase base de elemento. Los agentes de
escucha de instancia son instancias o elementos de una clase determinada en los que se han asociado uno o
varios controladores para ese evento enrutado mediante una llamada a AddHandler. Los eventos enrutados
existentes de WPF realizan llamadas a AddHandler como parte de las implementaciones add{} y remove{} del
contenedor de eventos common language runtime (CLR) del evento, que tambin es el modo en que se habilita
el mecanismo sencillo de XAML para asociar controladores de eventos a travs de una sintaxis de atributos. Por
consiguiente, en ltima instancia, incluso el uso sencillo de XAML equivale a una llamada a AddHandler.
Los elementos del rbol visual se comprueban para ver si tienen implementaciones del controlador registradas.
Los controladores se invocan potencialmente a lo largo de la ruta, en el orden que es inherente al tipo de
estrategia de enrutamiento para ese evento enrutado. Por ejemplo los eventos enrutados de propagacin
invocarn primero los controladores que estn asociados al mismo elemento que desencaden el evento
enrutado. A continuacin, el evento enrutado se va "propagando" sucesivamente por los elementos primarios
siguientes hasta que se alcance el elemento raz de la aplicacin.
Desde la perspectiva del elemento raz en una ruta de propagacin, si el control de clases o cualquier elemento
situado ms cerca del origen del evento enrutado invoca controladores que marcan los argumentos del evento

MCT: Luis Dueas

Pag 363 de 445

Manual de Windows Presentation Foundation


como controlados, no se invocan los controladores de los elementos raz y la ruta del evento se acorta de hecho
antes de alcanzar ese elemento raz. Sin embargo, la ruta no se detiene por completo, ya que se pueden
agregar controladores utilizando una condicional especial que indica que se deberan seguir invocando, incluso
si un controlador de clases o un controlador de instancias ha marcado el evento enrutado como controlado.
En un nivel ms profundo que la ruta del evento, tambin hay varios controladores de clases que podran
actuar sobre cualquier instancia determinada de una clase. Esto se debe a que el modelo de control de clases
para los eventos enrutados permite que cada una de las clases posibles de una jerarqua de clases registre su
propio controlador de clases para cada evento enrutado. Cada controlador de clases se agrega a un almacn
interno y cuando se construye la ruta de eventos para una aplicacin, se agregan todos los controladores de
clases a la ruta de eventos. Los controladores de clases se agregan a la ruta de forma tal que el controlador de
la clase ms derivada se invoca el primero y los controladores de clases de cada clase base sucesiva se invocan
despus. Generalmente, los controladores de clases no se registran para que tambin respondan a los eventos
enrutados que ya se marcaron como controlados. Por consiguiente, este mecanismo de control de clases
habilita una de estas dos opciones:

Las clases derivadas pueden complementar el control de clases heredado de la clase base agregando
un controlador que no marca el evento enrutado como controlado, porque el controlador de la clase
base se invocar despus que el controlador de la clase derivada.

Las clases derivadas pueden reemplazar el control de clases de la clase base agregando un controlador
de clases que marca el evento enrutado como controlado. Debera tener cuidado con este enfoque,
porque es posible que cambie el diseo del control de base deseado en reas como el aspecto visual,
la lgica de estados, el control de entrada y el control de comandos.

Control de clases de los eventos enrutados por las clases base de los controles
En el nodo de cada uno de los elementos de una ruta de eventos, los agentes de escucha de la clase tienen la
oportunidad de responder al evento enrutado antes de que lo haga cualquier agente de escucha de la instancia
del elemento. Por esta razn, a veces se utilizan los controladores de clases para suprimir eventos enrutados
que una implementacin de una clase de control determinada no desea que se propaguen ms, o para
proporcionar un control especial de ese evento enrutado que es una caracterstica de la clase. Por ejemplo, una
clase podra desencadenar su propio evento especfico de la clase que contiene caractersticas ms concretas
sobre el significado de alguna condicin de los datos proporcionados por el usuario en el contexto de esa clase
en particular. La implementacin de la clase podra marcar el evento enrutado ms general como controlado.
Los controladores de clases normalmente se agregan de forma que no se invoquen para los eventos enrutados
cuyos datos de evento compartidos ya se han marcado como controlados, pero para casos atpicos tambin hay
una firma RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) que registra los controladores de clases
para que tambin se invoquen cuando los eventos enrutados se marquen como controlados.
Elementos virtuales de controlador de clases
Algunos elementos, particularmente los elementos base como UIElement, exponen mtodos virtuales
"On*Event" y "OnPreview*Event" vacos que corresponden a su lista de eventos enrutados pblicos. Estos
mtodos virtuales se pueden reemplazar para implementar un controlador de clases para ese evento enrutado.
Las clases de elementos base registran estos mtodos virtuales como su controlador de clases para cada uno
de esos eventos enrutados utilizando RegisterClassHandler(Type, RoutedEvent, Delegate, Boolean) tal como se
explic anteriormente. Los mtodos virtuales de On*Event hacen que sea mucho ms fcil implementar el
control de clases para los eventos enrutados pertinentes, sin que sea necesaria una inicializacin especial en
constructores estticos para cada tipo. Por ejemplo, puede agregar el control de clases para el evento
DragEnter en cualquier clase derivada UIElement reemplazando el mtodo virtual OnDragEnter. Dentro del
reemplazo, podra controlar el evento enrutado, desencadenar otros eventos, iniciar lgica especfica de la clase
que podra cambiar las propiedades de elementos en instancias, o cualquier combinacin de esas acciones. En
general, debera llamar a la implementacin base en dichos reemplazos aun cuando marque el evento como

MCT: Luis Dueas

Pag 364 de 445

Manual de Windows Presentation Foundation


controlado. Se recomienda encarecidamente llamar a la implementacin base porque el mtodo virtual est en
la clase base. El modelo virtual protegido estndar que consiste en llamar a las implementaciones base desde
cada elemento virtual bsicamente reemplaza y es semejante a un mecanismo similar que es nativo al control
de clases de eventos enrutados, segn el cual se llama a los controladores de clases para todas las clases de
una jerarqua de clases en cualquier instancia determinada, comenzando por el controlador de la clase ms
derivada y continuando hasta el controlador de la clase base. Slo debera omitir la llamada a la
implementacin base si su clase tiene un requisito deliberado para cambiar la clase base que controla la lgica.
La decisin de llamar a la implementacin base antes o despus de su cdigo de reemplazo depender de la
naturaleza de su implementacin.
Control de clases de los eventos de entrada
Todos los mtodos virtuales de los controladores de clases se registran de forma que slo se invocan en los
casos en que no haya ningn tipo de datos de evento compartidos que ya se hayan marcado como controlados.
Por otra parte, slo para los eventos de entrada, las versiones de tnel y de propagacin normalmente se
desencadenan de forma secuencial y comparten los datos de los eventos. Esto supone que para un par
determinado de controladores de clases de eventos de entrada donde uno es la versin de tnel y el otro es la
versin de propagacin, puede que no desee marcar inmediatamente el evento como controlado. Si implementa
el mtodo virtual de control de clases de tnel para marcar el evento como controlado, evitar que se invoque
el controlador de clases de propagacin (y tambin evitar que se invoque cualquier controlador de instancias
normalmente registrado desde el evento de tnel o de propagacin).
Una vez completado el control de clases en un nodo, se tienen en cuenta los agentes de escucha de la instancia
Agregar controladores de instancia que se desencadenan incluso si los eventos estn marcados como
controlados
El mtodo AddHandler proporciona una sobrecarga determinada que le permite agregar controladores que
sern invocados por el sistema de eventos cada vez que un evento alcance el elemento de control en la ruta,
incluso si algn otro controlador ya ha ajustado los datos del evento para marcarlo como controlado. Esto no se
es lo que se hace normalmente. En general, es posible escribir controladores para ajustar todas las reas de
cdigo de la aplicacin que podran verse influenciadas por un evento, sin tener en cuenta donde se control en
un rbol de elementos, incluso si se desean varios resultados finales. Por otra parte, lo normal es que slo haya
un elemento que necesite responder a ese evento y que la lgica de la aplicacin adecuada ya se haya
ejecutado. Pero la sobrecarga handledEventsToo est disponible para los casos excepcionales en que algn otro
elemento de un rbol de elementos o de una composicin de controles ya haya marcado un evento como
controlado, pero otros elementos situados ms arriba o ms abajo en el rbol de elementos (dependiendo de la
ruta) todava deseen que sean invocados sus propios controladores.
Cundo deben marcarse como no controlados los eventos controlados
Generalmente, los eventos enrutados que se marcan como controlados no se deberan marcar como no
controlados (volver a establecer Handled en false) incluso por los controladores que actan sobre
handledEventsToo. Sin embargo, algunos eventos de entrada tienen representaciones de eventos de alto nivel y
de nivel ms bajo que pueden superponerse cuando el evento de alto nivel se ve en una posicin en el rbol y
el evento de bajo nivel en otra. Por ejemplo, considere el caso en que un elemento secundario escucha un
evento clave de alto nivel como TextInput mientras un elemento primario escucha un evento de bajo nivel
como KeyDown. Si el elemento primario controla el evento de bajo nivel, el evento de nivel ms alto se puede
suprimir incluso en el elemento secundario que intuitivamente debera tener oportunidad de controlar el evento
en primer lugar.
En estas situaciones puede ser necesario agregar controladores a los elementos principales y a los elementos
secundarios para el evento de bajo nivel. La implementacin de controlador del elemento secundario puede
marcar el evento de bajo nivel como controlado, pero la implementacin de controlador del elemento primario
lo establecera de nuevo como no controlado para que los siguientes elementos situados ms arriba en el rbol
(as como el evento de alto nivel) puedan tener la oportunidad de responder. Esta situacin debera ser
bastante rara.

MCT: Luis Dueas

Pag 365 de 445

Manual de Windows Presentation Foundation


Supresin deliberada de eventos de entrada para la composicin de controles
El escenario principal donde se utiliza el control de clases de eventos enrutados es para los eventos de entrada
y los controles compuestos. Por definicin, un control compuesto consta de varios controles prcticos o clases
base de controles. A menudo el autor del control desea amalgamar todos los posibles eventos de entrada que
podran desencadenar cada uno de los subcomponentes para informar sobre el control completo como el nico
origen de los eventos. En algunos casos el autor del control podra desear suprimir por completo los eventos de
los componentes o sustituir un evento definido por componente que lleva ms informacin o implica un
comportamiento ms concreto. El ejemplo cannico que resulta evidente para cualquier autor de componentes
es cmo un control Windows Presentation Foundation (WPF)Button controla cualquier evento del mouse que al
final se resolver como el evento intuitivo que tienen todos los botones: un evento Click.
La clase base Button (ButtonBase) deriva de Control que a su vez deriva de FrameworkElement y de
UIElement, y la mayora de la infraestructura de eventos necesaria para el procesamiento de la entrada de los
controles est disponible en el nivel UIElement. En concreto, UIElement procesa eventos del Mouse generales
que controlan la prueba de posicionamiento para el cursor del mouse dentro de sus lmites, y proporciona
eventos distintos para las acciones de botones ms comunes, tales como MouseLeftButtonDown. UIElement
tambin

proporciona

un

mtodo

virtual

vaco

OnMouseLeftButtonDown

como

controlador

de

clases

prerregistrado para MouseLeftButtonDown, y ButtonBase lo reemplaza. De igual forma, ButtonBase utiliza


controladores de clases para MouseLeftButtonUp. En los reemplazos, a los que se les pasan los datos de los
eventos, las implementaciones marcan esa instancia de RoutedEventArgs como controlada estableciendo
Handled en true, y esos mismos datos de evento son lo que contina a lo largo del resto de la ruta hasta otros
controladores de clases y tambin hasta los controladores de instancias o los establecedores de eventos. Por
otra parte, el reemplazo de OnMouseLeftButtonUp desencadenar el evento Click a continuacin. El resultado
final

para

la

mayora

de

los

agentes

de

escucha ser

que

los

eventos

MouseLeftButtonDown

MouseLeftButtonUp "desaparecen" y son reemplazados por Click, un evento que tiene ms significado porque
se sabe que este evento tuvo su origen en un verdadero botn y no en alguna parte compuesta del botn o en
algn otro elemento en su totalidad.
Evitar la supresin de eventos por parte de los controles
A veces este comportamiento de supresin de eventos dentro de los controles individuales puede interferir con
intenciones un poco ms generales de lgica de control de eventos para una aplicacin. Por ejemplo, si por
alguna razn su aplicacin tena un controlador para MouseLeftButtonDown situado en el elemento raz de la
aplicacin,

observara

que

cualquier

clic

en

un

botn

del

mouse

no

invocara

los

controladores

MouseLeftButtonDown ni MouseLeftButtonUp en el nivel raz. El evento en s realmente se propag hacia arriba


(de nuevo, las rutas de evento no estn finalizadas realmente, pero el sistema de eventos enrutados cambia su
comportamiento de invocacin de controladores despus de marcarlo como controlado). Cuando el evento
enrutado lleg al botn, el control de clases ButtonBase marc MouseLeftButtonDown como controlado porque
deseaba sustituir el evento Click con ms significado. Por tanto, cualquier controlador MouseLeftButtonDown
estndar situado ms arriba en la ruta no sera invocado. En este caso, hay dos tcnicas que puede utilizar para
asegurarse de que sus controladores seran invocados.
La primera tcnica consiste en agregar deliberadamente el controlador mediante la firma handledEventsToo de
AddHandler(RoutedEvent, Delegate, Boolean). Una limitacin de este enfoque es que esta tcnica para asociar
un controlador de eventos slo puede utilizarse desde el cdigo, no desde el marcado. La sintaxis simple
consistente en especificar el nombre del controlador de eventos como un valor de atributo de evento a travs
de Lenguaje de marcado de aplicaciones extensible (XAML) no permite ese comportamiento.
La segunda tcnica slo funciona para los eventos de entrada, cuyas versiones de tnel y de propagacin del
evento enrutado estn emparejadas. Para estos eventos enrutados, puede agregar controladores al evento
enrutado equivalente de preview/tnel. Ese evento enrutado descender por la ruta partiendo de la raz, por lo
que el cdigo de control de la clase del botn no lo interceptara, presumiendo que asoci el controlador
preview en algn nivel de elemento antecesor en el rbol de elementos de la aplicacin. Si utiliza este enfoque,
tenga cuidado al marcar cualquier evento Preview como controlado. Para el ejemplo proporcionado con

MCT: Luis Dueas

Pag 366 de 445

Manual de Windows Presentation Foundation


PreviewMouseLeftButtonDown que se controla en el elemento raz, si marcara el evento como Handled en la
implementacin del controlador, realmente suprimira el evento Click. Este no suele ser el comportamiento
deseable.

3.6.5. Eventos de Vista Previa


Los eventos de vista previa, tambin denominados eventos de tnel, son eventos enrutados cuya direccin de
ruta se desplaza desde la raz de la aplicacin hacia el elemento que ha provocado el evento y se comunica
como el origen en los datos de evento. No todos los escenarios de eventos admiten o requieren los eventos de
vista previa; en este tema se describen las situaciones en que existe este tipo de eventos, cmo deben
controlarlos las aplicaciones o los componentes, y los casos en que puede ser conveniente crearlos en
componentes o clases personalizados.
Eventos de vista previa y entrada
Al administrar eventos de vista previa en general, extreme las precauciones en relacin con marcarlos como
controlados en los datos de evento. Controlar un evento de vista previa para cualquier elemento que no sea el
que lo provoc (aqul que se comunica como origen en los datos de evento) hace que no se proporcione a este
ltimo la oportunidad de controlar el evento que ha provocado. A veces, ste es el resultado deseado, en
particular si los elementos en cuestin existan en relaciones contenidas en una composicin de controles de un
control.
En concreto para los eventos de entrada, los eventos de vista previa tambin comparten instancias de datos de
evento con el evento de propagacin equivalente. Si utiliza un controlador de clase de evento de vista previa
para marcar como controlado el evento de entrada, no se invocar el controlador de clase de evento de entrada
de propagacin. Por otra parte, si utiliza un controlador de instancia de evento de vista previa para marcar el
evento como controlado, normalmente no se invocarn los controladores correspondientes al evento de
propagacin. Los controladores de clase o de instancia se pueden registrar o asociar con la opcin de invocarlos
aunque el evento est marcado como controlado, pero se trata de una tcnica de uso poco frecuente.
Evitar la supresin de eventos por parte de los controles
Un escenario donde se suelen utilizar eventos de vista previa es el control de eventos de entrada en controles
compuestos. A veces, el autor del control impide que se provoque determinado evento desde su control, quizs
para sustituir un evento definido por el componente que lleva ms informacin o implica un comportamiento
ms concreto. Por ejemplo, un Windows Presentation Foundation (WPF)Button suprime los eventos
MouseLeftButtonDown y MouseLeftButtonDown provocados por Button o sus elementos compuestos a favor de
capturar el mouse y provocar un evento Click que siempre provoca el propio Button. El evento y sus datos
siguen su curso a lo largo de la ruta, pero puesto que Button marca los datos de evento como Handled,
nicamente se invoca a los controladores del evento cuya actuacin se indica especficamente en el caso
handledEventsToo. Si otros elementos situados ms cerca de la raz de la aplicacin tuvieran que tener la
oportunidad de controlar un evento suprimido por un control, una alternativa consiste en asociar controladores
en cdigo especificando handledEventsToo en true. Sin embargo, es ms sencilla la tcnica de cambiar la
direccin de enrutamiento que se administra de modo que sea el equivalente de vista previa de un evento de
entrada. Por ejemplo, si un control suprime MouseLeftButtonDown, intente asociar en su lugar un controlador
para PreviewMouseLeftButtonDown. Esta tcnica slo funciona para los eventos de entrada del elemento base,
como MouseLeftButtonDown. Estos eventos de entrada utilizan pares de tnel/propagacin, provocan ambos
eventos y comparten los datos de evento.
Cada una de estas tcnicas tiene efectos secundarios o limitaciones. El efecto secundario de controlar el evento
de vista previa reside en que controlarlo en ese punto podra deshabilitar los controladores que esperan
controlar el evento de propagacin, y por consiguiente la limitacin consiste en que no suele ser conveniente
marcar el evento como controlado mientras se encuentre en la parte de la ruta correspondiente a la vista
previa. La limitacin de la tcnica de handledEventsToo es que no se puede especificar un controlador de
handledEventsToo en XAML como un atributo, hay que registrar el controlador de eventos en cdigo despus de
obtener una referencia de objeto al elemento al que se asociar el controlador.

MCT: Luis Dueas

Pag 367 de 445

Manual de Windows Presentation Foundation

3.6.6. Eventos de Cambio de Propiedades


Windows Presentation Foundation (WPF) define varios eventos que se provocan en respuesta a un cambio en el
valor de una propiedad. A menudo, la propiedad es una propiedad de dependencia. A veces, el propio evento es
un evento enrutado y, otras, un evento common language runtime (CLR) estndar. La definicin del evento
vara, dependiendo del escenario, porque algunos cambios de propiedad deben enrutarse preferentemente a
travs de un rbol de elementos, mientras que otros cambios de propiedad afectan tan slo al objeto cuya
propiedad se modifica.
Identificar un evento de cambio de propiedad
No todos los eventos que comunican un cambio de propiedad se identifican de manera explcita, ya sea
mediante un modelo de firma o de denominacin. En general, en la descripcin del evento de la documentacin
del kit de desarrollo de software (SDK) se indica si el evento est vinculado directamente a un cambio en el
valor de una propiedad y se proporcionan referencias cruzadas entre esta ltima y el evento.
Eventos RoutedPropertyChanged
Algunos eventos utilizan un delegado y un tipo de datos de evento que se usan explcitamente para los eventos
de cambio de propiedad. El tipo de datos de evento es RoutedPropertyChangedEventArgs<(Of <(T>)>) y el
delegado es RoutedPropertyChangedEventHandler<(Of <(T>)>). Tanto los datos como el delegado del evento
tienen un parmetro de tipo genrico que se utiliza para especificar, al definir el controlador, el tipo real de la
propiedad que cambia. Los datos del evento contienen dos propiedades, OldValue y NewValue, que se pasan
como argumento de tipo en los datos de evento.
El elemento "Routed" del nombre indica que el evento de cambio de propiedad se registra como un evento
enrutado. La ventaja de enrutar un evento de cambio de propiedad es que el nivel superior de un control puede
recibir este tipo de eventos cuando se modifica el valor de las propiedades de los elementos secundarios
(elementos compuestos del control). Por ejemplo, se puede crear un control que incorpore un control
RangeBase, como Slider. Si cambia el valor de la propiedad Value en el elemento de control deslizante, puede
ser conveniente controlar este cambio en el control primario, en lugar de en dicho elemento.
Al haber un valor anterior y otro nuevo, podra caerse en la tentacin de utilizar este controlador de eventos
como un validador del valor de la propiedad. Sin embargo, no es esta la intencin del diseo de la mayora de
los eventos de cambio de propiedad. En general, se proporcionan los valores para permitir actuar con ellos en
otras reas lgicas del cdigo, pero no se recomienda modificar valores desde el interior del controlador de
eventos, ya que podra provocar una recursividad involuntaria segn cmo se implemente este ltimo.
Si la propiedad es una propiedad de dependencia personalizada, o si trabaja con una clase derivada donde ha
definido el cdigo de creacin de instancias, existe un mecanismo mucho mejor para realizar el seguimiento de
los cambios de las propiedades integrado en el sistema de propiedades de WPF: las devoluciones de llamada
CoerceValueCallback y PropertyChangedCallback a las propiedades del sistema.
Eventos DependencyPropertyChanged
Otros

dos

tipos

que

forman

parte

de

un

escenario

de

evento

de

cambio

de

propiedad

son

DependencyPropertyChangedEventArgs y DependencyPropertyChangedEventHandler. Los eventos de estos


cambios de propiedad no se enrutan; se trata de eventos CLR estndar. DependencyPropertyChangedEventArgs
es

un

tipo

de

informes

de

datos

de

eventos

inusual,

porque

no

se

deriva

de

EventArgs;

DependencyPropertyChangedEventArgs es una estructura, no una clase.


Los eventos que utilizan DependencyPropertyChangedEventArgs y DependencyPropertyChangedEventHandler
son ligeramente ms comunes que los eventos RoutedPropertyChanged. Un ejemplo de un evento que utiliza
estos tipos es IsMouseCapturedChanged.

MCT: Luis Dueas

Pag 368 de 445

Manual de Windows Presentation Foundation


Al igual que RoutedPropertyChangedEventArgs<(Of <(T>)>), DependencyPropertyChangedEventArgs tambin
comunica un valor anterior y un valor nuevo para la propiedad. Asimismo, son aplicables las mismas
consideraciones sobre lo que se puede hacer con los valores; en general no se recomienda que se intente
cambiar de nuevo los valores en el remitente en respuesta al evento.
Desencadenadores de propiedad
Un concepto estrechamente relacionado con los eventos de cambio de propiedad son los desencadenadores de
propiedad. Un desencadenador de propiedad se crea dentro de un estilo o plantilla, y permite crear un
comportamiento condicional basado en el valor de la propiedad a la que se asigna el desencadenador de
propiedad.
La propiedad correspondiente a un desencadenador de propiedad debe ser de dependencia. Puede ser (y suele
ser) una propiedad de dependencia de slo lectura. Un indicador adecuado para saber cundo una propiedad de
dependencia expuesta por un control est diseada (al menos en parte) para actuar como desencadenador de
propiedad, es que su nombre empiece por "Is". Las propiedades que tienen este nombre suelen ser propiedades
de dependencia de tipo Boolean de slo lectura cuyo principal escenario consiste en informar sobre un estado
del control que pueda afectar a la interfaz de usuario en tiempo real y, por consiguiente, es probable que sea
un desencadenador de propiedad.
Algunas de estas propiedades tambin tienen un evento de cambio de propiedad dedicado. Por ejemplo, la
propiedad IsMouseCaptured tiene un evento de cambio de propiedad IsMouseCapturedChanged. La propiedad
en s es de

slo lectura, y su valor lo

ajusta el sistema de entrada, que provoca el evento

IsMouseCapturedChanged cada vez que se produce un cambio en tiempo real.


En comparacin con un evento de cambio propiedad autntico, el uso de un desencadenador de propiedad que
acte en caso de cambio de propiedad tiene algunas limitaciones.
Los desencadenadores de propiedad funcionan aplicando una lgica de coincidencia exacta. Es preciso
especificar una propiedad y un valor que indique el valor concreto que provocar que el desencadenador se
active. Por ejemplo: <Setter Property="IsMouseCaptured" Value="true"> ... </Setter>. Debido a esta
limitacin, la mayora de los usos de los desencadenadores de propiedad se centran en las propiedades de tipo
Boolean o en aqullas que toman un valor de enumeracin dedicado, cuyo intervalo de valores posibles es lo
bastante manejable para definir un desencadenador para cada caso. O bien, puede que para algunos valores
especiales nicamente haya desencadenadores de propiedad, por ejemplo, cuando un recuento de elementos
llega a cero, y que no haya ningn desencadenador para los casos en que el valor de la propiedad vuelva a
cambiar y deje de ser cero (en lugar de desencadenadores para todos los casos, en esta situacin podra
necesitar un controlador de eventos mediante cdigo, o bien un comportamiento predeterminado que cambie al
estado anterior cuando el valor sea distinto de cero).
La sintaxis de los desencadenadores de propiedad es anloga a las instrucciones "if" de programacin. Si la
condicin de activacin se cumple, entonces se "ejecuta" el "cuerpo" del desencadenador de propiedad. El
"cuerpo" de un desencadenador de propiedad no es cdigo, sino marcado. Ese marcado est limitado al uso de
uno o ms elementos Setter para establecer otras propiedades del objeto donde se aplica el estilo o la plantilla.
Para compensar la condicin "if" de un desencadenador de propiedad que posee gran variedad de valores
posibles, suele ser aconsejable establecer ese mismo valor de propiedad en un valor predeterminado mediante
Setter. De esta manera, el establecedor contenido en Trigger tendr la prioridad cuando se cumpla la condicin
de activacin, y el objeto Setter que no est contenido en Trigger tendr prioridad siempre que no se cumpla la
condicin de activacin.
Los desencadenadores de propiedad suelen ser adecuados para escenarios en que deben cambiar una o varias
propiedades de aspecto basndose en el estado de otra propiedad del mismo elemento.

MCT: Luis Dueas

Pag 369 de 445

Manual de Windows Presentation Foundation

3.6.7. Control de Eventos en Visual Basic y WPF


En concreto para el lenguaje Microsoft Visual Basic .NET, puede utilizar la palabra clave Handles especfica del
lenguaje para asociar controladores de eventos a instancias, en lugar de asociar controladores de eventos a
atributos o de utilizar el mtodo AddHandler. Sin embargo, la tcnica de Handles para asociar controladores a
instancias tiene algunas limitaciones, porque la sintaxis de Handles no puede admitir algunas de las
caractersticas especficas de evento enrutado del sistema de eventos de WPF.
Utilizar "Handles" en un aplicacin de WPF
Los controladores de eventos que se conectan a instancias y eventos mediante Handles se deben definir dentro
de la declaracin de clase parcial de la instancia; este requisito tambin se aplica a los controladores de
eventos que se asignan a travs de valores de atributo de elementos. Slo puede especificar Handles para un
elemento en la pgina que tiene un valor de la propiedad Name (o el Atributo x:Name declarado). Esto es
porque la propiedad Name en XAML crea la referencia de instancia necesaria para admitir el formato de
referencia Instancia.Evento que la sintaxis de Handles requiere. El nico elemento que se puede utilizar para
Handles sin una referencia a Name es la instancia del elemento raz que define la clase parcial.
Puede asignar el mismo controlador a varios elementos separando las referencias Instancia.Evento que
aparecen despus de Handles con comas.
Puede utilizar Handles para asignar ms de un controlador a la misma referencia Instancia.Evento. No asigne
importancia al orden en el que se proporcionan los controladores en la referencia de Handles; suponga que los
controladores que controlan el mismo evento se pueden invocar en cualquier orden.
Para quitar un controlador que se agreg con Handles en la declaracin, puede llamar a RemoveHandler.
Puede utilizar Handles para asociar controladores para eventos enrutados, siempre que asocie los controladores
a las instancias que definen el evento controlado en sus tablas de miembros. Para los eventos enrutados, los
controladores que se asocian con Handles siguen las mismas reglas de enrutamiento que los asociados como
atributos XAML o con la firma comn de AddHandler. Esto significa que si el evento est marcado ya como
controlado (la propiedad Handled de los datos de evento es True), entonces los controladores asociados con
Handles no se invocan en respuesta a esa instancia de evento. El evento podra marcarse como controlado por
controladores de instancia en otro elemento de la ruta, o por el control de clases del elemento actual o de otros
anteriores en la ruta. Para los eventos de entrada que admiten eventos emparejados de tnel y propagacin, la
ruta de tnel puede haber marcado como controlado el par de eventos.
Limitaciones de "Handles" para la adicin de controladores
Handles no puede hacer referencia a los controladores correspondientes a eventos asociados. Debe utilizar el
mtodo

de

descriptor

de

acceso

add

para

ese

evento

asociado

atributos

de

evento

nombreDeTipo.nombreDeEvento en XAML.
Para los eventos enrutados, nicamente se puede usar Handles para asignar controladores para instancias para
las que ese evento exista en la tabla de miembros de instancia. Sin embargo, con los eventos enrutados en
general, un elemento primario puede ser un agente de escucha para un evento a partir de los elementos
secundarios, aunque el elemento primario no tenga ese evento en su tabla de miembros. En la sintaxis de
atributo, puede especificar esto mediante un atributo en formato nombreDeTipo.nombreDeMiembro que
certifica cul de los tipos define en realidad el evento que desea controlar. Por ejemplo, un elemento Page
primario (sin ningn evento Click definido) puede realizar escuchas para eventos del clic de botn asignando un
controlador

de

atributo

en

formato

Button.Click.

Sin

embargo,

Handles

no

admite

el

formato

nombreDeTipo.nombreDeMiembro, porque debe admitir un formato de Instancia.Evento en conflicto.


Handles no puede asociar controladores que se invocan para eventos que ya estn marcados como controlados.
En su lugar, debe utilizar cdigo y llamar a la sobrecarga handledEventsToo del mtodo AddHandler
(RoutedEvent, Delegate, Boolean).

MCT: Luis Dueas

Pag 370 de 445

Manual de Windows Presentation Foundation


Cmo implementa WPF la funcionalidad de "Handles"
Al compilar una pgina Lenguaje de marcado de aplicaciones extensible (XAML), el archivo intermedio declara
referencias FriendWithEvents a todos los elementos de la pgina cuya propiedad Name est establecida (o cuyo
Atributo x:Name se ha declarado). Cada instancia con nombre es potencialmente un elemento que se puede
asignar a un controlador a travs de Handles.
Nota:
Dentro de Microsoft Visual Studio, IntelliSense puede completar los elementos que estn disponibles una
referencia a Handles de una pgina. Sin embargo, podra necesitarse un paso de compilacin para que el
archivo intermedio rellene todas las referencias Friends.

3.6.8. Modelos WeakEvent


En las aplicaciones tpicas, es posible que los controladores que se asocian a los orgenes de eventos no se
destruirn en coordinacin con el objeto de agente de escucha que asoci el controlador al origen. Esta
situacin puede provocar prdidas de memoria. Windows Presentation Foundation (WPF) introduce un modelo
de diseo concreto que se puede utilizar para resolver este problema; para ello, proporciona una clase de
administrador dedicada para eventos concretos e implementa una interfaz para los agentes de escucha de ese
evento. Este modelo de diseo se denomina modelo WeakEvent.
Por qu implementar el modelo WeakEvent?
Realizar escuchas de eventos puede provocar prdidas de memoria. La tcnica tpica para realizar escuchas de
eventos consiste en utilizar la sintaxis especfica del lenguaje que asocia un controlador a un evento en un
origen. Por ejemplo, en C#, esa sintaxis es: source.SomeEvent += new SomeEventHandler(MyEventHandler) .
Esta tcnica crea una referencia segura desde el origen de evento al agente de escucha de evento. En general,
al asociar un controlador de eventos para un agente de escucha, la duracin de objeto del origen influye en la
duracin de objeto del agente (a menos que el controlador de eventos se quite explcitamente). Sin embargo,
en determinadas circunstancias puede ser conveniente controlar la duracin de objeto del agente de escucha
tan slo mediante otros factores, tales como si pertenece actualmente al rbol visual de la aplicacin, y no
mediante la duracin del origen. Cada vez que la duracin de objeto del origen es superior a la del agente de
escucha, el modelo de eventos normal provoca una prdida de memoria: el agente de escucha se mantiene
activo ms tiempo del previsto.
El modelo WeakEvent est diseado para resolver este problema de prdida de memoria. El modelo WeakEvent
se puede usar siempre que un agente de escucha necesite registrarse para un evento pero no conozca
explcitamente cundo debe cancelar ese registro, y siempre que la duracin de objeto del origen supere la del
objeto "til" del agente de escucha. (Corresponde al programador definir el concepto de "til".) El modelo
WeakEvent permite al agente de escucha registrarse para el evento y recibirlo sin que ello afecte en modo
alguno a sus caractersticas de duracin de objeto. En efecto, la referencia implcita del origen no se tiene en
cuenta al decidir si el agente de escucha es apto para la recoleccin de elementos no utilizados. Se trata de una
referencia dbil ("weak", en ingls), concepto del que toman su nombre el modelo WeakEvent y las API
relacionadas. El agente de escucha puede someterse a la recopilacin de elementos no utilizados o destruirse
de alguna otra forma, y el origen puede continuar sin conservar las referencias al objeto que se ha destruido no
recopilables en el controlador.
Quin debe implementar el modelo WeakEvent?
Implementar el modelo WeakEvent resulta interesante principalmente para los autores de controles. Esto se
debe a que el autor de un control es responsable en gran medida del comportamiento y la contencin del
control y del efecto que ejerce en las aplicaciones en las que se inserta. Esto incluye el comportamiento de la
duracin de objeto del control, y en particular la administracin del problema de prdida de memoria descrito.

MCT: Luis Dueas

Pag 371 de 445

Manual de Windows Presentation Foundation


Algunos escenarios se prestan de forma inherente a la aplicacin del modelo WeakEvent. Uno de ellos es el
enlace de datos, donde suele suceder que un objeto de origen, que es un origen de datos, sea completamente
independiente de un objeto de agente de escucha, que es un destino de enlace. El modelo WeakEvent ya se
aplica a muchos aspectos del enlace de datos de WPF en lo relativo a cmo se implementan los eventos.
Cmo implementar el modelo WeakEvent
La implementacin del modelo WeakEvent se divide en tres aspectos:

Derivar un administrador de la clase WeakEventManager.


Implementar la interfaz IWeakEventListener en cualquier clase que desee registrar agentes de escucha
para el evento dbil sin generar una referencia segura al origen.

Al registrar los agentes de escucha, no utilice los descriptores de acceso convencionales de agregar y
quitar del evento donde desea que el agente de escucha utilice el modelo. En su lugar, utilice las
implementaciones de "RemoveListener" y "AddListener" del objeto WeakEventManager dedicado para
ese evento.

WeakEventManager
Normalmente, se crean las clases de administrador en relacin 1:1 a los eventos que implementan el modelo.
Por ejemplo, si tiene un evento Spin, derivara una clase SpinEventManager como administrador del evento
dbil dedicado para el evento. Si el evento existe en ms de una clase de origen y, en general, se comporta
igual en todas y comparte el mismo tipo de datos de evento, puede utilizarse el mismo administrador para cada
una de ellas.
La lista de comprobacin de implementacin para derivar de la clase WeakEventManager consiste en invalidar
dos mtodos virtuales y exponiendo diversos miembros ms cuyos nombres no se rigen especficamente por
una plantilla virtual, pero que debe existir de todos modos. Las invalidaciones se utilizan para iniciar o finalizar
el modo de entrega de eventos por la infraestructura de WPF. Los dems miembros son necesarios para
proporcionar funcionalidad que permita que sus propias implementaciones de IWeakEventListener puedan
utilizar WeakEventManager para asociar agentes de escucha al evento.
IWeakEventListener
Una clase que implementa IWeakEventListener tiene una sola responsabilidad: implementar el mtodo de
interfaz ReceiveWeakEvent. La implementacin de ReceiveWeakEvent debe ser centralizada y dirigir cualquier
referencia de evento que exista en esa clase al objeto WeakEventManager adecuado.
Asociar agentes de escucha
Supongamos que tiene un evento ClockwiseSpin (definido por Spinner) que es un evento convencional. Si
desea utilizar el modelo para este evento, debe usar una clase ClockwiseSpinEventManager existente derivada
de WeakEventManager o bien implementarla personalmente. Si tiene una clase de agente de escucha
SpinListener que utilizar como agente de escucha, la tcnica convencional (sin utilizar el modelo) para asociar
el controlador sera emplear la sintaxis +=:
spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);
Pero si tiene una clase que implementa IWeakEventListener y que tiene en cuenta el evento ClockwiseSpin y su
administrador en la implementacin, la sintaxis que debe utilizar en su lugar para el modelo WeakEvent es:
ClockwiseSpinEventManager.AddListener(spinnerInstance, this);
A continuacin, la lgica de control del evento se especifica dentro de uno de los casos de la implementacin de
ReceiveWeakEvent en la clase, no como un controlador basado en delegado convencional.
Implementar el modelo para eventos externos
Un aspecto interesante del modelo WeakEvent es que le permite implementar el modelo con un evento que no
forme parte de la base de cdigo. Desde la perspectiva del origen, la manera de asociar los controladores a su
evento no vara, y se controla por WeakEventManager. Slo es necesario definir WeakEventManager para ese

MCT: Luis Dueas

Pag 372 de 445

Manual de Windows Presentation Foundation


evento y, a continuacin, tener en cuenta ese evento como parte de la lgica de ReceiveWeakEvent en
cualquier agente de escucha probable que utilice el modelo para escuchar ese evento.

3.6.9. Temas Cmo sobre Eventos


Los temas de esta seccin describen cmo utilizar los eventos de WPF.

3.6.9.1. Cmo: Agregar un Controlador de Eventos mediante Cdigo


En este ejemplo se muestra cmo agregar un controlador de eventos a un elemento mediante cdigo.
Si desea agregar un controlador de eventos a un elemento XAML, y se ha cargado ya la pgina de marcado que
contiene el elemento, debe agregar el controlador mediante cdigo. Como alternativa, si est construyendo el
rbol de elementos para una aplicacin mediante cdigo solamente y no se declara ningn elemento mediante
XAML, puede llamar a mtodos concretos para agregar controladores de eventos al rbol de elementos
construido.
Ejemplo
En el ejemplo siguiente se agrega un nuevo Button a una pgina existente que se define inicialmente en XAML.
Un archivo de cdigo subyacente implementa un mtodo de control de eventos y, a continuacin, agrega ese
mtodo como un nuevo controlador de eventos de Button.
En el ejemplo de C# se utiliza el operador += para asignar un controlador a un evento. Se trata del mismo
operador que se utiliza para asignar un controlador en el modelo de control de eventos common language
runtime (CLR). Microsoft Visual Basic no admite a este operador para la adicin de controladores de eventos. En
su lugar, requiere una de estas dos tcnicas:

Utilice el mtodo AddHandler, junto con un operador AddressOf, para hacer referencia a la
implementacin del controlador de eventos.

Utilice la palabra clave Handles como parte de la definicin del controlador de eventos. Esta tcnica no

se muestra aqu.
<TextBlock Name="text1">Start by clicking the button below</TextBlock>
<Button Name="b1" Click="MakeButton">Make new button and add handler to it</Button>
Public Partial Class RoutedEventAddRemoveHandler
Private Sub MakeButton(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim b2 As Button = New Button()
b2.Content = "New Button"
AddHandler b2.Click, AddressOf Onb2Click
root.Children.Insert(root.Children.Count, b2)
DockPanel.SetDock(b2, Dock.Top)
text1.Text = "Now click the second button..."
b1.IsEnabled = False
End Sub
Private Sub Onb2Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
text1.Text = "New Button (b2) Was Clicked!!"
End Sub
Nota:
Agregar un controlador de eventos en la pgina XAML analizada inicialmente es mucho ms sencillo.
Dentro del elemento de objeto donde desea agregar el controlador de eventos, agregue un atributo que
coincida con el nombre del evento que desea controlar. A continuacin, especifique el valor de ese
atributo como el nombre del mtodo de control de eventos que defini en el archivo de cdigo
subyacente de la pgina XAML.

3.6.9.2. Cmo: Controlar un Evento Enrutado


En este ejemplo se muestra cmo funcionan los eventos de propagacin y cmo se escribe un controlador
capaz de procesar los datos del evento enrutado.
Ejemplo

MCT: Luis Dueas

Pag 373 de 445

Manual de Windows Presentation Foundation


En Windows Presentation Foundation (WPF), los elementos se organizan organizados en una estructura de rbol
de elementos. El elemento primario puede participar en el control de los eventos provocados inicialmente por
elementos secundarios del rbol de elementos. Esto es posible gracias al enrutamiento de eventos.
Los eventos enrutados suelen seguir una de las dos estrategias de enrutamiento, propagacin o tnel. Este
ejemplo se centra en el evento de propagacin y utiliza el evento ButtonBase.Click para mostrar cmo funciona
el enrutamiento.
En el ejemplo siguiente se utiliza la sintaxis de atributo de XAML para asociar un controlador de eventos a un
elemento primario comn, que en este ejemplo es StackPanel. En lugar de asociar los controladores de eventos
individuales a cada elemento secundario Button, en el ejemplo se utiliza la sintaxis de atributo para asociar el
controlador de eventos al elemento primario StackPanel. Este modelo de control de eventos muestra cmo
utilizar el enrutamiento de eventos como tcnica para reducir el nmero de elementos a los que se asocia un
controlador. Todos los eventos de propagacin de cada Button se enrutan a travs del elemento primario.
Observe que en el elemento primario StackPanel, el nombre del evento Click especificado como atributo se
certifica parcialmente nombrando la clase Button. La clase Button es una clase derivada de ButtonBase que
tiene el evento Click en su lista de miembros. Esta tcnica de la certificacin parcial para asociar un controlador
de eventos es necesaria si el evento controlado no existe en la lista de miembros del elemento al que est
asociado el controlador del evento enrutado.
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SDKSample.RoutedEventHandle"
Name="dpanel"
Button.Click="HandleClick">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</StackPanel.Resources>
<Button Name="Button1">Item 1</Button>
<Button Name="Button2">Item 2</Button>
<TextBlock Name="results"/>
</StackPanel>

3.6.9.3. Cmo: Crear un Evento Enrutado Personalizado


Para que un evento personalizado admita el enrutamiento de eventos, es preciso registrar un RoutedEvent
mediante el mtodo RegisterRoutedEvent. En este ejemplo se muestran los fundamentos para la creacin de
evento enrutado personalizado.
Ejemplo
Como se muestra en el ejemplo siguiente, primero se registra RoutedEvent mediante el mtodo
RegisterRoutedEvent. Por convencin, el nombre del campo esttico RoutedEvent debe finalizar con el sufijo
Event. En este ejemplo, el nombre del evento es Tap y la estrategia de enrutamiento del evento es Bubble.
Despus de la llamada de registro, puede proporcionar descriptores de acceso common language runtime (CLR)
de agregar y quitar al evento.
Tenga en cuenta que aunque el evento se provoca a travs del mtodo virtual OnTap en este ejemplo concreto,
la manera de provocar un evento o cmo responda este a los cambios depender de sus necesidades.
Observe tambin que en este ejemplo se implementa bsicamente una subclase completa de Button; esa
subclase se genera como un ensamblado independiente y, a continuacin, se crea una instancia como una clase
personalizada en una pgina Lenguaje de marcado de aplicaciones extensible (XAML) independiente. El motivo
de ello es ilustrar el concepto de que los controles con subclases pueden insertarse en rboles compuestos de
otros controles y que, en esta situacin, los eventos personalizados de estos controles tienen exactamente las

MCT: Luis Dueas

Pag 374 de 445

Manual de Windows Presentation Foundation


mismas funciones de enrutamiento de eventos que cualquier elemento nativo de Windows Presentation
Foundation (WPF).
Public Class MyButtonSimple
Inherits Button
' Create a custom routed event by first registering a RoutedEventID
' This event uses the bubbling routing strategy
Public Shared ReadOnly TapEvent As RoutedEvent =
EventManager.RegisterRoutedEvent("Tap", RoutingStrategy.Bubble,
GetType(RoutedEventHandler), GetType(MyButtonSimple))
' Provide CLR accessors for the event
Public Custom Event Tap As RoutedEventHandler
AddHandler(ByVal value As RoutedEventHandler)
Me.AddHandler(TapEvent, value)
End AddHandler
RemoveHandler(ByVal value As RoutedEventHandler)
Me.RemoveHandler(TapEvent, value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As RoutedEventArgs)
Me.RaiseEvent(e)
End RaiseEvent
End Event
' This method raises the Tap event
Private Sub RaiseTapEvent()
Dim newEventArgs As New RoutedEventArgs(MyButtonSimple.TapEvent)
MyBase.RaiseEvent(newEventArgs)
End Sub
' For demonstration purposes we raise the event when the MyButtonSimple is clicked
Protected Overrides Sub OnClick()
Me.RaiseTapEvent()
End Sub
End Class
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:SDKSampleLibrary;assembly=SDKSampleLibrary"
x:Class="SDKSample.RoutedEventCustomApp" >
<Window.Resources>
<Style TargetType="{x:Type custom:MyButtonSimple}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Background" Value="#808080"/>
</Style>
</Window.Resources>
<StackPanel Background="LightGray">
<custom:MyButtonSimple Name="mybtnsimple" Tap="TapHandler">Click to see Tap
custom event work</custom:MyButtonSimple>
</StackPanel>
</Window>
Los eventos de tnel se crean la misma manera, pero con la propiedad RoutingStrategy establecida en Tunnel
en la llamada de registro. Por convencin, los eventos de tnel de WPF llevan el prefijo "Preview".

3.6.9.4. Cmo: Buscar el Elemento de Origen en un Controlador de Eventos


En este ejemplo se muestra cmo buscar el elemento de origen en un controlador de eventos.
Ejemplo
En el ejemplo siguiente se muestra un controlador de eventos Click que se declara en un archivo de cdigo
subyacente. Cuando un usuario hace clic en el botn al que el controlador est asociado, el controlador cambia
el valor de una propiedad. El cdigo del controlador utiliza la propiedad Source de los datos del evento enrutado
que se comunican en los argumentos de evento para cambiar el valor de la propiedad Width del elemento
Source.
Private Sub HandleClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
'You must cast the object as a Button element, or at least as FrameworkElement, to
set Width
Dim srcButton As Button
srcButton = CType(e.Source, Button)
srcButton.Width = 200
End Sub

3.6.9.5. Cmo: Agregar Control de Clases a un Evento Enrutado


Los eventos enrutados se pueden controlar mediante controladores de clase o de instancia en cualquier nodo
concreto de la ruta. En primer lugar, se invocan los controladores de clase, que las implementaciones de clase

MCT: Luis Dueas

Pag 375 de 445

Manual de Windows Presentation Foundation


pueden utilizar para suprimir eventos del control de instancias o introducir otros comportamientos especficos
de eventos en eventos que pertenecen a las clases base. En este ejemplo se muestran dos tcnicas
estrechamente relacionadas para implementar controladores de clase.
Ejemplo
En este ejemplo se utiliza una clase personalizada basada en el panel Canvas. La premisa bsica de la
aplicacin es que la clase personalizada introduce comportamientos en sus elementos secundarios, lo que
incluye interceptar los clics con el botn primario del mouse y marcarlos como controlados, antes de invocar a
la clase del elemento secundario o a cualquier controlador de instancia.
La

clase

UIElement

expone

un

mtodo

virtual

que

habilita

el

control

de

clases

en

el

evento

PreviewMouseLeftButtonDown, simplemente invalidando el evento. sta es la manera ms simple de


implementar el control de clases si este tipo de mtodo virtual est disponible en algn punto de la jerarqua de
la clase. En el cdigo siguiente se muestra la implementacin de OnPreviewMouseLeftButtonDown en
"MyEditContainer", que se deriva de Canvas. La implementacin marca el evento como controlado en los
argumentos y, a continuacin, agrega cdigo para aplicar al elemento de origen un cambio bsico visible.
protected override void
OnPreviewMouseRightButtonDown(System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true; //suppress the click event and other leftmousebuttondown
responders
MyEditContainer ec = (MyEditContainer)e.Source;
if (ec.EditState)
{ ec.EditState = false; }
else
{ ec.EditState = true; }
base.OnPreviewMouseRightButtonDown(e);
}
Si no hay ningn mtodo virtual disponible en las clases base o para ese mtodo concreto, el control de clases
se

puede

agregar

directamente

mediante

un

mtodo

de

utilidad

de

la

clase

EventManager,

RegisterClassHandler. nicamente debe llamarse a este mtodo dentro de la inicializacin esttica de clases
que

agregan

el

control

de

clases.

En

este

ejemplo

se

agrega

otro

controlador

para

PreviewMouseLeftButtonDown y, en este caso, la clase registrada es la clase personalizada. En contraste,


cuando se utilizan mtodos virtuales, la clase registrada es, en realidad, la clase base UIElement. En aquellos
casos en que tanto las clases base como las subclases registran el control de clases, se invocan primero los
controladores subclases. El comportamiento en una aplicacin sera: en primer lugar, este controlador
mostrara su cuadro de mensaje y, a continuacin, se mostrara el cambio visual en el controlador del mtodo
virtual.
static MyEditContainer()
{
EventManager.RegisterClassHandler(typeof(MyEditContainer),
PreviewMouseRightButtonDownEvent, new RoutedEventHandler(LocalOnMouseRightButtonDown));
}
internal static void LocalOnMouseRightButtonDown(object sender, RoutedEventArgs e)
{
MessageBox.Show("this is invoked before the On* class handler on UIElement");
//e.Handled = true;
//uncommenting this would cause ONLY the subclass' class handler to respond
}

3.7. Acciones del Usuario y Comandos


El subsistema Windows Presentation Foundation (WPF) proporciona una nueva API eficaz para las acciones del
usuario. Los comandos constituyen un mecanismo de entrada en Windows Presentation Foundation (WPF) que
proporciona la administracin de acciones del usuario en un nivel ms semntico que la entrada de dispositivo.
Ejemplos de comandos son las operaciones Copiar, Cortar y Pegar de muchas aplicaciones.

3.7.1. Informacin General sobre Acciones del Usuario


El subsistema de Windows Presentation Foundation (WPF) proporciona una API eficaz para aceptar datos de
entrada desde distintos dispositivos, como el mouse, el teclado y el lpiz ptico.

MCT: Luis Dueas

Pag 376 de 445

Manual de Windows Presentation Foundation


En este tema se describen los servicios proporcionados por WPF y se explica la arquitectura de los sistemas de
entrada.
API de entrada
La exposicin de la API de entrada primaria se encuentra en las clases de elementos base: UIElement,
ContentElement, FrameworkElement y FrameworkContentElement. Estas clases proporcionan funcionalidad
para los eventos de entrada relacionados con la presin de teclas, los botones del mouse, la rueda del mouse,
el movimiento del mouse, la administracin del foco y la captura del mouse, por citar algunos. Colocando la API
de entrada en los elementos base, en lugar de tratar todos los eventos de entrada como un servicio, la
arquitectura de entrada permite que los eventos de entrada tengan su origen en un objeto determinado de la
interfaz de usuario y admitan un esquema de enrutamiento de eventos en el que ms de un elemento tenga
oportunidad de controlar un evento de entrada. Muchos eventos de entrada tienen un par de eventos
asociados. Por ejemplo, el evento de presin de tecla est asociado a los eventos KeyDown y PreviewKeyDown.
La diferencia entre estos eventos estriba en cmo se enrutan al elemento de destino. Tunelizacin de eventos
de vista previa en el rbol de elementos, del elemento raz al elemento de destino. Propagacin de eventos de
propagacin, del elemento de destino al elemento raz.
Clases de teclado y de mouse
Adems de la API de entrada de las clases de elementos base, las clases Keyboard y Mouse proporcionan una
API adicional para trabajar con los datos de entrada del teclado y del mouse.
Como ejemplos de API de entrada de la clase Keyboard pueden citarse la propiedad Modifiers, que devuelve las
ModifierKeys que se encuentran presionadas en estos momentos y el mtodo IsKeyDown, que determina si est
presionada una tecla especificada.
En el ejemplo siguiente se usa el mtodo GetKeyStates para determinar si una Key se encuentra en estado
presionado.
// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison.
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
btnNone.Background = Brushes.Red;
}
Como ejemplos de la API de entrada de la clase Mouse pueden citarse MiddleButton, que obtiene el estado del
botn central del mouse, y DirectlyOver, que obtiene el elemento sobre el que se encuentra actualmente el
puntero del mouse.
En el ejemplo siguiente se determina si el LeftButton del mouse se encuentra en estado Pressed.
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
Las clases Mouse y Keyboard se abordan con ms detalle a lo largo de esta informacin general.
Entrada del lpiz
WPF dispone de compatibilidad integrada para Stylus. Stylus es un sistema de entrada manuscrita que se
populariz gracias a Tablet PC. Las aplicaciones de WPF pueden considerar el lpiz como si se tratara de un
mouse mediante la API del mouse, pero WPF tambin expone una abstraccin de dispositivo de lpiz que utiliza
un modelo similar al del teclado y el mouse. Todas las API relacionadas con el lpiz incluyen la palabra "Stylus".
Dado que el lpiz puede actuar como un mouse, las aplicaciones que slo son compatibles con la entrada del
mouse pueden obtener automticamente cierto grado de compatibilidad con el lpiz. Cuando el lpiz se utiliza
de esta forma, la aplicacin tiene la oportunidad de controlar el evento de lpiz adecuado y, a continuacin,
controla el evento de mouse correspondiente. Adems, hay otros servicios de nivel superior, como la entrada
manuscrita, que tambin estn disponibles a travs de la abstraccin de dispositivo de lpiz.

MCT: Luis Dueas

Pag 377 de 445

Manual de Windows Presentation Foundation


Enrutamiento de eventos
Un FrameworkElement puede incluir otros elementos como elementos secundarios en su modelo de contenido,
formando as un rbol de elementos. En WPF, el elemento primario puede participar en la entrada dirigida a sus
elementos secundarios o a otros descendientes controlando los eventos. Esto resulta especialmente til para
crear controles partiendo de otros ms pequeos, un proceso que recibe el nombre de "composicin de
controles" o "composicin".
El enrutamiento de eventos es un proceso que consiste en reenviar eventos a varios elementos para que un
objeto o elemento determinado a lo largo de la ruta pueda decidir si ofrece una respuesta significativa (a travs
de un proceso de control) a un evento que podra tener su origen en otro elemento. Los eventos enrutados
utilizan uno de estos tres mecanismos de enrutamiento: directo, propagacin y tunelizacin. En el enrutamiento
directo, el elemento de origen es el nico elemento que recibe notificacin y el evento no se enruta a ningn
otro elemento. Sin embargo, el evento enrutado directo proporciona algunas funciones adicionales que slo
estn presentes para los eventos enrutados por oposicin a los eventos CLR estndar. La propagacin asciende
por el rbol de elementos notificando primero al elemento que origin el evento, a continuacin al elemento
primario, y as sucesivamente. La tunelizacin se inicia en la raz del rbol de elementos y desciende por este
hasta finalizar en el elemento de origen inicial.
Generalmente, los eventos de entrada de WPF se presentan en parejas que constan de un evento de tnel y de
un evento de propagacin. Los eventos de tnel se distinguen de los eventos de propagacin mediante el
prefijo "Preview". Por ejemplo, PreviewMouseMove es la versin de tnel de un evento de movimiento del
mouse y MouseMove es la versin de propagacin de ese mismo evento. Este emparejamiento de eventos es
una convencin que se implementa en el nivel de elemento y no es ninguna funcin inherente del sistema de
eventos de WPF.
Controlar los eventos de entrada
Para recibir la entrada en un elemento, debe existir un controlador de eventos asociado a ese evento concreto.
En XAML este proceso es muy sencillo: se hace referencia al nombre del evento como un atributo del elemento
que escuchar este evento. A continuacin, se establece el valor del atributo en el nombre del controlador de
eventos que se define, basado en un delegado. El controlador de eventos debe escribirse en cdigo, como C#, y
puede incluirse en un archivo de cdigo subyacente.
Los eventos de teclado se producen cuando el sistema operativo notifica acciones de teclas que se producen
mientras el foco del teclado se encuentra en un elemento. Los eventos de mouse y de lpiz se dividen en dos
categoras: eventos que notifican cambios en la posicin del puntero en relacin con el elemento y eventos que
notifican cambios de estado en los botones del dispositivo.
Ejemplo de evento de entrada de teclado
En el ejemplo siguiente se realizan escuchas para detectar cundo se presiona la tecla de direccin izquierda.
Se crea un elemento StackPanel con un control Button. La instancia de Button tiene asociado un controlador de
eventos para escuchar cundo se presiona la tecla de direccin izquierda.
En la primera seccin del ejemplo se crean los controles StackPanel y Button, y el controlador de eventos se
asocia al evento KeyDown.
<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();
// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";
// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);

MCT: Luis Dueas

Pag 378 de 445

Manual de Windows Presentation Foundation


// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);
La segunda seccin del ejemplo est escrita en cdigo y en ella se define el controlador de eventos. Cuando se
presiona la tecla de direccin izquierda y el control Button tiene el foco de teclado, se ejecuta el controlador y
cambia el color Background de Button. Si se presiona una tecla que no es tecla de direccin izquierda, el color
Background de Button vuelve a establecerse en su color original.
private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
Button source = e.Source as Button;
if (source != null)
{
if (e.Key == Key.Left)
{
source.Background = Brushes.LemonChiffon;
}
else
{
source.Background = Brushes.AliceBlue;
}
}
}
Ejemplo de evento de entrada del mouse
En el ejemplo siguiente, el color Background de Button cambia cuando el puntero del mouse entra en Button. El
color Background se restaura cuando el mouse sale de Button.
En la primera seccin del ejemplo se crean los controles StackPanel y Button, y se asocian controladores de
eventos para los eventos MouseEnter y MouseLeave a Button.
<StackPanel>
<Button Background="AliceBlue"
MouseEnter="OnMouseExampleMouseEnter"
MouseLeave="OnMosueExampleMouseLeave">Button
</Button>
</StackPanel>
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();
// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";
// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);
// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);
La segunda seccin del ejemplo est escrita en cdigo y en ella se definen los controladores de eventos.
Cuando el mouse entra en Button, el color Background de Button cambia a SlateGray. Cuando el mouse sale de
Button, el color Background de Button vuelve a establecerse en AliceBlue.
private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
// Cast the source of the event to a Button.
Button source = e.Source as Button;
// If source is a Button.
if (source != null)
{
source.Background = Brushes.SlateGray;
}
}
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
// Cast the source of the event to a Button.
Button source = e.Source as Button;
// If source is a Button.
if (source != null)
{
source.Background = Brushes.AliceBlue;
}
}
Entrada de texto
El evento TextInput le permite escuchar la entrada de texto de forma independiente del dispositivo. El teclado
constituye el medio principal de entrada de texto, pero los dispositivos de voz, escritura a mano y otros
dispositivos de entrada tambin pueden generar la entrada de texto.

MCT: Luis Dueas

Pag 379 de 445

Manual de Windows Presentation Foundation


En el caso de las acciones del teclado, WPF enva primero los eventos KeyDown o KeyUp adecuados. Si no se
controlan dichos eventos y la tecla es de texto (en lugar de ser una tecla de control como las teclas de direccin
o de funcin), se desencadena un evento TextInput. No siempre existe una asignacin unvoca simple entre los
eventos KeyDown o KeyUp y TextInput, ya que varias presiones de tecla pueden generar un nico carcter de
entrada de texto y una sola presin de tecla pueden generar cadenas de varios caracteres. Esto suele suceder
con idiomas como el chino, el japons y el coreano, que utilizan Editores de mtodos de entrada (IMEs) para
generar los miles de caracteres posibles de sus alfabetos correspondientes.
Cuando WPF enva un evento KeyUp o KeyDown, Key se establece en System si las presiones de tecla pueden
formar parte de un evento TextInput (por ejemplo, si se presiona ALT+S). Esto permite al cdigo de un
controlador de eventos KeyDown comprobar si existe System y, si se encuentra, dejar el procesamiento al
controlador del evento TextInput que se desencadena a continuacin. En estos casos, pueden utilizarse las
distintas propiedades del argumento TextCompositionEventArgs para determinar las presiones de tecla
originales. Del mismo modo, si hay un IME activo, Key presenta el valor ImeProcessed y ImeProcessedKey
proporciona la presin o las presiones de tecla originales.
En el ejemplo siguiente, se define un controlador para el evento Click y otro para el evento KeyDown.
El primer segmento de cdigo o marcado crea la interfaz de usuario.
<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";
// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);
// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);
El segundo segmento de cdigo contiene los controladores de eventos.
private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
{
handle();
e.Handled = true;
}
}
private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
handle();
e.Handled = true;
}
public void handle()
{
MessageBox.Show("Pretend this opens a file");
}
Dado que los eventos de entrada se propagan a la ruta de nivel superior de eventos, StackPanel recibe la
entrada independientemente del elemento que tenga el foco de teclado. Primero se notifica al control TextBox y
slo se llama al controlador OnTextInputKeyDown si TextBox no control la entrada. Si se utiliza el evento
PreviewKeyDown en lugar del evento KeyDown, se llama primero al controlador OnTextInputKeyDown.
En este ejemplo, la lgica de control se ha escrito dos veces, una para CTRL+O y otra para el evento de clic del
botn. Esto puede simplificarse utilizando comandos en lugar de controlar directamente los eventos de entrada.
Foco
Hay dos conceptos principales relacionados con el foco en WPF: el foco de teclado y el foco lgico.

MCT: Luis Dueas

Pag 380 de 445

Manual de Windows Presentation Foundation


Foco de teclado
El foco de teclado hace referencia al elemento que recibe las acciones del teclado. Slo puede haber un
elemento en todo el escritorio que tenga el foco de teclado. En WPF, el elemento que tenga el foco de teclado
tendr la propiedad IsKeyboardFocused establecida en true. El mtodo Keyboard esttico FocusedElement
devuelve el elemento que tiene el foco de teclado actualmente.
El foco de teclado puede obtenerse usando la tecla de tabulacin hasta llegar a un elemento o haciendo clic con
el mouse en determinados elementos, como TextBox. El foco de teclado tambin puede obtenerse mediante
programacin utilizando el mtodo Focus en la clase Keyboard. Focus intenta asignar el foco de teclado al
elemento especificado. El elemento devuelto por Focus es el elemento que tiene el foco de teclado actualmente.
Para que un elemento obtenga el foco de teclado, las propiedades Focusable y IsVisible deben estar
establecidas en true. Algunas clases, como Panel, tienen la propiedad Focusable establecida en false de forma
predeterminada; por lo tanto, puede que tenga que establecer esta propiedad en true si desea que ese
elemento pueda obtener el foco.
En el ejemplo siguiente se utiliza Focus para establecer el foco de teclado en un control Button. El lugar
recomendado para establecer el foco inicial en una aplicacin es el controlador de eventos Loaded.
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}
Foco lgico
El foco lgico hace referencia al FocusManager.FocusedElement de un mbito de foco. Puede haber varios
elementos con el foco lgico en una aplicacin, pero slo puede haber uno con el foco lgico en un mbito de
foco determinado.
Un mbito de foco es un elemento contenedor que realiza un seguimiento de la propiedad FocusedElement
dentro de su mbito. Cuando el foco salga de un mbito de foco, el elemento que tenga el foco perder el foco
de teclado, pero conservar el foco lgico. Cuando el foco regrese al mbito de foco, el elemento que tenga el
foco obtendr el foco de teclado. Esto permite cambiar el foco de teclado entre varios mbitos de foco, pero
garantiza que el elemento que tiene el foco dentro del mbito de foco siga siendo el elemento que tiene el foco
cuando este regrese.
En Lenguaje de marcado de aplicaciones extensible (XAML) un elemento puede convertirse en un mbito de
foco estableciendo la propiedad asociada FocusManager IsFocusScope en true o mediante cdigo, estableciendo
la propiedad asociada con el mtodo SetIsFocusScope.
En el ejemplo siguiente, un StackPanel se convierte en un mbito de foco estableciendo la propiedad asociada
IsFocusScope.
<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
Las clases de WPF, que son mbitos de foco de forma predeterminada, son Window, Menu, ToolBar y
ContextMenu.
Un elemento que tenga el foco de teclado tambin tendr el foco lgico para el mbito de foco al que
pertenezca; por lo tanto, al establecer el foco en un elemento con el mtodo Focus de la clase Keyboard o las
clases del elemento base, se intentar asignar al elemento el foco de teclado y el foco lgico.

MCT: Luis Dueas

Pag 381 de 445

Manual de Windows Presentation Foundation


Para determinar cul es el elemento que tiene el foco en un mbito de foco, utilice el mtodo
GetFocusedElement. Para cambiar el elemento que tiene el foco para un mbito de foco, utilice el mtodo
SetFocusedElement.
Posicin del mouse
La API de entrada de WPF proporciona informacin til con respecto a los espacios de coordenadas. Por
ejemplo, la coordenada (0,0) es la coordenada superior izquierda, pero, de qu elemento del rbol? Del
elemento de destino de la entrada? Del elemento que asoci al controlador de eventos? O de algn otro? Para
evitar confusiones, la API de entrada de WPF exige que se especifique el marco de referencia al trabajar con
coordenadas obtenidas a travs del mouse. El mtodo GetPosition devuelve la coordenada del puntero del
mouse en relacin con el elemento especificado.
Captura del mouse
Los dispositivos de mouse concretamente presentan una caracterstica modal que se denomina captura del
mouse. La captura del mouse se utiliza para mantener un estado de entrada de transicin cuando se inicia una
operacin de arrastrar y colocar, de forma que no necesariamente se produzcan otras operaciones relacionadas
con la posicin nominal en pantalla del puntero del mouse. Durante el arrastre, el usuario no puede hacer clic
sin que se anule la operacin de arrastrar y colocar, lo que hace que la mayora de las indicaciones de
mouseover sean inapropiadas mientras el origen del arrastre mantiene la captura del mouse. El sistema de
entrada expone las API que pueden determinar el estado de captura del mouse, as como las API que pueden
forzar la captura del mouse a un elemento concreto o borrar el estado de captura del mouse.
Comandos
Los comandos habilitan el control de entrada en un nivel ms semntico que la entrada del dispositivo. Los
comandos son directivas simples, como Cut, Copy, Paste u Open. Los comandos son tiles para centralizar la
lgica de comandos. Se podra obtener acceso al mismo comando desde un control Menu de ToolBar, o a travs
de un mtodo abreviado de teclado. Los comandos tambin proporcionan un mecanismo para deshabilitar los
controles cuando el comando deja de estar disponible.
RoutedCommand es la implementacin WPF de la interfaz ICommand. Cuando se ejecuta RoutedCommand, se
desencadenan los eventos PreviewExecuted y Executed en el destino del comando, que se tunelizan y se
propagan por el rbol de elementos al igual que cualquier otra entrada. Si no se establece ningn destino de
comando, el elemento que tenga el foco de teclado ser el destino del comando. La lgica que ejecuta el
comando est asociada a un elemento CommandBinding. Cuando un evento Executed alcanza un elemento
CommandBinding

para

ese

comando

en

concreto,

se

llama

ExecutedRoutedEventHandler

en

CommandBinding. Este controlador ejecuta la accin del comando.


WPF proporciona una biblioteca de comandos comunes que consta de ApplicationCommands, MediaCommands,
ComponentCommands, NavigationCommands y EditingCommands; o tambin puede definir la suya propia.
En el ejemplo siguiente se muestra cmo configurar un elemento MenuItem para que cuando se haga clic en l
invoque el comando Paste en TextBox, suponiendo que TextBox tenga el foco de teclado.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command

MCT: Luis Dueas

Pag 382 de 445

Manual de Windows Presentation Foundation


pasteMenuItem.Command = ApplicationCommands.Paste;
El sistema de entrada y los elementos base
Los eventos de entrada, como los eventos asociados definidos por las clases Mouse, Keyboard y Stylus, los
desencadena el sistema de entrada y se insertan en una posicin determinada del modelo de objetos basada en
una prueba de posicionamiento del rbol visual en tiempo de ejecucin.
Cada uno de los eventos que Mouse, Keyboard y Stylus definen como un evento asociado tambin vuelven a
exponerlo las clases de elementos base UIElement y ContentElement como un evento enrutado nuevo. Los
eventos enrutados de los elementos base los generan las clases que controlan el evento asociado original y que
reutilizan los datos de los eventos.
Cuando el evento de entrada se asocia a un elemento de origen determinado a travs de su implementacin de
evento de entrada de elemento base, puede enrutarse a lo largo del resto de una ruta de eventos basada en
una combinacin de objetos del rbol lgico y visual, y puede controlarse mediante cdigo de aplicacin. En
general, resulta ms conveniente controlar estos eventos de entrada relacionados con dispositivos utilizando los
eventos enrutados en UIElement y ContentElement, ya que puede utilizarse una sintaxis de controlador de
eventos ms intuitiva, tanto en XAML como en el cdigo. Tambin podra optar por controlar el evento asociado
que inici el proceso, pero tendra que enfrentarse a varios problemas: el evento asociado podra estar marcado
como controlado por el control de clases del elemento base y tendra que utilizar mtodos de descriptor de
acceso en lugar de una sintaxis de eventos autnticos para asociar controladores a los eventos asociados.

3.7.2. Informacin General sobre Comandos


Los comandos constituyen un mecanismo de entrada en Windows Presentation Foundation (WPF) que ofrece la
administracin de acciones del usuario en un nivel ms semntico que la entrada de dispositivo. Los ejemplos
de comandos son las operaciones Copiar, Cortary Pegar que se encuentran en muchas aplicaciones.
Esta informacin general define qu comandos hay en WPF, qu clases forman parte del modelo de comandos,
y cmo utilizar y crear comandos en las aplicaciones.
Qu son los comandos?
El sistema de comandos de WPF est basado en RoutedCommand y RoutedEvent. Un comando no tiene que ser
un objeto RoutedCommand y puede simplemente implementar la interfaz ICommand, lo que se explicar ms
adelante, pero el grueso de esta informacin general se centrar en el modelo RoutedCommand.
Lo que hace los comandos diferentes de un simple controlador de eventos asociado a un botn o a un
temporizador es que los comandos separan la semntica y el autor de una accin de su lgica. Esto permite que
varios orgenes dispares invoquen la misma lgica de comando y permite personalizar la lgica de comando
para diferentes destinos.
Ejemplos de comandos son las operaciones de edicin Copiar, Cortary Pegar, que se encuentran en muchas
aplicaciones. Las semnticas del comando son coherentes entre aplicaciones y clases, pero la lgica de la accin
es especfica del objeto determinado sobre el que se acta. La combinacin de teclas CTRL+X invoca el
comando Cortar en clases de texto, clases de imagen y exploradores web, pero la lgica real para realizar la
operacin de Cortar est definida por el objeto o la aplicacin en el que se est produciendo el corte y no en el
origen que invoc el comando. Un objeto de texto puede cortar el texto seleccionado en el portapapeles,
mientras que un objeto de imagen puede cortar la imagen seleccionada; sin embargo, se puede utilizar el
mismo origen de comando, un objeto KeyGesture o un botn de ToolBar para invocar el comando en ambas
clases.
Ejemplo de comando simple en WPF
La manera ms simple de utilizar un comando en WPF es utilizar un objeto RoutedCommand predefinido de una
de las clases de biblioteca de comandos; utilice un control con compatibilidad nativa para administrar el
comando; y utilice un control con compatibilidad nativa para invocar un comando. El comando Paste es uno de

MCT: Luis Dueas

Pag 383 de 445

Manual de Windows Presentation Foundation


los comandos predefinidos de la clase ApplicationCommands. El control TextBox tiene lgica integrada para
administrar el comando Paste. La clase MenuItem tiene compatibilidad nativa para invocar comandos.
En el ejemplo siguiente se muestra cmo configurar un elemento MenuItem para que, cuando se haga clic en
l, invoque el comando Paste en un objeto TextBox, suponiendo que TextBox tenga el foco de teclado.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
Cuatro conceptos bsicos en los comandos WPF
El modelo de comando enrutado de WPF se puede descomponer en cuatro conceptos bsicos: el comando, el
origen del comando, el destino del comando y el enlace del comando:

El comando es la accin que se va a ejecutar.


El origen del comando es el objeto que invoca el comando.
El destino del comando es el objeto en el que se ejecuta el comando.
El enlace del comando es el objeto que asigna la lgica de comando al comando.

En el ejemplo anterior, el comando Paste es el comando, el objeto MenuItem es el origen del comando, el
objeto TextBox es el destino del comando y en enlace del comando lo proporciona el control TextBox. Hay que
indicar que no siempre sucede que el objeto CommandBinding lo suministre el control que es la clase de
destino del comando. Con frecuencia, el objeto CommandBinding debe ser creado por el desarrollador de la
aplicacin; tambin puede ocurrir que el objeto CommandBinding est asociado a un antecesor del destino del
comando.
Commands
Los comandos de WPF se crean implementando la interfaz ICommand. ICommand expone dos mtodos,
Execute y CanExecute, y un evento, CanExecuteChanged. Execute realiza las acciones que estn asociadas al
comando. CanExecute determina si el comando se puede ejecutar en el destino del comando actual. El evento
CanExecuteChanged se produce si el administrador de comandos que centraliza las operaciones de comandos
detecta un cambio en el origen del comando que podra invalidar un comando que se ha iniciado pero que el
enlace de comando an no ha ejecutado. La implementacin de WPF de ICommand es la clase RoutedCommand
y el centro de inters de esta informacin general.
Los principales orgenes de entrada en WPF son el mouse, el teclado, la entrada manuscrita y los comandos
enrutados. Las entradas ms orientadas a dispositivo utilizan un objeto RoutedEvent para notificar a los objetos
de una pgina de aplicacin que se ha producido un evento de entrada. Un RoutedCommand no es diferente.
Los mtodos Execute y CanExecute de una objeto RoutedCommand no contienen la lgica de aplicacin para el
comando, sino que provocan eventos enrutados que se tunelizan y se propagar a travs del elemento hasta que
encuentran un objeto con CommandBinding. El objeto CommandBinding contiene los controladores para estos
eventos y son los controladores los que realizan el comando.
El mtodo Execute de un objeto RoutedCommand provoca los eventos PreviewExecuted y Executed en el
destino del comando. El mtodo CanExecute de un objeto RoutedCommand provoca los eventos CanExecute y
PreviewCanExecute en el destino del comando. Estos eventos se tunelizan y se propagan a travs del rbol de
elementos hasta que encuentran un objeto que tiene un objeto CommandBinding para ese comando en
particular.

MCT: Luis Dueas

Pag 384 de 445

Manual de Windows Presentation Foundation


WPF

proporciona

un

conjunto

de

comandos

enrutados

comunes

distribuido

entre

varias

clases:

MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands y EditingCommands.


Estas clases constan solamente de los objetos RoutedCommand y no de la lgica de implementacin del
comando. La lgica de implementacin es responsabilidad del objeto en el que se ejecuta el comando.
Orgenes de comando
Un origen de comando es el objeto que invoca el comando. Ejemplos de orgenes de comando son MenuItem,
Button y KeyGesture.
Los orgenes de comando en WPF implementan generalmente la interfaz ICommandSource.
ICommandSource expone tres propiedades: Command, CommandTarget y CommandParameter:

Command es el comando a ejecutar cuando se invoca el origen de comando.


CommandTarget es el objeto en el que se ejecuta el comando. Hay que destacar que en WPF la
propiedad CommandTarget de ICommandSource solamente es aplicable cuando la interfaz ICommand
es un objeto RoutedCommand. Si se establece la propiedad CommandTarget en un objeto
ICommandSource y el comando correspondiente no es de tipo RoutedCommand, se omite el destino
del comando. Si no se establece CommandTarget, el destino del comando ser el elemento que tenga
el foco del teclado.

CommandParameter es un tipo de datos definido por el usuario utilizado para pasar informacin a los
controladores que implementan el comando.

Las clases WPF que implementan ICommandSource son ButtonBase, MenuItem, Hyperlink y InputBinding.
ButtonBase, MenuItemy Hyperlink invocan un comando cuando se hace clic en ellos y InputBinding invoca un
comando cuando se realiza el InputGesture asociado.
En el ejemplo siguientes se muestra cmo usar un objeto MenuItem en un objeto ContextMenu como origen de
comando para el comando Properties.
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Properties" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
StackPanel cmdSourcePanel = new StackPanel();
ContextMenu cmdSourceContextMenu = new ContextMenu();
MenuItem cmdSourceMenuItem = new MenuItem();
// Add ContextMenu to the StackPanel.
cmdSourcePanel.ContextMenu = cmdSourceContextMenu;
cmdSourcePanel.ContextMenu.Items.Add(cmdSourceMenuItem);
// Associate Command with MenuItem.
cmdSourceMenuItem.Command = ApplicationCommands.Properties;
Habitualmente, un origen de comando escuchar el evento CanExecuteChanged. Este evento informa al origen
de comando que es posible que haya cambiado la capacidad del comando para ejecutarse en el destino de
comando actual. El origen de comando puede consultar el estado actual del objeto RoutedCommand utilizando
el mtodo CanExecute. El origen de comando se puede deshabilitar a s mismo si no se puede ejecutar el
comando. Un ejemplo de esto es un objeto MenuItem que se atena cuando un comando no se puede ejecutar.
Un objeto InputGesture se puede utilizar como origen de comando. Dos tipos de movimientos de entrada en
WPF son KeyGesture y MouseGesture. Puede pensar en un objeto KeyGesture como en un mtodo abreviado de
teclado, tal como CTRL+C. Un objeto KeyGesture consta de un objeto Key y un conjunto de ModifierKeys. Un
objeto MouseGesture consta de un objeto MouseAction y un conjunto opcional de ModifierKeys.
Para que un InputGesture acte como un origen de comando, debe estar asociado a un comando. Hay varias
maneras de lograrlo. Una manera es utilizar un objeto InputBinding.
En el ejemplo siguiente se muestra cmo crear un objeto KeyBinding entre un objeto KeyGesture y un objeto
RoutedCommand.

MCT: Luis Dueas

Pag 385 de 445

Manual de Windows Presentation Foundation


<Window.InputBindings>
<KeyBinding Key="B"
Modifiers="Control"
Command="ApplicationCommands.Open" />
</Window.InputBindings>
KeyGesture OpenKeyGesture = new KeyGesture(Key.B,ModifierKeys.Control);
KeyBinding OpenCmdKeybinding = new KeyBinding(ApplicationCommands.Open,OpenKeyGesture);
this.InputBindings.Add(OpenCmdKeybinding);
Otra manera de asociar un objeto InputGesture a un objeto RoutedCommand es agregar el objeto InputGesture
a la coleccin InputGestureCollection del objeto RoutedCommand.
En el ejemplo siguiente se muestra cmo agregar un objeto KeyGesture a la coleccin InputGestureCollection
de un objeto RoutedCommand.
KeyGesture OpenCmdKeyGesture = new KeyGesture(Key.B,
ModifierKeys.Control);
ApplicationCommands.Open.InputGestures.Add(OpenCmdKeyGesture);
CommandBinding
Un objeto CommandBinding asocia un comando con los controladores de eventos que implementan el comando.
La clase CommandBinding contiene una propiedad Command, y eventos PreviewExecuted, Executed,
PreviewCanExecute y CanExecute.
Command es el comando al que se est asociando CommandBinding. Los controladores de eventos asociados a
los eventos PreviewExecuted y Executed implementan la lgica del comando. Los controladores de eventos
asociados a los eventos PreviewCanExecute y CanExecute determinan si el comando puede ejecutarse en el
destino de comando actual.
En el ejemplo siguiente se muestra cmo crear un objeto CommandBinding en el objeto Window raz de una
aplicacin. El comando CommandBinding asocia el comando Open con los controladores Executed y CanExecute
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(ApplicationCommands.Open,
OpenCmdExecuted,OpenCmdCanExecute);
this.CommandBindings.Add(OpenCmdBinding);
A continuacin, se crea el objeto ExecutedRoutedEventHandler y un objeto CanExecuteRoutedEventHandler. El
objeto ExecutedRoutedEventHandler abre un control MessageBox que muestra una cadena que indica que se ha
ejecutado el comando. CanExecuteRoutedEventHandler establece la propiedad CanExecute en true.
Private Sub OpenCmdExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
Dim command, targetobj As String
command = CType(e.Command, RoutedCommand).Name
targetobj = CType(sender, FrameworkElement).Name
MessageBox.Show("The " + command + " command has been invoked on target object " +
targetobj)
End Sub
Private Sub OpenCmdCanExecute(ByVal sender As Object, ByVal e As
CanExecuteRoutedEventArgs)
e.CanExecute = True
End Sub
Un objeto CommandBinding se asocia a un objeto especfico, tal como el objeto Window raz de la aplicacin o
un control. El objeto al que se asocia CommandBinding define el mbito del enlace. Por ejemplo, un objeto
CommandBinding asociado a un antecesor del destino de comando puede ser alcanzado por el evento Executed,
pero un objeto CommandBinding asociado a un descendiente del destino de comando no se puede alcanzar.
sta es una consecuencia directa de la manera en que los objetos RoutedEvent se tuneliza y propagan desde el
objeto que provoca el evento.
En algunas situaciones, el objeto CommandBinding est asociado al propio destino de comando, como ocurre
con la clase TextBox y los comandos Cut, Copy y Paste. Bastante a menudo, sin embargo, es ms cmodo
asociar el objeto CommandBinding a un antecesor del destino de comando, tal como el objeto Window principal
o el objeto Application, sobre todo si el mismo objeto CommandBinding puede utilizarse para varios destinos de
comando. stas son decisiones de diseo que desear considerar cuando cree la infraestructura de comandos.

MCT: Luis Dueas

Pag 386 de 445

Manual de Windows Presentation Foundation


Destino de comando
El destino de comando es el elemento en el que se ejecuta el comando. En lo referente a un objeto
RoutedCommand, el destino de comando es el elemento en el que se inicia el enrutado de CanExecute y
Executed. Como se indic previamente, en WPF, la propiedad CommandTarget de ICommandSource solamente
se aplica cuando ICommand es RoutedCommand. Si se establece la propiedad CommandTarget en un objeto
ICommandSource y el comando correspondiente no es de tipo RoutedCommand, se omite el destino del
comando.
El origen de comando puede establecer explcitamente el destino de comando. Si el destino de comando no est
definido, se utilizar como destino de comando el elemento que tenga el foco de teclado. Una de las ventajas
de utilizar el elemento con el foco de teclado como destino de comando es que permite al desarrollador de
aplicaciones utilizar el mismo origen de comando para invocar un comando en varios destinos, sin tener que
hacer un seguimiento del destino de comando. Por ejemplo, si un objeto MenuItem invoca el comando Pegar en
una aplicacin que tiene un control TextBox y un control PasswordBox, el destino puede ser el objeto TextBox o
PasswordBox segn qu control tenga el foco de teclado.
En el ejemplo siguiente se muestra cmo establecer explcitamente el destino de comando en marcado y en
cdigo subyacente.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=mainTextBox}" />
</Menu>
<TextBox Name="mainTextBox"/>
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
CommandManager
El objeto CommandManager desempea varias funciones relacionadas con comandos. Proporciona un conjunto
de

mtodos

estticos

para agregar

quitar

controladores

de

eventos

PreviewExecuted,

Executed,

PreviewCanExecute y CanExecute de un elemento concreto. Proporciona un medio para registrar objetos


CommandBinding y InputBinding en una clase concreta. El objeto CommandManager tambin proporciona un
medio, a travs del evento RequerySuggested, para notificar a un comando cundo debe provocar el evento
CanExecuteChanged.
El

mtodo

InvalidateRequerySuggested

fuerza

al

objeto

CommandManager

provocar

el

evento

RequerySuggested. Esto es til para condiciones que deban deshabilitar o habilitar un comando pero que no
conozca el objeto CommandManager.
Biblioteca de comandos
WPF proporciona un conjunto de comandos predefinidos. La biblioteca de comandos est compuesta de las
clases

siguientes:

ApplicationCommands,

NavigationCommands,

MediaCommands,

EditingCommands

ComponentCommands. Estas clases proporcionan comandos como Cut, BrowseBack y BrowseForward, Play,
Stop y Pause.
Muchos de estos comandos incluyen un conjunto de enlaces de entrada predeterminados. Por ejemplo, si
especifica que la aplicacin administra el comando de copia, obtendr automticamente el enlace de teclado
"CTRL + C". Tambin obtendr los enlaces para otros dispositivos de entrada, como los movimientos de lpiz de
Tablet PC e informacin de voz.

MCT: Luis Dueas

Pag 387 de 445

Manual de Windows Presentation Foundation


Cuando haga referencia a comandos de las diversas bibliotecas de comandos utilizando XAML, habitualmente
podr omitir el nombre de clase de la clase de biblioteca que exponga la propiedad de comando esttica.
Generalmente, los nombres de comando son inequvocos como cadenas y los tipos propietarios existen para
proporcionar una agrupacin lgica de comandos, pero no son necesarios para la anulacin de ambigedades.
Por ejemplo, puede especificar Command="Cut" en lugar de Command="ApplicationCommands.Cut", ms
detallado. ste es un mecanismo de conveniencia integrado en el procesador WPFXAML para comandos (ms
concretamente, es un comportamiento del convertidor de tipos de ICommand, al que el procesador de
WPFXAML hace referencia en el momento de la carga).
Crear comandos personalizados
Si los comandos de las clases de la biblioteca de comandos no satisfacen sus necesidades, puede crear
comandos propios. Hay dos formas de crear un comando personalizado. La primera es empezar desde la nada e
implementar la interfaz ICommand. La otra manera, el enfoque ms comn consiste en crear un objeto
RoutedCommand o RoutedUICommand.

3.7.3. Informacin General sobre el Foco


Hay dos conceptos principales relacionados con el foco en WPF: el foco de teclado y el foco lgico. El foco de
teclado se refiere al elemento que recibe las acciones del teclado y el foco lgico se refiere al elemento que
tiene el foco dentro de un mbito de foco. Estos conceptos se describen con detalle en esta informacin
general. Entender la diferencia entre estos conceptos es importante para crear aplicaciones complejas que
tienen varias zonas donde se puede obtener el foco.
Las principales clases que participan en administracin del foco son Keyboard, FocusManager y las clases de
elementos base, como UIElement y ContentElement.
La clase Keyboard corresponde principalmente al foco de teclado y la clase FocusManager, al foco lgico,
aunque no se trata de una distincin absoluta. Un elemento que tiene el foco de teclado tambin tiene el foco
lgico, pero un elemento que tiene el foco lgico no tiene necesariamente el de teclado. Esto resulta patente
cuando se usa la clase Keyboard para establecer el elemento que tiene el foco de teclado, ya que tambin
establece el foco lgico en l.
Foco de teclado
El foco de teclado se refiere al elemento que est recibiendo actualmente las acciones del teclado. Slo puede
haber un elemento en todo el escritorio que tenga el foco de teclado. En WPF, el elemento que tenga el foco de
teclado tendr la propiedad IsKeyboardFocused establecida en true. La propiedad FocusedElement esttica de
la clase Keyboard obtiene el elemento que tiene actualmente el foco de teclado.
Para que un elemento obtenga el foco de teclado, las propiedades Focusable y IsVisible de los elementos base
deben estar establecidas en true. Algunas clases, como la clase base Panel, tienen la propiedad Focusable
establecida en false de manera predeterminada; por consiguiente, debe establecer Focusable en true si desea
que un elemento de este tipo pueda obtener el foco de teclado.
El foco de teclado se puede obtener a travs de la interaccin con el usuario con la interfaz de usuario, por
ejemplo, cuando presiona la tecla de tabulacin para desplazarse hasta un elemento o hace clic con el mouse
en algunos elementos. El foco de teclado tambin se puede obtener mediante programacin utilizando el
mtodo Focus de la clase Keyboard. El mtodo Focus intenta proporcionar el foco de teclado al elemento
especificado. El elemento devuelto es aqul que tiene el foco de teclado, y que puede ser un elemento diferente
al solicitado el objeto que tena el foco anterior o el que tiene el nuevo bloquea la solicitud.
En el ejemplo siguiente se utiliza el mtodo Focus para establecer el foco de teclado en un control Button.
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}

MCT: Luis Dueas

Pag 388 de 445

Manual de Windows Presentation Foundation


La propiedad IsKeyboardFocused de las clases de elementos base obtiene un valor que indica si el elemento
tiene el foco de teclado. La propiedad IsKeyboardFocusWithin de las clases de elementos base obtiene un valor
que indica si el elemento o cualquiera de sus elementos secundarios visuales tiene el foco de teclado.
Al establecer el foco inicial cuando se inicia la aplicacin, el elemento que reciba el foco debe estar conectado a
PresentationSource y debe tener las propiedades Focusable y IsVisible establecidas en true. El lugar
recomendado para establecer el foco inicial en una aplicacin es el controlador de eventos Loaded. Tambin se
puede utilizar una devolucin de llamada Dispatcher llamando a Invoke o a BeginInvoke.
Foco lgico
El foco lgico hace referencia al FocusManager.FocusedElement de un mbito de foco. Un mbito de foco es un
elemento que realiza un seguimiento de la propiedad FocusedElement dentro de su mbito. Cuando el foco de
teclado salga de un mbito de foco, el elemento que tenga el foco perder el foco de teclado, pero conservar
el foco lgico. Cuando el foco de teclado regrese al mbito de foco, el elemento que tenga el foco obtendr el
foco de teclado. Esto permite cambiar el foco de teclado entre varios mbitos de foco, pero garantiza que el
elemento que tiene el foco dentro del mbito de foco recupere el foco de teclado cuando este regrese al mbito
de foco.
Puede haber varios elementos con el foco lgico en una aplicacin, pero slo puede haber uno con el foco lgico
en un mbito de foco determinado.
Un elemento que tiene el foco de teclado tambin tiene el foco lgico para el mbito de foco al que pertenece.
Un elemento se puede convertir en un mbito de foco en Lenguaje de marcado de aplicaciones extensible
(XAML) estableciendo la propiedad asociada IsFocusScope de FocusManager en true. En cdigo, un elemento se
puede convertir en un mbito de foco llamando a SetIsFocusScope.
En el ejemplo siguiente, un StackPanel se convierte en un mbito de foco estableciendo la propiedad asociada
IsFocusScope.
<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
GetFocusScope devuelve el mbito de foco del elemento especificado.
Las clases de WPF, que son mbitos de foco de forma predeterminada, son Window, MenuItem, ToolBar y
ContextMenu.
GetFocusedElement obtiene el elemento que tiene el foco dentro del mbito de foco especificado.
SetFocusedElement establece el elemento que tiene el foco en el mbito de foco especificado.
SetFocusedElement se utiliza normalmente para establecer el elemento que tiene el foco inicial.
En el ejemplo siguiente se establece el elemento que tiene el foco en un mbito de foco y se obtiene el
elemento que tiene el foco de un mbito de foco.
// Sets the focused element in focusScope1
// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);
// Gets the focused element for focusScope 1
IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);
Navegacin mediante teclado
La clase KeyboardNavigation es responsable de implementar la navegacin mediante foco de teclado
predeterminada cuando se presiona una de las teclas de navegacin. Las teclas de navegacin son: TAB,
MAYS+TAB, CTRL+TAB, CTRL+MAYS+TAB, y las teclas FLECHA ARRIBA, FLECHA ABAJO, FLECHA
IZQUIERDA y FECHA DERECHA.

MCT: Luis Dueas

Pag 389 de 445

Manual de Windows Presentation Foundation


El comportamiento de navegacin de un contenedor de navegacin se puede cambiar estableciendo las
propiedades asociadas TabNavigation, ControlTabNavigation y DirectionalNavigation de KeyboardNavigation.
Estas propiedades son del tipo KeyboardNavigationMode y sus valores posibles son Continue, Local, Contained,
Cycle, Once y None. El valor predeterminado es Continue, que significa que el elemento no es un contenedor de
navegacin.
En el ejemplo siguiente se crea un control Menu con varios objetos MenuItem. La propiedad asociada
TabNavigation se establece en Cycle en el control Menu. Cuando se cambie el foco mediante la tecla de
tabulacin en Menu, el foco se desplazar desde cada elemento y, cuando se alcance el ltimo elemento,
volver al primero.
<Menu KeyboardNavigation.TabNavigation="Cycle">
<MenuItem Header="Menu Item 1" />
<MenuItem Header="Menu Item 2" />
<MenuItem Header="Menu Item 3" />
<MenuItem Header="Menu Item 4" />
</Menu>
Menu navigationMenu = new Menu();
MenuItem item1 = new MenuItem();
MenuItem item2 = new MenuItem();
MenuItem item3 = new MenuItem();
MenuItem item4 = new MenuItem();
navigationMenu.Items.Add(item1);
navigationMenu.Items.Add(item2);
navigationMenu.Items.Add(item3);
navigationMenu.Items.Add(item4);
KeyboardNavigation.SetTabNavigation(navigationMenu, KeyboardNavigationMode.Cycle);
Navegacin con el foco mediante programacin
Las API adicionales para trabajar con el foco son MoveFocus y PredictFocus.
MoveFocus cambia el foco al elemento siguiente en la aplicacin. Se utiliza TraversalRequest para especificar la
direccin. El objeto FocusNavigationDirection que se pasa a MoveFocus especifica las distintas direcciones en
que se puede mover el foco, como First, Last, Up y Down.
En el ejemplo siguiente se utiliza MoveFocus para cambiar el elemento que tiene el foco.
// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;
// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);
// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
// Change keyboard focus.
if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(request);
}
PredictFocus devuelve el objeto que recibira el foco si este se cambiara. En la actualidad, el mtodo
PredictFocus nicamente admite los valores Up, Down, Left y Right.
Eventos de foco
Los eventos relacionados con el foco de

teclado

son

PreviewGotKeyboardFocus, GotKeyboardFocus,

PreviewLostKeyboardFocus y LostKeyboardFocus. Los eventos se definen como eventos asociados de la clase


Keyboard, pero resulta ms directo tener acceso a ellos como los eventos enrutados equivalentes de las clases
de elementos base.
El evento GotKeyboardFocus se provoca cuando el elemento obtiene el foco de teclado. El evento
LostKeyboardFocus se provoca cuando el elemento pierde el foco de teclado. Si se administra el evento
PreviewGotKeyboardFocus o PreviewLostKeyboardFocusEvent y la propiedad Handled se establece en true, el
foco no cambiar.
En el ejemplo siguiente se asocian los controladores de eventos de GotKeyboardFocus y LostKeyboardFocus a
TextBox.
<Border BorderBrush="Black" BorderThickness="1"
Width="200" Height="100" Margin="5">

MCT: Luis Dueas

Pag 390 de 445

Manual de Windows Presentation Foundation


<StackPanel>
<Label HorizontalAlignment="Center" Content="Type Text In This TextBox" />
<TextBox Width="175"
Height="50"
Margin="5"
TextWrapping="Wrap"
HorizontalAlignment="Center"
VerticalScrollBarVisibility="Auto"
GotKeyboardFocus="TextBoxGotKeyboardFocus"
LostKeyboardFocus="TextBoxLostKeyboardFocus"
KeyDown="SourceTextKeyDown"/>
</StackPanel>
</Border>
Cuando TextBox obtiene el foco de teclado, la propiedad Background de TextBox se cambia a LightBlue.
private void TextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox source = e.Source as TextBox;
if (source != null)
{
// Change the TextBox color when it obtains focus.
source.Background = Brushes.LightBlue;
// Clear the TextBox.
source.Clear();
}
}
Cuando TextBox pierde el foco del teclado, la propiedad Background de TextBox se vuelve a establecer en el
color blanco.
private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox source = e.Source as TextBox;
if (source != null)
{
// Change the TextBox color when it loses focus.
source.Background = Brushes.White;
// Set the hit counter back to zero and updates the display.
this.ResetCounter();
}
}
Los eventos relacionados con el foco lgico son GotFocus y LostFocus. Estos eventos se definen en
FocusManager como eventos asociados, pero FocusManager no expone contenedores de eventos CLR.
UIElement y ContentElement exponen estos eventos de un modo ms conveniente.

3.7.4. Aplicar Estilo a los Controles al Recibir el Foco y FocusVisualStyle


Windows Presentation Foundation (WPF) proporciona dos mecanismos paralelos para cambiar el aspecto visual
de un control cuando recibe el foco de teclado. El primer mecanismo consiste en utilizar los establecedores de
propiedad para propiedades tales como IsKeyboardFocused dentro del estilo o la plantilla que se aplica al
control. El segundo mecanismo consiste en proporcionar un estilo independiente como valor de la propiedad
FocusVisualStyle; este "estilo visual de foco" crea un rbol visual independiente para un adorno que dibuja
encima del control, en lugar de cambiar el rbol visual del mismo u otro elemento de la interfaz de usuario
reemplazndolo. En este tema se describen los escenarios donde es apropiado cada uno de estos mecanismos.
Este tema contiene las secciones siguientes.
Finalidad del estilo visual de foco
La caracterstica de estilo visual de foco proporciona un "modelo de objetos" comn para especificar
informacin visual al usuario basndose en la navegacin mediante el teclado a cualquier elemento de la
interfaz de usuario. Esto es posible sin aplicar una nueva plantilla al control ni conocer la composicin de la
plantilla concreta.
Sin embargo, y precisamente porque la caracterstica de estilo visual de foco funciona sin conocer las plantillas
de control, la informacin visual que se puede mostrar para un control utilizando un estilo visual de foco es
necesariamente limitada. Lo que la caracterstica hace en realidad es superponer a un rbol visual diferente (un
adorno) sobre el rbol visual creado por la representacin de un control a travs de su plantilla. Este rbol
visual independiente se define mediante un estilo que rellena la propiedad FocusVisualStyle.
Comportamiento predeterminado del estilo visual de foco

MCT: Luis Dueas

Pag 391 de 445

Manual de Windows Presentation Foundation


Los estilos visuales de foco slo actan cuando la accin de foco se inicia desde el teclado. Los cambios de foco
provocados por acciones del mouse o mediante programacin deshabilitan el modo de estilos visuales de foco.
Los temas para los controles incluyen un comportamiento de estilo visual de foco predeterminado que pasa a
ser el estilo visual de foco para todos los controles del tema. Este estilo de tema se identifica mediante el valor
de la clave esttica FocusVisualStyleKey. Al declarar su propio estilo visual de foco en el nivel de aplicacin, se
reemplaza este comportamiento de estilo predeterminado de los temas. Como alternativa, si define el tema
completo, entonces deber utilizar esta misma clave para definir el estilo correspondiente al comportamiento
predeterminado para todo el tema.
En los temas, el estilo visual de foco predeterminado suele ser muy simple. A continuacin, se muestra una
aproximacin sin detallar:
<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle StrokeThickness="1"
Stroke="Black"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Cundo utilizar estilos visuales de foco
Conceptualmente, el aspecto de los estilos visuales de foco aplicados a los controles debe ser coherente para
todos los controles. Una manera de asegurar la coherencia es cambiar el estilo visual de foco nicamente si
est creando un tema completo, donde cada control que se defina obtendr exactamente el mismo estilo visual
de foco, o bien una variacin de un estilo que guarde una relacin visual en todos los controles. Como
alternativa, puede utilizar el mismo estilo (o estilos similares) para aplicrselos a todos los elementos que
pueden recibir el foco del teclado de una pgina o una interfaz de usuario.
Los estilos visuales de foco no estn pensados para establecer la propiedad FocusVisualStyle de estilos de
controles individuales que no forman parte de un tema. Esto se debe a que un comportamiento visual
incoherente en los distintos controles puede dar lugar a una experiencia del usuario confusa con respecto al
foco de teclado. Si su intencin es controlar los comportamientos especficos de cada control en cuanto al foco
de teclado que no son coherentes de manera deliberada para todo el tema, un enfoque mucho mejor consiste
en utilizar desencadenadores en estilos para propiedades de estados de entrada individuales, como IsFocused o
IsKeyboardFocused.
Los estilos visuales de foco actan exclusivamente para el foco de teclado. Como a tales, los estilos visuales de
foco son un tipo de caracterstica de accesibilidad. Si desea efectuar cambios en la interfaz de usuario para
cualquier tipo de foco, ya sea mediante el mouse, el teclado o programacin, no debe utilizar los estilos visuales
de foco sino establecedores y desencadenadores de estilos o plantillas que funcionen partiendo del valor de las
propiedades de foco generales, como IsFocused o IsFocusWithin.
Cmo crear un estilo visual de foco
El estilo que se crea para un estilo visual de foco siempre debe tener la propiedad TargetType de Control. El
estilo debe consistir principalmente en un objeto ControlTemplate. No se especifica el tipo de destino de modo
que sea el tipo con que se asigna el estilo visual de foco a FocusVisualStyle.
Dado que el tipo de destino siempre es Control, debe aplicar los estilos mediante propiedades que sean
comunes a todos los controles (propiedades de la clase Control y sus clases base). Debe crear una plantilla que
funcione correctamente como una superposicin a un elemento de la interfaz de usuario y que no ocultare
reas funcionales del control. En general, esto significa que la informacin visual debe aparecer fuera de los
mrgenes del control, o en forma de efectos temporales o discretos que no bloqueen las pruebas de
posicionamiento del control al que se aplica el estilo visual de foco. Las propiedades que puede utilizar en el

MCT: Luis Dueas

Pag 392 de 445

Manual de Windows Presentation Foundation


enlace de plantillas que resultan tiles para determinar las dimensiones y la posicin de la plantilla de
superposicin incluyen: ActualHeight, ActualWidth, Margin y Padding.
Alternativas al uso de un estilo visual de foco
En aquellas situaciones en que no sea apropiado utilizar un estilo visual de foco, ya sea porque el estilo se
aplica a controles individuales o porque se desea un mayor control sobre la plantilla de control, existen muchas
otras propiedades y tcnicas accesibles capaces de crear comportamiento visual en respuesta a los cambios de
foco.
Los desencadenadores, establecedores y establecedores de eventos se describen con detalle en Aplicar estilos y
plantillas.
IsKeyboardFocused
Si tiene particular inters en el foco de teclado, puede utilizar la propiedad de dependencia IsKeyboardFocused
para un Trigger de propiedad. Un desencadenador de propiedad de un estilo o plantilla constituye una tcnica
ms adecuada para definir el comportamiento de foco de teclado muy especfico de un control nico y que no
coincida visualmente con el comportamiento de foco de teclado de los dems controles.
Otra propiedad de dependencia similar es IsKeyboardFocusWithin, que podra resultar adecuada si desea indicar
visualmente que el foco de teclado se encuentra en algn punto de una composicin de controles o dentro del
rea funcional del control. Por ejemplo, puede colocar un desencadenador de IsKeyboardFocusWithin de tal
forma que un panel que agrupe varios controles aparezca distinto, aunque el foco de teclado se encuentre, en
concreto, en uno de los elementos individuales de ese panel.
Tambin puede utilizar los eventos GotKeyboardFocus y LostKeyboardFocus (as como sus equivalentes de vista
previa). Puede utilizar estos eventos como base para un objeto EventSetter o escribir controladores para los
eventos en el cdigo subyacente.
Otras propiedades de foco
Si desea que todas las posibles causas del cambio de foco generen un comportamiento visual, debe basar un
establecedor o desencadenador en la propiedad de dependencia IsFocused o, si lo prefiere, en los eventos
GotFocus o LostFocus utilizados para un EventSetter.

3.7.5. Temas Cmo sobre Acciones del Usuario y Comandos


En los temas de esta seccin se describe cmo usar las acciones del usuario y la infraestructura de comandos
en Windows Presentation Foundation (WPF).

3.7.5.1. Cmo: Habilitar un Comando


En el siguiente ejemplo se muestra cmo utilizar comandos en Windows Presentation Foundation (WPF). En el
ejemplo se muestra cmo asociar un comando RoutedCommand a un control Button, crear un objeto
CommandBinding y crear los controladores de eventos que implementan RoutedCommand.
Ejemplo
En la primera seccin de cdigo se crea la interfaz de usuario (UI), que est compuesta de un control Button y
un control StackPanel, y se crea tambin un objeto CommandBinding que asocia los controladores de comando
a un comando RoutedCommand.
La propiedad Command de Button se asocia al comando Close.
El objeto CommandBinding se agrega al objeto CommandBindingCollection del objeto Window raz. Los
controladores de eventos Executed y CanExecute se asocian a este enlace y al comando Close.

MCT: Luis Dueas

Pag 393 de 445

Manual de Windows Presentation Foundation


Sin CommandBinding no hay ninguna lgica de comando, nicamente un mecanismo para invocar el comando.
Cuando se hace clic en Button, se provoca el evento PreviewExecuted asociado al comando RoutedEvent en el
destino del comando, seguido por el evento Executed asociado al comando RoutedEvent. Estos eventos
recorren el rbol de elementos en busca de un enlace CommandBinding para ese comando concreto. Cabe
destacar que, debido a que RoutedEvent tuneliza y traspasa el rbol de elementos, se deben extremar las
precauciones al elegir el lugar donde se coloca CommandBinding. Si CommandBinding est en un nodo
relacionado con el destino del comando o en otro nodo que no est en la ruta de RoutedEvent, no se tendr
acceso a CommandBinding.
<Window x:Class="WCSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CloseCommand"
Name="RootWindow">
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close"
Executed="CloseCommandHandler"
CanExecute="CanExecuteHandler"/>
</Window.CommandBindings>
<StackPanel Name="MainStackPanel">
<Button Command="ApplicationCommands.Close"
Content="Close File" />
</StackPanel>
</Window>
// Create ui elements.
StackPanel CloseCmdStackPanel = new StackPanel();
Button CloseCmdButton = new Button();
CloseCmdStackPanel.Children.Add(CloseCmdButton);
// Set Button's properties.
CloseCmdButton.Content = "Close File";
CloseCmdButton.Command = ApplicationCommands.Close;
// Create the CommandBinding.
CommandBinding CloseCommandBinding = new CommandBinding(
ApplicationCommands.Close, CloseCommandHandler, CanExecuteHandler);
// Add the CommandBinding to the root Window.
RootWindow.CommandBindings.Add(CloseCommandBinding);
En la seccin de cdigo siguiente se implementan los controladores de eventos Executed y CanExecute.
El controlador Executed llama a un mtodo para cerrar el archivo abierto. El controlador CanExecute llama a un
mtodo para determinar si un archivo est abierto. Si hay un archivo abierto, la propiedad CanExecute se
establece en true; de lo contrario, se establece en false.
// Executed event handler.
private void CloseCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
// Calls a method to close the file and release resources.
CloseFile();
}
// CanExecute event handler.
private void CanExecuteHandler(object sender, CanExecuteRoutedEventArgs e)
{
// Call a method to determine if there is a file open.
// If there is a file open, then set CanExecute to true.
if (IsFileOpened())
{
e.CanExecute = true;
}
// if there is not a file open, then set CanExecute to false.
else
{
e.CanExecute = false;
}
}

3.7.5.2. Cmo: Cambiar el Tipo de Cursor


En este ejemplo se muestra cmo cambiar el objeto Cursor del puntero del mouse para un elemento concreto y
para la aplicacin.
Este ejemplo consta de un archivo Lenguaje de marcado de aplicaciones extensible (XAML) y de un archivo de
cdigo subyacente.
Ejemplo

MCT: Luis Dueas

Pag 394 de 445

Manual de Windows Presentation Foundation


Se crea la interfaz de usuario que consiste en un control ComboBox donde seleccionar el objeto Cursor
deseado, un par de objetos RadioButton para determinar si el cambio del cursor se aplica a un solo elemento o
a la aplicacin completa, y un objeto Border que es el elemento al que se aplica el nuevo cursor.
<StackPanel>
<Border Width="300">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<StackPanel Margin="10">
<Label HorizontalAlignment="Left">Cursor Type</Label>
<ComboBox Width="100"
SelectionChanged="CursorTypeChanged"
HorizontalAlignment="Left"
Name="CursorSelector">
<ComboBoxItem Content="AppStarting" />
<ComboBoxItem Content="ArrowCD" />
<ComboBoxItem Content="Arrow" />
<ComboBoxItem Content="Cross" />
<ComboBoxItem Content="HandCursor" />
<ComboBoxItem Content="Help" />
<ComboBoxItem Content="IBeam" />
<ComboBoxItem Content="No" />
<ComboBoxItem Content="None" />
<ComboBoxItem Content="Pen" />
<ComboBoxItem Content="ScrollSE" />
<ComboBoxItem Content="ScrollWE" />
<ComboBoxItem Content="SizeAll" />
<ComboBoxItem Content="SizeNESW" />
<ComboBoxItem Content="SizeNS" />
<ComboBoxItem Content="SizeNWSE" />
<ComboBoxItem Content="SizeWE" />
<ComboBoxItem Content="UpArrow" />
<ComboBoxItem Content="WaitCursor" />
<ComboBoxItem Content="Custom" />
</ComboBox>
</StackPanel>
<!-- The user can select different cursor types using this ComboBox -->
<StackPanel Margin="10">
<Label HorizontalAlignment="Left">Scope of Cursor</Label>
<StackPanel>
<RadioButton Name="rbScopeElement" IsChecked="True"
Checked="CursorScopeSelected">Display Area Only</RadioButton>
<RadioButton Name="rbScopeApplication"
Checked="CursorScopeSelected">Entire Appliation</RadioButton>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
<!-- When the mouse pointer is over this Border -->
<!-- the selected cursor type is shown -->
<Border Name="DisplayArea" Height="250" Width="400"
Margin="20" Background="AliceBlue">
<Label HorizontalAlignment="Center">
Move Mouse Pointer Over This Area
</Label>
</Border>
</StackPanel>
El cdigo subyacente siguiente crea un controlador de eventos SelectionChanged al que se llama cuando se
cambia el tipo de cursor en el control ComboBox. Una instruccin switch aplica un filtro al nombre del cursor y
establece la propiedad Cursor del objeto Border, denominado DisplayArea.
Si el cambio del cursor se establece en "Entire Application", la propiedad OverrideCursor se establece en la
propiedad Cursor del control Border. Esto obliga al cursor a cambiar para toda la aplicacin.
' When the Radiobox changes, a new cursor type is set
Private Sub CursorTypeChanged(ByVal sender As Object, ByVal e As
SelectionChangedEventArgs)
Dim item As String = CType(e.Source, ComboBox).SelectedItem.Content.ToString()
Select Case item
Case "AppStarting"
DisplayArea.Cursor = Cursors.AppStarting
Case "ArrowCD"
DisplayArea.Cursor = Cursors.ArrowCD
Case "Arrow"
DisplayArea.Cursor = Cursors.Arrow
Case "Cross"
DisplayArea.Cursor = Cursors.Cross
Case "HandCursor"
DisplayArea.Cursor = Cursors.Hand
Case "Help"
DisplayArea.Cursor = Cursors.Help
Case "IBeam"
DisplayArea.Cursor = Cursors.IBeam

MCT: Luis Dueas

Pag 395 de 445

Manual de Windows Presentation Foundation


Case "No"
DisplayArea.Cursor = Cursors.No
Case "None"
DisplayArea.Cursor = Cursors.None
Case "Pen"
DisplayArea.Cursor = Cursors.Pen
Case "ScrollSE"
DisplayArea.Cursor = Cursors.ScrollSE
Case "ScrollWE"
DisplayArea.Cursor = Cursors.ScrollWE
Case "SizeAll"
DisplayArea.Cursor = Cursors.SizeAll
Case "SizeNESW"
DisplayArea.Cursor = Cursors.SizeNESW
Case "SizeNS"
DisplayArea.Cursor = Cursors.SizeNS
Case "SizeNWSE"
DisplayArea.Cursor = Cursors.SizeNWSE
Case "SizeWE"
DisplayArea.Cursor = Cursors.SizeWE
Case "UpArrow"
DisplayArea.Cursor = Cursors.UpArrow
Case "WaitCursor"
DisplayArea.Cursor = Cursors.Wait
Case "Custom"
DisplayArea.Cursor = CustomCursor
End Select
' if the cursor scope is set to the entire application
' use OverrideCursor to force the cursor for all elements
If (cursorScopeElementOnly = False) Then
Mouse.OverrideCursor = DisplayArea.Cursor
End If
End Sub

3.7.5.3. Cmo: Detectar el Estado de un Botn del Mouse


En este ejemplo se muestra cmo utilizar eventos de botn del mouse y la propiedad MouseButtonState para
determinar si un botn del mouse concreto est presionado o no.
Este ejemplo consta de un archivo Lenguaje de marcado de aplicaciones extensible (XAML) y de un archivo de
cdigo subyacente.
Ejemplo
En el cdigo siguiente se crea la interfaz de usuario, que est compuesta de un control TextBlock dentro de un
control StackPanel, y se asocian los controladores de eventos para los eventos MouseLeftButtonDown y
MouseLeftButtonUp.
<StackPanel Height="100" Width="100"
MouseLeftButtonDown="HandleButtonDown"
MouseLeftButtonUp="HandleButtonDown"
Background="#d08080"
DockPanel.Dock="Left">
<TextBlock>Click on Me</TextBlock>
</StackPanel>
En el siguiente cdigo subyacente se crean los

controladores

de

eventos

MouseLeftButtonUp

MouseLeftButtonDown. Cuando se presiona el botn primario, se aumentan las dimensiones de TextBlock.


Cuando se suelta el botn primario, las dimensiones de TextBlock se restauran a su alto y ancho originales.
Partial Public Class Window1
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
Private Sub HandleButtonDown(ByVal sender As Object, ByVal e As
MouseButtonEventArgs)
' Casting the source to a StackPanel
Dim sourceStackPanel As StackPanel = CType(e.Source, StackPanel)
' If the button is pressed then make dimensions larger.
If e.ButtonState = MouseButtonState.Pressed Then
sourceStackPanel.Width = 200
sourceStackPanel.Height = 200
' If the button is released then make dimensions smaller.
ElseIf e.ButtonState = MouseButtonState.Released Then
sourceStackPanel.Width = 100
sourceStackPanel.Height = 100
End If
End Sub
End Class

MCT: Luis Dueas

Pag 396 de 445

Manual de Windows Presentation Foundation

3.7.5.4. Cmo: Cambiar el Color de un Elemento mediante Eventos de Foco


En este ejemplo se muestra cmo cambiar el color de un elemento cuando recibe y pierde el foco utilizando los
eventos GotFocus y LostFocus.
Este ejemplo consta de un archivo Lenguaje de marcado de aplicaciones extensible (XAML) y un archivo de
cdigo subyacente.
Ejemplo
En el XAML siguiente se crea la interfaz de usuario, que est compuesta de dos objetos Button, y se asocian los
controladores de eventos para los eventos GotFocus y LostFocus a los objetos Button.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Height" Value="20"/>
<Setter Property="Width" Value="250"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
</Style>
</StackPanel.Resources>
<Button
GotFocus="OnGotFocusHandler"
LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyboard Focus</Button>
<Button
GotFocus="OnGotFocusHandler"
LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyborad Focus</Button>
</StackPanel>
En el siguiente cdigo subyacente se crean los controladores de eventos GotFocus y LostFocus. Cuando Button
recibe el foco del teclado, la propiedad Background de Button se cambia al color rojo. Cuando Button pierde el
foco del teclado, la propiedad Background de Button se vuelve a establecer en el color blanco.
Partial Public Class Window1
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
'raised when Button gains focus. Changes the color of the Button to red.
Private Sub OnGotFocusHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim tb As Button = CType(e.Source, Button)
tb.Background = Brushes.Red
End Sub
'raised when Button loses focus. Changes the color back to white.
Private Sub OnLostFocusHandler(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim tb As Button = CType(e.Source, Button)
tb.Background = Brushes.White
End Sub
End Class

3.7.5.5. Cmo: Aplicar FocusVisualStyle a un Control


En este ejemplo se muestra cmo crear un estilo visual de foco en los recursos y aplicar el estilo a un control,
utilizando la propiedad FocusVisualStyle.
Ejemplo
En el ejemplo siguiente se define un estilo que crea una composicin de controles adicional que se aplica
nicamente cuando ese control recibe el foco del teclado en la interfaz de usuario (UI). Para ello, se define un
estilo con ControlTemplate, y luego se hace referencia a ese estilo como un recurso al establecer la propiedad
FocusVisualStyle.
Un rectngulo externo que parece un borde se coloca fuera del rea rectangular. A menos que se modifique de
otro modo, la operacin de ajuste de tamao del estilo utiliza las propiedades ActualHeight y ActualWidth del
control rectangular donde se aplica el estilo visual de foco. En este ejemplo se establecen valores negativos
para Margin, a fin de que el borde parezca ligeramente fuera del control que tiene el foco.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="MyFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>

MCT: Luis Dueas

Pag 397 de 445

Manual de Windows Presentation Foundation


<Rectangle Margin="-2" StrokeThickness="1" Stroke="Red" StrokeDashArray="1 2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel Background="Ivory" Orientation="Horizontal">
<Canvas Width="10"/>
<Button Width="100" Height="30" FocusVisualStyle="{DynamicResource MyFocusVisual}">
Focus Here</Button>
<Canvas Width="100"/>
<Button Width="100" Height="30" FocusVisualStyle="{DynamicResource MyFocusVisual}">
Focus Here</Button>
</StackPanel>
</Page>
FocusVisualStyle se aplica adems de cualquier estilo de plantilla de control que proceda de un estilo explcito o
de un estilo de tema; sigue siendo posible crear el estilo primario de un control mediante ControlTemplate y
estableciendo ese estilo en la propiedad Style.
Los estilos visuales de foco deben utilizarse de manera coherente en un tema o una interfaz de usuario, en
lugar de utilizar uno diferente para cada elemento que pueda recibir el foco.

3.7.5.6. Cmo: Detectar cuando se Presiona la Tecla Enter


En este ejemplo se muestra cmo detectar cundo se presiona la tecla Enter en el teclado.
Este ejemplo consta de un archivo Lenguaje de marcado de aplicaciones extensible (XAML) y un archivo de
cdigo subyacente.
Ejemplo
Cuando el usuario presiona la tecla Enter en el control TextBox, los datos que se han especificado en el cuadro
de texto aparecen en otra rea de la interfaz de usuario (UI).
El XAML siguiente crea la interfaz de usuario, que est compuesta de un control StackPanel, TextBlock y
TextBox.
<StackPanel>
<TextBlock Width="300" Height="20">
Type some text into the TextBox and press the Enter key.
</TextBlock>
<TextBox Width="300" Height="30" Name="textBox1"
KeyDown="OnKeyDownHandler"/>
<TextBlock Width="300" Height="100" Name="textBlock1"/>
</StackPanel>
En el siguiente cdigo subyacente se crea el controlador de eventos KeyDown. Si la tecla que se presiona es
Enter, se muestra un mensaje en el control TextBlock.
Private Sub OnKeyDownHandler(ByVal sender As Object, ByVal e As KeyEventArgs)
If (e.Key = Key.Return) Then
textBlock1.Text = "You Entered: " + textBox1.Text
End If
End Sub

3.7.5.7. Cmo: Crear un Efecto de Activacin mediante Eventos


En este ejemplo se muestra cmo cambiar el color de un elemento cuando el puntero del mouse entra y sale
del rea ocupada por el elemento.
Este ejemplo consta de un archivo Lenguaje de marcado de aplicaciones extensible (XAML) y un archivo de
cdigo subyacente.
Nota:
En este ejemplo se muestra cmo utilizar los eventos, pero la manera recomendada de lograr este mismo
efecto es utilizar Trigger en un estilo.
Ejemplo
En el XAML siguiente se crea la interfaz de usuario, que est compuesta de un objeto Border alrededor de un
objeto TextBlock, y se asocian los controladores de eventos MouseEnter y MouseLeave a Border.

MCT: Luis Dueas

Pag 398 de 445

Manual de Windows Presentation Foundation


<StackPanel>
<Border MouseEnter="OnMouseEnterHandler"
MouseLeave="OnMouseLeaveHandler"
Name="border1" Margin="10"
BorderThickness="1"
BorderBrush="Black"
VerticalAlignment="Center"
Width="300" Height="100">
<Label Margin="10" FontSize="14"
HorizontalAlignment="Center">Move Cursor Over Me</Label>
</Border>
</StackPanel>
En el siguiente cdigo subyacente se crean los controladores de eventos MouseEnter y MouseLeave. Cuando el
puntero del mouse entra en el objeto Border, el fondo de Border se cambia al color rojo. Cuando el puntero del
mouse sale del objeto Border, el fondo de Border se vuelve a establecer en el color blanco.
Partial Public Class Window1
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
' raised when mouse cursor enters the are occupied by the element
Private Sub OnMouseEnterHandler(ByVal sender As Object, ByVal e As MouseEventArgs)
border1.Background = Brushes.Red
End Sub
' raised when mouse cursor leaves the are occupied by the element
Private Sub OnMouseLeaveHandler(ByVal sender As Object, ByVal e As MouseEventArgs)
border1.Background = Brushes.White
End Sub
End Class

3.7.5.8. Cmo: Crear un Objeto que Siga el Puntero del Mouse


En este ejemplo se muestra cmo cambiar las dimensiones de un objeto cuando el puntero del mouse se
mueve por la pantalla.
El ejemplo incluye un archivo Lenguaje de marcado de aplicaciones extensible (XAML) que crea la interfaz de
usuario (UI) y un archivo de cdigo subyacente que crea el controlador de eventos.
Ejemplo
En el XAML siguiente se crea la interfaz de usuario, que est compuesta de un elemento Ellipse dentro de un
control StackPanel, y se asocia el controlador de eventos para el evento MouseMove.
<Window x:Class="WCSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="mouseMoveWithPointer"
Height="400"
Width="500">
<Canvas MouseMove="MouseMoveHandler"
Background="LemonChiffon">
<Ellipse Name="ellipse" Fill="LightBlue"
Width="100" Height="100"/>
</Canvas>
</Window>
En el siguiente cdigo subyacente se crea el controlador de eventos MouseMove. Cuando el puntero del mouse
se mueve, el alto y el ancho de Ellipse aumentan y disminuyen.
' raised when the mouse pointer moves.
' Expands the dimensions of an Ellipse when the mouse moves.
Private Sub OnMouseMoveHandler(ByVal sender As Object, ByVal e As MouseEventArgs)
'Get the x and y coordinates of the mouse pointer.
Dim position As System.Windows.Point
position = e.GetPosition(Me)
Dim pX As Double
pX = position.X
Dim pY As Double
pY = position.Y
'Set the Height and Width of the Ellipse to the mouse coordinates.
ellipse1.Height = pY
ellipse1.Width = pX
End Sub

3.7.5.9. Cmo: Agregar un Comando a un Elemento de Men


En el ejemplo siguiente se muestra cmo configurar un control MenuItem como origen de comando para el
comando Paste.

MCT: Luis Dueas

Pag 399 de 445

Manual de Windows Presentation Foundation


Ejemplo
Los controles MenuItem, como Button y Hyperlink, implementan ICommandSource. ICommandSource expone
entre otras las propiedades Command y CommandTarget. Command es el comando que se invocar, y
CommandTarget es el elemento donde se iniciar el enrutamiento de eventos cuando se invoque el comando. Si
no se define CommandTarget, el elemento que tenga el foco de teclado se establecer como destino.
La clase que implementa ICommandSource define el significado del hecho de invocar el comando. MenuItem y
Button definen el evento Click como manera de invocar el comando. Si el comando no se puede ejecutar en la
propiedad CommandTarget determinada, MenuItem se deshabilita. Cuando el comando se puede ejecutar en la
propiedad CommandTarget, MenuItem se habilita.
En este ejemplo, se crea un control MenuItem en el objeto Window principal de la aplicacin. La propiedad
Command se establece en el comando Paste. CommandTarget no se define para MenuItem; por consiguiente,
el destino del comando ser el elemento que tenga el foco de teclado.
Puesto que la clase TextBox proporciona la lgica para el comando Paste, no se requiere un objeto
CommandBinding. Si el control que administra el comando no proporciona la lgica para la ejecucin del
comando,

se

necesita

CommandBinding

para

enlazar

ExecutedRoutedEventHandler

CanExecuteRoutedEventHandler a RoutedCommand.
<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MenuItemCommandTask">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Command="ApplicationCommands.Paste" Width="75" />
</Menu>
<TextBox BorderBrush="Black" BorderThickness="2" Margin="25"
TextWrapping="Wrap">
The MenuItem will not be enabled until
this TextBox gets keyboard focus
</TextBox>
</DockPanel>
</Window>

3.7.5.10. Cmo: Crear un Comando RoutedCommand


En este ejemplo se muestra cmo crear un comando RoutedCommand personalizado y cmo implementarlo
creando un controlador ExecutedRoutedEventHandler y un controlador CanExecuteRoutedEventHandler y
asocindolos a un enlace CommandBinding.
Ejemplo
El primer paso para crear RoutedCommand es definir el comando y crear una instancia de l.
public static RoutedCommand CustomRoutedCommand = new RoutedCommand();
Para utilizar el comando en una aplicacin, es preciso crear los controladores de eventos que definen qu hace
el comando
private void ExecutedCustomCommand(object sender,ExecutedRoutedEventArgs e)
{
MessageBox.Show("Custom Command Executed");
}
// CanExecuteRoutedEventHandler that only returns true if
// the source is a control.
private void CanExecuteCustomCommand(object sender, CanExecuteRoutedEventArgs e)
{
Control target = e.Source as Control;
if(target != null)
{
e.CanExecute = true;
}
else
{
e.CanExecute = false;
}
}

MCT: Luis Dueas

Pag 400 de 445

Manual de Windows Presentation Foundation


Luego, se crea un enlace CommandBinding que asocia el comando a los controladores de eventos.
CommandBinding se crea para un objeto concreto. Este objeto define el mbito de CommandBinding en el rbol
de elementos
<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:custom="clr-namespace:SDKSamples"
Height="600" Width="800">
<Window.CommandBindings>
<CommandBinding Command="{x:Static custom:Window1.CustomRoutedCommand}"
Executed="ExecutedCustomCommand"
CanExecute="CanExecuteCustomCommand" />
</Window.CommandBindings>
CommandBinding customCommandBinding = new CommandBinding(
CustomRoutedCommand, ExecutedCustomCommand, CanExecuteCustomCommand);
// attach CommandBinding to root window
this.CommandBindings.Add(customCommandBinding);
El paso final consiste en invocar el comando. Una manera de invocar un comando es asociarlo a una interfaz
ICommandSource, como un Button.
<StackPanel>
<Button Command="{x:Static custom:Window1.CustomRoutedCommand}"
Content="CustomRoutedCommand"/>
</StackPanel>
// create the ui
StackPanel CustomCommandStackPanel = new StackPanel();
Button CustomCommandButton = new Button();
CustomCommandStackPanel.Children.Add(CustomCommandButton);
CustomCommandButton.Command = CustomRoutedCommand;
Cuando se hace clic en el objeto Button, se llama al mtodo Execute del comando RoutedCommand
personalizado. RoutedCommand provoca los eventos enrutados PreviewExecuted y Executed. Estos eventos
recorren el rbol de elementos en busca de un enlace CommandBinding para ese comando concreto. Si se
encuentra un enlace CommandBinding, se llama al controlador ExecutedRoutedEventHandler asociado a
CommandBinding.

3.7.5.11. Cmo: Implementar ICommandSource


En este ejemplo se muestra cmo crear un origen de comando implementando ICommandSource. Un origen de
comando es un objeto que sabe cmo invocar un comando. La interfaz ICommandSource expone tres
miembros: Command, CommandParameter y CommandTarget. Command es el comando que se invocar.
CommandParameter es un tipo de datos definido por el usuario que se pasa desde el origen de comando al
mtodo que administra el comando. CommandTarget es el objeto en que se ejecuta el comando.
En este ejemplo, se crea una clase que crea una subclase del control Slider e implementa ICommandSource.
Ejemplo
WPF proporciona varias clases que implementan ICommandSource, como Button, MenuItem y ListBoxItem. El
origen de comando define cmo invoca un comando. Los objetos Button y MenuItem invocan un comando
cuando se hace clic en ellos. Un objeto ListBoxItem invoca un comando cuando se hacer doble clic en l. Estas
clases slo se convierten en el origen de un comando cuando se establece su propiedad Command.
En este ejemplo se invoca al comando cuando se mueve el control deslizante, o dicho con ms exactitud,
cuando se cambia la propiedad Value.
A continuacin, se muestra la definicin de clase.
public class CommandSlider : Slider, ICommandSource
{
public CommandSlider() : base()
{
}
El paso siguiente es implementar los miembros de ICommandSource. En este ejemplo, las propiedades se
implementan como objetos DependencyProperty. Esto permite que las propiedades utilicen el enlace de datos.
Aqu se muestra nicamente la propiedad Command.

MCT: Luis Dueas

Pag 401 de 445

Manual de Windows Presentation Foundation


// Make Command a dependency property so it can use databinding.
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command",typeof(ICommand),typeof(CommandSlider),
new PropertyMetadata((ICommand)null,new PropertyChangedCallback(CommandChanged)));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
Lo siguiente es la devolucin de llamada de cambio de DependencyProperty.
// Command dependency property change callback.
private static void CommandChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
CommandSlider cs = (CommandSlider)d;
cs.HookUpCommand((ICommand)e.OldValue,(ICommand)e.NewValue);
}
El paso siguiente consiste en agregar y quitar el comando que est asociado al origen de comando. No se puede
sobrescribir simplemente la propiedad Command cuando se agrega un nuevo comando, porque antes se deben
quitar los controladores de eventos asociados al comando anterior, si lo hay.
// Add a new command to the Command Property.
private void HookUpCommand(ICommand oldCommand, ICommand newCommand)
{
// If oldCommand is not null, then we need to remove the handlers.
if (oldCommand != null)
{
RemoveCommand(oldCommand, newCommand);
}
AddCommand(oldCommand, newCommand);
}
// Remove an old command from the Command Property.
private void RemoveCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = CanExecuteChanged;
oldCommand.CanExecuteChanged -= handler;
}
// Add the command.
private void AddCommand(ICommand oldCommand, ICommand newCommand)
{
EventHandler handler = new EventHandler(CanExecuteChanged);
canExecuteChangedHandler = handler;
if (newCommand != null)
{
newCommand.CanExecuteChanged += canExecuteChangedHandler;
}
}
El ltimo paso consiste en crear la lgica para el controlador de CanExecuteChanged y el mtodo Execute.
El evento CanExecuteChanged notifica al origen de comando que es posible que haya cambiado la capacidad del
comando para ejecutarse en el destino de comando actual. Cuando un origen de comando recibe este evento,
normalmente llama al mtodo CanExecute del comando. Si el comando no se puede ejecutar en el destino de
comando actual, el origen de comando se suele deshabilitar. Si el comando s se puede ejecutar en el destino
de comando actual, el origen de comando se suele habilitar.
private void CanExecuteChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
RoutedCommand command = this.Command as RoutedCommand;
// If a RoutedCommand.
if (command != null)
{
if (command.CanExecute(CommandParameter, CommandTarget))
{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}
// If a not RoutedCommand.
else
{
if (Command.CanExecute(CommandParameter))

MCT: Luis Dueas

Pag 402 de 445

Manual de Windows Presentation Foundation


{
this.IsEnabled = true;
}
else
{
this.IsEnabled = false;
}
}

}
El ltimo paso es el mtodo Execute. Si el comando es RoutedCommand, se llama al mtodo Execute de
RoutedCommand; de lo contrario, se llama al mtodo ICommand Execute.
// If Command is defined, moving the slider will invoke the command;
// Otherwise, the slider will behave normally.
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
if (this.Command != null)
{
RoutedCommand command = Command as RoutedCommand;
if (command != null)
{
command.Execute(CommandParameter, CommandTarget);
}
else
{
((ICommand)Command).Execute(CommandParameter);
}
}
}

3.7.5.12. Cmo: Enlazar un Comando a un Control sin la Compatibilidad de


Comandos
En el ejemplo siguiente se muestra cmo enlazar RoutedCommand a un objeto Control que no tiene
compatibilidad integrada para el comando.
Ejemplo
Windows Presentation Foundation (WPF) proporciona una biblioteca de comandos comunes que los
programadores de aplicaciones suelen utilizar. Las clases que componen la biblioteca de comandos son:
ApplicationCommands, ComponentCommands, NavigationCommands, MediaCommands y EditingCommands.
Los objetos RoutedCommand estticos que componen estas clases no proporcionan la lgica de los comandos.
La lgica del comando se asocia al comando mediante CommandBinding. Muchos controles de WPF tienen
compatibilidad integrada con algunos de los comandos de la biblioteca de comandos. Por ejemplo, TextBox
admite muchos de los comandos de edicin de aplicacin, tales como Paste, Copy, Cut, Redo y Undo. El
programador de aplicaciones no tiene que hacer nada especial para que estos comandos funcionen con estos
controles. Si el control TextBox es el destino del comando al ejecutar ste ltimo, administrar el comando
mediante el objeto CommandBinding integrado en el control.
A continuacin se muestra cmo utilizar un control Button como origen de comando del comando Open. Se crea
un objeto CommandBinding que asocia el controlador CanExecuteRoutedEventHandler especificado, y
CanExecuteRoutedEventHandler a RoutedCommand.
Primero, se crea el origen del comando. Button se utiliza como origen del comando.
<Button Command="ApplicationCommands.Open" Name="MyButton" Height="50" Width="200">
Open (KeyBindings: Ctrl+R, Ctrl+0)
</Button>
// Button used to invoke the command
Button CommandButton = new Button();
CommandButton.Command = ApplicationCommands.Open;
CommandButton.Content = "Open (KeyBindings: Ctrl-R, Ctrl-0)";
MainStackPanel.Children.Add(CommandButton);
A continuacin, se crean ExecutedRoutedEventHandler y CanExecuteRoutedEventHandler. El controlador
ExecutedRoutedEventHandler simple abre un MessageBox para indicar que se ejecut el comando.
CanExecuteRoutedEventHandler establece la propiedad CanExecute en true. Normalmente, el controlador de

MCT: Luis Dueas

Pag 403 de 445

Manual de Windows Presentation Foundation


posibilidad de ejecucin realizara comprobaciones ms robustas para ver si el comando se pudo ejecutar en el
destino de comando actual.
Private Sub OpenCmdExecuted(ByVal sender As Object, ByVal e As ExecutedRoutedEventArgs)
Dim command, targetobj As String
command = CType(e.Command, RoutedCommand).Name
targetobj = CType(sender, FrameworkElement).Name
MessageBox.Show("The " + command + " command has been invoked on target object " +
targetobj)
End Sub
Private Sub OpenCmdCanExecute(ByVal s As Object,ByVal e As CanExecuteRoutedEventArgs)
e.CanExecute = True
End Sub
Por ltimo, se crea un objeto CommandBinding en el elemento Window raz de la aplicacin que asocia los
controladores de eventos enrutados al comando Open.
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
// Creating CommandBinding and attaching an Executed and CanExecute handler
CommandBinding OpenCmdBinding = new CommandBinding(
ApplicationCommands.Open,OpenCmdExecuted,OpenCmdCanExecute);
this.CommandBindings.Add(OpenCmdBinding);

3.7.5.13. Cmo: Enlazar un Comando a un Control con la Compatibilidad de


Comandos
En el ejemplo siguiente se muestra cmo enlazar RoutedCommand a un objeto Control que tiene compatibilidad
integrada para el comando.
Ejemplo
Windows Presentation Foundation (WPF) proporciona una biblioteca de comandos comunes que los
programadores de aplicaciones suelen utilizar. Las clases que componen la biblioteca de comandos son:
ApplicationCommands, ComponentCommands, NavigationCommands, MediaCommands y EditingCommands.
Los objetos RoutedCommand estticos que componen estas clases no proporcionan la lgica de los comandos.
La lgica del comando se asocia al comando mediante CommandBinding. Algunos controles tienen enlaces
CommandBinding integrados para algunos comandos. Este mecanismo permite que la semntica de un
comando permanezca igual, mientras que la implementacin real puede cambiar. Por ejemplo, un control
TextBox administra el comando Paste de manera distinta que un control diseado para admitir imgenes, pero
el concepto bsico del significado de pegar algo no cambia. El comando no puede proporcionar la lgica de
comando, sta debe proporcionarla el control o la aplicacin.
Muchos controles de WPF s tienen compatibilidad integrada con algunos de los comandos de la biblioteca de
comandos. Por ejemplo, TextBox admite muchos de los comandos de edicin de aplicacin, tales como Paste,
Copy, Cut, Redo y Undo. El programador de aplicaciones no tiene que hacer nada especial para que estos
comandos funcionen con estos controles. Si el control TextBox es el destino del comando al ejecutar este
ltimo, administrar el comando mediante el objeto CommandBinding integrado en el control.
A continuacin se muestra cmo utilizar MenuItem como origen del comando Paste, donde TextBox es el
destino del comando. Toda la lgica que define cmo TextBox realiza la operacin de pegar est integrada en el
control TextBox.
Se crea MenuItem y se establece su propiedad Command en el comando Paste. CommandTarget no se
establece explcitamente en el objeto TextBox. Cuando CommandTarget no se establece, el destino del
comando es elemento que tiene el foco del teclado. Si el elemento que tiene el foco del teclado no admite el
comando Paste o en este momento no puede ejecutarlo (por ejemplo, si el portapapeles est vaco), entonces
el control MenuItem estar deshabilitado.
<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

MCT: Luis Dueas

Pag 404 de 445

Manual de Windows Presentation Foundation


Title="MenuItemCommandTask">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Command="ApplicationCommands.Paste" Width="75" />
</Menu>
<TextBox BorderBrush="Black" BorderThickness="2" Margin="25"
TextWrapping="Wrap">
The MenuItem will not be enabled until
this TextBox gets keyboard focus
</TextBox>
</DockPanel>
</Window>
// Window1 constructor
public Window1()
{
InitializeComponent();
// Instantiating UIElements.
DockPanel mainPanel = new DockPanel();
Menu mainMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
TextBox mainTextBox = new TextBox();
// Associating the MenuItem with the Paste command.
pasteMenuItem.Command = ApplicationCommands.Paste;
// Setting properties on the TextBox.
mainTextBox.Text =
"The MenuItem will not be enabled until this TextBox receives keyboard focus.";
mainTextBox.Margin = new Thickness(25);
mainTextBox.BorderBrush = Brushes.Black;
mainTextBox.BorderThickness = new Thickness(2);
mainTextBox.TextWrapping = TextWrapping.Wrap;
// Attaching UIElements to the Window.
this.AddChild(mainPanel);
mainMenu.Items.Add(pasteMenuItem);
mainPanel.Children.Add(mainMenu);
mainPanel.Children.Add(mainTextBox);
// Defining DockPanel layout.
DockPanel.SetDock(mainMenu, Dock.Top);
DockPanel.SetDock(mainTextBox, Dock.Bottom);
}

3.8. Recursos WPF


Los recursos de Windows Presentation Foundation (WPF) proporcionan una manera simple de reutilizar los
objetos y valores que se definen habitualmente.

3.8.1. Informacin General sobre Recursos


En esta introduccin se describe el uso de los recursos de WPF como una manera simple de reutilizar los
objetos y valores que se definen de forma comn. Esta introduccin se centra en cmo utilizar los recursos en
XAML. Tambin se pueden crear y obtener acceso a los recursos utilizando cdigo o, de forma intercambiable,
cdigo y Lenguaje de marcado de aplicaciones extensible (XAML).
Utilizar recursos en XAML
En el ejemplo siguiente se define un objeto SolidColorBrush como un recurso en el elemento raz de una
pgina. A continuacin, el ejemplo hace referencia al recurso y lo utiliza para establecer las propiedades de
varios elementos secundarios, incluyendo un objeto Ellipse, un objeto TextBlock y un objeto Button.
<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>
<Style TargetType="TextBlock" x:Key="TitleText">
<Setter Property="Background" Value="Blue"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="#4E87D4"/>
<Setter Property="FontFamily" Value="Trebuchet MS"/>
<Setter Property="Margin" Value="0,40,10,10"/>
</Style>
<Style TargetType="TextBlock" x:Key="Label">
<Setter Property="DockPanel.Dock" Value="Right"/>
<Setter Property="FontSize" Value="8"/>
<Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
<Setter Property="FontFamily" Value="Arial"/>

MCT: Luis Dueas

Pag 405 de 445

Manual de Windows Presentation Foundation


<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,3,10,0"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
<DockPanel>
<TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
<TextBlock Style="{StaticResource Label}">Label</TextBlock>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36"
Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
<Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30"
Background="{StaticResource MyBrush}" Margin="40">Button</Button>
<Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100"
Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
</DockPanel>
</Border>
</StackPanel>
</Page>
Cada elemento del marco de trabajo (FrameworkElement o FrameworkContentElement) tiene una propiedad
Resources, que es la que contiene los recursos (como un objeto ResourceDictionary) definidos por un recurso.
Los recursos se pueden definir en cualquier elemento. Sin embargo, normalmente se definen en el elemento
raz que, en el ejemplo, es Page.
Cada recurso incluido en un diccionario de recursos debe tener una clave nica. Al definir los recursos en el
marcado, se asigna la clave nica a travs de x:Key (atributo). Normalmente, la clave es una cadena; sin
embargo, tambin se puede establecer en objetos de otros tipos utilizando las extensiones de marcado
adecuadas. Las claves de recursos que no son de cadena se utilizan en ciertas reas de caractersticas en WPF,
principalmente en los estilos, los recursos de componentes y los estilos de datos.
Una vez definido un recurso, se puede hacer referencia al recurso que se debe utilizar para un valor de
propiedad utilizando una sintaxis de extensin de marcado de recursos que especifique el nombre de la clave,
como por ejemplo:
<Button Background="{StaticResource MyBrush}"/>
<Ellipse Fill="{StaticResource MyBrush}"/>
En el ejemplo anterior, cuando el cargador XAML procesa el valor {StaticResource MyBrush} para la propiedad
Background de Button, la lgica de bsqueda de recursos comprueba primero la existencia del elemento Button
en el diccionario de recursos. Si Button no tiene una definicin de la clave de recurso MyBrush (no la tiene; su
coleccin de recursos est vaca), la bsqueda comprueba a continuacin el elemento primario de Button, que
es Page. As, cuando se define un recurso en el elemento raz Page, todos los elementos del rbol lgico del
objeto Page pueden tener acceso a l y se puede reutilizar el mismo recurso para establecer el valor de
cualquier propiedad que acepte el objeto Type que representa el recurso. En el ejemplo anterior, el mismo
recurso MyBrush establece dos propiedades diferentes: la propiedad Background de un objeto Button y la
propiedad Fill de un objeto Rectangle.
Recursos estticos y recursos dinmicos
Se puede hacer referencia a un recurso como un recurso esttico o como un recurso dinmico. Para ello, se
utiliza Extensin de marcado StaticResource o Extensin de marcado DynamicResource. Una extensin de
marcado es una caracterstica de XAML que permite especificar una referencia de objeto y que procesa la
cadena del atributo y devuelve el objeto a un cargador XAML.
Cuando se utiliza una extensin de marcado, normalmente se proporcionan uno o varios parmetros en forma
de cadena que son procesados por dicha extensin de marcado, en lugar de evaluarse en el contexto de la
propiedad que se est estableciendo. Extensin de marcado StaticResource procesa una clave buscando el valor
para dicha clave en todos los diccionarios de recursos disponibles. Esto sucede durante la carga, que es el
momento en el que el proceso de carga necesita asignar el valor de la propiedad que acepta la referencia de
recurso esttico. Extensin de marcado DynamicResource, por el contrario, procesa una clave creando una
expresin, y dicha expresin permanece sin evaluar hasta que se ejecuta la aplicacin, momento en el cual se
evala y proporciona un valor.

MCT: Luis Dueas

Pag 406 de 445

Manual de Windows Presentation Foundation


Al hacer referencia a un recurso, las consideraciones siguientes pueden influir a la hora de decidir si se va a
utilizar una referencia de recurso esttico o una referencia de recurso dinmico:

El diseo general utilizado para crear los recursos para la aplicacin (por pgina, en la aplicacin, en
XAML separado, en un ensamblado slo para recursos).

La funcionalidad de la aplicacin: la actualizacin de recursos en tiempo real forma parte de los


requisitos de la aplicacin?

El comportamiento de bsqueda respectivo de ese tipo de referencia de recurso.


El tipo concreto de recurso o de propiedad, as como el comportamiento nativo de esos tipos.

Recursos estticos
Las referencias de recursos estticos funcionan mejor en las circunstancias siguientes:

El diseo de la aplicacin concentra la mayora de sus recursos en diccionarios de recursos en el nivel


de aplicacin o de pgina. Las referencias de recursos estticos no se vuelven a evaluar basndose en
los comportamientos en tiempo de ejecucin, como recargar una pgina, por lo que puede haber cierta
mejora en el rendimiento si se evita el uso de grandes cantidades de referencias de recursos dinmicos
cuando no son necesarias para el diseo de los recursos y de la aplicacin.

Est estableciendo el valor de una propiedad que no est en un objeto DependencyObject o Freezable.

Est creando un diccionario de recursos que se compilar en una DLL y que se empaquetar como
parte de la aplicacin o se compartir entre distintas aplicaciones.

Est creando un tema para un control personalizado y est definiendo recursos que se utilizan dentro
de los temas. En este caso, no es conveniente utilizar el comportamiento de bsqueda de referencia de
recursos dinmicos, sino el comportamiento de referencia de recursos estticos con objeto de que la
bsqueda sea predecible y se circunscriba al tema. Con una referencia de recursos dinmicos, incluso
una referencia dentro de un tema permanecer sin evaluar hasta el tiempo de ejecucin, y existe la
posibilidad de que cuando se aplique el tema, algn elemento local redefina una clave a la que el tema
est intentando hacer referencia, con lo que dicho elemento se encontrar antes que el propio tema
durante la bsqueda. Si este es el caso, el tema no se comportar de la manera esperada.

Est utilizando los recursos para establecer un gran nmero de propiedades de dependencia. Las
propiedades de dependencia permiten el almacenamiento en cach del valor efectivo tal y como ha
sido habilitado por el sistema de propiedades, por lo que si se proporciona un valor para una propiedad
de dependencia que se puede evaluar en el momento de la carga, dicha propiedad no tendr que
comprobar la existencia de una expresin que se ha vuelto a evaluar y podr devolver el ltimo valor
efectivo. Esta tcnica puede suponer una mejora en el rendimiento.

Desea cambiar el recurso subyacente para todos los consumidores o mantener instancias modificables
independientes para cada consumidor utilizando Atributo x:Shared.

Comportamiento de la bsqueda de recursos estticos


1.

El proceso de bsqueda comprueba la presencia de la clave solicitada dentro del diccionario de


recursos definido por el elemento que establece la propiedad.

2.

A continuacin, el proceso de bsqueda recorre en sentido ascendente el rbol lgico, hacia el


elemento primario y su diccionario de recursos. Este proceso contina hasta que se alcanza el elemento
raz.

3.

Por ltimo, se comprueban los recursos de la aplicacin. Los recursos de la aplicacin son los
existentes dentro del diccionario de recursos definido por el objeto Application para la aplicacin de WPF.

MCT: Luis Dueas

Pag 407 de 445

Manual de Windows Presentation Foundation


Las referencias de recursos estticos desde un diccionario de recursos deben hacer referencia a un recurso que
haya sido definido lxicamente con anterioridad. Las referencias adelantadas no se pueden resolver mediante
una referencia de recurso esttico. Por este motivo, si utiliza referencias de recursos estticos, debe disear la
estructura de los diccionarios de recursos de tal forma que los recursos pensados para su uso individual se
definan en o cerca del principio de los respectivos diccionarios.
La bsqueda de recursos estticos se puede ampliar a los temas, o a los recursos del sistema, pero esto slo se
admite porque el cargador XAML aplaza la solicitud. Este aplazamiento es necesario para que el tema en tiempo
de ejecucin en el momento cargar la pgina se aplique correctamente a la aplicacin. Sin embargo, no se
recomienda el uso de referencias de recursos estticos a claves que slo existen en temas o como recursos del
sistema. Esto se debe a que dichas referencias no se vuelven a evaluar si el usuario cambia el tema en tiempo
real. Las referencias de recursos dinmicos son ms confiables cuando se solicitan recursos del tema o del
sistema. La excepcin se produce cuando el propio elemento del tema solicita otro recurso. Por las razones
mencionadas anteriormente, estas referencias deberan ser referencias de recursos estticos.
El comportamiento de excepcin vara si no se encuentra una referencia de recurso esttico. Si se aplazase el
recurso, la excepcin se producira en tiempo de ejecucin. Si no se aplazase el recurso, la excepcin se
producira en el momento de la carga.
Recursos dinmicos
Los recursos dinmicos funcionan mejor en las circunstancias siguientes:

El valor del recurso depende de condiciones que no se conocen hasta el tiempo de ejecucin. Esto
incluye los recursos del sistema, o los recursos que de otra forma seran establecidos por el usuario.
Por ejemplo, puede crear valores de establecedor que hacen referencia a las propiedades del sistema,
de la forma expuesta por SystemColors, SystemFonts o SystemParameters. Estos valores son
autnticamente dinmicos porque proceden del entorno en tiempo de ejecucin del usuario y del
sistema operativo. Tambin es posible tener temas de nivel de aplicacin que pueden cambiar, en los
que el acceso a recursos de nivel de pgina tambin debe capturar los cambios.

Est creando o haciendo referencia a los estilos del tema para un control personalizado.

Desea ajustar el contenido de un objeto ResourceDictionary durante la duracin de una aplicacin.

Dispone de una estructura de recursos compleja que tiene interdependencias, y en la que es posible
que se necesite una referencia adelantada. A diferencia de las referencias de recursos estticos, las
referencias de recursos dinmicos admiten las referencias adelantadas, ya que no es necesario evaluar
el recurso hasta el tiempo de ejecucin y, por consiguiente, las referencias adelantadas no son un
concepto pertinente.

Est haciendo referencia a un recurso que es de gran tamao desde la perspectiva de un espacio de
compilacin o de trabajo, y es posible que dicho recurso no se utilice inmediatamente al cargar la
pgina. Las referencias de recursos estticos siempre se cargan desde XAML al cargar la pgina; sin
embargo, una referencia de un recurso dinmico no lo hace hasta que se utiliza realmente.

Est creando un estilo cuyos valores de establecedor podran proceder de otros valores influenciados
por los temas o por otras configuraciones del usuario.

Est aplicando recursos a elementos que podran haber cambiado de elemento primario en el rbol
lgico durante la duracin de la aplicacin. Al cambiar el elemento primario, tambin se cambia
potencialmente el mbito de bsqueda de recursos, por lo que si desea que el recurso para un
elemento que ha cambiado de elemento primario se vuelva a evaluar dependiendo del nuevo mbito,
siempre debe utilizar una referencia de recurso dinmico.

MCT: Luis Dueas

Pag 408 de 445

Manual de Windows Presentation Foundation


Comportamiento de la bsqueda de recursos dinmicos
El comportamiento de bsqueda de recursos para una referencia de recurso dinmico es similar al
comportamiento de bsqueda establecido en el cdigo si se llama a FindResource o a SetResourceReference.
1.

El proceso de bsqueda comprueba la presencia de la clave solicitada dentro del diccionario de


recursos definido por el elemento que establece la propiedad.

Si el elemento define una propiedad Style, se comprueba el diccionario Resources dentro de


Style.

Si el elemento define una propiedad Template, se comprueba el diccionario Resources dentro


de FrameworkTemplate.

2.

A continuacin, el proceso de bsqueda recorre en sentido ascendente el rbol lgico, hacia el


elemento primario y su diccionario de recursos. Este proceso contina hasta que se alcanza el elemento
raz.

3.

Por ltimo, se comprueban los recursos de la aplicacin. Los recursos de la aplicacin son los
existentes dentro del diccionario de recursos definido por el objeto Application para la aplicacin de WPF.

4.

Se comprueba la existencia del tema activo actualmente en el diccionario de recursos de temas. Si el


tema cambia en tiempo de ejecucin, se vuelve a evaluar el valor.

5.

Se comprueban los recursos del sistema.

El comportamiento de excepcin (si existe) vara:

Si una llamada a FindResource solicita un recurso, y ste no se encuentra, se inicia una excepcin.

Si una llamada a TryFindResource solicita un recurso, y ste no se encuentra, no se inicia ninguna


excepcin, pero el valor devuelto es null. Si la propiedad que se establece no acepta null, todava es
posible que se inicie un excepcin ms profunda (esto depende de la propiedad individual que se est
estableciendo).

Si una referencia de recurso dinmico solicitara un recurso en XAML, y ste no se encontrara, el


comportamiento depender del sistema general de propiedades, pero el comportamiento general es
como si no se hubiera producido ninguna operacin de configuracin de propiedades en el nivel en el
que existe el recurso. Por ejemplo, si intenta establecer el fondo de un elemento de botn individual
utilizando un recurso que no se ha podido evaluar, no se devuelve ningn conjunto de valores, pero el
valor efectivo todava puede proceder de otros participantes en el sistema de propiedades y en la
prioridad de valores. Por ejemplo, el valor del fondo todava podra proceder de un estilo de botn
definido localmente o del estilo del tema. Para las propiedades que no se definen en los estilos de
tema, el valor efectivo despus de una evaluacin de recursos con errores podra proceder del valor
predeterminado en los metadatos de la propiedad.

Restricciones
Las referencias de recursos dinmicos tienen algunas restricciones importantes. Al menos debe cumplirse una
de las condiciones siguientes:

La propiedad que se establece debe ser una propiedad en un objeto FrameworkElement o


FrameworkContentElement. Dicha propiedad debe estar respaldada por un objeto DependencyProperty

La referencia es para un valor dentro de un objeto Style Setter.


La propiedad que se establece debe ser una propiedad en un objeto Freezable que se proporciona
como un valor para una propiedad de FrameworkElement o FrameworkContentElement, o un valor
Setter.

MCT: Luis Dueas

Pag 409 de 445

Manual de Windows Presentation Foundation


Dado que la propiedad que se establece debe ser una propiedad de DependencyProperty o Freezable, la
mayora de los cambios en la propiedad se pueden propagar a la interfaz de usuario debido a que dichos
cambios (el valor de recurso dinmico modificado) estn confirmados por el sistema de propiedades. La
mayora de los controles incluyen lgica que forzar otro diseo del control si cambia un objeto
DependencyProperty y esa propiedad podra afectar al diseo. Sin embargo, no est garantizado que todas las
propiedades que tengan una Extensin de marcado DynamicResource como valor proporcionen ste de manera
que se actualicen en tiempo real en la interfaz de usuario. Esa funcionalidad podra variar dependiendo de la
propiedad, as como del tipo que posea sta o incluso de la estructura lgica de la aplicacin.
Estilos, plantillas de datos y claves implcitas
Anteriormente, se ha dicho que todos los elementos de un objeto ResourceDictionary deben tener una clave.
Sin embargo, eso no significa que todos los recursos deben tener un atributo x:Key explcito. Varios tipos de
objetos admiten una clave implcita cuando se definen como un recurso, donde el valor de la clave est
asociado al valor de otra propiedad. Esto se conoce como una clave implcita, mientras que un atributo x:Key es
una clave explcita. Se puede sobrescribir cualquier clave implcita especificando una clave explcita.
Un escenario muy importante para los recursos es el obtenido al definir un objeto Style. De hecho, Style se
define casi siempre como una entrada en un diccionario de recursos, ya que los estilos estn pensados
intrnsecamente para su reutilizacin.
Los estilos para los controles se pueden crear con una clave implcita; as mismo, tambin se puede hacer
referencia a ellos mediante dicha clave. Los estilos del tema que definen la apariencia predeterminada de un
control se basan en esta clave implcita. La clave implcita desde el punto de vista de la solicitud es el objeto
Type del propio control. La clave implcita desde el punto de vista de la definicin del recurso es la propiedad
TargetType del estilo. Por consiguiente, si est creando temas para controles personalizados, al crear estilos
que interactan con estilos de tema existentes no necesita especificar un x:Key (atributo) para ese objeto
Style. Y si desea utilizar los estilos con tema, no es necesario que especifique ningn estilo. Por ejemplo, la
definicin de estilo siguiente funciona, aunque el recurso Style no parece tener una clave:
<Style TargetType="Button">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush>
<GradientStop Offset="0.0" Color="AliceBlue"/>
<GradientStop Offset="1.0" Color="Salmon"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="18"/>
</Style>
En realidad, el estilo tiene una clave: la clave implcita typeof(Button). En el marcado, puede especificar
directamente una propiedad TargetType como nombre del tipo (o tambin puede utilizar {x:Type...} para
devolver un objeto Type.
A travs de los mecanismos de estilo del tema predeterminado utilizados por WPF, ese estilo se aplica como el
estilo en tiempo de ejecucin de un objeto Button en la pgina, aunque el propio objeto Button no intenta
especificar su propiedad Style o una referencia de recurso concreta al estilo. El estilo definido en la pgina se
encontrar antes que el estilo de diccionario de tema en la secuencia de bsqueda, utilizando la misma clave
que este ltimo estilo. Tambin podra especificar <Button>Hello</Button> en cualquier lugar de la pgina, y el
estilo definido con la propiedad TargetType de Button se aplicara a ese botn. Si lo desea, tambin puede
asignar explcitamente al estilo el mismo valor de tipo que TargetType, por motivos de claridad en el marcado,
pero eso es opcional.
Las claves implcitas para los estilos no se aplican en un control si OverridesDefaultStyle es true (observe
tambin que OverridesDefaultStyle se podra establecer como parte del comportamiento nativo para la clase de
control, en lugar de establecerse explcitamente en una instancia del control). Asimismo, para poder admitir las

MCT: Luis Dueas

Pag 410 de 445

Manual de Windows Presentation Foundation


claves implcitas para los escenarios de clase derivada, el control debe invalidar DefaultStyleKey (todos los
controles existentes proporcionados como parte de WPF hacen esto).
DataTemplate tambin tiene una clave implcita. La clave implcita para un objeto DataTemplate es el valor de
la propiedad DataType. DataType tambin se puede especificar como el nombre del tipo en lugar de hacerlo
explcitamente utilizando {x:Type...}.

3.8.2. Recursos y Cdigo


Esta informacin general se concentra en cmo se puede obtener acceso a los recursos de Windows
Presentation Foundation (WPF) o cmo crearlos mediante cdigo en lugar de mediante la sintaxis Lenguaje de
marcado de aplicaciones extensible (XAML).
Acceso a los recursos mediante cdigo
Las claves que identifican los recursos si se definen mediante XAML tambin se utilizan para recuperar recursos
concretos cuando se solicita el recurso en el cdigo. La manera ms simple de recuperar un recurso desde el
cdigo es llamar al mtodo FindResource o TryFindResource desde los objetos de nivel de marco de trabajo de
la aplicacin. La diferencia de comportamiento entre estos mtodos reside en lo que ocurre si no se encuentra
la clave solicitada. FindResource inicia una excepcin; TryFindResource no inicia una excepcin, sino que
devuelve null. Cada mtodo toma la clave de recurso como parmetro de entrada y devuelve un objeto con
establecimiento flexible de tipos. Normalmente, una clave de recurso es una cadena, pero ocasionalmente se
utilizan otros tipos de datos; consulte la seccin Utilizar objetos como claves para obtener detalles al respecto.
Lo habitual es convertir el objeto devuelto al tipo requerido por la propiedad que se est estableciendo al
solicitar el recurso. La lgica de bsqueda para la resolucin del recurso de cdigo es igual que en el caso de
XAML de referencia de recurso dinmico. La bsqueda de recursos comienza desde el elemento que realiza la
llamada, y contina a los elementos primarios sucesivos del rbol lgico. La bsqueda contina avanzando por
los recursos de la aplicacin, los temas y los recursos del sistema si es necesario. Una solicitud mediante cdigo
de un recurso tendr en cuenta correctamente los cambios en tiempo de ejecucin que puedan hacerse en los
diccionarios de recursos despus de cargarlos desde XAML, as como los cambios que se hagan en los recursos
del sistema en tiempo real.
A continuacin, se muestra un breve ejemplo de cdigo que busca un recurso por su clave y utiliza el valor
devuelto para establecer una propiedad, que se implementa como controlador del evento Click.
void SetBGByResource(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
b.Background = (Brush)this.FindResource("RainbowBrush");
}
Un mtodo alternativo para asignar una referencia de recurso es SetResourceReference. Este mtodo toma dos
parmetros: la clave del recurso y el identificador correspondiente a una propiedad de dependencia
determinada que est presente en la instancia de elemento a la que debera estar asignado el valor de recurso.
Funcionalmente, este mtodo es igual, y tiene la ventaja de no requerir ninguna conversin de los valores
devueltos.
Otra manera ms de tener acceso a los recursos mediante programacin es obtener acceso al contenido de la
propiedad Resources como diccionario. Tener acceso al diccionario contenido por esta propiedad tambin
constituye la manera de agregar nuevos recursos a las colecciones existentes, comprobar si la coleccin ya ha
aceptado un nombre de clave determinado y realizar otras operaciones de diccionario o coleccin. Si est
escribiendo una aplicacin de WPF mediante cdigo en su totalidad, tambin puede crear la coleccin completa
en cdigo, asignarle claves y, a continuacin, asignar la coleccin acabada a la propiedad Resources de un
elemento establecido. Esto se describe en la seccin siguiente.
Puede indizar dentro de cualquier coleccin Resources determinada utilizando una clave concreta como ndice,
pero debe tener en cuenta que al tener acceso al recurso de esta manera no se siguen las reglas de tiempo de
ejecucin normales para la resolucin de recursos. nicamente se tiene acceso a esa coleccin en particular. La

MCT: Luis Dueas

Pag 411 de 445

Manual de Windows Presentation Foundation


bsqueda de recursos no recorrer el mbito hasta la raz ni la aplicacin si no se encuentra ningn objeto
vlido en la clave solicitada. Sin embargo, este enfoque puede presentar ventajas de rendimiento en algunos
casos precisamente por esta restriccin del mbito de bsqueda de la clave.
Crear recursos mediante cdigo
Si est creando una aplicacin de WPF completa mediante cdigo, es posible que tambin desee crear los
recursos de esa aplicacin mediante cdigo. Para ello, cree una nueva instancia de ResourceDictionary y, a
continuacin, agregue todos los recursos al diccionario mediante llamadas sucesivas a ResourceDictionary.Add.
Despus, utilice el ResourceDictionary as creado para establecer la propiedad Resources en un elemento que
est presente en el mbito de una pgina, o la propiedad Application.Resources. Tambin puede mantener
ResourceDictionary como objeto independiente sin agregarlo a un elemento. Sin embargo, si lo hace, deber
tener acceso a los recursos contenidos en l por su clave de elemento, como si se tratase de un diccionario
genrico. Si un ResourceDictionary no est asociado a la propiedad Resources de un elemento o existir como
parte del rbol del elemento y no tendr ningn mbito en la secuencia de bsqueda utilizada por FindResource
y otros mtodos relacionados.
Utilizar objetos como claves
La mayora de los usos de recursos establecen la clave de recurso en una cadena. Sin embargo, en varias
caractersticas de WPF deliberadamente no se utiliza un tipo de cadena para especificar las claves, sino un
objeto. La capacidad de que la clave de un recurso sea un objeto se utiliza en la compatibilidad de estilos y
temas de WPF. Las claves de los estilos de los temas que se convierten en el estilo predeterminado de un
control que, salvo ste, no tiene ningn otro estilo, se determinan mediante el objeto Type del control al que se
deben aplicar. El hecho de que la clave sea un tipo proporciona un mecanismo de bsqueda confiable que
funciona en las instancias predeterminadas de cada tipo de control. Adems, el tipo se puede detectar por
reflexin y utilizar para las clases de estilos derivadas aunque, por lo dems, el tipo derivado no tenga ningn
estilo predeterminado. Puede especificar una clave Type para un recurso definido en XAML utilizando Extensin
de marcado x:Type. Existen extensiones similares para otros usos de clave que no son de cadena y que
admiten las caractersticas de WPF, como Extensin de marcado ComponentResourceKey.

3.8.3. Diccionarios de Recursos Combinados


Los recursos de Windows Presentation Foundation (WPF) admiten los diccionarios de recursos combinados. Esta
caracterstica proporciona una manera de definir la parte correspondiente a los recursos de una aplicacin de
WPF fuera de la aplicacin de XAML compilada. As, los recursos se pueden compartir entre las aplicaciones y
tambin quedan aislados de un modo ms cmodo para su localizacin.
Introduccin de un diccionario de recursos combinado
En el marcado, se utiliza la sintaxis siguiente para introducir un diccionario de recursos combinado en una
pgina:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="myresourcedictionary.xaml"/>
<ResourceDictionary Source="myresourcedictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
Observe que el elemento ResourceDictionary no tiene x:Key (atributo), que generalmente se requiere para
todos los elementos en una coleccin de recursos. Sin embargo, otra referencia a ResourceDictionary dentro de
la coleccin MergedDictionaries constituye un caso especial, reservado para este escenario de diccionario de
recursos combinado. El objeto ResourceDictionary que introduce un diccionario de recursos combinado no
puede tener x:Key (atributo). Normalmente, cada objeto ResourceDictionary de la coleccin MergedDictionaries
especifica un atributo Source. El valor de Source debe ser un identificador de recursos uniforme (URI) que se
resuelve como la ubicacin del archivo de recursos que se va a combinar. El destino de ese URI debe ser otro
archivo XAML, cuyo elemento raz es ResourceDictionary.

MCT: Luis Dueas

Pag 412 de 445

Manual de Windows Presentation Foundation

Nota:
Es vlido definir recursos dentro de un objeto ResourceDictionary especificado como diccionario combinado,
ya sea como alternativa a especificar la propiedad Source, o bien adems de los recursos incluidos desde el
origen especificado. Sin embargo, ste no es un escenario comn; el escenario principal para los
diccionarios combinados es combinar recursos procedentes de ubicaciones de archivo externas. Si desea
especificar los recursos dentro del marcado de una pgina, deber definirlos en el objeto
ResourceDictionary principal, y no en los diccionarios combinados.
Comportamiento de los diccionarios combinados
Los recursos de un diccionario combinado ocupan una ubicacin en el mbito de bsqueda de recursos que se
encuentra justo despus del mbito del diccionario de recursos principal con el que se combinan. Aunque una
clave de recurso debe ser nica dentro de cualquier diccionario individual, una clave puede existir varias veces
en un conjunto de diccionarios combinados. En este caso, el recurso que se devuelve proceder del ltimo
diccionario situado secuencialmente en la coleccin MergedDictionaries. Si la coleccin MergedDictionaries se ha
definido en XAML, entonces el orden de los diccionarios combinados de la coleccin es el orden de los
elementos que se indica en el marcado. Si una clave est definida en el diccionario principal y tambin en un
diccionario que se ha combinado, entonces el recurso que se devuelve proceder del diccionario principal. Estas
reglas de mbito se aplican igualmente para referencias de recursos estticos y referencias de recursos
dinmicos.
Diccionarios combinados y cdigo
Los diccionarios combinados se pueden agregar a un diccionario Resources mediante cdigo. El objeto
ResourceDictionary predeterminado inicialmente vaco que existe para cualquier propiedad Resources tambin
tiene una propiedad de coleccin MergedDictionaries predeterminada inicialmente vaca. Para agregar un
diccionario combinado mediante cdigo, se obtiene una referencia al objeto ResourceDictionary primario
deseado, se obtiene el valor de su propiedad MergedDictionaries y se llama a Add en la Collection genrica
contenida en MergedDictionaries. El objeto que se agrega debe ser un nuevo ResourceDictionary. En el cdigo,
no se establece la propiedad Source. En cambio, se debe obtener un objeto ResourceDictionary creando o
cargando uno. Una manera de cargar un ResourceDictionary existente consiste en llamar a XamlReader.Load en
una secuencia de archivo XAML existente que tiene un ResourceDictionary raz y, a continuacin, convertir el
valor devuelto de XamlReader.Load a ResourceDictionary.
URI de diccionarios de recursos combinados
Existen varias tcnicas para incluir un diccionario de recursos combinado, que vienen dadas por el formato de
identificador de recursos uniforme (URI) que se utilizar. En lneas generales, estas tcnicas se pueden dividir
en dos categoras: los recursos que se compilan como parte del proyecto y recursos que no se compilan como
parte del proyecto.
Para los recursos que se compilan como parte del proyecto, puede utilizar una ruta de acceso relativa que hace
referencia a la ubicacin del recurso. La ruta de acceso relativa se evala durante la compilacin. El recurso se
debe definir como parte del proyecto como una accin de compilacin de recurso. Si incluye un archivo .xaml
de recursos en el proyecto como recurso, no ser preciso copiar el archivo de recursos en el directorio de
resultados, el recurso ya est incluido dentro de la aplicacin compilada. Tambin puede utilizar la accin de
compilacin de contenido, pero en este caso deber copiar los archivos en el directorio de resultados y tambin
implementar los archivos de recursos en la misma relacin de ruta de acceso que la aplicacin ejecutable.
Nota:
No utilice la accin de compilacin de recurso incrustado. La propia accin de compilacin se admite para
aplicaciones de WPF, pero la resolucin de Source no incorpora ResourceManager, por lo que no puede
separar el recurso individual de la secuencia. Podra utilizar la accin de recurso incrustado para otros fines,
siempre que, adems, utilice ResourceManager para tener acceso a los recursos.
Una tcnica relacionada es utilizar un pack URI a un archivo de XAML y hacer referencia a l como el origen. El
pack URI permite las referencias a los componentes de ensamblados a los que se hace referencia, y otras
tcnicas.

MCT: Luis Dueas

Pag 413 de 445

Manual de Windows Presentation Foundation


Para los recursos que no se compilan como parte del proyecto, el URI se evala en tiempo de ejecucin. Puede
utilizar un transporte de URI comn, como file: o http: para hacer referencia al archivo de recursos. La
desventaja de utilizar el enfoque de recursos no compilados es que el acceso con file: requiere pasos de
implementacin adicionales y que el acceso con http: implica la zona de seguridad de Internet.
Reutilizar diccionarios combinados
Puede reutilizar o compartir los diccionarios de recursos combinados entre las aplicaciones, porque se puede
hacer referencia al diccionario de recursos que se va a combinar mediante cualquier identificador de recursos
uniforme (URI) vlido. Cmo se lleve esto a cabo exactamente depender de la estrategia de implementacin
de aplicaciones y del modelo de aplicacin utilizado. La citada estrategia de pack URI proporciona una manera
de utilizar como origen comn durante la programacin un recurso combinado en varios proyectos, para lo que
se comparte una referencia de ensamblado. En este escenario, el cliente distribuye los recursos y, como
mnimo, una de las aplicaciones debe implementar el ensamblado al que se hace referencia. Tambin es posible
hacer referencia a los recursos combinados a travs de un URI distribuido que utiliza el protocolo http.
Escribir diccionarios combinados como archivos de aplicaciones locales o en el almacenamiento compartido local
constituyen otros tantos escenarios posibles de implementacin de diccionarios y aplicaciones.
Localizacin
Si los recursos que es preciso localizar estn aislados en diccionarios que se combinan en los diccionarios
primarios, y que se mantienen como XAML dinmico, estos archivos se pueden localizar por separado. Esta
tcnica constituye una alternativa ligera a la localizacin de los ensamblados de recursos satlite.

3.8.4. Temas Cmo de Recursos


Los temas en esta seccin describen cmo utilizar los recursos de Windows Presentation Foundation (WPF).

3.8.4.1. Cmo: Definir y Hacer Referencia a un Recurso


En este ejemplo se muestra cmo definir un recurso y hacer referencia a l utilizando un atributo en Lenguaje
de marcado de aplicaciones extensible (XAML).
Ejemplo
En el ejemplo siguiente se definen dos tipos de recursos: un recurso SolidColorBrush y varios recursos Style. El
recurso SolidColorBrush MyBrush se utiliza para proporcionar el valor de varias propiedades, cada una de las
cuales toma un valor de tipo Brush. Cada uno de los recursos Style (PageBackground, TitleText y Label) est
destinado a un tipo de control determinado. Los estilos establecen varias propiedades diferentes para los
controles de destino, cuando se hace referencia a ese recurso de estilo por su clave de recurso y se utiliza para
establecer la propiedad Style de varios elementos de control concretos definidos en XAML.
Observe que una de las propiedades de de los establecedores (setters) del estilo Label tambin hace referencia
al recurso MyBrush definido anteriormente. Se trata de una tcnica comn, pero es importante recordar que los
recursos se analizan y escriben en un diccionario de recursos en el orden en que se indican. Tambin se
solicitan los recursos en el orden en que se encuentran en el diccionario si se utiliza Extensin de marcado
StaticResource para hacer referencia a ellos desde el interior de otro recurso. Asegrese de que todos los
recursos a los que haga referencia se hayan definido en la coleccin de recursos antes del punto en que se
solicita ese recurso. Si es necesario, puede omitir el orden estricto de creacin de referencias a recursos
utilizando la Extensin de marcado DynamicResource para hacer referencia lugar al recurso en tiempo de
ejecucin, pero debe tener en cuenta que esta tcnica de DynamicResource influye en el rendimiento.
<Page Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
<Style TargetType="Border" x:Key="PageBackground">
<Setter Property="Background" Value="Blue"/>
</Style>

MCT: Luis Dueas

Pag 414 de 445

Manual de Windows Presentation Foundation


<Style TargetType="TextBlock" x:Key="TitleText">
<Setter Property="Background" Value="Blue"/>
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="#4E87D4"/>
<Setter Property="FontFamily" Value="Trebuchet MS"/>
<Setter Property="Margin" Value="0,40,10,10"/>
</Style>
<Style TargetType="TextBlock" x:Key="Label">
<Setter Property="DockPanel.Dock" Value="Right"/>
<Setter Property="FontSize" Value="8"/>
<Setter Property="Foreground" Value="{StaticResource MyBrush}"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,3,10,0"/>
</Style>
</Page.Resources>
<StackPanel>
<Border Style="{StaticResource PageBackground}">
<DockPanel>
<TextBlock Style="{StaticResource TitleText}">Title</TextBlock>
<TextBlock Style="{StaticResource Label}">Label</TextBlock>
<TextBlock DockPanel.Dock="Top" HorizontalAlignment="Left" FontSize="36"
Foreground="{StaticResource MyBrush}" Text="Text" Margin="20" />
<Button DockPanel.Dock="Top" HorizontalAlignment="Left" Height="30"
Background="{StaticResource MyBrush}" Margin="40">Button</Button>
<Ellipse DockPanel.Dock="Top" HorizontalAlignment="Left" Width="100"
Height="100" Fill="{StaticResource MyBrush}" Margin="40" />
</DockPanel>
</Border>
</StackPanel>
</Page>

3.8.4.2. Cmo: Usar Recursos de Aplicaciones


En este ejemplo se muestra cmo utilizar los recursos de aplicaciones.
Ejemplo
En el ejemplo siguiente se muestra un archivo de definicin de aplicacin. El archivo de definicin de aplicacin
define una seccin de recursos (un valor para la propiedad Resources). Los recursos definidos en el nivel de
aplicacin estn accesibles para todas las dems pginas que forman parte de la aplicacin. En este caso, el
recurso es un estilo declarado. Dado que un estilo completo que incluye una plantilla de control puede ser
largo, en este ejemplo se omite la plantilla de control que se define dentro del establecedor de la propiedad
ContentTemplate del estilo.
<Application.Resources>
<Style TargetType="Button" x:Key="GelButton" >
<Setter Property="Margin" Value="1,2,1,2"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
...
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
En el ejemplo siguiente se muestra una pgina XAML que hace referencia al recurso del nivel de aplicacin
definido en el ejemplo anterior. Se hace referencia al recurso mediante una Extensin de marcado
StaticResource que especifica la clave de recurso nica para el recurso solicitado. No se encuentra ningn
recurso cuya clave sea "GelButton" en la pgina actual, por lo que el mbito de bsqueda de recurso del
recurso solicitado contina ms all de la pgina actual hasta los recursos definidos en el nivel de aplicacin.
<StackPanel
Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Height="50" Width="250" Style="{StaticResource GelButton}" Content="Button 1"/>
<Button Height="50" Width="250" Style="{StaticResource GelButton}" Content="Button 2"/>
</StackPanel>

3.8.4.3. Cmo: Utilizar SystemFonts


En este ejemplo se muestra cmo utilizar los recursos estticos de la clase SystemFonts para aplicar un estilo a
un botn o personalizarlo.

MCT: Luis Dueas

Pag 415 de 445

Manual de Windows Presentation Foundation


Ejemplo
Los recursos del sistema exponen diversos valores determinados por el sistema como recursos y propiedades,
para ayudarle a crear efectos visuales coherentes con la configuracin del sistema. SystemFonts es una clase
que contiene valores de fuentes del sistema como propiedades estticas y tambin propiedades que hacen
referencia a las claves de recurso que pueden utilizarse para tener acceso dinmicamente a esos valores en
tiempo de ejecucin. Por ejemplo, CaptionFontFamily es un valor SystemFonts y CaptionFontFamilyKey es su
clave de recurso correspondiente.
En XAML, puede utilizar los miembros de SystemFonts como propiedades estticas o como referencias
dinmicas a recursos (donde se use como clave el valor de la propiedad esttica). Utilice una referencia
dinmica a un recurso si desea que la mtrica de la fuente se actualice automticamente mientras se ejecuta la
aplicacin; de lo contrario, utilice una referencia esttica al valor.
Nota:
Las claves de recurso tienen el sufijo "Key" anexado al nombre de propiedad.
En el ejemplo siguiente se muestra cmo obtener acceso a las propiedades de SystemFonts como valores
estticos y utilizarlas para aplicar un estilo a un botn o personalizarlo. En este ejemplo de marcado se asignan
los valores de SystemFonts a un botn.
<Button Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="3"
FontSize="{x:Static SystemFonts.IconFontSize}"
FontWeight="{x:Static SystemFonts.MessageFontWeight}"
FontFamily="{x:Static SystemFonts.CaptionFontFamily}">
SystemFonts
</Button>
Para utilizar los valores de SystemFonts en el cdigo, no tiene que utilizar un valor esttico o una referencia de
recurso dinmica. En lugar de ello, utilice las propiedades que no son claves de la clase SystemFonts. Aunque
en apariencia las propiedades que no son claves se definen como propiedades estticas, el comportamiento en
tiempo de ejecucin de WPF cuando est hospedado en el sistema hace que se vuelvan a evaluar las
propiedades en tiempo real y que se reflejen correctamente los cambios a los valores del sistema controlados
por el usuario. En el ejemplo siguiente se muestra cmo especificar la configuracin de las fuentes de un botn.
Button btncsharp = new Button();
btncsharp.Content = "SystemFonts";
btncsharp.Background = SystemColors.ControlDarkDarkBrush;
btncsharp.FontSize = SystemFonts.IconFontSize;
btncsharp.FontWeight = SystemFonts.MessageFontWeight;
btncsharp.FontFamily = SystemFonts.CaptionFontFamily;
cv1.Children.Add(btncsharp);

3.8.4.4. Cmo: Usar Claves de Fuentes del Sistema


Los recursos del sistema exponen varias medidas del sistema como recursos para ayudar a los programadores
a crear elementos visuales coherentes con la configuracin del sistema. SystemFonts es una clase que contiene
tanto valores de fuentes del sistema como recursos de fuentes del sistema vinculados a los valores, por
ejemplo, CaptionFontFamily y CaptionFontFamilyKey.
Las medidas de las fuentes del sistema se pueden utilizar como recursos estticos o dinmicos. Utilice un
recurso dinmico si desea que la medida de la fuente se actualice automticamente mientras se ejecuta la
aplicacin; de lo contrario, utilice un recurso esttico.
Nota:
Los recursos dinmicos tienen la palabra clave Key anexada al nombre de propiedad.
En el ejemplo siguiente se muestra cmo obtener acceso a recursos dinmicos de fuentes del sistema y
utilizarlos para aplicar un estilo a un botn o personalizarlo. Este ejemplo XAML crea un estilo de botn que
asigna los valores SystemFonts a un botn.
Ejemplo
<Style x:Key="SimpleFont" TargetType="{x:Type Button}">
<Setter Property = "FontSize" Value= "{DynamicResource {x:Static

MCT: Luis Dueas

Pag 416 de 445

Manual de Windows Presentation Foundation


SystemFonts.IconFontSizeKey}}"/>
<Setter Property = "FontWeight" Value= "{DynamicResource {x:Static
SystemFonts.MessageFontWeightKey}}"/>
<Setter Property = "FontFamily" Value= "{DynamicResource {x:Static
SystemFonts.CaptionFontFamilyKey}}"/>
</Style>

3.8.4.5. Cmo: Utilizar SystemParameters


En este ejemplo se muestra cmo obtener acceso a las propiedades de SystemParameters y utilizarlas para
aplicar un estilo a un botn o personalizarlo.
Ejemplo
Los recursos del sistema exponen diversos valores del sistema como recursos, a fin de ayudarle a crear efectos
visuales coherentes con la configuracin del sistema. SystemParameters es una clase que contiene tanto
propiedades de los valores de los parmetros del sistema como claves de recurso que se enlazan a los valores.
Por

ejemplo,

FullPrimaryScreenHeight

es

un

valor

de

la

propiedad

SystemParameters

FullPrimaryScreenHeightKey es la clave de recurso correspondiente.


En XAML, puede utilizar los miembros de SystemParameters como propiedades estticas o como referencias de
recurso dinmicas (donde se use como clave el valor de la propiedad esttica). Utilice una referencia dinmica a
un recurso si desea que el valor del sistema se actualice automticamente mientras se ejecuta la aplicacin; de
lo contrario, utilice una referencia esttica. Las claves de recurso tienen el sufijo Key anexado al nombre de
propiedad.
En el ejemplo siguiente se muestra cmo obtener acceso a los valores estticos de SystemParameters y
utilizarlos para aplicar un estilo a un botn o personalizarlo. En este de cdigo de marcado de ejemplo se ajusta
el tamao del botn aplicndole valores de SystemParameters.
<Button FontSize="8" Margin="10, 10, 5, 5" Grid.Column="0" Grid.Row="5"
HorizontalAlignment="Left"
Height="{x:Static SystemParameters.CaptionHeight}"
Width="{x:Static SystemParameters.IconGridWidth}">
SystemParameters
</Button>
Para utilizar los valores de SystemParameters en el cdigo, no tiene que utilizar referencias estticas o
referencias de recurso dinmicas. En su lugar, utilice los valores de la clase SystemParameters. Aunque en
apariencia las propiedades que no son claves se definen como propiedades estticas, el comportamiento en
tiempo de ejecucin de WPF cuando est hospedado en el sistema hace que se vuelvan a evaluar las
propiedades en tiempo real y que se reflejen correctamente los cambios a los valores del sistema controlados
por el usuario. En el ejemplo siguiente se muestra cmo establecer el ancho y el alto de un botn mediante los
valores de SystemParameters.
Button btncsharp = new Button();
btncsharp.Content = "SystemParameters";
btncsharp.FontSize = 8;
btncsharp.Background = SystemColors.ControlDarkDarkBrush;
btncsharp.Height = SystemParameters.CaptionHeight;
btncsharp.Width = SystemParameters.IconGridWidth;
cv2.Children.Add(btncsharp);

3.8.4.6. Cmo: Utilizar Claves de Parmetros del Sistema


Los recursos del sistema exponen varias mtricas del sistema como recursos para ayudar a los programadores
a crear elementos visuales coherentes con la configuracin del sistema. SystemParameters es una clase que
contiene tanto claves de recursos como valores de parmetros del sistema que se enlazan a valores, por
ejemplo, FullPrimaryScreenHeight y FullPrimaryScreenHeightKey. Las mtricas de los parmetros del sistema
se pueden utilizar como recursos estticos o dinmicos. Utilice un recurso dinmico si desea que la mtrica del
parmetro se actualice automticamente mientras se ejecuta la aplicacin; de lo contrario, utilice un recurso
esttico.
Nota:
Los recursos dinmicos tienen la palabra clave Key anexada al nombre de propiedad.

MCT: Luis Dueas

Pag 417 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente se muestra cmo obtener acceso a recursos dinmicos de parmetros del sistema y
utilizarlos para aplicar un estilo a un botn o personalizarlo. En este ejemplo de XAML se ajusta el tamao de
un botn asignando valores de SystemParameters al ancho y alto del botn.
Ejemplo
<Style x:Key="SimpleParam" TargetType="{x:Type Button}">
<Setter Property = "Height" Value= "{DynamicResource {x:Static
SystemParameters.CaptionHeightKey}}"/>
<Setter Property = "Width" Value= "{DynamicResource {x:Static
SystemParameters.IconGridWidthKey}}"/>
</Style>

3.9. Estilos y Plantillas: Conceptual


Los estilos y plantillas de Windows Presentation Foundation (WPF) hacen referencia a un conjunto de
caractersticas (estilos, plantillas, desencadenadores y guiones grficos) que permiten a los diseadores de
aplicaciones, documentos o interfaces de usuario crear aplicaciones visualmente atractivas y estandarizar la
apariencia del producto.

3.9.1. Aplicar Estilos y Plantillas


Los estilos y plantillas de Windows Presentation Foundation (WPF) hacen referencia a un conjunto de
caractersticas (estilos, plantillas, desencadenadores y guiones grficos) que permiten a los diseadores de una
aplicacin, documento o interfaz de usuario (UI) crear efectos visualmente atractivos y estandarizar de manera
coherente la apariencia del producto. Aunque un autor o diseador puede personalizar ampliamente la
apariencia de las aplicaciones una por una, se necesita un modelo robusto de estilos y plantillas para permitir el
mantenimiento y el uso compartido de la apariencia tanto dentro de una aplicacin como entre las diversas
aplicaciones. Windows Presentation Foundation (WPF) proporciona ese modelo.
Otra caracterstica del modelo de estilos de WPF es la separacin de la presentacin y la lgica. Esto significa
que los diseadores pueden trabajar en la apariencia de una aplicacin utilizando solamente XAML, al mismo
tiempo que los desarrolladores trabajan en la lgica de programacin utilizando C# o Visual Basic.
En esta informacin general se explica la aplicacin Ejemplo Introduction to Styling and Templating, que tiene
dos elementos TextBlock y un control ListBox enlazado a una lista de imgenes:

Esta informacin general se centra en los aspectos de estilos y plantillas de la aplicacin y no aborda los
conceptos de enlace de datos.
Adems, es importante entender los recursos, que permiten reutilizar los estilos y las plantillas.
Fundamentos de estilos
Puede considerar un objeto Style como una manera cmoda de aplicar un conjunto de valores de propiedades a
ms de un elemento. Por ejemplo, considere los siguientes elementos

TextBlock y su apariencia

predeterminada:
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>

MCT: Luis Dueas

Pag 418 de 445

Manual de Windows Presentation Foundation


Puede cambiar la apariencia predeterminada estableciendo directamente propiedades como FontSize y
FontFamily en cada elemento TextBlock. Sin embargo, si desea que los elementos TextBlock compartan algunas
propiedades, puede crear un objeto Style en la seccin Resources del archivo XAML, como se muestra aqu:
<Window.Resources>
...
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
...
</Window.Resources>
Cuando establezca la propiedad TargetType del estilo en el tipo TextBlock, el estilo se aplicar a todos los
elementos TextBlock de la ventana.
Ahora, los elementos TextBlock aparecern de la manera siguiente:

Extender los estilos


Quizs desee que los dos elementos TextBlock compartan algunos valores de propiedad, como FontFamily y un
valor de HorizontalAlignment centrado, pero tambin desee que el texto "My Pictures" tenga algunas
propiedades adicionales. Para ello, cree un nuevo estilo basado en el primer estilo, como se muestra aqu:
<Window.Resources>
...
<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
...
</Window.Resources>
Observe que al estilo anterior se le asigna un atributo x:Key. Para aplicar el estilo, establezca la propiedad Style
del elemento TextBlock en el valor de x:Key, como se muestra aqu:
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
El estilo de este elemento TextBlock tiene ahora el valor de la propiedad HorizontalAlignment establecido en
Center, el valor de la propiedad FontFamily establecido en Comic Sans MS, el valor de la propiedad FontSize
establecido en 26 y el valor de la propiedad Foreground establecido en el objeto LinearGradientBrush que se
muestra en el ejemplo. Observe que hemos invalidado el valor de FontSize del estilo base. Si hay ms de un
objeto Setter que establezca la misma propiedad de Style, el objeto Setter que se declare en ltimo lugar
tendr prioridad.
A continuacin se muestra la apariencia que tendrn los elementos TextBlock:

Este estilo TitleText extiende el estilo creado para el tipo TextBlock. Tambin puede extender un estilo que
tenga un atributo x:Key utilizando el valor de x:Key. Para ver un ejemplo, vea el que se proporciona para la
propiedad BasedOn.
Relacin entre la propiedad TargetType y el atributo x:Key

MCT: Luis Dueas

Pag 419 de 445

Manual de Windows Presentation Foundation


Como se muestra en el primer ejemplo, si se establece la propiedad TargetType en TextBlock sin asignar al
estilo un atributo x:Key, el estilo se aplicar a todos los elementos TextBlock. En este caso, el atributo x:Key se
establece implcitamente en {x:Type TextBlock}. Esto significa que si se establece explcitamente el atributo
x:Key en un valor que no sea {x:Type TextBlock}, el objeto Style no se aplicar automticamente a todos los
elementos TextBlock. Es preciso aplicar explcitamente el estilo (utilizando el valor de x:Key) a los elementos
TextBlock. Si el estilo est en la seccin de recursos y no se establece la propiedad TargetType del estilo, se
deber proporcionar un atributo x:Key.
Adems de proporcionar un valor predeterminado para x:Key, la propiedad TargetType especifica el tipo al que
se aplican las propiedades del establecedor. Si no se especifica un valor de TargetType, se debern certificar las
propiedades

de

los

objetos

Setter

con

un

nombre

de

clase,

utilizando

la

sintaxis

Property="ClassName.Property". Por ejemplo, en lugar de establecer Property="FontSize", se deber establecer


Property en "TextBlock.FontSize" o "Control.FontSize".
Observe tambin que muchos controles de WPF son una combinacin de otros controles de WPF. Si crea un
estilo que se aplique a todos los controles de un tipo, puede que obtenga resultados inesperados. Por ejemplo,
si crea un estilo cuyo objetivo sea el tipo de TextBlock en un objeto Window, el estilo se aplicar a todos los
controles TextBlock de la ventana, aunque el elemento TextBlock forme parte de otro control, como un control
ListBox.
Estilos y recursos
Puede utilizar un estilo en cualquier elemento que derive de FrameworkElement o FrameworkContentElement.
La manera ms comn de declarar un estilo es declararlo como un recurso en la seccin Resources de un
archivo XAML, como se muestra en los ejemplos anteriores. Dado que los estilos son recursos, siguen las
mismas reglas de mbito que se aplican a todos los recursos; la ubicacin donde se declara un estilo afecta a la
parte donde se puede aplicar. Por ejemplo, si se declara el estilo en el elemento raz del archivo XAML de
definicin de la aplicacin, el estilo se puede usar en cualquier parte de la aplicacin. Si se crea una aplicacin
de navegacin y se declara el estilo en uno de sus archivos XAML, el estilo slo se puede usar en ese archivo
XAML.
Establecer estilos mediante programacin
Para asignar mediante programacin un estilo con nombre a un elemento, obtenga el estilo de la coleccin de
recursos y asgnelo a la propiedad Style del elemento. Observe que los elementos de una coleccin de recursos
son de tipo Object, de modo que debe convertir el estilo recuperado en un objeto Style antes de asignarlo a la
propiedad Style. Por ejemplo, para establecer el estilo TitleText definido de un control TextBlock denominado
textblock1, siga este procedimiento:
textblock1.Style = (Style)(this.Resources["TitleText"]);
Tenga en cuenta que, una vez aplicado un estilo, ste queda sellado y no puede cambiarse. Si desea cambiar
dinmicamente un estilo que ya se ha aplicado, deber crear un nuevo estilo para reemplazar el existente.
Puede crear un objeto que elija el estilo que se va a aplicar basndose en una lgica personalizada.
Enlaces, recursos dinmicos y controladores de eventos
Observe que puede usar la propiedad Setter.Value para especificar una Enlazar extensin de marcado o una
Extensin de marcado DynamicResource.
Hasta ahora, hemos explicado solamente el uso de establecedores para establecer el valor de la propiedad. En
un estilo, tambin se pueden especificar los controladores de eventos.
Plantillas de datos
En esta aplicacin de ejemplo, hay un control ListBox enlazado a una lista de fotos:
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
Este control ListBox tiene ahora la siguiente apariencia:

MCT: Luis Dueas

Pag 420 de 445

Manual de Windows Presentation Foundation

La mayora de los controles tienen algn tipo de contenido y ese contenido suele proceder de los datos a los
que se est enlazando. En este ejemplo, los datos son la lista de fotos. En WPF, utilice DataTemplate para
definir la representacin visual de los datos. Bsicamente, el contenido de DataTemplate determina la
apariencia de los datos en la aplicacin representada.
En la aplicacin de ejemplo, cada objeto Photo personalizado tiene una propiedad Source de tipo cadena que
especifica la ruta de acceso del archivo de imagen. Actualmente, los objetos de foto aparecen como rutas de
acceso de archivo.
Para que las fotos aparezcan como imgenes, debe crear un objeto DataTemplate como un recurso:
<Window.Resources>
...
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
...
</Window.Resources>
Observe que la propiedad DataType es muy similar a la propiedad TargetType de Style. Si DataTemplate est
en la seccin de recursos, al especificar la propiedad DataType en un tipo y no asignarle un atributo x:Key,
DataTemplate se aplicar cada vez que aparezca ese tipo. Siempre tiene la opcin de asignar a DataTemplate
un atributo x:Key y, a continuacin, establecerlo como StaticResource para las propiedades que admiten tipos
DataTemplate, como la propiedad ItemTemplate o la propiedad ContentTemplate.
El objeto DataTemplate del ejemplo anterior define esencialmente que, siempre que haya un objeto Photo, ste
debe aparecer como un control Image dentro de un control Border. Con este objeto DataTemplate, la aplicacin
tiene ahora esta apariencia:

El modelo de plantillas de datos proporciona otras caractersticas. Por ejemplo, si se muestran datos de
coleccin que contengan otras colecciones con un tipo HeaderedItemsControl como un control Menu o un
control TreeView, ah est el objeto HierarchicalDataTemplate. Otra caracterstica de las plantillas de datos es el
objeto DataTemplateSelector, que permite elegir el objeto DataTemplate que se va a utilizar basndose en una
lgica personalizada.
Plantillas de control
Este tema contiene las subsecciones siguientes.

Sin utilizar ControlTemplate


Qu es ControlTemplate?
Crear un objeto ControlTemplate

MCT: Luis Dueas

Pag 421 de 445

Manual de Windows Presentation Foundation

Propiedad IsItemsHost
ItemsPresenter y ContentPresenter
TemplateBinding

Ahora que las fotos aparecen como imgenes, vamos a mostrarlas horizontalmente en lugar de verticalmente;
el control ListBox se va a mostrar horizontalmente.
Sin utilizar ControlTemplate
En primer lugar, es importante sealar que no es necesario utilizar el objeto ControlTemplate para que el
control ListBox sea horizontal. ListBox tiene la propiedad ItemsPanel, que permite establecer un objeto
ItemsPanelTemplate, la plantilla que controla el diseo de los elementos del control ListBox. Una opcin es
crear simplemente un estilo de ListBox y establecer la propiedad ItemsPanel, como en el ejemplo siguiente:
<Style TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
Este procedimiento funciona bien y el resultado es un control ListBox horizontal. En este ejemplo se muestra
que, dependiendo del escenario, puede haber otras opciones adems de reemplazar el objeto ControlTemplate.
Para este ejemplo, si deseamos obtener un control ListBox horizontal que tenga propiedades adicionales, como
esquinas redondeadas, necesitamos trabajar con el objeto ControlTemplate del control ListBox.
Antes de proporcionar un ejemplo para mostrar cmo hacerlo, es importante explicar primero el concepto de
ControlTemplate.
Qu es ControlTemplate?
La mayora de controles tienen una apariencia y un comportamiento. Considere un botn: la apariencia es el
rea elevada que se puede presionar y el comportamiento es el evento Click que se provoca en respuesta a un
clic.
En ocasiones, puede haber un control que proporcione el comportamiento necesario, pero no la apariencia
necesaria. Hasta ahora, hemos mostrado que puede utilizar establecedores de estilo para establecer valores de
propiedad que afecten a la apariencia del control. Sin embargo, para cambiar la estructura de un control o
establecer valores de propiedad en los componentes de un control, debe utilizar un objeto ControlTemplate.
En WPF, el objeto ControlTemplate de un control define su apariencia. Puede cambiar la estructura y la
apariencia de un control definiendo un nuevo objeto ControlTemplate para el control. En muchos casos, esto
ofrece suficiente flexibilidad como para no tener que escribir controles personalizados. Si no define un objeto
ControlTemplate propio para el control, debe obtener la plantilla predeterminada que se ajuste al tema del
sistema; es esta plantilla la que da la apariencia predeterminada al control Button.
Recuerde que al crear un objeto ControlTemplate para el control, se reemplaza el objeto ControlTemplate
completo. Por ejemplo, puede definir el objeto ControlTemplate de un control Button de la manera siguiente.
Observe que el elemento ContentPresenter simplemente marca dnde debe ir la propiedad Content del control
Button. Explicaremos las diferentes partes en una seccin posterior.
<Style TargetType="Button">
<!--Set to true to not get any properties from the themes.-->
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>

MCT: Luis Dueas

Pag 422 de 445

Manual de Windows Presentation Foundation


</Setter.Value>
</Setter>
</Style>
Una vez aplicado, el control Button aparece como Ellipse:

Recuerde que la apariencia que presenta el control Button cuando tiene el foco o est presionado forma parte
de la apariencia predeterminada del botn que est reemplazando. Por consiguiente, en funcin de sus
necesidades, quiz desee incluir en la definicin la apariencia que debe tener el botn cuando est presionado.
Cuando cree un objeto ControlTemplate, la mejor manera de empezar es utilizar los Ejemplos de
ControlTemplate. Si realmente necesita examinar las partes de las que se compone un control, puede echar una
mirada al archivo de temas ubicado en Temas o puede utilizar la funcionalidad Show Visual Tree de XAMLPad,
una aplicacin que se instala con Kit de desarrollo de software de Windows (SDK).
Crear un objeto ControlTemplate
Ahora, vamos a continuar con nuestro ejemplo y crear un objeto ControlTemplate que defina un control ListBox
horizontal y con esquinas redondeadas. Para reemplazar el objeto ControlTemplate de un control, establezca la
propiedad Template en el nuevo objeto ControlTemplate.
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center"
HorizontalAlignment="Center" IsItemsHost="True"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Cuando se establece la propiedad Template de esta manera, no hay realmente ninguna diferencia con el
establecimiento de otras propiedades de control mediante Style: se usa un objeto Style como una herramienta
que ayuda a establecer la propiedad Template. Esto significa que otra manera de establecer un objeto
ControlTemplate es establecer directamente la propiedad Template en el control. Si procede de esta manera,
crea un objeto ControlTemplate en la seccin Resources, le asigna un atributo x:Key y, a continuacin, lo utiliza
como un recurso esttico.
Como puede ver en el ejemplo anterior, la clase ControlTemplate tiene una propiedad TargetType que es similar
a la propiedad TargetType de la clase Style. No obstante, observe que, a diferencia de Style y DataTemplate,
los objetos ControlTemplate no tienen la nocin de una clave implcita. En otras palabras, si tiene un objeto
ControlTemplate independiente con la propiedad TargetType establecida en un tipo, el objeto ControlTemplate
no se aplicar automticamente a ese tipo. Observe tambin que se requiere la propiedad TargetType en un
objeto ControlTemplate si la definicin de la plantilla contiene un objeto ContentPresenter.
Experimente con el objeto ControlTemplate. Por ejemplo, reemplace el control StackPanel con un control
WrapPanel, establezca la propiedad HorizontalScrollBarVisibility del control ScrollViewer en Disabled y, a
continuacin, establezca el ancho del control ListBox en 300. (WrapPanel solamente coloca elementos en la fila
siguiente cuando la primera fila se queda sin espacio. Si no establece la propiedad HorizontalScrollBarVisibility
del control ScrollViewer en Disabled, la primera fila no se queda sin espacio porque es posible desplazarse hasta
el final. Como resultado, el control WrapPanel no ajusta los elementos.)
Propiedad IsItemsHost
En este ejemplo, una propiedad importante que debe estar presente es la propiedad IsItemsHost. La propiedad
IsItemsHost se utiliza para indicar en la plantilla de un control ItemsControl (controles como ListBox que tienen
una lista de elementos) dnde deben ir los elementos generados. Si se establece la propiedad en true en el

MCT: Luis Dueas

Pag 423 de 445

Manual de Windows Presentation Foundation


control StackPanel, cualquier elemento que se agregue al control ListBox se incluir en el control StackPanel.
Observe que esta propiedad solamente funciona en los tipos Panel.
ItemsPresenter y ContentPresenter
Sin embargo, observe que al especificar un panel en ControlTemplate y marcarlo como IsItemsHost de esta
manera, el usuario del control no puede reemplazar ItemsPanel sin utilizar un objeto ControlTemplate. Por
consiguiente, proceda solamente de esta manera si sabe con seguridad que no desea reemplazar el panel sin
usar una plantilla. Tambin puede utilizar el elemento ItemsPresenter para marcar dnde deben ir los
elementos y, a continuacin, especificar un objeto ItemsPanelTemplate estableciendo la propiedad ItemsPanel.
La pgina ItemsPanelTemplate incluye un ejemplo en el que se muestra cmo hacerlo.
Si crea una plantilla para un control ContentControl, como Button, el elemento correspondiente es el control
ContentPresenter. De manera similar, coloque este elemento en el objeto ControlTemplate del tipo
ContentControl para indicar dnde debe mostrarse el contenido, tal como se indica en el ejemplo de la seccin
Qu es ControlTemplate?.
TemplateBinding
Cabe observar asimismo que en el ejemplo anterior el valor de Background se establece en {TemplateBinding
ListBox.Background}. De esta forma, se indica simplemente que el valor de la propiedad Background de Border
debe sincronizarse con el valor de Background establecido en el control ListBox. TemplateBinding es similar a
Binding. De hecho, TemplateBinding es ms eficaz pero menos funcional que Binding; utilizar TemplateBinding
es equivalente a utilizar Binding con la propiedad Source establecida en RelativeSource.TemplatedParent.
Utilice TemplateBinding en ControlTemplate cuando desee que el usuario del control controle los valores de
determinadas propiedades. TemplateBinding es una extensin de marcado representada por la clase
TemplateBindingExtension.
Quiz haya observado que DataTemplate y ControlTemplate son similares en tanto que su contenido se
convierte en la visualizacin de un objeto. Con la definicin de ControlTemplate del control ListBox, la aplicacin
tiene ahora la siguiente apariencia:

Desencadenadores
Style, ControlTemplate y DataTemplate tienen una propiedad Triggers que puede contener un conjunto de
desencadenadores. Un desencadenador establece propiedades o inicia acciones, como animaciones, cuando
cambia un valor de propiedad o cuando se provoca un evento.
Este tema contiene las subsecciones siguientes.

Desencadenadores de propiedades
Desencadenadores de eventos y guiones grficos
MultiTrigger, DataTrigger y MultiDataTrigger

Desencadenadores de propiedades
Para mostrar cmo se utilizan los desencadenadores para establecer propiedades, hagamos que cada elemento
ListBoxItem sea parcialmente transparente a menos que est seleccionado.

MCT: Luis Dueas

Pag 424 de 445

Manual de Windows Presentation Foundation


El estilo siguiente establece el valor de la propiedad Opacity de un elemento ListBoxItem en 0.5. Cuando el
valor de la propiedad IsSelected es true, sin embargo, el valor de Opacity se establece en 1.0:
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Opacity" Value="1.0" />
</Trigger>
...
</Style.Triggers>
</Style>
En este ejemplo se utiliza una clase Trigger para establecer un valor de propiedad, pero observe que la clase
Trigger tambin tiene las propiedades EnterActions y ExitActions que permiten a un desencadenador realizar
acciones.
Observe que tambin hemos establecido la propiedad MaxHeight del elemento ListBoxItem en 75. En la captura
de pantalla siguiente, el tercer elemento es el elemento seleccionado:

Desencadenadores de eventos y guiones grficos


Acabamos de mostrar que un objeto Trigger establece valores de propiedad o inicia acciones en funcin del
valor de una propiedad. Otro tipo de desencadenador es EventTrigger, que inicia un conjunto de acciones en
funcin de la aparicin de un evento. Por ejemplo, los siguientes objetos EventTrigger especifican que, cuando
el puntero del mouse entre en el elemento ListBoxItem, la propiedad MaxHeight se establezca en 90 durante un
perodo de 0.2 segundos. Cuando el mouse sale del elemento, la propiedad se establece de nuevo en el valor
original durante un perodo de 1 segundo. Observe que no es necesario especificar el valor de la propiedad To
para la animacin MouseLeave. Esto se debe a que la animacin puede realizar un seguimiento del valor
original.
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
En la captura de pantalla siguiente, el mouse est sealando el tercer elemento:

MultiTrigger, DataTrigger y MultiDataTrigger

MCT: Luis Dueas

Pag 425 de 445

Manual de Windows Presentation Foundation


Adems de Trigger y EventTrigger, hay otros tipos de desencadenadores. MultiTrigger permite establecer
valores de propiedad en funcin de varias condiciones. DataTrigger y MultiDataTrigger se utilizan cuando la
propiedad de la condicin est enlazada a datos.
Recursos y temas compartidos
Una aplicacin Windows Presentation Foundation (WPF) tpica puede tener varios recursos de interfaz de
usuario aplicados en toda la aplicacin. Este conjunto de recursos puede considerarse el tema de la aplicacin.
Windows Presentation Foundation (WPF) proporciona compatibilidad para empaquetar los recursos de la
interfaz de usuario como un tema utilizando un diccionario de recursos encapsulado como la clase
ResourceDictionary.
Los temas de Windows Presentation Foundation (WPF) se definen mediante el mecanismo de estilos y plantillas
que Windows Presentation Foundation (WPF) expone para personalizar los efectos visuales de cualquier
elemento.
Los recursos de tema de Windows Presentation Foundation (WPF) estn almacenados en diccionarios de
recursos incrustados. Estos diccionarios de recursos deben incrustarse en un ensamblado firmado y pueden
incrustarse en el mismo ensamblado que el propio cdigo o en un ensamblado paralelo. En el caso de
PresentationFramework.dll, el ensamblado que contiene los controles de Windows Presentation Foundation
(WPF), los recursos de tema estn en una serie de ensamblados paralelos.
El tema se convierte en el ltimo lugar donde se va a buscar el estilo de un elemento. Normalmente, la
bsqueda de un recurso adecuado se realizar recorriendo primero de manera ascendente el rbol de
elementos; a continuacin, se buscar en la coleccin de recursos de la aplicacin y, finalmente, se consultar
el sistema. De este modo, los autores de aplicaciones podrn redefinir el estilo de cualquier objeto en el nivel
de rbol o de aplicacin antes de alcanzar el tema.
Los diccionarios de recursos se pueden definir como archivos individuales que permiten reutilizar un tema en
varias aplicaciones. Tambin se pueden crear temas intercambiables definiendo varios diccionarios de recursos
que proporcionen los mismos tipos de recursos pero con diferentes valores. Redefinir estos estilos u otros
recursos en el nivel de aplicacin es el enfoque recomendado para aplicar una mscara a una aplicacin.
Para compartir un conjunto de recursos entre aplicaciones, incluidos los estilos y las plantillas, puede crear un
archivo XAML y definir un objeto ResourceDictionary. Por ejemplo, eche una mirada a la siguiente captura de
pantalla que muestra parte del Ejemplo Styling with ControlTemplates:

Si se fija en los archivos XAML del ejemplo, observar que todos los archivos tienen lo siguiente:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
Es el uso compartido de shared.xaml, que define un objeto ResourceDictionary que contiene un conjunto de
recursos de estilo y de pincel que permite que los controles del ejemplo tengan una apariencia coherente.

MCT: Luis Dueas

Pag 426 de 445

Manual de Windows Presentation Foundation

3.9.2. Cmo: Buscar Elementos Generados por un Objeto ControlTemplate


En este ejemplo se muestra cmo buscar elementos generados por un objeto ControlTemplate.
Ejemplo
En el ejemplo siguiente se muestra un estilo que crea un objeto ControlTemplate simple para la clase Button:
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Margin="5" Name="grid">
<Ellipse Stroke="DarkBlue" StrokeThickness="2">
<Ellipse.Fill>
<RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
<GradientStop Color="Azure" Offset="0.1" />
<GradientStop Color="CornflowerBlue" Offset="1.1" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<ContentPresenter Name="content" Margin="10"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Para buscar un elemento dentro de la plantilla una vez aplicada, puede llamar al mtodo FindName de
Template. En el ejemplo siguiente se crea un cuadro de mensaje que muestra el valor de ancho real de Grid
dentro de la plantilla de control:
// Finding the grid that is generated by the ControlTemplate of the Button
Grid gridInTemplate = (Grid)myButton1.Template.FindName("grid", myButton1);
// Do something to the ControlTemplate-generated grid
MessageBox.Show("The actual width of the grid in the ControlTemplate: "
+ gridInTemplate.GetValue(Grid.ActualWidthProperty).ToString());

3.10. Sistema de Diseo


En este tema se describe el sistema de diseo de Windows Presentation Foundation (WPF). Entender cmo y
cundo se producen los clculos de diseo es esencial para crear interfaces de usuario de alto rendimiento con
un aspecto profesional.
Sistema de diseo
El trmino "diseo" describe el proceso de medir y organizar los integrantes de la coleccin Children de un
elemento Panel y, a continuacin, dibujarlos en la pantalla. Se trata de un proceso intensivo y, cuanto mayor es
la coleccin Children, mayor es el nmero de clculos realizados. Tambin se puede incluir mayor complejidad
segn el comportamiento de diseo definido por el elemento Panel que posee la coleccin. Un diseo
relativamente sencillo, como Canvas, puede producir un rendimiento excelente si no se requiere un Panel ms
complejo, como Grid.
Cada vez que un UIElement secundario cambia su posicin, tiene el potencial de desencadenar un nuevo paso
del sistema de diseo. Como a tal, es importante entender los eventos que pueden invocar el sistema del
diseo, puesto que la invocacin innecesaria puede deteriorar el rendimiento de la aplicacin.
En su versin ms simple, el diseo es un sistema recursivo que conduce a la configuracin del tamao,
posicin y representacin de un elemento en la pantalla. El sistema de diseo completa dos pasos por cada
miembro de la coleccin Children: un paso de medida y un paso de organizacin. Cada Panel secundario
proporciona sus propios mtodos MeasureOverride y ArrangeOverride para lograr su propio comportamiento de
diseo concreto. Se trata de la serie de eventos que se producen cada vez que se invoca el sistema de diseo.
1.

Un UIElement secundario comienza el proceso de diseo midiendo, en primer lugar, propiedades


bsicas.

2.

Se evalan las propiedades de tamao definidas en FrameworkElement, como Width, Height y Margin.

3.

Se aplica la lgica concreta de Panel, como la direccin de Dock o la Orientation de apilado.

4.

El contenido se organiza despus de medir todos los elementos secundarios.

MCT: Luis Dueas

Pag 427 de 445

Manual de Windows Presentation Foundation


5.
6.

Se dibuja la coleccin Children en la pantalla.


Se invoca el proceso de nuevo si se agregan Children adicionales a la coleccin, se aplica una
LayoutTransform o se llama al mtodo UpdateLayout.

Este proceso, y los medios por los que se invoca, se define con mayor detalle en las secciones siguientes.
Rectngulos de seleccin de elementos
Al pensar en el diseo de una aplicacin en Windows Presentation Foundation (WPF), es importante entender el
rectngulo de seleccin que rodea todos los elementos. Esta abstraccin ayuda a comprender el
comportamiento del sistema de diseo. Cada FrameworkElement utilizado por el sistema de diseo se puede
considerar como un rectngulo que se inserta en una particin del diseo. Se expone una clase,
LayoutInformation, que puede devolver los lmites geomtricos de la asignacin de diseo de un elemento, o su
ranura. El sistema, calculando el espacio de pantalla disponible, determina el tamao de ese rectngulo, el
tamao de cualquier restriccin, las propiedades especficas del diseo, como el margen y el relleno, y el
comportamiento individual del elemento Panel primario. Al procesar estos datos, el sistema puede calcular la
posicin de todos los elementos secundarios de un Panel determinado. Es importante recordar que las
caractersticas de tamao definidas en el elemento primario (como un Border) afectan a sus elementos
secundarios.
Como ejemplo, tomemos el siguiente escenario de diseo simple.

Este diseo se puede lograr utilizando el Lenguaje de marcado de aplicaciones extensible (XAML) siguiente.
<Grid Name="myGrid" Background="LightSteelBlue" Height="150">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Name="txt1" Margin="5" FontSize="16" FontFamily="Verdana" Grid.Column="0"
Grid.Row="0">Hello World!</TextBlock>
<Button Click="getLayoutSlot1" Width="125" Height="25" Grid.Column="0"
Grid.Row="1">Show Bounding Box</Button>
<TextBlock Name="txt2" Grid.Column="1" Grid.Row="2"/>
</Grid>
El elemento TextBlock solitario se hospeda dentro de una Grid. Aunque el texto rellena slo la esquina superior
izquierda de la columna en la que se ha colocado, en realidad el espacio asignado para TextBlock es mucho
mayor. El rectngulo de seleccin de cualquier objeto FrameworkElement se puede recuperar utilizando el
mtodo GetLayoutSlot. Con este mtodo, el rectngulo de seleccin del elemento TextBlock queda superpuesto
(esto es posible porque el TextBlock se hospeda en una Grid, un elemento Panel que permite compartir las
coordenadas de diseo).

Como queda claro ahora por la lnea blanca que lo rodea, la particin asignada al elemento TextBlock es, en
realidad, mucho mayor que el espacio que rellena. Al agregar elementos adicionales a Grid, esta asignacin se
puede reducir o expandir, dependiendo del tipo y el tamao de los elementos que se agregan.
La ranura de diseo de TextBlock se devuelve y convierte en un Path mediante el mtodo GetLayoutSlot, una
tcnica que puede resultar til para mostrar el rectngulo de seleccin de un elemento.
Private Sub getLayoutSlot1(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim myRectangleGeometry As New RectangleGeometry
myRectangleGeometry.Rect = LayoutInformation.GetLayoutSlot(txt1)

MCT: Luis Dueas

Pag 428 de 445

Manual de Windows Presentation Foundation


Dim myGeometryDrawing As New GeometryDrawing
Dim myPath As New Path
myPath.Data = myRectangleGeometry
myPath.Stroke = Brushes.LightGoldenrodYellow
myPath.StrokeThickness = 5
Grid.SetColumn(myPath, 0)
Grid.SetRow(myPath, 0)
myGrid.Children.Add(myPath)
txt2.Text = "LayoutSlot is equal to "+LayoutInformation.GetLayoutSlot(txt1).ToString
End Sub
Medir y organizar elementos secundarios
Cuando se representa el contenido de un objeto Window, se invoca el sistema del diseo automticamente.
Para mostrar el contenido, el Content de la ventana debe definir un Panel raz que sirve para definir un marco
que permite organizar los miembros de Children en la pantalla.
El primer paso del diseo es la medicin, que evala cada miembro de la coleccin Children. El proceso
comienza con una llamada al mtodo Measure. Se llama a este mtodo dentro de la implementacin del
elemento Panel primario y no es preciso llamarla explcitamente para que el diseo tenga lugar.
En primer lugar, se evalan las propiedades de tamao nativas de UIElement, como Clip y Visibility. Esto
genera un valor denominado constraintSize, que se pasa a MeasureCore.
En segundo lugar, se procesan las propiedades de marco definidas en FrameworkElement, lo que afecta al valor
de constraintSize. Estas propiedades suelen a describir las caractersticas de tamao del UIElement subyacente,
como Height, Width, Margin y Style. Cada una de estas propiedades puede modificar el espacio necesario para
mostrar el elemento. A continuacin, se llama a MeasureOverride con constraintSize como parmetro.
Nota:
Existe una diferencia entre las propiedades de Height y Width, y ActualHeight y ActualWidth. Por ejemplo,
la propiedad ActualHeight es un valor calculado que se basa en otras entradas de alto y en el sistema de
diseo. El propio sistema del diseo establece el valor, basndose en un paso de representacin real; por
consiguiente, puede existir un pequeo desfase con respecto al valor establecido de propiedades como
Height, que constituyen la base del cambio de entrada.
Dado que ActualHeight es un valor calculado, debe tener en cuenta que puede haber varios cambios
incrementados o registrados del mismo como resultado de las diversas operaciones realizadas por el
sistema de diseo. El sistema de diseo puede calcular el espacio de medidas necesario para los elementos
secundarios, las restricciones impuestas por el elemento principal, etc.
El objetivo definitivo del paso de la medida es que el elemento secundario determine su DesiredSize, lo que
sucede durante la llamada a MeasureCore. Este valor lo almacena Measure para utilizarlo durante el proceso de
organizacin del contenido.
El proceso de organizacin se inicia con una llamada al mtodo Arrange. Durante el paso de organizacin, el
elemento Panel primario genera un rectngulo que representa los lmites del elemento secundario. Este valor se
pasa al mtodo ArrangeCore para procesarlo.
El mtodo ArrangeCore evala el DesiredSize del elemento secundario y tambin cualquier margen adicional
que pueda afectar al tamao representado del elemento; a continuacin, genera un arrangeSize que se pasa a
ArrangeOverride del panel como parmetro. ArrangeOverride genera el finalSize del elemento secundario y, por
ltimo, el mtodo ArrangeCore efecta una ltima evaluacin de las propiedades de desplazamiento, tales
como el margen o la alineacin, y coloca el elemento secundario dentro de su ranura de diseo. El elemento
secundario no necesita rellenar el espacio asignado completo, y con frecuencia no lo hace. A continuacin, el
control se devuelve al Panel primario y el proceso del diseo se completa.
Elementos de panel y comportamientos de diseo personalizado
Windows Presentation Foundation (WPF) incluye un conjunto derivado de elementos Panel que habilitan
numerosos diseos complejos. Los escenarios comunes, como apilar elementos, se consiguen con facilidad
mediante el elemento StackPanel; otros diseos dinmicos ms libres y complejos son posibles gracias a
Canvas.
En la tabla siguiente se resumen los elementos de diseo disponibles.

MCT: Luis Dueas

Pag 429 de 445

Manual de Windows Presentation Foundation

Nombre del
panel

Descripcin

Canvas

Define una rea en la que pueden colocarse explcitamente los elementos secundarios
utilizando las coordenadas relativas al rea del control Canvas.

DockPanel

Define un rea en la que se pueden organizar horizontalmente o verticalmente los


elementos secundarios, uno respecto al otro.

Grid

Define un rea de cuadrcula flexible que se compone de columnas y filas.

StackPanel

Organiza los elementos secundarios en una nica lnea que se puede orientar horizontal
o verticalmente.

VirtualizingPanel

Proporciona un marco para elementos Panel que "virtualizan" su recoleccin de datos


secundarios. sta es una clase abstracta.

WrapPanel

Organiza los elementos secundarios secuencialmente de izquierda a derecha y traslada


el contenido a la lnea siguiente cuando alcanza el borde del cuadro contenedor. La
clasificacin siguiente se realiza secuencialmente de arriba abajo o de izquierda a
derecha, en funcin del valor de la propiedad Orientation.

Para los escenarios que requieren un diseo de aplicacin que no es posible utilizando cualquiera de los
elementos Panel predefinidos, se pueden conseguir comportamientos de diseo personalizados heredando de
Panel e invalidando los mtodos MeasureOverride y ArrangeOverride.
Consideraciones sobre el rendimiento del diseo
El diseo es un proceso recursivo. Cada elemento secundario de una coleccin Children se procesa durante
cada invocacin del sistema. Como resultado, debe evitarse activar el sistema cuando no es necesario. Las
sugerencias siguientes pueden ayudarle a lograr un rendimiento ms alto.
Las propiedades de dependencia cuyos valores pueden hacer que el sistema de diseo se inicialice se marcan
con marcadores pblicos. AffectsMeasure y AffectsArrange proporcionan pistas tiles sobre qu cambios del
valor de la propiedad forzarn una actualizacin recursiva del sistema del diseo. En general, cualquier
propiedad que puede afectar al tamao del rectngulo de seleccin de un elemento debera establecer la marca
AffectsMeasure en true.
LayoutTransform puede ser una manera muy til de afectar al contenido de una interfaz de usuario (UI). Sin
embargo, si no es necesario que el efecto de la transformacin afecte a la posicin de otros elementos, es
mejor utilizar RenderTransform en su lugar, ya que RenderTransform no invoca el sistema del diseo.
LayoutTransform aplica su transformacin y fuerza una actualizacin del diseo recursiva para tener en cuenta
la nueva posicin del elemento afectado.
Evite las llamadas innecesarias a UpdateLayout. Este mtodo fuerza una actualizacin del diseo recursiva y no
suele ser necesario. A menos que est seguro de que se requiere una actualizacin completa, deje que el
sistema de diseo llame a este mtodo en su lugar.
Al tratar con una coleccin Children grande, puede ser conveniente utilizar VirtualizingStackPanel en lugar de
un StackPanel normal. Al "virtualizar" la coleccin secundaria, VirtualizingStackPanel nicamente conserva en la
memoria los objetos que se encuentran actualmente dentro del rea de visualizacin del elemento primario.
Como resultado, el rendimiento se mejora sustancialmente en la mayora de los escenarios.

3.11. Ajuste de Pxeles en Aplicaciones de WPF


El sistema de grficos de WPF utiliza unidades independientes del dispositivo para que sean independientes de
la resolucin y del dispositivo. Cada pxel independiente del dispositivo ajusta su escala automticamente al
valor de puntos por pulgada (dpi) del sistema. Esto proporciona a las aplicaciones de WPF un ajuste de escala
correcto para las distintas configuraciones de dpi y hace que la aplicacin detecte este valor de dpi
automticamente.

MCT: Luis Dueas

Pag 430 de 445

Manual de Windows Presentation Foundation


Sin embargo, esta independencia de dpi puede crear representaciones de bordes irregulares debido al
suavizado (anti-aliasing). Estas anomalas de la imagen, que suelen aparecer como bordes borrosos o
semitransparentes, pueden producirse cuando un borde se encuentra en medio de un pxel de dispositivo en
vez de situarse entre pxeles de dispositivo. Para solucionar este problema, WPF proporciona una manera de
ajustar (o fijar) los bordes de los objetos en un rbol visual a los pxeles de dispositivo a travs del ajuste de
pxeles, lo que elimina los bordes semitransparentes generados por el suavizado (anti-aliasing).
El ajuste de pxeles es un medio para suprimir estas anomalas visuales aplicando pequeos desplazamientos a
la geometra del objeto visual a fin de alinearla con los pxeles del dispositivo.
Ajuste de pxeles para representacin con suavizado (anti-aliasing)
Lneas ntidas
Sin

el

ajuste

de

pxeles,

las

lneas

representadas

con

suavizado

(anti-aliasing)

pueden

parecer

semitransparentes si el borde no se encuentra entre los pxeles del dispositivo. En la ilustracin siguiente se
muestra el resultado de representar con suavizado una lnea con un grosor de un solo pxel cuando se
encuentra en medio de un pxel del dispositivo (izquierda) y cuando se encuentra entre pxeles del dispositivo
(derecha).
Representacin de lnea con suavizado.

Con el ajuste de pxeles, las lneas suavizadas se ajusta, o fijan, a los pxeles del dispositivo y parecen ntidas,
con lo que se elimina la representacin de lneas semitransparentes. En el ejemplo siguiente se muestra el
efecto de la propiedad SnapsToDevicePixels en una lnea con un grosor de un solo pxel. Al cambiar lentamente
el tamao de la ventana, se muestran las anomalas que aparecen en una lnea no ajustada (izquierda) y el
tamao fijo de la lnea que s se ha ajustado (derecho) a medida que cambia su posicin.
<Page x:Class="PixelSnapping.Lines"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Lines" Name="linesPage">
<StackPanel Width="150" Margin="7" Orientation="Horizontal">
<!-- Single pixel line with pixel snapping turned OFF.-->
<Rectangle SnapsToDevicePixels="False"
Width="45.5" Margin="10" Height="1" Fill="Red"/>
<!-- Single pixel line with pixel snapping turned ON.-->
<Rectangle SnapsToDevicePixels="True"
Width="45.5" Margin="10" Height="1" Fill="Red"/>
</StackPanel>
<!-- Background Grid -->
<Page.Background>
<DrawingBrush Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Page.Background>
</Page>
Nota:
SnapsToDevicePixels nicamente afecta a los elementos que se encuentran en el recorrido de la pasada
de diseo. Pueden establecerse lneas de gua en un objeto Drawing mediante la propiedad GuidelineSet
del objeto DrawingGroup. Para establecer manualmente las lneas de gua de un objeto Visual, cree
nuevas lneas de gua mediante las propiedades VisualYSnappingGuidelines y VisualXSnappingGuidelines.
El ajuste de pxeles nicamente afecta a la nitidez de las lneas horizontales y verticales, no afecta a las lneas
diagonales.

MCT: Luis Dueas

Pag 431 de 445

Manual de Windows Presentation Foundation


Objetos adyacentes
El suavizado (anti-aliasing) tambin puede producir anomalas visuales cuando los bordes entre los objetos son
colindantes y el borde adyacente no queda alineado exactamente entre una fila o una columna de pxeles del
dispositivo. La escena con suavizado puede suavizar el borde utilizando el color de fondo subyacente, lo que
genera un efecto de permeabilidad en que el borde entre los objetos parece de color transparente. En la
ilustracin siguiente se muestra este efecto de permeabilidad.
Objetos colindantes con efecto de permeabilidad.

Con el ajuste de pxeles habilitado, los bordes colindantes se ajustan a los pxeles del dispositivo para quitar el
efecto de permeabilidad. En el ejemplo siguiente se muestra el efecto de la propiedad SnapsToDevicePixels en
objetos colindantes. Al cambiar lentamente el tamao de la ventana, se presenta el problema de permeabilidad
en los rectngulos sin ajustar (izquierda), mientras que en los rectngulos ajustados (derecha) permanecen
unidos sin irregularidades visuales.
<Page x:Class="PixelSnapping.Seeping"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Seeping">
<StackPanel Orientation="Horizontal" Height="100">
<Border
SnapsToDevicePixels="False"
Margin="10" BorderThickness="1" BorderBrush="Black" Height="80"
Background="White">
<StackPanel Height="100.0">
<Rectangle Width="20" Height="20" Fill="Red"/>
<Rectangle Width="20" Height="20" Fill="Red"/>
<Rectangle Width="20" Height="20" Fill="Red"/>
<Rectangle Width="20" Height="20" Fill="Red"/>
</StackPanel>
</Border>
<Border
SnapsToDevicePixels="True"
Margin="10" BorderThickness="1" BorderBrush="Black" Height="80"
Background="White">
<StackPanel Height="100.0">
<Rectangle Width="20" Height="20" Fill="Red"/>
<Rectangle Width="20" Height="20" Fill="Red"/>
<Rectangle Width="20" Height="20" Fill="Red"/>
<Rectangle Width="20" Height="20" Fill="Red"/>
</StackPanel>
</Border>
</StackPanel>
<!-- Background Grid -->
<Page.Background>
<DrawingBrush Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Page.Background>
</Page>

MCT: Luis Dueas

Pag 432 de 445

Manual de Windows Presentation Foundation


Observe que en los rectngulos ajustados no se estable explcitamente un valor para la propiedad
SnapsToDevicePixels. nicamente se necesita establecer la propiedad en true en la raz para habilitar el
comportamiento en todos los elementos secundarios.
Texto
Windows Presentation Foundation (WPF) siempre genera el texto con suavizado (anti-aliasing) y, si es esttico,
se le aplica ajuste de pxeles. Esto ayuda a dar un aspecto ms ntido al texto con suavizado, al situar los glifos
directamente en la cuadrcula de pxeles, lo que proporciona un texto ms claro. Sin embargo, cuando Windows
Presentation

Foundation

(WPF)

detecta

cualquier

movimiento

similar

una

animacin,

como

un

desplazamiento, un ajuste de escala o una conversin animada, el ajuste de pxeles se desactiva hasta que se
completa el movimiento. Cuando la animacin o el movimiento de desplazamiento termina, se vuelve a animar
lentamente el ajuste de pxeles.
Lneas de gua
Bsicamente, el ajuste de pxeles se controla mediante lneas de gua. Las lneas de gua ayudan a ajustar las
geometras a una cuadrcula de pxeles del dispositivo. En la mayora de los casos, el ajuste de pxeles mediante
la propiedad SnapsToDevicePixels da lugar al resultado deseado. Sin embargo, esta propiedad no siempre est
disponible, sobre todo cuando se utilizan objetos Drawing o se trata directamente con un DrawingContext; en
estos casos es preciso establecer lneas de gua para lograr la nitidez deseada que el ajuste de pxeles
proporciona.
Para establecer las lneas de gua en los objetos Drawing y DrawingContext, se utiliza la clase GuidelineSet.
Esta clase permite crear lneas de gua horizontales y verticales que se pueden aplicar a DrawingGroup o se
puedan insertar en DrawingContext para los comandos de dibujo subsiguientes. Las lneas de gua indican al
dibujo qu lneas se deben ajustar a un pxel del dispositivo.
Las lneas de gua tambin se pueden establecer en el nivel de los objetos Visual cambiando las colecciones de
lneas

de

gua

horizontales

verticales.

Se

tiene

acceso

ellas

travs

de

las

propiedades

VisualYSnappingGuidelines y VisualXSnappingGuidelines.
Imgenes de mapa de bits
Debido al carcter independiente de dpi de WPF, las interfaz de usuario basadas en mapas de bits pueden dar
lugar a resultados de presentacin no deseados. Las escenas con suavizado (anti-aliasing) pueden emborronar
una imagen a causa de los problemas de alineacin de los pxeles fraccionarios. Esto se cumple en particular
para las imgenes que contienen cambios de alta frecuencia, tales como las lneas de un solo pxel con
elementos adyacentes en contraste (como lneas negras y blancas alternas). En la ilustracin siguiente se
muestran las diferencias de calidad de imagen de una imagen alineada (izquierda) y una imagen desplazada de
modo que no est alineada con los pxeles del dispositivo (derecho).
Alineacin de la imagen con los pxeles del dispositivo.

Un escenario comn para las imgenes de una interfaz de usuario es centrar una imagen que representa un
icono dentro de otro objeto. Dado que los iconos suelen ser imgenes pequeas con cambios de alta frecuencia,
puede ser preciso ajustar el diseo de la aplicacin para evitar las anomalas visuales generadas por el
suavizado (anti-aliasing).
Para centrar correctamente una imagen, el contenedor debe tener un ancho y un alto pares si el ancho y el alto
en pxeles de la imagen son pares. Si el ancho y el alto de la imagen son impares, el ancho y el alto del
elemento contenedor tambin debern ser impares.

MCT: Luis Dueas

Pag 433 de 445

Manual de Windows Presentation Foundation


En el ejemplo siguiente se crean dos objetos Border que contienen una Image. El borde superior tiene un ancho
y un alto pares, para coincidir con los de la imagen. El borde inferior tiene un ancho y un alto impares.
En la ilustracin siguiente se muestra el resultado del ejemplo y el efecto que tiene el tamao del contenedor
en la imagen.

<Page x:Class="PixelSnapping.Images"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Images">
<StackPanel>
<!-- Image has a pixel dimension of 144x96. -->
<!-- Because the image has a even width and height,
an even border width and height allows the image to proper center.
-->
<Border HorizontalAlignment="Left" VerticalAlignment="Top" Width="200" Height="100">
<Image HorizontalAlignment="Center" VerticalAlignment="Center"
Source="sharpness.png" Stretch="None"/>
</Border>
<!-- Image has a pixel dimension of 144x96. -->
<!-- Because the image has a even width and height,
an odd border width and height causes the image to soften.
-->
<Border HorizontalAlignment="Left" VerticalAlignment="Top" Width="201" Height="101">
<Image HorizontalAlignment="Center" VerticalAlignment="Center"
Source="sharpness.png" Stretch="None"/>
</Border>
</StackPanel>
<!-- Grid Background -->
<Page.Background>
<DrawingBrush Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="White">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="0,0,1,1" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z " Brush="#CCCCFF" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="#CCCCFF" />
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Page.Background>
</Page>
Por desgracia, la alineacin con los pxeles del dispositivo no se garantiza con slo ajustar el tamao del objeto
contenedor. El diseo de la aplicacin en su conjunto puede afectar a la alineacin de la imagen. El valor de
puntos por pulgada (dpi) de pantalla tambin afecta a la alineacin de las imgenes. En el ejemplo anterior, la
alineacin de la imagen funcionar nicamente si la pantalla est establecida en 96 puntos por pulgada (dpi).
Con cualquier otra configuracin, deber ajustarse el diseo a fin de alojar la configuracin de pantalla.
Siempre que sea posible, deben evitarse las imgenes de alta frecuencia en las aplicaciones de Windows
Presentation Foundation (WPF).

3.12. Modelo de Subprocesos


Windows Presentation Foundation (WPF) se ha diseado para ahorrar a los programadores las dificultades de
los subprocesos. Como resultado, la mayora de los programadores de WPF no tendrn que escribir una interfaz
que utilice ms de un subproceso. Dado que los programas con subprocesos son complejos y difciles de
depurar, se deben evitar cuando existan soluciones de un nico subproceso.
No importa cmo est de bien estructurado, no obstante, ningn marco de trabajo de interfaz de usuario podr
ofrecer siempre una solucin de un nico subproceso para todo tipo de problemas. WPF se acerca, pero hay

MCT: Luis Dueas

Pag 434 de 445

Manual de Windows Presentation Foundation


todava situaciones en las que varios subprocesos mejorarn la capacidad de respuesta de la interfaz de usuario
(UI) o el rendimiento de la aplicacin. Despus de explicar algunos temas bsicos, este documento explora
algunas de estas situaciones y, a continuacin, concluye con una explicacin de algunos detalles de ms bajo
nivel.
Informacin general y el distribuidor
Habitualmente, las aplicaciones de WPF se inician con dos subprocesos: uno para administrar la representacin
y otro para administrar la interfaz de usuario. El subproceso de representacin se ejecuta realmente de forma
oculta en segundo plano, mientras que el subproceso de la interfaz de usuario recibe la entrada, administra los
eventos, pinta la pantalla y ejecuta el cdigo de aplicacin. La mayora de las aplicaciones utilizan un nico
subproceso de interfaz de usuario, aunque en algunas situaciones es mejor utilizar varios. Lo explicaremos
despus con un ejemplo.
El subproceso de interfaz de usuario pone en la cola los elementos de trabajo dentro de un objeto denominado
Dispatcher. Dispatcher selecciona los elementos de trabajo en funcin de la prioridad y ejecuta cada uno hasta
que se completan. Cada subproceso de la interfaz de usuario debe tener al menos un objeto Dispatcher, y cada
Dispatcher puede ejecutar elementos de trabajo en exactamente un subproceso.
El truco para generar aplicaciones eficaces y fciles de usar es maximizar el rendimiento de Dispatcher
manteniendo pequeo el tamao de los elementos de trabajo. De este modo, los elementos nunca quedan
obsoletos en la cola Dispatcher a la espera de ser procesados. Cualquier retraso perceptible entre la entrada y
la respuesta puede frustrar a un usuario.
Cmo se supone, entonces, que las aplicaciones WPF administran grandes operaciones? Qu ocurre si el
cdigo

implica

un

clculo

grande

necesita

consultar

una

base

de

datos

de

algn

servidor

remoto? Normalmente, la respuesta es administrar la operacin grande en un subproceso independiente,


dejando el subproceso de la interfaz de usuario libre para ocuparse de los elementos de la cola de
Dispatcher. Cuando la operacin grande se haya completado, puede informar de su resultado al subproceso de
la interfaz de usuario para la presentacin.
Histricamente, Windows solamente permite obtener acceso a los elementos de la interfaz de usuario al
subproceso que los cre. Esto significa que un subproceso de fondo a cargo de alguna tarea de ejecucin
prolongada no podr actualizar un cuadro de texto cuando se haya completado. Windows lo hace as para
garantizar la integridad de los componentes de la interfaz de usuario. Un cuadro de lista puede parecer extrao
si un subproceso de fondo actualiza su contenido durante la presentacin.
WPF tiene un mecanismo de exclusin mutua integrado que exige esta coordinacin. La mayora de las clases
de WPF se derivan de DispatcherObject. En la construccin, un objeto DispatcherObject almacena una
referencia al objeto Dispatcher vinculado al subproceso actualmente en ejecucin. En efecto, DispatcherObject
se asocia al subproceso que lo crea. Durante la ejecucin de programas, un objeto DispatcherObject puede
llamar a su mtodo pblico VerifyAccess. VerifyAccess examina el objeto Dispatcher asociado al subproceso
actual y lo compara con la referencia Dispatcher almacenada durante la construccin. Si no coinciden,
VerifyAccess inicia una excepcin. VerifyAccess est destinado a ser llamado al principio de cada mtodo
perteneciente a un objeto DispatcherObject.
Si solamente un subproceso puede modificar la interfaz de usuario, cmo interactan con el usuario los
subprocesos de fondo? Un subproceso de fondo puede pedir al subproceso de la interfaz de usuario que realice
una operacin en su nombre. Lo hace registrando un elemento de trabajo con el objeto Dispatcher del
subproceso de la interfaz de usuario. La clase Dispatcher proporciona dos mtodos para registrar elementos de
trabajo: Invoke y BeginInvoke. Ambos mtodos programan un delegado para la ejecucin. Invoke es una
llamada sincrnica, es decir, no vuelve hasta que el subproceso de la interfaz de usuario termina realmente de
ejecutar el delegado. BeginInvoke es asincrnico y vuelve inmediatamente.

MCT: Luis Dueas

Pag 435 de 445

Manual de Windows Presentation Foundation


El objeto Dispatcher ordena los elementos de la cola por prioridad. Hay diez niveles que se puede especificar al
agregar un elemento a la cola Dispatcher. Estas prioridades se mantienen en la enumeracin DispatcherPriority.
Subprocesos en accin: ejemplos
Una aplicacin de un nico subproceso con un clculo de ejecucin prolongada
La mayora de las interfaces grficas de usuario (GUIs) emplean una gran parte de su tiempo inactivo
esperando eventos generados en respuesta a las interacciones con el usuario Con una programacin cuidadosa,
este tiempo de inactividad se puede usar constructivamente, sin que afecte a la capacidad de respuesta de la
interfaz de usuario. El modelo de subprocesos de WPF no permite que la entrada interrumpa una operacin que
ocurra en el subproceso de la interfaz de usuario. Esto significa que debe asegurarse de volver peridicamente
al objeto Dispatcher para procesar los eventos de entrada pendientes antes de que queden obsoletos.
Considere el ejemplo siguiente:

Esta sencilla aplicacin cuenta en orden ascendente desde tres, buscando nmeros primos. Cuando el usuario
hace clic en el botn Inicio, la bsqueda comienza. Cuando el programa encuentra un nmero primo, actualiza
la interfaz de usuario con su deteccin. En cualquier punto, el usuario puede detener la bsqueda.
Aunque es bastante simple, la bsqueda de nmeros primos podra continuar para siempre, lo que presenta
algunas dificultades. Si administrramos toda la bsqueda completa dentro del controlador del evento clic del
botn, nunca daramos al subproceso de la interfaz de usuario la oportunidad de administrar otros eventos. La
interfaz de usuario no podra responder a entradas ni mensajes del proceso. Nunca actualizara la pantalla ni
respondera a clics del mouse.
Podramos realizar la bsqueda de nmeros primos en un subproceso independiente, pero entonces
encontraramos problemas de sincronizacin. Con un enfoque de un nico subproceso, podemos actualizar
directamente la etiqueta que muestra el mayor nmero encontrado.
Si dividimos la tarea de clculo en fragmentos manejables, podemos volver peridicamente a los eventos de
Dispatcher y de proceso Podemos dar una oportunidad a WPF para que vuelva a dibujar y procesar la entrada.
La mejor forma de dividir el tiempo de proceso entre el clculo y el control de eventos es administrar el clculo
desde el objeto Dispatcher. Utilizando el mtodo BeginInvoke, podemos programar las comprobaciones de
nmeros primos en la misma cola de la que se extraen los eventos de la interfaz de usuario. En nuestro
ejemplo, programamos solamente una comprobacin de nmero primo cada vez. Una vez completada la
comprobacin del primer nmero primo, programamos inmediatamente la siguiente comprobacin. Esta
comprobacin slo contina una vez administrados los eventos de la interfaz de usuario pendientes.

MCT: Luis Dueas

Pag 436 de 445

Manual de Windows Presentation Foundation

Microsoft Word realiza la revisin ortogrfica mediante este mecanismo. La revisin ortogrfica se hace en
segundo plano utilizando el tiempo de inactividad del subproceso de la interfaz de usuario. Echemos una mirada
al cdigo.
En el ejemplo siguiente se muestra el XAML que crea la interfaz de usuario.
<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Prime Numbers" Width="260" Height="75">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" >
<Button Content="Start" Click="StartOrStop" Name="startStopButton"
Margin="5,0,5,0"/>
<TextBlock Margin="10,5,0,0">Biggest Prime Found:</TextBlock>
<TextBlock Name="bigPrime" Margin="4,5,0,0">3</TextBlock>
</StackPanel>
</Window>
En el cdigo siguiente se muestra el cdigo subyacente:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Threading;
namespace SDKSamples
{
public partial class Window1 : Window
{
public delegate void NextPrimeDelegate();
//Current number to check
private long num = 3;
private bool continueCalculating = false;
public Window1() : base()
{
InitializeComponent();
}
private void StartOrStop(object sender, EventArgs e)
{
if (continueCalculating)
{
continueCalculating = false;
startStopButton.Content = "Resume";
}
else
{
continueCalculating = true;
startStopButton.Content = "Stop";
startStopButton.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
new NextPrimeDelegate(CheckNextNumber));
}
}
public void CheckNextNumber()
{
// Reset flag.
NotAPrime = false;
for (long i = 3; i <= Math.Sqrt(num); i++)
{
if (num % i == 0)
{
// Set not a prime flag to ture.
NotAPrime = true;
break;
}
}
// If a prime number.
if (!NotAPrime)
{
bigPrime.Text = num.ToString();
}
num += 2;
if (continueCalculating)

MCT: Luis Dueas

Pag 437 de 445

Manual de Windows Presentation Foundation


{
startStopButton.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.SystemIdle,
new NextPrimeDelegate(this.CheckNextNumber));
}
}
private bool NotAPrime = false;
}
}
En el ejemplo siguiente se muestra el controlador de evento para el control Button.
private void StartOrStop(object sender, EventArgs e)
{
if (continueCalculating)
{
continueCalculating = false;
startStopButton.Content = "Resume";
}
else
{
continueCalculating = true;
startStopButton.Content = "Stop";
startStopButton.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new NextPrimeDelegate(CheckNextNumber));
}
}
Adems de actualizar el texto del control Button, este controlador es responsable de programar la primera
comprobacin de nmero primo agregando un delegado a la cola de Dispatcher. En algn momento despus de
que este controlador de eventos haya completado su trabajo, Dispatcher seleccionar este delegado para la
ejecucin.
Como mencionamos anteriormente, BeginInvoke es el miembro Dispatcher que se utiliza para programar un
delegado para la ejecucin. En este caso, elegimos la prioridad SystemIdle. El objeto Dispatcher solamente
ejecutar este delegado cuando no haya ningn evento importante por procesar. La capacidad de respuesta de
la interfaz de usuario es ms importante que la comprobacin de nmeros. Tambin pasamos un nuevo
delegado que representa la rutina de la comprobacin de nmeros.
public void CheckNextNumber()
{
// Reset flag.
NotAPrime = false;
for (long i = 3; i <= Math.Sqrt(num); i++)
{
if (num % i == 0)
{
// Set not a prime flag to ture.
NotAPrime = true;
break;
}
}
// If a prime number.
if (!NotAPrime)
{
bigPrime.Text = num.ToString();
}
num += 2;
if (continueCalculating)
{
startStopButton.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.SystemIdle,
new NextPrimeDelegate(this.CheckNextNumber));
}
}
private bool NotAPrime = false;
Este mtodo comprueba si el siguiente nmero impar es primo. Si es primo, el mtodo actualiza directamente
el controlbigPrimeTextBlock para que refleje su deteccin. Podemos hacerlo porque el clculo se est
produciendo en el mismo subproceso que se utiliz para crear el componente. Si hubiramos decidido utilizar
un subproceso independiente para el clculo, tendramos que haber utilizado un mecanismo de sincronizacin
ms complicado y ejecutar la actualizacin en el subproceso de la interfaz de usuario. Mostraremos esta
situacin a continuacin.
Administrar una operacin de bloqueo con un subproceso de fondo
Administrar operaciones de bloqueo en una aplicacin grfica puede ser difcil. No es deseable llamar a mtodos
de bloqueo desde controladores de eventos, porque la aplicacin parecer congelarse. Podemos utilizar un
subproceso independiente para administrar estas operaciones, pero cuando terminemos, tendremos que

MCT: Luis Dueas

Pag 438 de 445

Manual de Windows Presentation Foundation


sincronizar con el subproceso de la interfaz de usuario porque no podemos modificar directamente la GUI desde
nuestro subproceso de trabajo. Podemos utilizar Invoke o BeginInvoke para insertar delegados en el objeto
Dispatcher del subproceso de la interfaz de usuario. En el futuro, estos delegados se ejecutarn con permiso
para modificar los elementos de la interfaz de usuario.
En este ejemplo, imitamos una llamada a procedimiento remoto que recupera un boletn meteorolgico.
Utilizamos un subproceso de trabajo independiente para ejecutar esta llamada y programamos un mtodo de
actualizacin en el objeto Dispatcher del subproceso interfaz de usuario cuando terminamos.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;
namespace SDKSamples
{
public partial class Window1 : Window
{
// Delegates to be used in placking jobs onto the Dispatcher.
private delegate void NoArgDelegate();
private delegate void OneArgDelegate(String arg);
// Storyboards for the animations.
private Storyboard showClockFaceStoryboard;
private Storyboard hideClockFaceStoryboard;
private Storyboard showWeatherImageStoryboard;
private Storyboard hideWeatherImageStoryboard;
public Window1(): base()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Load the storyboard resources.
showClockFaceStoryboard =
(Storyboard)this.Resources["ShowClockFaceStoryboard"];
hideClockFaceStoryboard =
(Storyboard)this.Resources["HideClockFaceStoryboard"];
showWeatherImageStoryboard =
(Storyboard)this.Resources["ShowWeatherImageStoryboard"];
hideWeatherImageStoryboard =
(Storyboard)this.Resources["HideWeatherImageStoryboard"];
}
private void ForecastButtonHandler(object sender, RoutedEventArgs e)
{
// Change the status image and start the rotation animation.
fetchButton.IsEnabled = false;
fetchButton.Content = "Contacting Server";
weatherText.Text = "";
hideWeatherImageStoryboard.Begin(this);
// Start fetching the weather forecast asynchronously.
NoArgDelegate fetcher = new NoArgDelegate(this.FetchWeatherFromServer);
fetcher.BeginInvoke(null, null);
}
private void FetchWeatherFromServer()

MCT: Luis Dueas

Pag 439 de 445

Manual de Windows Presentation Foundation


{
// Simulate the delay from network access.
Thread.Sleep(4000);
// Tried and true method for weather forecasting - random numbers.
Random rand = new Random();
String weather;
if (rand.Next(2) == 0)
{
weather = "rainy";
}
else
{
weather = "sunny";
}
// Schedule the update function in the UI thread.
tomorrowsWeather.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new OneArgDelegate(UpdateUserInterface), weather);
}
private void UpdateUserInterface(String weather)
{
//Set the weather image
if (weather == "sunny")
{
weatherIndicatorImage.Source = (ImageSource)this.Resources[
"SunnyImageSource"];
}
else if (weather == "rainy")
{
weatherIndicatorImage.Source = (ImageSource)this.Resources[
"RainingImageSource"];
}
//Stop clock animation
showClockFaceStoryboard.Stop(this);
hideClockFaceStoryboard.Begin(this);
//Update UI text
fetchButton.IsEnabled = true;
fetchButton.Content = "Fetch Forecast";
weatherText.Text = weather;
}
private void HideClockFaceStoryboard_Completed(object sender,
EventArgs args)
{
showWeatherImageStoryboard.Begin(this);
}
private void HideWeatherImageStoryboard_Completed(object sender,
EventArgs args)
{
showClockFaceStoryboard.Begin(this, true);
}

}
}
A continuacin se muestran algunos de los detalles que se deben tener en cuenta.

Crear el controlador del botn


private void ForecastButtonHandler(object sender, RoutedEventArgs e)
{
// Change the status image and start the rotation animation.
fetchButton.IsEnabled = false;
fetchButton.Content = "Contacting Server";
weatherText.Text = "";
hideWeatherImageStoryboard.Begin(this);
// Start fetching the weather forecast asynchronously.
NoArgDelegate fetcher = new NoArgDelegate(this.FetchWeatherFromServer);
fetcher.BeginInvoke(null, null);
}
Cuando se hace clic en el botn, se muestra el dibujo del reloj y se inicia su animacin. Deshabilitamos el
botn. Invocamos el mtodo FetchWeatherFromServer en un nuevo subproceso y a continuacin volvemos,
para permitir que el objeto Dispatcher procese los eventos mientras esperamos la llegada del boletn
meteorolgico.

Capturar la informacin meteorolgica


private void FetchWeatherFromServer()
{
// Simulate the delay from network access.
Thread.Sleep(4000);
// Tried and true method for weather forecasting - random numbers.
Random rand = new Random();
String weather;
if (rand.Next(2) == 0)
{

MCT: Luis Dueas

Pag 440 de 445

Manual de Windows Presentation Foundation


weather = "rainy";
}
else
{
weather = "sunny";
}
// Schedule the update function in the UI thread.
tomorrowsWeather.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.Normal,
new OneArgDelegate(UpdateUserInterface), weather);
}
Para mantener las cosas simples, en este ejemplo no tenemos realmente ningn cdigo de conexin de red. En
su lugar, simulamos el retraso de acceso de red haciendo que nuestro nuevo subproceso espere durante cuatro
segundos. En este tiempo, el subproceso de la interfaz de usuario original contina ejecutndose y
respondiendo a eventos. Para mostrarlo, hemos dejado la animacin ejecutndose y los botones maximizar y
minimizar tambin continan funcionando.

Actualizar la interfaz de usuario


private void UpdateUserInterface(String weather)
{
//Set the weather image
if (weather == "sunny")
{
weatherIndicatorImage.Source = (ImageSource)this.Resources[
"SunnyImageSource"];
}
else if (weather == "rainy")
{
weatherIndicatorImage.Source = (ImageSource)this.Resources[
"RainingImageSource"];
}
//Stop clock animation
showClockFaceStoryboard.Stop(this);
hideClockFaceStoryboard.Begin(this);
//Update UI text
fetchButton.IsEnabled = true;
fetchButton.Content = "Fetch Forecast";
weatherText.Text = weather;
}
Cuando el objeto Dispatcher del subproceso de la interfaz de usuario tiene tiempo, ejecuta la llamada
programada a UpdateUserInterface. Este mtodo detiene la animacin del reloj y elige una imagen que describa
la informacin meteorolgica. Muestra esta imagen y restaura el botn "fetch forecast" (capturar previsin).
Varias ventanas, varios subprocesos
Algunas aplicaciones de WPF requieren varias ventanas de nivel superior. Es absolutamente aceptable que una
combinacin de subproceso/Dispatcher administre varias ventanas, pero hay ocasiones en las que varios
subprocesos funcionarn mejor. Esto es especialmente cierto si existe alguna oportunidad de que una de las
ventanas monopolice el subproceso.
El Explorador de Windows funciona de este modo. Cada nueva ventana del Explorador pertenece al proceso
original, pero se crea bajo el control de un subproceso independiente.
Utilizando un control Frame de WPF, podemos mostrar pginas web. Podemos crear fcilmente un sustituto
sencillo de Internet Explorer. Empezamos con una caracterstica importante: la capacidad de abrir una nueva
ventana del explorador. Cuando el usuario hace clic en el botn "new window" (nueva ventana), iniciamos una
copia de nuestra ventana en un subproceso independiente. De este modo, las operaciones de ejecucin
prolongada o de bloqueo de una de las ventanas no bloquearn todas las otras ventanas.
En realidad, el modelo del explorador web tiene su propio y complicado modelo de subprocesos. Lo hemos
elegido porque debe resultar conocido para la mayora de los lectores.
En el ejemplo siguiente se muestra el cdigo.
<Window x:Class="SDKSamples.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MultiBrowse" Height="600" Width="800" Loaded="OnLoaded">
<StackPanel Name="Stack" Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Button Content="New Window"

MCT: Luis Dueas

Pag 441 de 445

Manual de Windows Presentation Foundation


Click="NewWindowHandler" />
<TextBox Name="newLocation"
Width="500" />
<Button Content="GO!"
Click="Browse" />
</StackPanel>
<Frame Name="placeHolder"
Width="800"
Height="550"></Frame>
</StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Threading;
using System.Threading;
namespace SDKSamples
{
public partial class Window1 : Window
{
public Window1() : base()
{
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
placeHolder.Source = new Uri("http://www.msn.com");
}
private void Browse(object sender, RoutedEventArgs e)
{
placeHolder.Source = new Uri(newLocation.Text);
}
private void NewWindowHandler(object sender, RoutedEventArgs e)
{
Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}
private void ThreadStartingPoint()
{
Window1 tempWindow = new Window1();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
}
}
Los siguientes segmentos de subprocesamiento de este cdigo son los ms interesantes para nosotros en este
contexto:
private void NewWindowHandler(object sender, RoutedEventArgs e)
{
Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
}
Se llama a este mtodo cuando se hace clic en el botn "new window". Crea un nuevo subproceso y lo inicia de
forma asincrnica.
private void ThreadStartingPoint()
{
Window1 tempWindow = new Window1();
tempWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}
Este mtodo es el punto inicial para el nuevo subproceso. Creamos una nueva ventana bajo el control de este
subproceso.

WPF

crea

automticamente

un

nuevo

objeto

Dispatcher

para

administrar

el

nuevo

subproceso. Todo lo que tenemos que hacer para que la ventana sea funcional es iniciar el objeto Dispatcher.
Detalles tcnicos y puntos problemticos
Escribir componentes usando subprocesos
La Gua del desarrollador de Microsoft .NET Framework describe un modelo de cmo un componente puede
exponer comportamiento asincrnico a sus clientes. Por ejemplo, suponga que deseamos empaquetar el
mtodo FetchWeatherFromServer en un componente reutilizable, no grfico. Siguiendo el modelo de Microsoft
.NET Framework estndar, tendra un aspecto similar al siguiente.
public class WeatherComponent : Component

MCT: Luis Dueas

Pag 442 de 445

Manual de Windows Presentation Foundation


{

//gets weather: Synchronous


public string GetWeather()
{
string weather = "";
//predict the weather
return weather;
}
//get weather: Asynchronous
public void GetWeatherAsync()
{
//get the weather
}
public event GetWeatherCompletedEventHandler GetWeatherCompleted;

public class GetWeatherCompletedEventArgs : AsyncCompletedEventArgs


{
public GetWeatherCompletedEventArgs(Exception error, bool canceled,
object userState, string weather)
:
base(error, canceled, userState)
{
_weather = weather;
}
public string Weather
{
get { return _weather; }
}
private string _weather;
}
public delegate void GetWeatherCompletedEventHandler(object sender,
GetWeatherCompletedEventArgs e);
GetWeatherAsync utilizara una de las tcnicas antes descritas, tal como crear un subproceso de fondo para
hacer el trabajo de forma asincrnica, sin bloquear el subproceso de llamada.
Una de las partes ms importantes de este modelo es la llamada al mtodo MethodNameCompleted en el
mismo subproceso que llam al mtodo MethodNameAsync para comenzar. Podra hacerlo con bastante
facilidad con WPF, almacenando CurrentDispatcher; sin embargo, el componente no grfico solamente se podra
utilizar en aplicaciones de WPF, no en programas de formularios Windows Forms o ASP.NET.
La clase DispatcherSynchronizationContext soluciona esta necesidad; piense en ella como en una versin
simplificada de Dispatcher que tambin funciona con otros marcos de interfaz de usuario.
public class WeatherComponent2 : Component
{
public string GetWeather()
{
return fetchWeatherFromServer();
}
private DispatcherSynchronizationContext requestingContext = null;
public void GetWeatherAsync()
{
if (requestingContext != null)
throw new InvalidOperationException("This component can only handle 1 async
request at a time");
requestingContext =
(DispatcherSynchronizationContext)DispatcherSynchronizationContext.Current;
NoArgDelegate fetcher = new NoArgDelegate(this.fetchWeatherFromServer);
// Launch thread
fetcher.BeginInvoke(null, null);
}
private void RaiseEvent(GetWeatherCompletedEventArgs e)
{
if (GetWeatherCompleted != null) GetWeatherCompleted(this, e);
}
private string fetchWeatherFromServer()
{
// do stuff
string weather = "";
GetWeatherCompletedEventArgs e =
new GetWeatherCompletedEventArgs(null, false, null, weather);
SendOrPostCallback callback = new SendOrPostCallback(DoEvent);
requestingContext.Post(callback, e);
requestingContext = null;
return e.Weather;
}
private void DoEvent(object e)
{
//do stuff
}
public event GetWeatherCompletedEventHandler GetWeatherCompleted;

MCT: Luis Dueas

Pag 443 de 445

Manual de Windows Presentation Foundation


public delegate string NoArgDelegate();
}
Bombeo anidado
A veces no es factible bloquear completamente el subproceso de la interfaz de usuario. Consideremos el
mtodo Show de la clase MessageBox. Show no vuelve hasta que el usuario hace clic en el Aceptar. Sin
embargo, crea una ventana que debe tener un bucle de mensajes para ser interactiva. Mientras estamos
esperando a que el usuario haga clic en Aceptar, la ventana de la aplicacin original no responde a la entrada
del usuario. No obstante, contina procesando los mensajes de actualizacin de la pantalla. La ventana original
se redibuja cuando se cubre y se revela.

Algn subproceso debe estar a cargo de la ventana de cuadro de mensaje. WPF podra crear simplemente un
nuevo subproceso para la ventana de cuadro de mensaje, pero este subproceso no podra representar los
elementos deshabilitados en la ventana original (recuerde la explicacin anterior sobre la exclusin mutua). En
su lugar, WPF utiliza un sistema de procesado de mensajes anidados. La clase Dispatcher incluye un mtodo
especial denominado PushFrame, que almacena el punto de ejecucin actual de una aplicacin y, a
continuacin, comienza un nuevo bucle de mensajes. Cuando finaliza el bucle de mensajes anidados, la
ejecucin se reanuda despus de la llamada original a PushFrame.
En este caso, PushFrame mantiene el contexto de programa en la llamada a MessageBox.Show e inicia un
nuevo bucle de mensajes para actualizar la ventana de fondo y administrar la entrada en la ventana de cuadro
de mensaje. Cuando el usuario hace clic en Aceptar y borra la ventana emergente, se sale del bucle anidado y
se reanuda el control despus de la llamada a Show.
Eventos enrutados obsoletos
El sistema de eventos enrutados de WPF notifica a los rboles completos cuando se provoca algn evento.
<Canvas MouseLeftButtonDown="handler1" Width="100" Height="100">
<Ellipse Width="50" Height="50" Fill="Blue" Canvas.Left="30" Canvas.Top="50"
MouseLeftButtonDown="handler2"/>
</Canvas>
Cuando se presiona el botn primario del mouse sobre la elipse, se ejecuta handler2. Cuando finaliza handler2,
el evento se pasa al objeto Canvas, que utiliza handler1 para procesarlo. Esto solamente pasa si handler2 no
marca explcitamente el objeto de evento como administrado.
Es posible que handler2 tarde mucho tiempo en procesar este evento. handler2 podra utilizar PushFrame para
iniciar un bucle de mensajes anidado que no volviera durante horas. Si handler2 no marca el evento como
administrado cuando finaliza este bucle de mensajes, el evento se pasa al rbol aunque sea muy antiguo.
Volver a entrar y bloqueo
El mecanismo de bloqueo de common language runtime (CLR) no se comporta exactamente como se podra
imaginar; podra esperarse que un subproceso cesara completamente de funcionar al solicitar un bloqueo. En
realidad, el subproceso contina recibiendo y procesando mensajes de alta prioridad. Esto ayuda a evitar
interbloqueos y minimiza la sensibilidad de las interfaces, pero introduce la posibilidad de errores sutiles.
Durante la mayor parte del tiempo no necesitar saber nada sobre esto pero, en raras circunstancias (que
habitualmente implican mensajes de ventanas de Win32 o componentes COM STA) puede merecer la pena
conocer este tema.
La mayora de las interfaces no se han creado pensando en la seguridad de los subprocesos, porque los
programadores trabajan partiendo del supuesto de que nunca habr ms de un subproceso con acceso a la
interfaz de usuario. En este caso, ese subproceso nico puede modificar el entorno en momentos inesperados,

MCT: Luis Dueas

Pag 444 de 445

Manual de Windows Presentation Foundation


produciendo

efectos

indeseables

que

el

mecanismo

de

exclusin

mutua

de

DispatcherObject

debe

resolver. Considere el siguiente pseudocdigo:

La mayor parte del tiempo es correcto, pero hay momentos en WPF en los que tal vuelta a entrar inesperada
realmente puede causar problemas. Por lo tanto, en ciertos momentos clave, WPF llama a DisableProcessing,
que cambia la instruccin de bloqueo para que ese subproceso utilice el bloqueo sin vuelta a entrar de WPF, en
lugar del bloqueo CLRhabitual.
Entonces, por qu el equipo de CLR eligi este comportamiento? Tena que ver con los objetos COM STA y el
subproceso de finalizacin. Cuando un objeto se somete a la recopilacin de elementos no utilizados, su mtodo
Finalize se ejecuta en el subproceso finalizador dedicado, no en el subproceso de la interfaz de usuario. Ah
reside el problema, porque un objeto COM STA creado en el subproceso de la interfaz de usuario slo se puede
desechar en el subproceso de la interfaz de usuario. CLR realiza el equivalente de BeginInvoke) (en este caso
utilizando el mtodo SendMessage de Win32. Sin embargo, si el subproceso de la interfaz de usuario est
ocupado, el subproceso finalizador se atasca y no se puede desechar el objeto COM STA, lo que crea una grave
prdida de memoria. En consecuencia, el equipo de CLR tom esta decisin para que los bloqueos funcionaran
como lo hacen.
La tarea de WPF es evitar que se vuelva a entrar de forma inesperada sin reintroducir la prdida de memoria,
que es el motivo por el que no bloqueamos la vuelta a entrar en todas partes.

MCT: Luis Dueas

Pag 445 de 445

Vous aimerez peut-être aussi