137
Programación en .Net (Avanzado) WPF

Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

  • Upload
    soyhyo

  • View
    1.093

  • Download
    62

Embed Size (px)

Citation preview

Page 1: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

Programación en .Net (Avanzado) WPF

Page 2: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

2

MARÍA TERESA CRESPI NOIR

PROGRAMACIÓN EN .NET

(AVANZADO) - MANUAL

WPF

Buffa Sistemas S.R.L

2010

Buenos Aires

Page 3: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

3

Programación en .Net (Avanzado) - Manual WPF Crespi Noir, María Teresa 1a Edición Buffa Sistemas SRL Alsina 655 4° Piso Buenos Aires ISBN Nº 978-987-25214-2-4 Multigraphic Avenida Belgrano 520 – Capital Federal 10 de agosto de 2010

Crespi Noir, María Teresa Programación en .Net (Avanzado) - Manual WPF Buenos Aires : Buffa Sistemas S.R.L., 2010. 307 p. ; 21 x 29,7 cm. ISBN 978-987-25214-2-4

(c), 2010 Buffa Sistemas SRL Queda hecho el depósito que establece la Ley 11.723. Libro de edición Argentina No se permite la reproducción parcial o total, el almacenamiento, el alquiler, la transmisión o la transformación de este libro, en cualquier forma o por cualquier medio, sea electrónico o mecánico, mediante fotocopias, digitalización u otros métodos, sin el permiso previo y escrito del editor.Su infracción está penada por las leyes 11723 y 25446.-

Page 4: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

4

Windows Presentation Foundation

(WPF)

Page 5: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

5

NOTA: El material incluido en el presente puede contener datos y ejemplos extraídos de sitios web públicos sin restricción de acceso. Los mismos son utilizados solamente a fines didácticos y pueden encontrarse en el final de la publicación agrupados bajo el título Links Relacionados.

Page 6: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

6

MÓDULO 1 : INTRODUCCIÓN A WPF ..................................................................................... 12

1- Introducción........................................................................................................................... 13 Definición ................................................................................................................................ 13 Programar con WPF ............................................................................................................... 13 Código de lenguaje marcado y código subyacente ................................................................ 13 XAML ...................................................................................................................................... 13 Código Subyacente ................................................................................................................. 14 Aplicaciones WPF ................................................................................................................... 15 Seguridad ................................................................................................................................ 15

2- Conceptos Básicos ............................................................................................................... 15 Controles ................................................................................................................................. 15 Diseño ..................................................................................................................................... 15 Enlace de Datos ...................................................................................................................... 16 Gráficos ................................................................................................................................... 16 Formas 2D .............................................................................................................................. 17 Geometrías 2D ........................................................................................................................ 17 Efectos 2D ............................................................................................................................... 17 Representaciones 3D.............................................................................................................. 17 Animaciones ............................................................................................................................ 17 Multimedia ............................................................................................................................... 17 Texto y Tipografía ................................................................................................................... 18 Documentos ............................................................................................................................ 18 Anotaciones ............................................................................................................................ 18 Empaquetado .......................................................................................................................... 18 Impresión ................................................................................................................................ 18 Personalización ....................................................................................................................... 19

3- Eventos y Comandos ............................................................................................................ 20 Información general sobre Eventos Enrutados ....................................................................... 20 Árboles de elementos WPF .................................................................................................... 21 Enrutamiento de eventos ........................................................................................................ 22 Eventos enrutados y composición .......................................................................................... 22 Eventos adjuntos ..................................................................................................................... 23 Información general sobre Comandos enrutados ................................................................... 23 Enrutamiento de comandos .................................................................................................... 25 Definición de comandos .......................................................................................................... 25 Desafíos de los comandos enrutados..................................................................................... 25

MÓDULO 2: CREANDO APLICACIONES WPF ........................................................................ 26

1- Crear una aplicación WFP .................................................................................................... 27 Aplicación WPF ....................................................................................................................... 27 Clase Window ......................................................................................................................... 28 Configurar la ventana de inicio ............................................................................................... 28 Propiedades de la Clase Window ........................................................................................... 29 Controles WPF y su equivalente con Controles Windows Forms .......................................... 29 Controladores de Eventos ...................................................................................................... 31 Recursos ................................................................................................................................. 32 Recursos Estáticos y Dinámicos ............................................................................................. 32

Page 7: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

7

2- Controles de Diseño ............................................................................................................. 33 Sistema de Diseño de Interfase de Usuario ........................................................................... 33 Border ..................................................................................................................................... 34 Canvas .................................................................................................................................... 34 DockPanel ............................................................................................................................... 35 Grid.......................................................................................................................................... 36 StackPanel .............................................................................................................................. 37 GroupBox ................................................................................................................................ 37 Expander ................................................................................................................................. 38 InkCanvas ............................................................................................................................... 38 Menu ....................................................................................................................................... 39 Frame ...................................................................................................................................... 39 WrapPanel .............................................................................................................................. 40

3- Otros Controles ..................................................................................................................... 41 Label - AccessText.................................................................................................................. 41 TextBox ................................................................................................................................... 41 TextBlock ................................................................................................................................ 41 Button ...................................................................................................................................... 41 ListBox - ComboBox ............................................................................................................... 42 CheckBox ................................................................................................................................ 43 RadioButton ............................................................................................................................ 43 Otros Controles ....................................................................................................................... 44

4- Información General de Controles ...................................................................................... 45 Propiedades Generales de los Controles ............................................................................... 45 Creación dinámica de controles .............................................................................................. 45

MÓDULO 3: PERSONALIZANDO LA APARIENCIA DE APLICACIONES WPF .................... 47

1- Personalizar Apariencia ....................................................................................................... 48 Composición ........................................................................................................................... 48 Estilos ...................................................................................................................................... 48 Plantillas .................................................................................................................................. 50 Desencadenadores (Triggers) ................................................................................................ 52

2- Crear Controles de Usuario ................................................................................................. 54 Controles ................................................................................................................................. 54 Controles de Usuario .............................................................................................................. 54 Personalizando Controles de Usuario .................................................................................... 56 Controles Personalizados ....................................................................................................... 57

MÓDULO 4: ENLACE A DATOS ............................................................................................... 58

1- Enlazar Datos......................................................................................................................... 59 Enlace a Datos ........................................................................................................................ 59 Clase Binding ......................................................................................................................... 59 Modos de Enlazar – Propiedad Mode..................................................................................... 59 Momento del Enlace ............................................................................................................... 60 Propiedad Asociadas al Enlace de Datos ............................................................................... 61 Enlace entre Controles ........................................................................................................... 62 XmlDataProvider ..................................................................................................................... 63 ObjectDataProvider ................................................................................................................. 64

Page 8: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

8

MethodParameters.................................................................................................................. 65 DataTemplate .......................................................................................................................... 67 DataContext ............................................................................................................................ 68 Controles ListView - Gridview ................................................................................................. 69

2- Notificaciones de Cambio de Propiedad ............................................................................ 70 Interfase INotifyPropertyChanged ........................................................................................... 70

3- Convertir Datos ..................................................................................................................... 74 ValueConverters ..................................................................................................................... 74 Interfase IValueConverter ....................................................................................................... 74

4- Validar Datos ......................................................................................................................... 76 ValidationRules ....................................................................................................................... 76 Clase Binding.ValidationRule .................................................................................................. 77 IDataErrorInfo .......................................................................................................................... 79 ExceptionValidationRule ......................................................................................................... 81 DataErrorValidationRule ......................................................................................................... 81

MÓDULO 5: ENLACE A COLECCIONES ................................................................................. 82

1- Enlace a Colecciones ........................................................................................................... 83 Enlace a Colecciones.............................................................................................................. 83 Cómo implementar colecciones .............................................................................................. 83

2- Vistas de Colecciones .......................................................................................................... 86 Vistas de colecciones.............................................................................................................. 86 Cómo crear una vista .............................................................................................................. 86 Ordenar ................................................................................................................................... 86 Agrupar ................................................................................................................................... 87 Filtrar ....................................................................................................................................... 89 Punteros de elemento actual .................................................................................................. 91 Navegación de Colecciones ................................................................................................... 91

MÓDULO 6: ADMINISTRAR DOCUMENTOS ........................................................................... 93

1- Documentos........................................................................................................................... 94 Definición ................................................................................................................................ 94 Tipos de documentos .............................................................................................................. 94

2- Documentos Dinámicos (FlowDocuments) ........................................................................ 94 Definición ................................................................................................................................ 94 Contenedores para Documentos Dinámicos .......................................................................... 95 FlowDocumentScrollViewer .................................................................................................... 95 FlowDocumentPageViewer ..................................................................................................... 95 FlowDocumentReader ............................................................................................................ 96 Formateando Documentos Dinámicos.................................................................................... 96 Elementos en Bloque .............................................................................................................. 96 List ........................................................................................................................................... 97 Tabla ....................................................................................................................................... 98 Section .................................................................................................................................... 99 BlockUIContainer .................................................................................................................... 99 Elementos en Línea (Contenido dinámico) ........................................................................... 100

Page 9: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

9

3- Documentos Fijos ............................................................................................................... 101 Definición .............................................................................................................................. 101 PageContent ......................................................................................................................... 101 FixedPage ............................................................................................................................. 101 DocumentViewer ................................................................................................................... 102

4- Empaquetado e Impresión de Documentos ..................................................................... 104 Empaquetado ........................................................................................................................ 104 Empaquetar componentes .................................................................................................... 105 Documentos XPS (XPSDocument) ....................................................................................... 105 XpsDocumentWriter .............................................................................................................. 105 Impresión de Documentos .................................................................................................... 106

MÓDULO 7: GRÁFICOS, ANIMACIONES Y MULTIMEDIA ................................................... 107

1- Gráficos 2D .......................................................................................................................... 108 Dibujos y formas ................................................................................................................... 108 Shape .................................................................................................................................... 108 Propiedades de las formas ................................................................................................... 108 Drawing ................................................................................................................................. 109 Propiedad Clip ....................................................................................................................... 110 Brush ..................................................................................................................................... 110

2- Imágenes .............................................................................................................................. 112 Imágenes .............................................................................................................................. 112 Control Image ........................................................................................................................ 112 Girar, Convertir y Recortar Imágenes ................................................................................... 113 Expandir imágenes ............................................................................................................... 114 Pintar con imágenes ............................................................................................................. 115

3- Gráficos 3D .......................................................................................................................... 115 Viewport3D ............................................................................................................................ 115 Espacio de coordenadas 3D ................................................................................................. 116 Cámaras y proyecciones ...................................................................................................... 116 Elementos primitivos de modelo y malla............................................................................... 117 Materiales del Modelo ........................................................................................................... 118 Iluminar la escena ................................................................................................................. 118 Transformar modelos ............................................................................................................ 120 Animar modelos .................................................................................................................... 120 Transformaciones de Traslación ........................................................................................... 121 Transformaciones de Escala ................................................................................................ 123 Transformaciones de Giro .................................................................................................... 125

4- Multimedia............................................................................................................................ 127 Media API .............................................................................................................................. 127 Modos Media Playback ......................................................................................................... 127 SoundPlayer .......................................................................................................................... 128

MÓDULO 8: CONFIGURACIÓN Y DISTRIBUCIÓN ................................................................ 129

1- Configuración ...................................................................................................................... 130 Configurar Aplicaciones ........................................................................................................ 130 App.config ............................................................................................................................. 130

Page 10: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

10

Recuperando información de app.config .............................................................................. 132 Almacenar información en app.config en run-time .............................................................. 132

2- Distribución de Aplicaciones WPF .................................................................................... 132 XCopy ................................................................................................................................... 132 Microsoft Windows Installer .................................................................................................. 132 ClickOnce .............................................................................................................................. 133 Publicación ClickOnce .......................................................................................................... 133 Como Publicar ....................................................................................................................... 134 Comparación entre ClickOnce y Microsoft Windows Installer .............................................. 135

Links Relacionados ................................................................................................................. 137

Page 11: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

11

Audiencia Este curso está orientado a aquellos profesionales o estudiantes que quieran adquirir los conocimientos y habilidades necesarias para desarrollarse como proveedor de software independiente. Así mismo desarrolladores .NET (C#) que quieran incursionar en las nuevas tecnologías de .NET. Pre-requisitos Desarrolladores en Programación .NET (C #) o bien personas que hayan aprobado el curso de MS Net Junior (160 hs) Duración El curso tiene una duración de 28 horas reloj con una carga horaria no superior a 12 horas semanales. Al Finalizar el curso Después de completar este curso los alumnos serán capaces de:

Construir un interfase de usuario en una aplicación WPF

Personalizar la apariencia de una aplicación WPF

Crear controles de usuario en una aplicación WPF

Enlazar controles a fuentes de datos

Enlazar controles a colecciones

Manejar documentos en aplicaciones WPF

Trabajar con gráficos y multimedia en aplicaciones WPF

Configurar e instalar aplicaciones WPF

Page 12: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

12

Módulo 1

Introducción a WPF

Page 13: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

13

1- Introducción Definición Windows Presentation Foundation (WPF) es un sistema de presentación 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. El núcleo de WPF es un motor de representación independiente de la resolución y basado en vectores construido para aprovechar al máximo el hardware de gráficos moderno. WPF amplía el núcleo con un completo conjunto de características de programación de aplicaciones, entre las que se incluyen Lenguaje de marcado de aplicaciones extensible (XAML), controles, enlace de datos, diseño, gráficos 2D y 3D, animación, estilos, plantillas, documentos, multimedia, texto y tipografía. WPF se incluye en Microsoft .NET Framework, lo que permite crear aplicaciones que incorporen otros elementos de la biblioteca de clases de .NET Framework. Programar con WPF WPF constituye un subconjunto de tipos de .NET Framework, en su mayoría ubicados en el espacio de nombres de System.Windows. Si ha creado previamente aplicaciones con .NET Framework mediante tecnologías administradas como ASP.NET y formularios Windows Forms, los conceptos fundamentales de la programación en WPF deberán resultarle familiares; creará instancias de clases, definirá propiedades, llamará a métodos y controlará eventos con el lenguaje de programación de .NET Framework que prefiera, como C# o Visual Basic. Para admitir algunas de las funciones de WPF más eficaces y simplificar la experiencia de programación, WPF incluye construcciones de programación adicionales que mejoran las propiedades y los eventos Código de lenguaje marcado y código subyacente WPF proporciona mejoras de programación adicionales para el desarrollo de aplicaciones cliente de Windows. Una mejora evidente es la capacidad para programar una aplicación mediante código 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 aplicación, y los lenguajes de programación administrados (c#, visual Basic, etc.) para implementar su comportamiento. Esta separación entre la apariencia y el comportamiento aporta las ventajas siguientes:

Se reducen los costos de programación y mantenimiento, al no estar el marcado específico de la apariencia estrechamente relacionado con el código específico del comportamiento.

La programación es más eficaz porque los diseñadores pueden implementar la apariencia de una aplicación al mismo tiempo que los programadores implementan su comportamiento.

Se pueden utilizar varias herramientas de diseño para implementar y compartir el lenguaje marcado XAML, a fin de responder a los requisitos de los colaboradores de programación de aplicaciones. Microsoft Expression Blend proporciona una experiencia apropiada para los diseñadores, mientras que Visual Studio 2008 está dirigido a los programadores.

La globalización y localización de las aplicaciones WPF se ha simplificado en gran medida.

XAML XAML es un lenguaje de marcado basado en XML que se utiliza para implementar la apariencia de una aplicación mediante declaración. Se suele utilizar para crear ventanas, cuadros de

Page 14: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

14

diálogo, páginas y controles de usuario, así como para rellenarlos con controles, formas y gráficos. Ejemplo: <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Title="Ventana con un Botón" Width="250" Height="100"> <Button Name="button">Presionar</Button> </Window> El código XAML define una ventana y un botón mediante los elementos Window y Button, respectivamente. Cada elemento se configura con atributos o propiedades, como el atributo Title del elemento Window, para especificar el texto de la barra de título de la ventana. En tiempo de ejecución, WPF convierte los elementos y los atributos definidos en el marcado en instancias de clases de WPF. Puesto que XAML se basa en XML, la interfaz de usuario que se crea con este lenguaje se ensambla en una jerarquía de elementos anidados que se denomina árbol de elementos. El árbol de elementos proporciona una manera lógica e intuitiva de crear y administrar las interfases de usuario. Código Subyacente El comportamiento principal de una aplicación 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 botón) y llamar, en respuesta, a la lógica de negocios y de acceso a los datos. En WPF, este comportamiento se suele implementar en código asociado al marcado. Este tipo de código se denomina subyacente. En el ejemplo siguiente se muestran el código subyacente y el marcado actualizado del ejemplo anterior. <Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Title="Ventana con un Botón" Width="250" Height="100"> <Button Name="button" Click=”button_Click”>Presionar</Button> </Window> Código subyacente: using System.Windows; namespace EjemploWFP { public partial class miEjemplo : Window { public void button_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Probando Windows Presentation Foundation!"); } } }

Page 15: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

15

Aplicaciones WPF Microsoft .NET Framework, System.Windows, así como el código de lenguaje marcado y subyacente, constituyen la base de la experiencia de programación de aplicaciones en WPF. Además, WPF cuenta con características 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 aplicación. El modelo de aplicación admite la programación de aplicaciones independientes y hospedadas en explorador.

Aplicaciones independientes: Para las aplicaciones independientes, puede utilizar la clase Window para crear las ventanas y cuadros de diálogo a los que se tiene acceso desde las barras de menús y las barras de herramientas.

Aplicaciones hospedadas en explorador: También denominadas Aplicaciones del explorador XAML (XBAPs – XAML Browsers Applications, generan archivos con extensión xbap), puede crear páginas (Page) y funciones de página (PageFunction<T>) entre las que se puede navegar mediante hipervínculos (clases Hyperlink). Estas aplicaciones pueden hospedarse en Internet Explorer a partir de la versión 6.

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. Aún así, la mayoría de las características de WPF se pueden ejecutar con seguridad desde las XBAPs.

2- Conceptos Básicos Controles En WPF, un control es un término general que se aplica a una categoría de clases de WPF hospedadas en una ventana o una página, tienen una interfaz de usuario (UI) e implementa un comportamiento determinado. 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 administración del enfoque y la posición del mouse. A continuación se muestra la lista de controles de WPF integrados.

Botones: Button y RepeatButton.

Cuadros de diálogo: OpenFileDialog, PrintDialog y SaveFileDialog.

Entradas manuscritas digitales: InkCanvas y InkPresenter.

Documentos: DocumentViewer, FlowDocumentPageViewer, FlowDocumentReader, FlowDocumentScrollViewer y StickyNoteControl.

Entrada: TextBox, RichTextBox y PasswordBox.

Diseño: 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.

Menús: ContextMenu, Menu y ToolBar.

Navegación: Frame, Hyperlink, Page, NavigationWindow y TabControl.

Selección: CheckBox, ComboBox, ListBox, TreeView y RadioButton, Slider.

Información para el usuario: AccessText, Label, Popup, ProgressBar, StatusBar, TextBlock y ToolTip.

Diseño

Page 16: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

16

Al crear una interfaz de usuario, se organizan los controles según su ubicación y tamaño para crear un diseño. Un requisito fundamental de cualquier diseño es adaptarse a los cambios de tamaño de la ventana y de configuración de pantalla. En lugar de obligarle a escribir código que adapte el diseño en estas circunstancias, WPF le proporciona un sistema de diseño extensible de primera clase. La base del sistema de diseño es la situación relativa, que aumenta la capacidad de adaptación a los cambios en la configuración de las ventanas y de la pantalla. Además, el sistema de diseño administra la negociación entre los controles para determinar el diseño. La negociación es un proceso de dos pasos: en primer lugar, el control indica a su elemento primario qué ubicación y tamaño necesita; en segundo lugar, el elemento primario indica al control de qué espacio dispone. El sistema de diseño se expone a los controles secundarios mediante las clases base de WPF. Para los diseños comunes, como son las cuadrículas, el apilamiento y el acoplamiento, WPF incluye varios controles de diseño:

Canvas: los controles secundarios proporcionan su propio diseño.

DockPanel: los controles secundarios se alinean con los bordes del panel.

Grid: los controles secundarios se sitúan 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 línea en sentido horizontal o vertical.

WrapPanel: los controles secundarios se sitúan por orden de izquierda a derecha y se ajustan a la línea siguiente cuando hay más controles de los que caben en la línea actual.

Enlace de Datos La mayoría 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 tecnologías existentes, como Microsoft SQL Server y ADO.NET. Para simplificar la programación de aplicaciones, WPF proporciona un motor de enlace de datos que realiza estos pasos automáticamente. La unidad que constituye el núcleo 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). El motor de enlace de datos de WPF proporciona compatibilidad adicional que incluye validación, ordenación, filtrado y agrupación. Además, 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 estándar de WPF no es adecuada. Gráficos WPF presenta un conjunto extenso, escalable y flexible de características de gráficos que aportan las ventajas siguientes:

Gráficos independientes de la resolución e independientes del dispositivo. La unidad de medida básica del sistema de gráficos de WPF es el píxel independiente del dispositivo, que es 1/96 de pulgada, independientemente de la resolución de pantalla real, y que proporciona la base para la representación independiente de la resolución y del dispositivo. Cada píxel independiente del dispositivo se escala automáticamente para coincidir con el valor de puntos por pulgada (ppp) del sistema en que se representa.

Precisión mejorada. El sistema de coordenadas de WPF se mide con números de punto flotante de precisión doble, en lugar de precisión simple. Las transformaciones y los valores de opacidad también se expresan como doble precisión. WPF admite

Page 17: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

17

también una amplia gama de colores (scRGB) y proporciona compatibilidad integrada para administrar las entradas desde espacios de color diferentes.

Compatibilidad con gráficos avanzados y animación. WPF simplifica la programación de gráficos administrando automáticamente las escenas de animación.

Aceleración de hardware. El sistema de gráficos de WPF saca partido del hardware de gráficos para minimizar el uso de CPU.

Formas 2D WPF proporciona una biblioteca de formas 2D comunes dibujadas mediante vectores. Una función interesante de las formas es que no sirven únicamente para su presentación; las formas implementan muchas de las características que cabe esperar de los controles, incluida la entrada de datos desde el teclado y el Mouse. Geometrías 2D Las formas 2D proporcionadas por WPF abarcan el conjunto estándar de formas básicas. Sin embargo, puede que sea preciso crear formas personalizadas para facilitar el diseño de una interfaz de usuario personalizada. Para este fin, WPF proporciona las geometrías. Estas permiten 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 comprobación de visitas y la representación de datos de gráficos 2D. Efectos 2D Un subconjunto de las funciones 2D de WPF son los efectos visuales, tales como degradados, mapas de bits, dibujos, pintar con vídeos, rotación, ajuste de escala y sesgo. Todas ellas se aplican mediante pinceles. Representaciones 3D WPF también incluye funciones de representación 3D que se integran con los gráficos 2D para permitir la creación de interfases de usuarios más importantes. Animaciones La compatibilidad de WPF con la animación permite hacer que los controles crezcan, tiemblen, giren o se desvanezcan, crear transiciones de página interesante, y mucho más. Puede animar la mayoría de las clases de WPF, incluso las personalizadas. Multimedia Una manera de mostrar un contenido enriquecido es utilizar medios audiovisuales (multimedia). WPF proporciona compatibilidad especial con imágenes, vídeo y audio.

Imágenes: Las imágenes están presentes en la mayoría de las aplicaciones y WPF proporciona varias maneras de utilizarlas.

Video y Audio: El control MediaElement es capaz de reproducir vídeo y audio y presenta la flexibilidad suficiente para constituir la base de un reproductor multimedia personalizado. El marcado XAML siguiente implementa un reproductor multimedia.

Page 18: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

18

Texto y Tipografía Para facilitar una representación de texto de gran calidad, WPF ofrece las características siguientes:

Compatibilidad con fuentes OpenType.

Mejoras de ClearType.

Alto rendimiento que saca partido de la aceleración de hardware.

Integración de texto con multimedia, gráficos y animación.

Compatibilidad con fuentes internacionales y mecanismos de reserva. Documentos WPF permite trabajar de forma nativa con tres tipos de documentos: documentos dinámicos, documentos fijos y documentos de XML Paper Specification (XPS). WPF proporciona también servicios para crear, ver, administrar, anotar, empaquetar e imprimir documentos.

Documentos dinámicos: Los documentos dinámicos se han diseñado para optimizar su presentación y legibilidad ajustando dinámicamente su contenido y modificando su flujo cuando se producen cambios en el tamaño de la ventana y la configuración de pantalla.

Documentos Fijos: Los documentos fijos están destinados a aplicaciones que requieren una presentación con representación fiel (lo que se ve es lo que se obtiene, o WYSIWYG, en sus siglas en inglés) precisa, especialmente por lo que respecta a su impresión. Los usos típicos para los documentos fijos incluyen la creación de publicaciones, el procesamiento de textos y el diseño de formularios, donde es vital que se respete el diseño de página original. Los documentos fijos conservan la organización precisa de su contenido de una manera independiente del dispositivo. El diseño permanece inalterado en todos los casos, aunque la calidad del documento varía según 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 básicamente es una representación en forma de página de documentos electrónicos. XPS es un formato de documento abierto habilitado para varios exploradores y diseñado para facilitar la creación, el uso compartido, la impresión y el almacenamiento de documentos paginados.

Anotaciones Las anotaciones son notas o comentarios que se agregan a los documentos para marcar la información o resaltar elementos de interés, a fin de consultarlos más adelante. Aunque escribir notas en documentos impresos es fácil, la posibilidad de "escribir" notas en los documentos electrónicos con frecuencia es limitada o no está disponible en absoluto. Sin embargo, en WPF se proporciona un sistema de anotaciones que admite la inserción de notas rápidas y el resaltado. Empaquetado Las APISystem.IO.Packaging de WPF permiten que las aplicaciones organicen los datos, el contenido y los recursos en un único documento ZIP portátil, sencillo de distribuir y de fácil 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. También puede cifrar los paquetes mediante la administración de derechos para restringir el acceso a la información protegida. Impresión

Page 19: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

19

Microsoft .NET Framework incluye un subsistema de impresión al que WPF aporta, además, compatibilidad con el control de sistemas de impresión mejorados. Las mejoras de impresión incluyen las siguientes:

Instalación en tiempo real de servidores de impresión y colas remotos.

Detección dinámica de funciones de impresora.

Configuración dinámica de opciones de impresión.

Modificación del enrutamiento y las prioridades de los trabajos de impresión. Los documentos XPS presenta, además, una mejora fundamental del rendimiento. La ruta de acceso de Interfaz de dispositivo gráfico de Microsoft Windows (GDI) de impresión suele requerir dos conversiones:

La primera conversión del documento a un formato de procesador de impresión, como Metarchivo mejorado (EMF).

Una segunda conversión al lenguaje de descripción de páginas 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 impresión y un lenguaje de descripción de páginas. Esta compatibilidad ayuda a reducir el tamaño del archivo de cola y las cargas de las impresoras integradas en red. Personalización Para simplificar la organización de los controles en una interfase de usuario y asegurarse de que la organización se conserve aunque se modifiquen el tamaño de la ventana y la configuración de pantalla, se utiliza el sistema de diseño de WPF. Dado que la mayoría de las aplicaciones permiten a los usuarios interactuar con los datos, los enlaces de datos se utilizan para reducir el trabajo de integración de la interfaz de usuario con esos datos. A fin de mejorar la apariencia visual de la aplicación, se utiliza toda la gama de gráficos, animación y multimedia que WPF proporciona. Por último, si la aplicación funciona a través de texto y documentos, puede utilizar las funciones de tipografía, documentos, anotación, empaquetado e impresión 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 aplicación. Es posible que los datos no se muestren del modo más 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 aplicación. En muchos aspectos, una tecnología de presentación requiere la extensibilidad visual tanto como cualquier otro tipo de extensibilidad. Por esta razón, WPF proporciona gran variedad de mecanismos para la creación de experiencias de usuario únicas, incluido un modelo de contenido enriquecido para los controles, estilos, desencadenadores, plantillas de controles y datos, estilos, recursos de la interfaz de usuario, temas y máscaras.

Modelo de Contenido: El propósito principal de la mayoría de los controles de WPF es mostrar contenido. En WPF, el tipo y número 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. 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 diseño, texto, imágenes y formas.

Desencadenadores (Triggers): Aunque el propósito principal del marcado XAML es implementar la apariencia de una aplicación, también puede utilizar XAML para implementar algunos aspectos del comportamiento de una aplicación. Un ejemplo de

Page 20: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

20

ello es el uso de desencadenadores para cambiar la apariencia de una aplicación de acuerdo con las interacciones con el usuario.

Plantillas de Control: Las UIs predeterminadas para los controles de WPF suelen construirse a partir de otros controles y formas. A veces, la apariencia predeterminada de un control puede ser incongruente con la apariencia global de una aplicación. En este caso, puede utilizar una plantilla de control ControlTemplate para cambiar la apariencia de la interfase de usuario del control sin modificar su contenido ni su comportamiento.

Plantilla 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.

Estilos: Los estilos permiten a los programadores y diseñadores normalizar un aspecto determinado de sus productos. WPF proporciona un modelo de estilo sólido, que es la base del elemento Style.

Recursos: Los controles de una aplicación 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 la interfase de usuario (UI) para encapsular estos recursos en una ubicación única y poder reutilizarlos.

Temas y Máscaras: Desde una perspectiva visual, un tema define la apariencia global de Windows y de las aplicaciones que se ejecutan dentro del mismo. La apariencia definida por un tema establece la apariencia predeterminada de una aplicación 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), Clásico (Microsoft Windows 2000), etc. Estos temas están empaquetados en diccionarios de recursos que se resuelven cuando no se encuentran los recursos correspondientes en una aplicación. Por otro lado, la experiencia del usuario para algunas aplicaciones no procede necesariamente de los temas estándar. Tales UIs tienden a proporcionar temas personalizados, específicos de cada aplicación. Se denominan máscaras, y las aplicaciones con máscaras suelen proporcionar enlaces que permiten a los usuarios personalizar diversos aspectos de la máscara.

Controles Personalizados: Aunque WPF proporciona una amplísima compatibilidad con funciones de personalización, puede encontrar situaciones en que los controles existentes de WPF no satisfagan las necesidades de la aplicación o de los usuarios. WPF permite crear controles.

3- Eventos y Comandos Información general sobre Eventos Enrutados En los primeros pasos con WPF, lo más probable es que use eventos enrutados aún sin saber que los está usando. Por ejemplo, si agrega un botón a una ventana en el diseñador de Visual Studio®, modifica el nombre a miBoton y después hacer doble clic sobre él, el evento Click se conectará al marcado XAML y se agregará un controlador de eventos para este evento al código que hay tras la clase Window. Esto es lo mismo que la conexión de eventos en Windows Forms y ASP.NET. En concreto, en el marcado XAML para el botón, terminará por tener un código parecido a este: <Button Name=" miBoton " Click="miBoton_Click">Click Me</Button>

Page 21: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

21

La declaración de XAML para incorporar un evento es parecida a una asignación de propiedad en XAML, pero el resultado es un enlace de evento normal en el objeto que especificó el controlador de eventos. Si cambia la ventana al editor de código verá lo siguiente: private void myButton_Click(object sender, RoutedEventArgs e) { } Esto es igual a cualquier otra conexión de evento .NET, se tiene un delegado explícitamente declarado y enlazado a un evento de un objeto, y el delegado apunta a un método de control. El único indicio de que se están usando eventos enrutados es el tipo del argumento de evento para el evento Click, que es RoutedEventArgs. Entonces, ¿qué tienen de especial los eventos enrutados? 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ó. Para comprender mejor esta definición, necesitará antes comprender el modelo de composición elemental de WPF. Árboles de elementos WPF Si empieza con una ventana nueva en un proyecto y arrastra un botón en la ventana del diseñador, terminará con un árbol de elementos en el XAML parecido a éste (los atributos se omitieron para mejorar la claridad): <Window> <Grid> <Button/> </Grid> </Window> Cada uno de estos elementos representa una instancia en tiempo de ejecución de un tipo .NET correspondiente y la jerarquía declarada de elementos forma lo que se denomina un árbol lógico. Además, muchos controles de WPF son a su vez contenedores, lo que significa que pueden tener elementos secundarios. Por ejemplo, un Button puede tener un elemento secundario complejo como contenido. El árbol lógico se podría expandir como se muestra aquí: <Window> <Grid> <Button> <StackPanel> <Image/> <TextBlock/> </StackPanel> </Button> </Grid> </Window> Como puede imaginar, el árbol podría contener varias ramas y el árbol lógico puede crecer considerablemente en complejidad. Lo más importante a tener en cuenta sobre los elementos WPF del árbol lógico es que lo que se ve no es realmente lo que se obtiene en tiempo de ejecución. Cada uno de esos elementos suele ampliarse hasta formar un árbol más complejo de elementos visuales en tiempo de ejecución. Cuando hago clic en mi botón, puede que en realidad no esté haciendo clic en el elemento Button; puedo estar haciendo clic en un elemento secundario del árbol visual, posiblemente incluso uno que no se muestre en mi árbol lógico (como ButtonChrome). Por ejemplo, digamos que hago clic sobre la imagen que contiene mi botón. En realidad, el clic se manifiesta

Page 22: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

22

inicialmente como un evento de MouseLeftButtonDown incluido dentro del elemento Image. Pero de alguna forma esto hay que trasladarlo a un evento Click al nivel del Button. Es aquí donde entra en juego el enrutamiento en eventos. Enrutamiento de eventos Es importante entender un poco los árboles lógicos y visuales porque los eventos enrutados se enrutan principalmente según el árbol visual. Los eventos enrutados admiten una RoutingStrategy que puede ser Bubble, Tunnel o Direct.

Bubble es la más común y significa que un evento se propagará hacia la parte superior del árbol visual a partir del elemento origen hasta que se controle o alcance el elemento raíz. Esto le permite controlar un evento de un objeto aún más arriba de la jerarquía de elementos desde el elemento origen. Por ejemplo, se podría adjuntar un controlador Button.Click en elemento Grid que lo contiene en vez de directamente en el propio botón.

Tunnel: Los eventos Tunnel van en dirección contraria, se inician en el elemento raíz y van bajando por el árbol de elementos hasta que se controlan o alcanzan el elemento origen para el evento. Esto permite que los elementos precedentes intercepten el evento y lo controlen antes de que alcance el elemento origen. Los eventos Tunnel usan como prefijo de sus nombres Preview como convención (por ejemplo, PreviewMouseDown).

Direct: Los eventos directos se comportan como eventos normales de .NET Framework. El único controlador posible para el evento es un delegado que se enlaza al evento.

Eventos enrutados y composición Vayamos paso a paso para ver cómo el evento Button.Click se produce y regresa a casa, ya que es importante. Como he mencionado anteriormente, un usuario iniciará un evento Click con un evento MouseLeftButtonDown en algún elemento secundario del árbol visual del Button, como en el caso de Image en el ejemplo anterior. Cuando se produce el evento MouseLeftButtonDown dentro del elemento Image, se inicia un evento PreviewMouseLeftButtonDown en la raíz y profundiza hacia Image. Si ningunos de los controladores establecen la marca Handled en verdadero para el evento de vista previa, se inicia la propagación del evento MouseLeftButtonDown desde el elemento Image hasta que

Page 23: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

23

llega a Button. El botón controla ese evento, establece la marca Handled en verdadero y acciona su propio evento Click. Las implicaciones son bastante eficaces. Por ejemplo, si elijo reemplazar la apariencia predeterminada del botón aplicando una plantilla de control que contenga un elemento Ellipse, no tengo que hacer nada para garantizar que los clics hechos fuera de Ellipse no accionen el evento Click. Los clics que quedan justo fuera del borde de Ellipse seguirán estando dentro de los límites rectangulares de mi botón, pero Ellipse tiene su propia detección de aciertos para MouseLeftButtonDown, cosa que no ocurre para las partes vacías del botón que están fuera de Ellipse. Así que sólo los clics que se hacen dentro de Ellipse accionan el evento MouseLeftButtonDown. Sigue estando controlado por la clase Button a la que se adjunta la plantilla, así que se obtendrá el comportamiento previsible incluso del botón personalizado. Esto también es un concepto muy importante que recordar al escribir sus propios controles compuestos personalizados, porque lo más probable es que necesite hacer cosas parecidas a las que hace Button para administrar eventos de elementos secundarios que se coloquen dentro de su control. Eventos adjuntos Los eventos adjuntos son eventos enrutados que admiten un enlace XAML sobre elementos distintos del tipo en el que se declara el evento. Por ejemplo, si desea que el elemento Grid esté atento al paso de un evento Button.Click, sólo tendría que enlazarlo de esta forma: <Grid Button.Click="myButton_Click"> <Button Name="myButton" >Presionar</Button> </Grid> Los eventos adjuntos sólo dan un poco más de flexibilidad en los sitios donde conecta sus controladores de eventos. Pero si los elementos están contenidos en la misma clase (como en este ejemplo), puede no resultar aparente qué diferencia hay porque, en ambos casos, el método de control sigue siendo sólo un método de la clase Window.

Información general sobre Comandos enrutados Los comandos enrutados de WPF ofrecen un mecanismo específico para enlazar controles de IU como botones de barra de herramientas y elementos de menú a controladores, sin tener que realizar muchos emparejamientos integrados ni código repetitivo en la aplicación. Los comandos enrutados ofrecen tres cosas importantes además del control normal de eventos:

Los elementos origen del comando enrutado (invocadores) pueden estar desconectados de los destinos de comandos (controladores), no es necesario que haya referencias directas entre ellos, como ocurriría si estuvieran vinculados por un controlador de eventos.

Los comandos enrutados habilitarán o deshabilitarán todos los controles de IU asociados cuando el controlador indica que el comando está deshabilitado.

Los comandos enrutados le permiten asociar métodos abreviados de teclado y otras formas de movimientos de entrada (movimientos de lápiz óptico, por ejemplo) como otra manera de invocar el comando.

Además, una variedad específica del comando enrutado (la clase RoutedUICommand) agrega la capacidad de definir una sola propiedad Text para usarla como indicaciones de texto de cualquier control que sea invocador para el comando. La propiedad Text también se puede localizar más fácilmente que visitando todos los controles del invocador asociado. Para declarar un comando en un invocador, sólo tiene que establecer una propiedad Command sobre el control que iniciará el comando:

Page 24: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

24

<Button Command="ApplicationCommands.Save">Guardar</Button> La propiedad Command la admiten MenuItem, Button, RadioButton, Checkbox, Hyperlink y otros controles. Para concretar y ver rápidamente las ventajas de los comandos enrutados, veamos un ejemplo sencillo. En la siguiente figura se puede ver una IU con dos TextBoxs y un botón de barra de herramientas para realizar una acción Cortar sobre el texto de los cuadros de texto.

Para poder conectar esto usando eventos, necesitaría definir un controlador Click para el botón de la barra de herramientas y ese código necesitaría hacer referencia a los dos cuadros de texto. Tendría que determinar qué cuadro de texto tiene el foco y llamar a operaciones apropiadas del portapapeles según la selección del texto en el control. También tendría que preocuparse de habilitar y deshabilitar el botón de la barra de herramientas según donde esté el foco y si se seleccionó algo en el cuadro de texto. Esto generaría un código complejo y desordenado. Con comandos, lo único que hay que hacer es establecer la propiedad Command del botón de la barra de herramientas en el comando ApplicationCommands.Cut que está definido en WPF y ya está listo. <StackPanel> <ToolBar DockPanel.Dock="Top" Height="25"> <Button Command="ApplicationCommands.Cut"> <Image Source="cut.ico"/> </Button> </ToolBar> <TextBox Name="txt1" Width="100" Height ="23"></TextBox> <TextBox Name="txt2" Width="100" Height ="23"></TextBox> </StackPanel> Ahora podría ejecutar la aplicación y comprobar que el botón de la barra de herramientas está inicialmente deshabilitado. Después de seleccionar texto en uno de los cuadros de texto, el botón de la barra de herramientas pasa a estar habilitado y, si se hace clic en él, el texto se corta y pasa al portapapeles. Y funcionaría para cualquier TextBox de cualquier lugar de la IU. Lo que sucede aquí es que la implementación de la clase TextBox tiene un enlace de comandos integrado para el comando Cut y encapsula automáticamente el control del portapapeles para ese comando (además de Copy y Paste). Pero, ¿cómo se invoca solamente el comando en el cuadro de texto enfocado, y cómo llega el mensaje al cuadro de texto para decirle que controle el comando? Aquí es donde entra en juego el enrutamiento de comandos.

Page 25: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

25

Enrutamiento de comandos La diferencia entre comandos enrutados y eventos enrutados es la forma en que el comando se dirige desde el invocador del comando al controlador del comando. Concretamente, los eventos enrutados se usan internamente para dirigir mensajes entre los invocadores y los controladores de comandos (mediante el enlace de comandos que se engancha en el árbol visual). Aquí podría haber una relación de varios a varios, pero sólo un controlador de comando estará realmente activo en cada momento. El controlador de comandos activo lo determina una combinación de las posiciones del invocador y del administrador de comandos en el árbol visual, y de la posición del foco en la interfase de usuario. Los eventos enrutados se usan para llamar al controlador de comandos activo para preguntarle si se debe habilitar el comando, así como para invocar al controlador de método Execute del controlador de comandos. Generalmente, un invocador de comandos busca un enlace de comandos entre su propia ubicación en el árbol visual y la raíz del árbol visual. Si encuentra uno, el controlador de comandos enlazado determinará si el comando está habilitado y se llamará cuando se invoque el comando. Si el comando está conectado a un control de una barra de herramientas o de un menú, entonces se ejecuta lógica adicional que también examina la ruta de acceso del árbol visual desde la raíz al elemento del foco buscando un enlace de comando. Definición de comandos Existen cinco clases de comandos integradas en WPF:

ApplicationCommands: Close, Cut, Copy, Paste, Save, Print

NavigationCommands: BrowseForward, BrowseBack, Zoom, Search

EditingCommands: AlignXXX, MoveXXX, SelectXXX

MediaCommands: Play, Pause, NextTrack, IncreaseVolume, Record, Stop

ComponentCommands: MoveXXX, SelectXXX, ScrollXXX, ExtendSelectionXXX XXX indica diversas operaciones como MoveNext y MovePrevious. Los comandos de cada clase están definidos como propiedades para que pueda conectarlos fácilmente. También puede usar estos comandos con una notación abreviada <Button Command="Save">Save</Button> Desafíos de los comandos enrutados Los comandos enrutados funcionan bien en escenarios de interfases de usuario sencillas, conectando barras de herramientas y elementos de menú, y controlando esas cosas que están emparejadas intrínsecamente al foco del teclado (como las operaciones con el portapapeles). Sin embargo, donde los comandos enrutados se muestran insuficientes, es cuando se empieza a crear interfases de usuario complejas, donde la lógica del control de comandos está en el código de soporte para las definiciones de vista y los invocadores de comando no siempre están dentro de una barra de herramientas o de un menú. El problema que surge al trabajar de este modo es que la habilitación y el control de lógica para un comando puede no formar parte del árbol visual directamente; en su lugar puede estar situada en un presentador o en un modelo de presentación. Además, el estado que determina si el comando debe habilitarse puede no tener relación con la situación de los invocadores de comandos y las vistas en el árbol visual. También puede encontrar casos donde haya más de un controlador válido al mismo tiempo para un comando particular. Para evitar los problemas potenciales de la ubicación del árbol visual con comandos enrutados, necesitará simplificar las cosas. Normalmente necesitará asegurarse de que los controladores de comando están en el mismo elemento o en niveles superiores del árbol visual del elemento que invocará el comando.

Page 26: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

26

Módulo 2

Creando Aplicaciones WPF

Page 27: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

27

1- Crear una aplicación WFP Aplicación WPF Dentro de Visual Studio:

En el menú Archivo, haga clic en Nuevo proyecto. Aparecerá el cuadro de diálogo de Nuevo proyecto.

Seleccione el lenguaje y elija Aplicación WPF.

Cambie el nombre de la aplicación.

Haga clic en Aceptar.

Se creará una nueva carpeta para el proyecto con el nombre del proyecto y, a continuación, mostrará el nuevo formulario WPF titulado Window1 en la vista Diseñador. Dentro de esta vista se puede trabajar el formulario de forma similar al de las aplicaciones Windows. Arrastre controles y modifique sus propiedades usando la ventana de propiedades. Escriba los atajadores de eventos en el archivo .xaml.cs o .xaml.vb según el lenguaje seleccionado. La ventana de WPF que se ve en la vista Diseñador es una representación visual de la ventana que se abrirá al iniciar la aplicación. En la vista Diseñador, puede arrastrar diversos controles desde el Cuadro de herramientas hasta la ventana WPF. Después de haber colocado un control a la ventana de WPF, Visual C# crea automáticamente código que hará que el control se sitúe apropiadamente cuando se ejecute el programa.

Page 28: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

28

Clase Window Permite crear, configurar, mostrar y administrar la duración de las ventanas y los cuadros de diálogo. El punto de interacción entre el usuario y una aplicación independiente es una ventana. Una ventana de WPF se compone de dos áreas distintas:

Un área no cliente, que hospeda los elementos gráficos de las ventanas, incluidos un icono, título, menú del sistema, botón para minimizar, botón para maximizar, botón para restablecer, botón para cerrar y un borde.

Un área cliente, que hospeda el contenido específico de la aplicación. <Window x:Class="AplWPF.Principal" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Principal" Height="500" Width="500" WindowStyle="ThreeDBorderWindow" ResizeMode="CanResize" ShowInTaskbar="True" WindowState="Maximized"> Configurar la ventana de inicio El archivo App.xaml y el archivo de código subyacente correspondiente se crean de forma predeterminada en un proyecto WPF. Este archivo contiene recursos de nivel de aplicación que pueden ser usados en cualquier documento de la aplicación. Dentro de este archivo se implementa la clase Application. La ventana de inicio se establece a través de la propiedad StartupUri.

<Application x:Class="WpfCSharp.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="Principal.xaml">

Page 29: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

29

<Application.Resources> </Application.Resources> </Application>

Propiedades de la Clase Window AllowsTransparency: Obtiene o establece un valor que indica si se puede ajustar la opacidad del formulario Background: Obtiene o establece un pincel (Brush) que describe el fondo de un control. BorderBrush: Obtiene o establece un pincel (Brush) que describe el fondo del borde de un control. BorderThickNess: Obtiene o establece el grosor del borde de un control. Cursor: Obtiene o establece el cursor que se muestra cuando el puntero del mouse se sitúa sobre este elemento. Foreground: Obtiene o establece un pincel (Brush) que describe el color de primer plano, generalmente la letra. Height: Obtiene o establece el alto sugerido del elemento, expresados en unidades independientes de dispositivo (1/96 de pulgada por unidad). Icon: Obtiene o establece el icono de una ventana. IsEnabled: Obtiene o establece si la ventana permite recibir entradas del usuario. Left: Obtiene o establece la posición del borde izquierdo de la ventana con respecto al escritorio. ResizeMode: Obtiene o establece el modo de cambio de tamaño. ShowInTaskBar: Obtiene o establece un valor que indica si la ventana tiene un botón de barra de tareas. SizeToContent: Obtiene o establece un valor que indica si una ventana ajustará automáticamente su tamaño al de su contenido. Title: Obtiene o establece el título de una ventana. Top: Obtiene o establece la posición del borde superior de la ventana con respecto al escritorio. TopMost: Obtiene o establece un valor que indica si una ventana aparece en el punto más alto en el orden Z. Width: Obtiene o establece el ancho del elemento, expresados en unidades independientes de dispositivo (1/96 de pulgada por unidad). WindowStartupLocation: Obtiene o establece la posición de la ventana cuando se muestra por primera vez. WindowState: Obtiene o establece un valor que indica si una ventana está restaurada, minimizada o maximizada. WindowStyle: Obtiene o establece el estilo de borde de una ventana. Controles WPF y su equivalente con Controles Windows Forms

Windows Forms WPF Comentarios

Button Button

CheckBox CheckBox

CheckedListBox ListBox Compuestos

ColorDialog

Page 30: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

30

ComboBox ComboBox

ContextMenuStrip ContextMenu

DataGridView Algunas funcionalidades de DataGridView se pueden reproducir usando los controles ListView y GridView.

DateTimePicker

ErrorProvider

FlowLayoutPanel WrapPanel o StackPanel

FolderBrowserDialog

FontDialog

Form Window

GroupBox GroupBox

HelpProvider No tiene ayuda con F1. Se puede reemplazar esta funcionalidad con ToolTips

ImageList

Label Label

LinkLabel Se puede utilizar la clase Hyperlink.

ListBox ListBox

ListView ListView Solo contiene la vista de detalle en formato de solo.

MaskedTextBox

MenuStrip Menu

MonthCalendar

NotifyIcon

NumericUpDown TextBox y dos RepeatButton

OpenFileDialog OpenFileDialog

PageSetupDialog

Panel Canvas

Page 31: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

31

PictureBox Image

PrintDialog PrintDialog

PrintDocument

PrintPreviewControl DocumentViewer

PrintPreviewDialog

ProgressBar ProgressBar

RadioButton RadioButton

RichTextBox RichTextBox

SaveFileDialog SaveFileDialog

SoundPlayer MediaPlayer

SplitContainer GridSplitter

StatusStrip StatusBar

TabControl TabControl

TableLayoutPanel Grid

TextBox TextBox

Timer DispatcherTimer

ToolStrip ToolBar

ToolTip ToolTip

TrackBar Slider

TreeView TreeView

WebBrowser Frame, System.Windows.Controls.WebBrowser

The Frame control can host HTML pages.

Controladores de Eventos Para crear un controlador de eventos se puede hacer doble clic sobre el control. De esta manera se crea el atajador del evento predeterminado de un control. También puede agregarse como atributo escribiendo sobre el editor XAML. Al escribir el nombre del evento o seleccionarlo de la lista de ayuda aparecerá una opción <Nuevo

Page 32: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

32

Controlador de Eventos> y el nombre de procedimientos posibles de ser seleccionados teniendo en cuenta la firma del atajador del evento seleccionado. El nombre predeterminado del atajador del evento será NombreObjeto_Evento. El controlador de eventos se escribirá en la clase asociada al formulario. Todas las librerías del Framework de .Net esta disponible para ser usada en este tipo de aplicaciones.

Recursos WPF provee recursos como una forma simple de reusar objetos y valores definidos. Se pueden crear recursos en XAML o por código. Todos los elementos de nivel FrameWork tienen la propiedad Resources, aunque generalmente se los usa en elementos de tipo raíz como Window. Los recursos deben contener una identificación única. Esta se declara usando x:Key. Generalmente la clave se la declara como carácter (string), aunque puede ser declarada usando otros tipos de datos. <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"/> <Setter Property="FontWeight" Value="Bold"/> <Setter Property="Margin" Value="0,3,10,0"/> </Style> </Page.Resources> Recursos Estáticos y Dinámicos Los recursos pueden ser referenciados en forma estática o dinámica. Esto se hace usando StaticResource o DynamicResource y el nombre del recurso que se está referenciando. La

Page 33: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

33

referencia estática procesa la clave buscando el valor en todos los recursos disponibles, esto ocurre durante la carga del proceso. En cambio la referencia dinámica procesa la clave creando una expresión que permanece sin ser evaluada hasta el momento de la ejecución, durante la ejecución evalúa la expresión y devuelve el valor. Cuando se va a crear una referencia a un recurso, las siguientes consideraciones deberían tenerse en cuenta para elegir cual de las dos opciones va a usarse:

Donde está creado el recurso, si es un recurso de ventana, de aplicación, de control, etc.

La funcionalidad de la aplicación

El comportamiento del recurso Cuando elegir StaticResource:

La mayoría de los recursos son de ventana o aplicación. Los recursos no son re evaluados durante la ejecución mejorando la performance.

Se está estableciendo alguna propiedad del objeto en Freezable

Se están creando recursos que serán compilados en una dll aparte.

Se están definiendo recursos que van a ser usados en Temas

Se están usando recursos con muchas propiedades de dependencia. Cuando elegir DynamicResource:

El valor del recurso depende de una condición que solo se conoce durante la ejecución.

Se están creando o referenciando Temas para un control personalizado

Se está intentando ajustar el contenido de ResourceDictionary

Cuando se usan recursos compilados

Cuando se referencia recursos pesados y el uso de ese recurso no es inmediato, o sea no se usa durante la carga de la ventana. Los recursos estáticos se cargan con la carga de la ventana, en cambio los dinámicos cuando se necesitan

Se aplican recursos a elemento que dependen de elementos padres. Al cambiar el elemento padre es posible que sea necesario cambiar el objeto hijo también.

<Button Background="{StaticResource MyBrush}"/> <Ellipse Fill="{StaticResource MyBrush}"/>

2- Controles de Diseño Sistema de Diseño de Interfase de Usuario El término diseño describe el proceso de medir y organizar los integrantes de la colección Children de un elemento contenedor y, a continuación, dibujarlos en la pantalla. Se trata de un proceso intensivo y, cuanto mayor es la colección Children, mayor es el número de cálculos realizados. También se puede incluir mayor complejidad según el comportamiento de diseño definido por el elemento contenedor que posee la colección. Un diseño relativamente sencillo, como Canvas, puede producir un rendimiento excelente si no se requiere un Panel más complejo como Grid. Cada vez que un elemento secundario cambia su posición, tiene el potencial de desencadenar un nuevo paso del sistema de diseño. Como a tal, es importante entender los eventos que pueden invocar el sistema del diseño, puesto que la invocación innecesaria puede deteriorar el rendimiento de la aplicación. En su versión más simple, el diseño es un sistema recursivo que conduce a la configuración del tamaño, posición y representación de un elemento en la pantalla. El sistema de diseño completa dos pasos por cada miembro de la colección Children: un paso de medida y un paso de organización. Se trata de la serie de eventos que se producen cada vez que se invoca el sistema de diseño.

Page 34: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

34

Un elemento secundario comienza el proceso de diseño midiendo, en primer lugar, propiedades básicas.

Se evalúan las propiedades de tamaño, como Width, Height y Margin.

Se aplica la lógica concreta del contenedor, como la dirección de Dock o la orientación (Orientation) de apilado.

El contenido se organiza después de medir todos los elementos secundarios.

Se dibuja la colección Children en la pantalla.

Se invoca el proceso de nuevo si se agregan Children adicionales a la colección. Al pensar en el diseño de una aplicación en Windows Presentation Foundation (WPF), es importante entender el rectángulo de selección que rodea todos los elementos. Esta abstracción ayuda a comprender el comportamiento del sistema de diseño. Cada elemento utilizado por el sistema de diseño se puede considerar como un rectángulo que se inserta en una partición del diseño. El sistema, calculando el espacio de pantalla disponible, determina el tamaño de ese rectángulo, el tamaño de cualquier restricción, las propiedades específicas del diseño, como el margen y el relleno, y el comportamiento individual del elemento primario. Al procesar estos datos, el sistema puede calcular la posición de todos los elementos secundarios de un contenedor determinado. Es importante recordar que las características de tamaño definidas en el elemento primario (como Border) afectan a sus elementos secundarios. Cuando se representa el contenido de un objeto Window, se invoca el sistema del diseño automáticamente. Para mostrar el contenido, el Content de la ventana debe definir un panel raíz que sirve para definir un marco que permite organizar los miembros de Children en la pantalla. A continuación se detallan los controles disponibles como paneles o contenedores. Border Dibuja un borde, un fondo o ambos alrededor de otro elemento. En el siguiente ejemplo se muestra un control Border que contiene un CheckBox. <Border Background="LightBlue" BorderBrush="Black" BorderThickness="2" CornerRadius="50" Padding="5" Height="36" VerticalAlignment="Top" Margin="100,44,116,0"> <CheckBox Name="Prueba" IsChecked="True" >Prueba</CheckBox> </Border>

Canvas Define un área en la que pueden colocarse explícitamente los elementos secundarios utilizando las coordenadas relativas al área del control Canvas. Canvas es el único elemento del panel que no tiene ninguna característica de diseño inherente. Tiene las propiedades predeterminadas Height y Width de cero. Siempre se da a los elementos secundarios de Canvas el tamaño máximo que requieren. Como resultado, la alineación vertical y horizontal no tiene ningún efecto en un control Canvas. Canvas es un control de diseño de nivel superior que puede utilizarse para la colocación absoluta del contenido secundario. En el siguiente ejemplo se muestra un control Canvas con dos TextBlock contenidos. El uso de las propiedades Canvas.Top y Canvas.Left permite posicionar los controles contenidos.

Page 35: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

35

<Canvas Background="LightSteelBlue"> <TextBlock FontSize="14" Canvas.Top="10" Canvas.Left="5">Hola Mundo!</TextBlock> <TextBlock FontSize="22" Canvas.Top="25" Canvas.Left="35">Hola</TextBlock> </Canvas>

DockPanel Define un área en la que se pueden organizar horizontalmente o verticalmente los elementos secundarios, uno respecto al otro. La posición de los elementos secundarios de un control DockPanel en la pantalla está determinada por la propiedad Dock de los elementos secundarios respectivos y el orden relativo de estos elementos secundarios en DockPanel. Por tanto, un conjunto de elementos secundarios con los mismos valores de la propiedad Dock se puede organizar de forma diferente en la pantalla dependiendo del orden de estos elementos secundarios dentro del DockPanel. La clasificación de los elementos secundarios afecta a la posición porque DockPanel recorre en iteración sus elementos secundarios en orden, y establece la posición de cada elemento en función del espacio restante. El método SetDock cambia la posición de un elemento respecto a otros elementos del mismo contenedor. Las propiedades de alineación, como HorizontalAlignment, cambian la posición de un elemento respecto a su elemento principal. Si establece la propiedad LastChildFill en true, que es el valor predeterminado, el último elemento secundario de DockPanel rellena siempre el espacio restante, sin tener en cuenta ningún valor que se haya establecido en este elemento. Para acoplar un elemento secundario en otra dirección, debe establecer la propiedad LastChildFill en false y especificar además una dirección de acoplamiento explícita para este último elemento secundario. En el siguiente ejemplo se muestra el uso de un control DockPanel con varios controles contenidos. La propiedad DockPanel permite posicionar los objetos. <DockPanel LastChildFill="True"> <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top"> <TextBlock Foreground="Black">Dock = "Top"</TextBlock> </Border> <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom"> <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock> </Border> <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left"> <TextBlock Foreground="Black">Dock = "Left"</TextBlock> </Border> <Border Background="White" BorderBrush="Black" BorderThickness="1">

Page 36: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

36

<TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock> </Border> </DockPanel>

Grid Define un área de cuadrícula flexible que está compuesta de columnas y filas. Los elementos secundarios de Grid se dibujan en el orden en que aparecen en el código. En consecuencia, se puede lograr un orden dispuesto en capas (también conocido como orden Z) cuando los elementos comparten las mismas coordenadas. Grid y Table comparten alguna funcionalidad común, pero se puede aplicar cada uno de ellos en escenarios adecuados para hacer un mejor uso de sus características integradas. Grid agrega elementos basándose en un índice de fila y columna; Table no lo hace. El elemento Grid permite la disposición en capas del contenido si puede haber más de un elemento dentro de una sola celda. Table no admite la disposición en capas. Los elementos secundarios de un elemento Grid se pueden colocar de forma absoluta con respecto a la esquina superior izquierda de los límites de su celda. Table no admite esta característica. Grid también proporciona un comportamiento de cambio de tamaño más flexible que Table. Grid utiliza el objeto GridLength para definir las características de ajuste de tamaño de RowDefinition o ColumnDefinition. En el siguiente ejemplo se muestra el uso del control Grid. La definición inicial de filas y columnas y el uso de las propiedades Grid.Row y Grid.Column para asociar los controles contenidos a la celda correspondiente. <Grid VerticalAlignment="Top" HorizontalAlignment="Left" ShowGridLines="True" Width="250" Height="100" Canvas.Left="80" Canvas.Top="67" Background="LightYellow" > <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <TextBlock FontSize="20" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="0">Productos Comprados</TextBlock> <TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="0">Enero</TextBlock> <TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="1">Febrero</TextBlock> <TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="2">Marzo</TextBlock>

Page 37: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

37

<TextBlock Grid.Row="2" Grid.Column="0" TextAlignment="Right" >50,000</TextBlock> <TextBlock Grid.Row="2" Grid.Column="1" TextAlignment="Right">100,000</TextBlock> <TextBlock Grid.Row="2" Grid.Column="2" TextAlignment="Right">150,000</TextBlock> <TextBlock FontSize="16" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="3">Total Units: 300,000</TextBlock> </Grid>

StackPanel Organiza los elementos secundarios en una única línea que se puede orientar horizontal o verticalmente. La propiedad Orientation permite organizar el contenido horizontal o verticalmente. En el siguiente ejemplo se muestra el uso del control StackPanel. La propiedad Orientation organiza los RadioButtons en forma vertical. <StackPanel Height="40" Width="115" Orientation="Vertical" > <RadioButton Name="rb1" Checked="rb_Checked" >Si</RadioButton> <RadioButton Name="rb2" Checked="rb_Checked" >No</RadioButton> </StackPanel>

GroupBox Representa un control que crea un contenedor que tiene un borde y un encabezado para el contenido de interfaz de usuario. Su propiedad de contenido es Content y su propiedad de encabezado es Header. En el siguiente ejemplo se muestra el uso del control GroupBox. La propiedad Header permite ponerle el título. El uso de un StackPanel, otro de los controles contenedores, permite organizar el cuerpo del GroupBox. <GroupBox Width="100" Height="100" Background="Beige" > <GroupBox.Header> <Label>Employee Data</Label> </GroupBox.Header> <StackPanel> <RadioButton HorizontalAlignment="Left" Height="16" Name="Opcion1" Width="120">Opción 1</RadioButton> <RadioButton HorizontalAlignment="Left" Height="16" Name="Opcion2" Width="120">Opción 2</RadioButton> </StackPanel> </GroupBox>

Page 38: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

38

Expander Representa el control que muestra un encabezado que tiene una ventana contraible que muestra el contenido. Su propiedad de contenido es Content y su propiedad de encabezado es Header. Si el contenido de la ventana expandida es demasiado grande para la ventana, puede ajustar el contenido de Expander en un control ScrollViewer para proporcionar el contenido desplazable. Expander no proporciona automáticamente la función de desplazamiento. En el siguiente ejemplo se muestra el uso del control Expander. Las propiedades de este control permiten controlar la expansión y contracción del cuerpo del mismo. <Expander Name="myExpander" HorizontalAlignment="Left" Header="Expandir" ExpandDirection="Down" IsExpanded="True" Width="100"> <TextBlock TextWrapping="Wrap"> Representa el control que muestra un encabezado que tiene una ventana contraible que muestra el contenido. </TextBlock> </Expander>

InkCanvas InkCanvas es un elemento que se puede utilizar para recibir y mostrar entradas de entrada manuscrita. Normalmente esta operación se lleva a cabo mediante el uso de un lápiz o un mouse que interactúan con un digitalizador para generar trazos de entrada manuscrita. Los trazos creados se representan como objetos Stroke y se pueden manipular mediante programación o a través de los datos proporcionados por el usuario. InkCanvas permite al usuario modificar o eliminar un objeto Stroke existente. <InkCanvas Name="ic" Background="LightSteelBlue" Canvas.Top="0" Canvas.Left="0" Height="200" Width="200" />

Page 39: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

39

Menu Representa un control de menú de Windows que le permite organizar jerárquicamente los elementos asociados a comandos y controladores de eventos. Presenta una lista de elementos que especifican comandos u opciones para una aplicación. Normalmente, al hacer clic en un elemento de un menú, se abre un submenú o una aplicación ejecuta un comando. MenuItem es el tipo más común de elemento de Menu. MenuItem puede contener elementos secundarios. En el siguiente ejemplo se muestra el uso del control Menu y la forma de crear los MenuItems. <Menu Name="menu1" Width="300" HorizontalAlignment="Left" VerticalAlignment="Top" > <MenuItem Header="_Archivo" > <MenuItem Header="A_brir" IsCheckable="true" /> <MenuItem Header="_Cerrar" IsCheckable="true" IsChecked="True" /> <MenuItem Header="_Guardar" > <MenuItem.Icon> <Image Source="setup.ico" Width="16" Height="16" /> </MenuItem.Icon> </MenuItem> <Separator /> <MenuItem Header="A_gregar" > <MenuItem Header="Proyecto" /> <MenuItem Header="Archivo" /> </MenuItem> </MenuItem> </Menu>

Frame Es un control de contenido que proporciona la capacidad para navegar y mostrar el contenido. Se puede hospedar dentro de otro contenido, como con otros controles y elementos. El

Page 40: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

40

contenido puede ser cualquier tipo de objeto de .NET Framework y archivos HTML. En general, sin embargo, las páginas son la manera preferida de empaquetar contenido para la navegación. A un contenido se puede navegar estableciendo la propiedad Source con el URI para el contenido deseado. Además, a un contenido se puede navegar utilizando una de las sobrecargas del método Navigate. <Frame Name="miFrame" Source="http://www.microsoft.com" />

WrapPanel Posiciona los elementos hijos en forma secuencial de izquierda a derecha, cortando el contenido de manera que quede sobre la línea siguiente al llegar al borde del contenedor. El orden se mantiene de arriba hacia abajo o de derecha a izquierda dependiente del valor de la propiedad Orientation. <Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2"> <WrapPanel Background="LightBlue" Width="200" Height="100"> <Button Width="200">Button 1</Button> <Button>Button 2</Button> <Button>Button 3</Button> <Button>Button 4</Button> </WrapPanel> </Border>

Page 41: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

41

3- Otros Controles Label - AccessText Representa la etiqueta de texto de un control. Esta clase proporciona compatibilidad funcional y visual con las teclas de acceso. Se utiliza con frecuencia para permitir el acceso rápido desde el teclado a controles como TextBox. Para asociar un control Label a otro control, establezca la propiedad Target en el control que debe obtener el foco cuando el usuario presione la tecla de acceso. Para establecer la tecla de acceso, agregue un guión bajo antes del carácter que debe ser la tecla de acceso. Se accede con Alt + la letra seleccionada. En el siguiente ejemplo al presionar Alt+D, el foco se posiciona en TextBox2 <DockPanel Margin="0,10,3,3" Grid.Column="0" Grid.Row="5"> <TextBox Name="textBox2" Width="100" Height="20"/> <Label Target="{Binding ElementName=textBox2}"> <AccessText FontSize="12" FontWeight="Bold">E_ditar</AccessText> </Label> </DockPanel> <TextBox Name="textBox3" Width="100" Height="20" Canvas.Top="30" />

TextBox Representa un control que se puede utilizar para mostrar o editar texto sin formato. <TextBox Name="tbSelectSomeText" Width="100" > Algún Texto</TextBox>

TextBlock Proporciona un control ligero que permite mostrar pequeños fragmentos de contenido dinámico. TextBlock se ha diseñado para que sea ligero y se ha preparado específicamente para integrar pequeños fragmentos de contenido dinámico en una interfaz de usuario (UI). TextBlock proporciona un rendimiento óptimo en la presentación de líneas únicas y un rendimiento apropiado en la presentación de hasta unas pocas líneas de contenido. <TextBlock Name="textBlock1" TextWrapping="Wrap" FontSize="14"> <Bold>TextBlock</Bold> esta diseñado para ser <Italic>liviano</Italic> </TextBlock>

Button Su propiedad de contenido es Content. Su evento principal es Click. En el siguiente ejemplo se muestra un botón que contiene una imagen y un texto formado por controles contenidos.

Page 42: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

42

<Button Name="btn5" Canvas.Left="64" Canvas.Top="17" Width="129" Height="33" Click="btnAceptar_Click" > <StackPanel Orientation="Horizontal" Width="Auto"> <Image Source="ms.jpg" Width="20" Height="20"></Image> <TextBlock Text="Aceptar" TextAlignment="Right" VerticalAlignment="Center" Width="69"></TextBlock> </StackPanel> </Button>

ListBox - ComboBox El ListBox permite mostrar una lista de ítems desplegada. Las propiedades de contenido son las colecciones Items e ItemsSource. La propiedad SelectionMode permite establecer cuantos ítems pueden ser seleccionados. La opciones son Single (1 solo ítem), Multiple (varios ítems) y Extended (se pueden seleccionar varios ítems consecutivos usando la tecla Shift o no consecutivos usando la tecla Ctrl). El ComboBox permite ocultar y desplegar la lista de ítems. Las propiedades IsEditable e IsReadOnly especifican cómo se comporta ComboBox cuando el usuario escribe una cadena para seleccionar un elemento o copia y pega un valor en el cuadro de texto. En el siguiente ejemplo vemos el uso de un ListBox sencillo. <ListBox Name="lb" Width="100" Height="55" SelectionChanged="PrintText" SelectionMode="Single"> <ListBoxItem>Item 1</ListBoxItem> <ListBoxItem>Item 2</ListBoxItem> <ListBoxItem>Item 3</ListBoxItem> </ListBox>

Estos controles permiten también el uso de listas con contengan CheckBox, imágenes, etc. como controles contenidos para cada ítem. <ListBox Name="lb" Width="251" Height="119" SelectionMode="Single" SelectionChanged="lb_SelectionChanged"> <ListBoxItem Background="LightCoral" FontFamily="Verdana" FontSize="12" FontWeight="Bold"> <CheckBox Name="chk1"> <StackPanel Orientation="Horizontal"> <Image Source="ms.jpg" Height="30"></Image> <TextBlock Text="Item 1" Width="174"></TextBlock> </StackPanel> </CheckBox> </ListBoxItem> <ListBoxItem Background="Green" FontFamily="Verdana" FontSize="12" FontWeight="Bold"> <CheckBox Name="chk2">

Page 43: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

43

<StackPanel Orientation="Horizontal"> <Image Source="nextover.jpg" Height="30"></Image> <TextBlock Text="Item 2" Width="174"></TextBlock> </StackPanel> </CheckBox> </ListBoxItem> </ListBox>

<ComboBox Height="25" Width="150" HorizontalAlignment="Center" VerticalAlignment="Top" IsEditable="True"> <CheckBox Name="Item1">Buenos Aires</CheckBox> <CheckBox Name="Item2">Córdoba</CheckBox> <CheckBox Name="Item3">Mendoza</CheckBox> </ComboBox>

CheckBox Representa un control que un usuario puede activar y desactivar. Pueden tener tres estados: activado, desactivado e indeterminado. <CheckBox Name="Prueba" IsChecked="True">Prueba</CheckBox>

RadioButton Representa un botón que el usuario puede seleccionar, pero no borrar. La propiedad IsChecked de RadioButton se puede establecer haciendo clic en él, pero sólo se puede borrar mediante programación. Normalmente se lo utiliza como elemento de un grupo de controles RadioButton. La selección está determinada por el estado de su propiedad IsChecked. Su evento principal es Checked. <StackPanel Height="40" Canvas.Left="35" Canvas.Top="43" Width="115"> <RadioButton Name="rb1" Checked="rb_Checked">Si</RadioButton> <RadioButton Name="rb2" Checked="rb_Checked">No</RadioButton> <RadioButton Name="rb3" Checked="rb_Checked">No sabe/no contesta</RadioButton> </StackPanel>

Page 44: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

44

Otros Controles

ToolBar: Identifica una barra de herramientas, como el control que contiene un conjunto de botones de comando en una ventana de la aplicación.

Slider: Identifica un control deslizante.

TreeView: Muestra datos jerárquicos, como una tabla de contenido, en una estructura de árbol.

StatusBar: Identifica un control de barra de estado.

ProgressBar: Identifica un control de barra de progreso, que indica visualmente el progreso de una operación prolongada.

PasswordBox: Representa un control diseñado para escribir y administrar las contraseñas.

<StackPanel> <ToolBar Height="26" Name="toolBar1" Width="200" > <Button> <Image Source="setup.ico"/> </Button> <Button>Nuevo</Button> <Button>Abrir</Button> </ToolBar> <Slider Height="21" Name="slider1" Width="100" /> <TreeView Height="150"> <TreeViewItem Header="Archivo"> <TreeViewItem Header="Nuevo" /> <TreeViewItem Header="Abrir" /> <TreeViewItem Header="Cerrar" /> </TreeViewItem> <TreeViewItem Header="Editar"> <TreeViewItem Header="Cortar" /> <TreeViewItem Header="Copiar" /> <TreeViewItem Header="Pegar" /> </TreeViewItem> </TreeView> <StatusBar Height="23" Name="statusBar1" Width="120" > <TextBlock Height="15" Text="Procesando...." /> <ProgressBar Height="15" Name="progressBar1" Width="100" Value="20" /> </StatusBar> <PasswordBox Name="pwdBox" Width="100" MaxLength="64" PasswordChar="*" /> </StackPanel>

Page 45: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

45

4- Información General de Controles Propiedades Generales de los Controles BitmapEffect: Obtiene o establece efectos visuales. <Button.BitmapEffect> <BevelBitmapEffect /> </Button.BitmapEffect>

<Button.BitmapEffect> <DropShadowBitmapEffect /> </Button.BitmapEffect>

Focusable: Obtiene o establece un valor que indica si el foco se puede establecer en este elemento. Para exigir que un elemento del panel reciba el foco, establezca la propiedad Focusable en true. HorizontalAlignment: Obtiene o establece las características de alineación horizontal que se aplican a este elemento cuando se crea dentro de un elemento primario, como un panel o control de elementos. IsEnabled: Obtiene o establece un valor que indica si este elemento está habilitado en la interfase de usuario. Margin: Permite establecer los márgenes de un control con respecto a su contenedor. Se escribe en el siguiente formato (izquierda, arriba, derecha y abajo). Ejemplo: Margin="50,10,50,10" MaxHeight: Obtiene o establece la restricción de alto máximo del elemento. MaxWidth: Obtiene o establece la restricción de ancho máximo del elemento. MinHeigth: Obtiene o establece la restricción de alto mínimo del elemento. MinWidth: Obtiene o establece la restricción de ancho mínimo del elemento. Opacity: Permite generar objetos transparentes o semi transparentes. Los valores aceptados van del 0 al 1, siendo 0 totalmente transparente y 1 totalmente opaco. Padding: Obtiene o establece el relleno interior del control. El relleno se establece en el orden siguiente: izquierda, arriba, derecha y abajo. El valor predeterminado es un grosor de 0 en los cuatro lados. VerticalAlignment: Obtiene o establece las características de alineación vertical que se aplican a este elemento cuando se crea dentro de un elemento primario, como un panel o control de elementos. Visibility: Obtiene o establece la visibilidad de la interfaz de usuario de este elemento. Creación dinámica de controles Todos los controles pueden ser también generados dinámicamente en tiempo de ejecución. // Crea la ventana principal de la aplicación mainWindow = new Window(); mainWindow.Title = "Grid Sample"; // Crea el control Grid Grid myGrid = new Grid(); myGrid.Width = 250; myGrid.Height = 100;

Page 46: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

46

myGrid.HorizontalAlignment = HorizontalAlignment.Left; myGrid.VerticalAlignment = VerticalAlignment.Top; myGrid.ShowGridLines = true; // Define la columnas ColumnDefinition colDef1 = new ColumnDefinition(); ColumnDefinition colDef2 = new ColumnDefinition(); ColumnDefinition colDef3 = new ColumnDefinition(); myGrid.ColumnDefinitions.Add(colDef1); myGrid.ColumnDefinitions.Add(colDef2); myGrid.ColumnDefinitions.Add(colDef3); // Define las filas RowDefinition rowDef1 = new RowDefinition(); RowDefinition rowDef2 = new RowDefinition(); RowDefinition rowDef3 = new RowDefinition(); RowDefinition rowDef4 = new RowDefinition(); myGrid.RowDefinitions.Add(rowDef1); myGrid.RowDefinitions.Add(rowDef2); myGrid.RowDefinitions.Add(rowDef3); myGrid.RowDefinitions.Add(rowDef4); // Agrega el texto a la primera celda TextBlock txt1 = new TextBlock(); txt1.Text = "Productos Comprados"; txt1.FontSize = 20; txt1.FontWeight = FontWeights.Bold; Grid.SetColumnSpan(txt1, 3); Grid.SetRow(txt1, 0); ..................................

Page 47: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

47

Módulo 3

Personalizando la Apariencia de

Aplicaciones WPF

Page 48: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

48

1- Personalizar Apariencia Composición Un requisito habitual para personalizar la apariencia de un control es crear controles compuestos, o sea que incluyan más de un control. La mayoría de los controles WPF son contenedores de otros controles. Puede usar la composición para incrustar los elementos XAML dentro de otros. En varios de los ejemplos mostrados en el capítulo anterior usamos esta técnica para la creación de los controles. <Button Name="btn5" Canvas.Left="64" Canvas.Top="17" Width="129" Height="33" Click="btnAceptar_Click" > <StackPanel Orientation="Horizontal" Width="Auto"> <Image Source="ms.jpg" Width="20" Height="20"></Image> <TextBlock Text="Aceptar" TextAlignment="Right" VerticalAlignment="Center" Width="69"></TextBlock> </StackPanel> </Button> Estilos Los estilos y plantillas permiten el mantenimiento y el uso compartido de la apariencia tanto dentro de una aplicación como entre las diversas aplicaciones. Hacen referencia a un conjunto de características que permiten a los diseñadores de aplicaciones, documentos o interfases de usuario crear aplicaciones visualmente atractivas y estandarizar la apariencia del producto. Otra característica del modelo de estilos de WPF es la separación de la presentación y la lógica. Esto significa que los diseñadores pueden trabajar en la apariencia de una aplicación utilizando solamente XAML, al mismo tiempo que los desarrolladores trabajan en la lógica de programación utilizando C# o Visual Basic. La clase Style permite generar los estilos en aplicaciones WPF. Puede establecer una clase Style en cualquier elemento que derive de FrameworkElement o FrameworkContentElement. Un estilo se suele declarar normalmente como un recurso de la sección de Resources. Puesto que los estilos son recursos, siguen las mismas reglas de ámbito que se aplican a todos los recursos; por tanto, cuando se declara un estilo, afecta a la parte donde se puede aplicar. Si, por ejemplo, se declara el estilo en el elemento raíz del archivo XAML de definición de la aplicación, el estilo se puede usar en cualquier parte de la aplicación. Si se crea una aplicación de navegación y se declara el estilo en uno de sus archivos XAML, el estilo sólo se puede usar en ese archivo XAML. La declaración de estilo está formada por un objeto Style que contiene una colección de uno o más objetos Setter. Cada objeto Setter consta de una propiedad Property y una propiedad Value. La propiedad es el nombre de la propiedad del elemento al que se aplica el estilo. Una vez declarado el estilo como recurso, se puede hacer referencia a él como en el caso de cualquier otro recurso. Si hubiera muchos estilos con la misma propiedad Property es establece el valor del declarado en último lugar. Si se establece la propiedad TargetType en un control sin asignar al estilo un atributo x:Key, el estilo se aplicará a todos los elementos de ese tipo. Esto significa que si se establece explícitamente el atributo x:Key en un valor, el objeto Style no se aplicará automáticamente a todos los elementos de ese tipo. Si el estilo está en la sección de recursos y no se establece la propiedad TargetType del estilo, se deberá proporcionar un atributo x:Key. En el ejemplo siguiente se define un estilo que se aplicará a todas las instancias del elemento Button. Como se ve en el ejemplo los botones toman automáticamente el estilo sin necesidad de asociarlo por código. <Window.Resources>

Page 49: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

49

<Style TargetType="{x:Type Button}"> <Setter Property="FontFamily" Value="Times New Roman" /> <Setter Property="FontSize" Value="30" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="Background" Value="#FFCA5132" /> </Style> </Window.Resources> <Button Height="54" Name="button1" Width="134">Button</Button>

En el siguiente ejemplo se muestra una declaración de estilo que afectará a la propiedad Background de una clase Control. La asignación del estilo a un control se hace en forma explícita. <Window.Resources> <Style x:Key="Style1"> <Setter Property="Control.Background" Value="Yellow"/> </Style> </Window.Resources> <StackPanel> <Label Content="Label Amarillo" Style="{StaticResource Style1}" Width="100"/> <Button Name="button1" Style="{StaticResource Style1}" Height="20" Width="50">Button</Button> </StackPanel>

En el siguiente ejemplo el estilo se aplica al control StackPanel y sus controles contenidos y no a toda la ventana. <StackPanel> <StackPanel.Resources> <Style TargetType="Button"> <Setter Property="Background"> <Setter.Value> <LinearGradientBrush> <GradientStop Color="#DDDDDD" Offset="0" /> <GradientStop Color="#88FF88" Offset=".6" /> <GradientStop Color="#EEEEEE" Offset="1" /> </LinearGradientBrush> </Setter.Value> </Setter> </Style> </StackPanel.Resources>

Page 50: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

50

<Button Height="50" Width="50"> <StackPanel> <TextBlock>Play</TextBlock> <Polygon Points="0,0 0,26 17,13" Fill="Black" /> </StackPanel> </Button> <Button Height="50" Width="50"> <StackPanel> <TextBlock>Play</TextBlock> <Polygon Points="0,0 0,26 17,13" Fill="Black" /> </StackPanel> </Button> </StackPanel>

Nota: Muchos controles de WPF constan de una combinación de otros controles de WPF, por lo que la creación de un estilo que se aplique a todos los controles de un tipo puede tener un gran impacto. Por ejemplo, si se crea un estilo cuyo destino son los controles TextBlock de un control Canvas, el estilo se aplica a todos los controles TextBlock del lienzo, aunque TextBlock forme parte de otro control, como ListBox. Plantillas Los estilos están limitados a la configuración de las propiedades predeterminadas en elementos XAML. Para una libertad completa de una apariencia del control, necesita usar plantillas. Para ello, debe crear un estilo y especificar la propiedad de plantilla. El valor de la propiedad de plantilla pasa a ser un elemento ControlTemplate que especifica cómo redactar el control. La mayoría de controles tienen una apariencia y un comportamiento. Considere un botón: 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. En el siguiente ejemplo se ha especificado un botón en forma de círculo con el icono de reproducción en el centro, colocando el icono de reproducción sobre un elemento elipse. El nuevo botón de plantilla aparece junto a un botón normal.

Page 51: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

51

<StackPanel> <StackPanel.Resources> <Style TargetType="{x:Type Button}" x:Key="PlayButton" > <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid> <Ellipse Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Stroke="DarkGray" VerticalAlignment="Top" HorizontalAlignment="Left" Fill="LightGray" /> <Polygon Points="18,12 18,38 35,25" Fill="Black" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </StackPanel.Resources> <Button Height="50" Width="100">Botón Normal</Button> <Button Height="50" Width="50" Style="{StaticResource PlayButton}" /> </StackPanel>

Otro ejemplo de cómo aplicar plantillas. Tenga en cuenta que la plantilla se aplica siempre a través de un estilo. Este ejemplo usa una plantilla que a través de un control Border redondea la forma de los botones. <Window.Resources> <ControlTemplate x:Key="PlantBotonAzul" TargetType="{x:Type Button}"> <Border BorderBrush="Navy" BorderThickness="1" CornerRadius="5" Background="CornflowerBlue"> <Grid> <Grid.RowDefinitions> <RowDefinition /> </Grid.RowDefinitions> <ContentPresenter Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </Border> </ControlTemplate> <Style x:Key="EstiloBotonAzul" TargetType="{x:Type Button}"> <Setter Property="Template" Value="{StaticResource PlantBotonAzul}" /> </Style> </Window.Resources> <Button Height="40" Name="button1" Width="120" Content="Aceptar" Style="{StaticResource EstiloBotonAzul}" />

Page 52: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

52

Desencadenadores (Triggers) La clase Trigger representa un desencadenador que aplica valores de propiedad o realiza acciones si se cumplen determinadas condiciones. WPF define propiedades que se corresponden con acciones del usuario final, como la propiedad IsMouseOver cuyo valor se establece en true cuando el usuario desplaza el puntero sobre un objeto, o bien, la correspondiente propiedad IsMouseOver de un objeto. La representación de las acciones del usuario final en los valores de propiedad junto con el elemento Trigger permite a los estilos de WPF cambiar en el marcado los valores de las propiedades según esas acciones del usuario final. Las propiedades cambiadas por los desencadenadores se restablecen automáticamente en su valor anterior si ya no se cumple la condición de activación. Los desencadenadores se optimizan para los estados transitorios de los que se espera que cambien y vuelvan a su estado original, como IsPressed en el control Button e IsSelected en el control ListBoxItem. La propiedad Property de interés debe ser una propiedad de dependencia. Observe que debe especificar las propiedades Property y Value en un objeto Trigger para que el desencadenador tenga sentido. La propiedad Setters de un objeto Trigger sólo puede estar formada por objetos Setter. En el siguiente ejemplo se muestra el uso de desencadenadores de manera que cada vez que se hace clic sobre un botón este cambia el tamaño de la letra de su contenido a 14 y cada vez que se pasa el Mouse por encima del mismo el color del fondo se vuelve rojo. <Window.Resources> <Style x:Key="TrCambioColor" TargetType="{x:Type Button}"> <Style.Triggers> <Trigger Property="IsPressed" Value="true"> <Setter Property = "FontSize" Value="14"/> </Trigger> <Trigger Property="IsMouseOver" Value="true"> <Setter Property = "Background" Value="red"/> </Trigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel > <Button Height="23" Name="button1" Width="75" Style="{StaticResource TrCambioColor}">Button</Button> </StackPanel>

Otro tipo de desencadenador es EventTrigger, que inicia un conjunto de acciones en función de la aparición de un evento. Los objetos EventTrigger inician un conjunto de propiedades Actions cuando se produce un evento enrutado especificado. Por ejemplo, quizá desee usar EventTrigger para iniciar un conjunto de animaciones cuando el puntero del mouse esté sobre

Page 53: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

53

cierto control de la interfaz de usuario (UI). A diferencia de Trigger, EventTrigger no tiene ningún concepto de finalización de estado, por lo que no se deshará la acción una vez que la condición que provocó el evento deje de ser verdadera. Tenga en cuenta que al usar EventTrigger, debe elegir eventos que no interfieran con el comportamiento inherente del control. Los controles como Button o TextBox realizan acciones concretas en los eventos de usuario como clics del mouse y eventos de teclado. Por ejemplo, si está creando un botón e intenta establecer el evento MouseDown como la propiedad RoutedEvent de EventTrigger, EventTrigger nunca se aplica porque el botón administra primero el evento. En su lugar, puede usar el evento PreviewMouseDown o un evento diferente. En el siguiente ejemplo, los objetos EventTrigger especifican que, cuando el puntero del mouse entre en el elemento Button, la propiedad Height se establezca en 90 durante un período de 0.2 segundos. Cuando el mouse sale del elemento, la propiedad se establece de nuevo en el valor original durante un período de 1 segundo. Note que se escriben ambos eventos de manera que la acción se detenga al cambiar el estado. <Window.Resources> <Style x:Key="TrCambioColor" TargetType="{x:Type Button}"> <Style.Triggers> <EventTrigger RoutedEvent="Mouse.MouseEnter"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:0.2" Storyboard.TargetProperty="Height" To="90" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> <EventTrigger RoutedEvent="Mouse.MouseLeave"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="Height" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel > <Button Height="23" Name="button1" Width="75" Style="{StaticResource TrCambioColor}">Button</Button> </StackPanel>

Page 54: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

54

Además de Trigger y EventTrigger, hay otros tipos de desencadenadores. MultiTrigger permite establecer valores de propiedad en función de varias condiciones. DataTrigger y MultiDataTrigger se utilizan cuando la propiedad de la condición está enlazada a datos.

2- Crear Controles de Usuario Controles Es imposible suministrar todos los controles que se podrían necesitar. Por este motivo existe la creación de controles. En Windows Presentation Foundation, la composición, el estilo y las plantillas habilitan la personalización de los controles existentes hasta un nivel sin precedentes en tecnologías anteriores, pero la creación de controles permite armar controles una única vez y re usarlos en distintos formularios o proyectos. El primer paso que debe dar antes de escribir su propio control es decidir qué método va a usar para crearlo. Existen dos maneras principales de crear controles en Windows Presentation Foundation: los controles de usuario y los controles personalizados. Ambos enfoques ofrecen ventajas.

Controles de usuario: Es un fragmento de una ventana o página. Permite incluir varios controles y su funcionalidad como una forma de encapsulamiento visual. Se los llama también controles compuestos.

Controles personalizados: Generalmente heredan de un solo control y nos permiten sumar funcionalidad o apariencia al mismo. Su propósito es mejorar los controles existentes.

Controles de Usuario Lo primero que debe hacer al crear un control de usuario es agregar un elemento nuevo a su proyecto. Si hace clic al proyecto con el botón secundario y luego a Agregar, no elija la opción de Control de Usuario del menú contextual. Lamentablemente, esta función intentará crear un control de usuario nuevo de Windows Forms. En su lugar, escoja la opción Agregar nuevo elemento. En el diálogo Agregar nuevo elemento, escoja el elemento Control de Usuario (WPF).

Page 55: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

55

Al crear el control de usuario nuevo se crea un archivo XAML y un archivo de código de seguridad. El archivo XAML es semejante al archivo principal, creado con proyectos nuevos de Windows Presentation Foundation; la diferencia es que el elemento raíz del archivo XAML nuevo es un elemento UserControl. Dentro del elemento UserControl debe crear el contenido que configurará su control. En el siguiente ejemplo se crea un UserControl para armar un botón redondo con el símbolo de play. <UserControl x:Class="WpfCSharp.UserControlWPF" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="55" Width="55"> <Grid> <Ellipse Width="50" Height="50" Stroke="DarkGray" VerticalAlignment="Top" HorizontalAlignment="Left" Name="BotonNegro" Fill="LightGray" /> <Polygon Name="IconoPlay" Points="18,12 18,38 35,25" Fill="Black" /> </Grid> </UserControl> A continuación se muestra el código para usar el control en una ventana. Antes de poder usar un control de usuario en una ventana debe referenciar la ventana al espacio de nombres y darle un alias a dicha referencia. Eso se hace agregando la línea xmlns:UC="clr-namespace:WpfCSharp" donde UC es el nombre que se va a dar al namespace del control. Si el control estuviera en otro ensamblado la línea a ingresar es xmlns:cust=”clr-namespace:CustomWPF;assembly=CustomWPF”

Page 56: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

56

<Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:UC="clr-namespace:WpfCSharp" Title="Window2" Height="300" Width="500" > <StackPanel> <TextBlock>Prueba de usercontrol</TextBlock> <UC:UserControlWPF HorizontalAlignment="left" /> </StackPanel> </Window>

Personalizando Controles de Usuario Cuando se crean controles muchas veces es necesario generar código no solo para poder interactuar con ellos, sino para encapsular funcionalidad. Al crear los controles descubrirá que es necesario implementar las propiedades, métodos y/o eventos para administrar tanto la apariencia del control como su comportamiento en el tiempo de ejecución. Por ejemplo, sería importante en el control creado en el ejemplo anterior obtener y establecer el color del icono. Para ello, se puede crear una propiedad como se muestra a continuación. Brush _ColorIcono = Brushes.Black; public Brush ColorIcono { get { return _ColorIcono; } set { _ColorIcono = value; IconoPlay.Fill = _ColorIcono; } } Y en la ventana que usa a este control se asigna el valor de la propiedad como cualquiera de las otras propiedades del control. <StackPanel> <TextBlock>Prueba de usercontrol</TextBlock> <UC:UserControlWPF HorizontalAlignment="left" ColorIcono="Red" /> </StackPanel>

Page 57: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

57

También podríamos crear un Control de Usuario WPF y cambiar las referencias a la clase UserControl por el control con el cual se desea trabajar, de manera de personalizar solamente un control. <Button x:Class="Pruebas.controlPrueba" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="23" Width="100"> </Button> public partial class controlPrueba : Button { public controlPrueba() { InitializeComponent(); } } Controles Personalizados Si deseamos agregar a la aplicación un control personalizado lo hacemos desde Agregar Elementos, Control Personalizado.

Una vez creado veremos la diferencia con respecto a los controles de usuario. Estos controles no tienen código XAML, por lo tanto necesitamos crear los controles que vayamos a utilizar mediante código subyacente lo cual genera un desarrollo mucho más complejo.

Page 58: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

58

Módulo 4

Enlace a Datos

Page 59: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

59

1- Enlazar Datos Enlace a Datos El enlazado de datos es el proceso que permite establecer una conexión entre la interfase de usuario y la lógica de negocios. Si el enlace es correcto y los datos proveen notificaciones correctamente, al cambiar los datos los elementos enlazados a ellos reflejan el cambio automáticamente y a su vez también debería funcionar en sentido inverso, o sea si modificamos el valor sobre los elementos, el dato asociado también se modifica. WPF proporciona una forma eficaz de enlace de datos. Con WPF, puede realizar la manipulación de datos mediante código Microsoft® .NET Framework, XAML o una combinación de ambos. Puede realizar el enlace a controles, propiedades públicas, XML u objetos, convirtiendo las operaciones de enlace de datos en tareas rápidas, flexibles y realmente fáciles. Para usar el enlace de datos de WPF, debe disponer siempre de un destino y un origen.

El destino del enlace puede ser cualquier elemento o propiedad accesible que se derive de DependencyProperty, un ejemplo es la propiedad Text del control TextBox.

El origen del enlace puede ser cualquier propiedad Public, incluidas propiedades de otros controles, objetos de common language runtime (CLR), elementos XAML, DataSets de ADO.NET, fragmentos XML, etc.

Clase Binding Define un enlace que conecta las propiedades de destinos de enlace y de orígenes de datos. Cada enlace debe especificar el elemento de destino, la propiedad de destino y el origen de datos. Las propiedades de uso más común de esta clase son:

Source: Referencia a la fuente de datos.

ElementName: El nombre del control al cual enlazamos una propiedad, se usa como alternativa de Source cuando el enlace es entre controles.

Path: Indica la propiedad del elemento al cual enlazaremos el dato

Converter: Instancia de una clase que implementa la interfase IValueConverter, que intercepta los movimientos de datos entre el origen y el destino de los datos o viceversa y permite la conversión de datos, el formateo de los mismo, etc. Son muy convenientes y se utilizan con frecuencia

Al crear un enlace se usará la propiedad ElementName cuando el enlace se genera contra otro elemento WPF. Se usará la propiedad Source cuando el objeto a enlazar no es un elemento WPF, por ejemplo cuando es un recurso. No es necesario especificar ninguno de esas dos propiedades cuando el enlace se hace mediando el uso del objeto DataContext. Modos de Enlazar – Propiedad Mode La etiqueta Binding permite también el atributo Mode. El atributo Mode define el modo de enlace que determinará el flujo de datos entre el origen y el destino.

Page 60: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

60

OneWay: los datos fluyen desde el origen hasta el destino cada vez que se realiza un cambio en el origen. Es el modo predeterminado

OneTime: Envía datos desde el origen al destino; sin embargo, hace esto sólo cuando se inicia la aplicación o cuando cambia el DataContext y, como resultado, no espera notificaciones de cambio en el origen.

OneWayToSource: Envía datos desde el destino al origen.

TwoWay: Envía los datos del origen al destino y si hay cambios en el valor de la propiedad de destino, éstos volverán a enviarse al origen.

La selección del modo de enlace apropiado es muy importante. Con frecuencia se emplea OneWay cuando se desea mostrar los datos a un usuario. Se usa TwoWay cuando se desea que el usuario pueda cambiar los datos en el control y que ese cambio se refleje en el origen de datos (por ejemplo un DataSet, objeto, XML u otro control de enlace). Se usa OneWayToSource cuando se desea permitir a un usuario cambiar el origen de datos sin que el origen de datos tenga que volver a enlazar sus datos al destino y se usa OneTime cuando se desea cargar datos de solo lectura al cargar la pantalla y que estos permanezcan sin cambios aunque se efectúen cambios en el origen de datos. DataContext="{Binding ElementName=Customer,Path=Items,Mode=OneWay}"

Momento del Enlace Por defecto el momento del enlace esta predefinido en cada control. Por ejemplo en el caso del ListBox el enlace se hace al momento de seleccionar un elemento, en cambio en el caso de un TextBox el enlace ocurre al perder el foco. Para cambiar el evento que provoca la devolución de los datos al origen, puede especificar un valor para el atributo UpdateSourceTrigger, que es la propiedad de enlace que define cuándo debe actualizarse el origen. Hay cuatro valores que pueden configurarse para UpdateSourceTrigger:

Default: se actualizará en el evento asociado por defecto al control

Explicit: el origen no se actualizará a menos que se llame desde el código al método UpdateSource de la clase BindingExpression.

LostFocus: indica que el origen se actualizará cuando el control del destino pierda el foco.

PropertyChanged: indica que el destino actualizará el origen cada vez que cambie la propiedad enlazada del control del destino. Esta configuración es útil si desea establecer el momento del enlace de forma personalizada.

En este ejemplo a medida que escribe en el TextBox se va escribiendo en el TextBlock, ya que el enlazado está sobre la propiedad Text y el momento establecido con la opción PropertyChanged es la modificación de esa propiedad: <StackPanel> <StackPanel.Resources> <TextBlock x:Key=" miFuente "></TextBlock> </StackPanel.Resources>

Page 61: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

61

<Label>Ingrese el nombre:</Label> <TextBox> <TextBox.Text> <Binding Source="{StaticResource miFuente }" Path="Name" UpdateSourceTrigger="PropertyChanged"/> </TextBox.Text> </TextBox> <Label>El nombre ingresado es:</Label> <TextBlock Text="{Binding Source={StaticResource miFuente }, Path=Name}"/> </StackPanel> Si modifica el valor de UpdateSourceTrigger a Default, el TextBlock se actualizará al perder el foco del TextBox, ya que ese es el evento predeterminado para ese control. En cambio si establece esta propiedad en Explicit deberá invocar al método UpdateSource de la clase BindingExpression. En el siguiente ejemplo se agregó un botón que en su evento Click que invoca a dicho método. De esta manera para actualizar el dato deberá presionar el botón que crea una instancia de la clase BindingExpression e invoca al método UpdateSource. <StackPanel> <StackPanel.Resources> <TextBlock x:Key="miFuente"></TextBlock> </StackPanel.Resources> <Label>Ingrese el Nombre:</Label> <TextBox Name="txtNombre"> <TextBox.Text> <Binding Source="{StaticResource miFuente}" Path="Name" UpdateSourceTrigger="Explicit" /> </TextBox.Text> </TextBox> <Button Height="23" Width="70" Content="Actualizar" Click="Button_Click"></Button> <Label>El nombre ingresado:</Label> <TextBlock Text="{Binding Source={StaticResource miFuente}, Path=Name}"/> </StackPanel> En la ventana de código: private void Button_Click(object sender, RoutedEventArgs e) { BindingExpression be = txtNombre.GetBindingExpression(TextBox.TextProperty); be.UpdateSource(); } Propiedad Asociadas al Enlace de Datos BindsDirectlyToSource: Esta propiedad establece un valor que indica si se va a evaluar la propiedad Path con respecto al elemento de datos o al objeto ObjectDataProvider. El valor por defecto de esta propiedad es false. Cuando es false evalúa la ruta de acceso con respecto al elemento de datos propiamente dicho; de lo contrario, cuando es verdadero, evaluará la ruta de acceso respecto al objeto ObjectDataProvider. En el ejemplo anterior debe estar en true, ya que la propiedad Path tiene el valor de una propiedad de ObjectDataProvider(MethodParameters) y no del elemento de datos.

Page 62: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

62

DisplayMemberPath: Indica el nombre de la propiedad del objeto de origen que será mostrada en el elemento enlazado. ItemsSource: Representa la colección que contiene los datos. Se usa cuando se enlaza a colecciones. IsSynchronizedWithCurrentItem: Indica si la selección debe mantener la propiedad SelectedItem sincronizada con el elemento actual en la propiedad Items. Puede establecer el valor de la propiedad IsSynchronizedWithCurrentItem en true para asegurarse de que el elemento seleccionado siempre se corresponde con la propiedad CurrentItem de ItemCollection. Se usa mucho en relaciones Cabecera-Detalle. Por ejemplo, suponga que existen dos controles ListBox con su propiedad ItemsSource establecida en el mismo origen. Establezca la propiedad IsSynchronizedWithCurrentItem en true en ambos cuadros de lista para asegurarse de que el elemento seleccionado en cada ListBox sea el mismo. Enlace entre Controles Es posible enlazar dos controles de manera de sincronizar los valores entre ellos. En el siguiente ejemplo se enlaza la propiedad Text de un TextBlock a un elemento seleccionado de un control ListBox. <StackPanel> <ListBox x:Name="lbProvincias" Width="248" Height="80"> <ListBoxItem Content="Buenos Aires"/> <ListBoxItem Content="Córdoba"/> <ListBoxItem Content="Mendoza"/> <ListBoxItem Content="Salta"/> <ListBoxItem Content="Neuquen"/> </ListBox> <TextBlock Width="248" Height="24" Text="Provincia elegida:" /> <TextBlock Width="248" Height="24"> <TextBlock.Text> <Binding ElementName="lbProvincias" Path="SelectedItem.Content"/> </TextBlock.Text> </TextBlock> </StackPanel>

La propiedad Text del TextBlock declara un enlace al elemento seleccionado del ListBox con la etiqueta <Binding>. El atributo ElementName de la etiqueta Binding indica el nombre del control al cual está enlazada la propiedad Text de TextBlock. El atributo Path indica la propiedad del elemento (en este caso ListBox) a la cual realizaremos el enlace. El resultado de este código es que cuando se selecciona una provincia del ListBox, el nombre de esa provincia se muestra en TextBlock.

Page 63: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

63

El código anterior también puede escribirse de manera abreviada: <TextBlock Width="248" Height="24" Text="{Binding ElementName=lbProvincias, Path=SelectedItem.Content}" /> XmlDataProvider El objeto XmlDataProvider puede usarse como origen de datos. Este objeto puede enlazar a un documento o fragmento XML que se encuentre incrustado en la etiqueta o en un archivo al que se hace referencia en una ubicación externa. Se debe dar a XmlDataProvider un valor x:Key de manera que se pueda hacer referencia a él a través de los destinos de enlace de datos. Tenga en cuenta el atributo XPath. Este atributo define el nivel del contenido XML que se usará como el origen de datos. Esto es muy útil cuando se enlaza a una estructura XML grande que puede incluirse en un archivo o base de datos y los datos a los que desea realizar el enlace no constituyen el elemento raíz. El contenido XML incrustado debe colocarse en una etiqueta <x:XData>. En este ejemplo los datos XML están incrustados dentro del XMLDataProvider <StackPanel> <StackPanel.Resources> <XmlDataProvider x:Key="Colores" XPath="/colores"> <x:XData> <colores> <color name="Azul"/> <color name="Verde"/> <color name="Amarillo"/> <color name="Blanco"/> <color name="Negro"/> </colores> </x:XData> </XmlDataProvider> </StackPanel.Resources> <ListBox x:Name="lbColor" Width="248" Height="56" ItemsSource="{Binding Source={StaticResource Colores}, XPath=color/@name}"> </ListBox> </StackPanel> Se puede crear un archivo XML y luego referenciar dicho archivo usando XMLDataProvider. El ejemplo siguiente enlaza a un archivo llamado Colores.xml. <StackPanel.Resources> <XmlDataProvider x:Key="Colores" Source="Colores.xml" XPath="/colores"/> </StackPanel.Resources> Archivo Colores.xml <?xml version="1.0" encoding="utf-8" ?> <colores > <color name="Azul"/> <color name="Verde"/> <color name="Amarillo"/>

Page 64: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

64

<color name="Blanco"/> <color name="Negro"/> </colores>

ObjectDataProvider Si se desea realizar un enlace a un objeto o a una lista de objetos, se puede utilizar el objeto ObjectDataProvider como un recurso. La propiedad ObjectType del ObjectDataProvider designa el objeto que proporcionará el origen de enlace de datos mientras que la propiedad MethodName indica el método que será invocado para obtener los datos. Existe otra serie de propiedades disponibles en ObjectDataProvider. La propiedad ConstructionParameters le permite pasar los parámetros al constructor de la clase que se invoca. Puede especificar también los parámetros mediante la propiedad MethodParameters y usar la propiedad ObjectInstance para especificar una instancia existente de un objeto como el origen. Si desea que los datos se recuperen de manera asincrónica, puede configurar la propiedad IsAsynchronous de ObjectDataProvider en true. A continuación el usuario podrá interactuar con la pantalla mientras espera que los datos rellenen el control de destino que está enlazado con el origen de ObjectDataProvider. Al agregar un ObjectDataProvider, es necesario calificar el espacio de nombres de la clase de origen de datos. En este caso, tengo que agregar un atributo xmlns a la etiqueta <Window> para que se califique el acceso directo y éste indique el espacio de nombres apropiado. En el siguiente ejemplo se crea una clase llamada Países la cual contiene un método llamado TraerPaises, el cual devuelve todos los países de una tabla de la base de datos AdventureWorks de SQL Server. public class Paises { public DataTable TraerPaises() { using (DataTable dt = new DataTable()) { using (SqlConnection cn = new SqlConnection(WpfCSharp.Properties.Settings.Default.AdvWorks)) { using (SqlDataAdapter da = new SqlDataAdapter("Select * from Person.CountryRegion", cn)) { da.Fill(dt); } } return dt; } } }

Page 65: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

65

Una vez generada la clase podemos generar la referencia al método usando el control ObjectDataProvider y asociarla a un control enlazable. Para poder llamar a la clase Paises deberá generar la referencia con la línea xmlns:svc="clr-namespace:WpfCSharp al igual que en el uso de controles. <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp"> <StackPanel> <StackPanel.Resources> <ObjectDataProvider x:Key="misPaises" ObjectType="{x:Type svc:Paises}" MethodName="TraerPaises"/> </StackPanel.Resources> <ListBox x:Name="lbPersons" Height="250" Width="200" ItemsSource="{Binding Source={StaticResource misPaises}}" DisplayMemberPath="Name" /> </StackPanel> </Window>

MethodParameters Permite armar la lista de parámetros para pasarlos en la llamada al método definido en la propiedad MethodName. El ejemplo siguiente muestra una clase Provincias que contiene un método TraerProvincias que recibe un parámetro de tipo carácter que permite devolver solo las provincias asociadas al código del país recibido. public class Provincias { public DataTable TraerProvincias(string Cod) { using (DataTable dt = new DataTable()) { using (SqlConnection cn = new SqlConnection(WpfCSharp.Properties.Settings.Default.AdvWorks))

Page 66: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

66

{ using (SqlDataAdapter da = new SqlDataAdapter("Select * From Person.stateProvince Where CountryRegionCode=@Cod", cn)) { da.SelectCommand.Parameters.Add(new SqlParameter("@Cod", SqlDbType.Char, 3)); da.SelectCommand.Parameters["@Cod"].Value = Cod; da.Fill(dt); } } return dt; } } } Usando ObjectDataProvider generamos la referencia a este método y con MethodParametes definimos su parámetro. Luego asociamos ese parámetro a un TextBox de manera de poder seleccionar distintos valores y mostramos la lista de provincias en un ListBox. <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp" xmlns:system="clr-namespace:System;assembly=mscorlib" > <StackPanel> <StackPanel.Resources> <ObjectDataProvider x:Key="ProvxPais" ObjectType="{x:Type svc:Provincias}" MethodName="TraerProvincias"> <ObjectDataProvider.MethodParameters> <system:String>US</system:String> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </StackPanel.Resources> <TextBox Name="txtPais" Width="200"> <TextBox.Text> <Binding Source="{StaticResource ProvxPais}" Path="MethodParameters[0]" BindsDirectlyToSource="true" UpdateSourceTrigger="PropertyChanged"/> </TextBox.Text> </TextBox> <ListBox x:Name="lbPersons" Height="250" Width="200" ItemsSource="{Binding Source={StaticResource ProvxPais}}" DisplayMemberPath="Name" /> </StackPanel> </Window>

Page 67: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

67

DataTemplate Se usa para generar una visualización de los datos personalizada. DataTemplate es el objeto que permite armar la plantilla de datos. En el siguiente ejemplo usa DataTemplate para modificar la apariencia de la lista de manera que el nombre del país se vea en negrita. <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp"> <StackPanel> <StackPanel.Resources> <ObjectDataProvider x:Key="misPaises" ObjectType="{x:Type svc:Paises}" MethodName="TraerPaises"/> <DataTemplate x:Key="LayoutPais" > <StackPanel Orientation="Horizontal" > <TextBlock Text="{Binding Path=CountryRegionCode}" /> <TextBlock Text=" - " /> <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" /> </StackPanel> </DataTemplate> </StackPanel.Resources> <ListBox x:Name="lbPersons" Height="250" Width="200" ItemsSource="{Binding Source={StaticResource misPaises}}" ItemTemplate="{DynamicResource LayoutPais}" /> </StackPanel> </Window>

Page 68: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

68

DataContext Todos los controles que derivan de FrameworkElement tienen la propiedad DataContext. Esta propiedad permite relacionarse con los datos. La propiedad DataContext es heredada por los elementos hijos del elemento al cual está asociada, por lo cual se recomienda asociarla a los elementos contenedores. Es muy útil para construir formularios en donde varias propiedades se asocian a datos de la misma fuente de datos. En el siguiente ejemplo enlaza el origen de datos al objeto Grid, de esta manera que todos los controles contenidos especifican solo el nombre del campo ya que el enlace principal está asociado a su contenedor. <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="300" Width="500"> <Window.Resources> <ObjectDataProvider x:Key="misPaises" ObjectType="{x:Type svc:Paises}" MethodName="TraerPaises"/> </Window.Resources> <Grid DataContext="{StaticResource misPaises}"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <TextBlock Grid.Column="0" Grid.Row="0" Height="21" Name="txbCodigo" Text="Código:" /> <TextBlock Grid.Column="0" Grid.Row="1" Height="21" Name="txbNombre" Text="Nombre:" /> <TextBlock Grid.Column="0" Grid.Row="2" Height="21" Name="txbFecha" Text="Fecha:" /> <TextBox Grid.Column="1" Grid.Row="0" Height="23" Name="txtCodigo" Text="{Binding CountryRegionCode}"/>

Page 69: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

69

<TextBox Grid.Column="1" Grid.Row="1" Height="23" Name="txtNombre" Text="{Binding Name}"/> <TextBox Grid.Column="1" Grid.Row="2" Height="23" Name="txtFecha" Text="{Binding ModifiedDate}"/> </Grid> </Window>

Controles ListView - Gridview WPF no tiene un control GridView pero este puede generarse usando un control ListView. ListView contiene una propiedad View que provee un objeto GridView. La propiedad Columns de un GridView contiene elementos del tipo GridViewColumn. La propiedad AllowsColumnReorder permite establecer si la columnas soportan ordenado o no. En el siguiente ejemplo usando la misma clase Países declarada en el ejemplo anterior generamos un ListView y organizamos las columnas del mismo usando el objeto GridView. <Window.Resources> <ObjectDataProvider x:Key="misPaises" ObjectType="{x:Type svc:Paises}" MethodName="TraerPaises"/> </Window.Resources> <ListView Height="150" Width="280" ItemsSource="{Binding Source={StaticResource misPaises}}" > <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Width="50" Header="Código" DisplayMemberBinding="{Binding Path=CountryRegionCode}"/> <GridViewColumn Width="200" Header="Nombre" DisplayMemberBinding="{Binding Path=Name}"/> </GridView.Columns> </GridView> </ListView.View> </ListView>

Page 70: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

70

2- Notificaciones de Cambio de Propiedad Interfase INotifyPropertyChanged Permite notificar a un cliente que el valor de una propiedad cambió. Se usa generalmente en clientes enlazados para notificarlos que una propiedad fue modificada. Para controlar estas notificaciones entre clientes y fuentes de datos enlazados se podría hacer de dos maneras:

Implementar una clase con la interfase INotifyPropertyChanged

Generar eventos de cambios para cada propiedad La primera opción es la recomendada. Supongamos el siguiente ejemplo. Tenemos una clase Persona con dos propiedades Nombre y Edad. public class Persona { private string _Nombre; public string Nombre { get { return _ Nombre; } set { _ Nombre =value;} } int _Edad; public int Edad { get { return _Edad; } set {_Edad=value;} } public Persona( ) {} public Persona(string pNombre, int pEdad) { Nombre = pNombre ; Edad = pEdad; } } Y la siguiente interfase de usuario que muestra los datos de una instancia de la clase Persona y permite modificar la edad cada vez que se presiona el botón de Cumpleaños: <Window x:Class="Notificaciones.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" Loaded="Window_Loaded"> <Grid VerticalAlignment="Top" HorizontalAlignment="Left" Width="250" Height="100"> <Grid.ColumnDefinitions > <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Grid.RowDefinitions > <RowDefinition /> <RowDefinition /> <RowDefinition />

Page 71: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

71

</Grid.RowDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" >Nombre:</TextBlock> <TextBox Grid.Row="0" Grid.Column="1" Height="23" Name="txtNombre" /> <TextBlock Grid.Row="1" Grid.Column="0">Edad:</TextBlock> <TextBox Name="txtEdad" Grid.Row="1" Grid.Column="1" Height="23"/> <Button Grid.Row="2" Grid.ColumnSpan="2" Name="btnCumple" Click="btnCumple_Click">Cumpleaños</Button> </Grid> </Window> public partial class Window1 : Window { Persona oPersona; public Window1() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { oPersona = new Persona("Juan", 10); txtNombre.Text = oPersona.Nombre; txtEdad.Text = oPersona.Edad.ToString(); } private void btnCumple_Click(object sender, RoutedEventArgs e) { oPersona.Edad++; MessageBox.Show("Feliz Cumpleaños"); // Actualizamos manualmente la propiedad txtEdad.Text = oPersona.Edad.ToString(); } }

Este ejemplo funciona perfectamente, pero como no tiene sincronizados los valores del oPersona con los TextBoxs estos tienen que actualizarse manualmente cada vez que se genera un cambio en alguno de los dos valores. Una forma para que la UI lleve registro de los cambios, mejor que la del ejemplo anterior, es que el objeto avise cuando una propiedad cambia, por ejemplo, lanzando un evento. La forma correcta de hacer esto, es que el objeto implemente INotifyPropertyChanged. using System.ComponentModel. public class Persona: INotifyPropertyChanged { ...... #region Miembros de INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; #endregion }

De esta manera deberíamos entonces agregar a la clase Persona las siguientes líneas. Estas líneas agregan un evento a la clase llamado PropertyChanged y el mismo es disparado a

Page 72: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

72

través del método Notificar, que es invocado por los Set de las propiedades, reflejando el cambio. public class Persona: INotifyPropertyChanged { private string _Nombre; public string Nombre { get { return _Nombre; } set { _Nombre = value; Notificar ("Nombre"); } } int _Edad; public int Edad { get { return _Edad; } set { _Edad=value; Notificar ("Edad"); } } public Persona( ) {} public Persona(string pNombre, int pEdad) { Nombre = pNombre ; Edad = pEdad; } public event PropertyChangedEventHandler PropertyChanged; protected void Notificar (string NombrePropiedad) { if (this.PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(NombrePropiedad)); } } } El código de la ventana quedaría de la siguiente manera. Atajamos el evento disparado por la clase Persona y además necesitaríamos también un mecanismo que detecte los cambios en la interfase gráfica, y los propague hacia el objeto, de manera que la sincronización sea en ambos sentidos. Para ellos atajamos el evento TextChanged de los TextBox y modificamos el valor de las propiedades. De esta manera mantenemos ambos valores sincronizados permanentemente.

Page 73: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

73

public partial class Window1 : Window { Persona oPersona; public Window1() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { oPersona = new Persona("Juan", 10); txtNombre.Text = oPersona.Nombre; txtEdad.Text = oPersona.Edad.ToString(); oPersona.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler( Persona_PropertyChanged); } private void btnCumple_Click(object sender, RoutedEventArgs e) { oPersona.Edad++; MessageBox.Show("Feliz Cumpleaños"); } private void Persona_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { switch( e.PropertyName ) { case "Nombre": txtNombre.Text = oPersona.Nombre; break; case "Edad": txtEdad.Text = oPersona.Edad.ToString(); break; } } private void txtNombre_TextChanged(object sender, TextChangedEventArgs e) { oPersona.Nombre = txtNombre.Text; } private void txtEdad_TextChanged(object sender, TextChangedEventArgs e) { oPersona.Edad = System.Convert.ToInt32(txtEdad.Text); } } Sin importar entonces en donde se de el cambio (objeto ,UI), ambos elementos se mantienen sincronizados. Claramente, la cantidad de código a escribir puede llegar a ser importante si la cantidad de objetos, propiedades de los objetos y eventos aumenta. Además, este tipo de tareas parecen

Page 74: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

74

bastante repetitivas. Por eso es que WPF las abstrae en funcionalidades del framework, dándole el nombre de Data Binding.

3- Convertir Datos ValueConverters Si se desea enlazar dos propiedades de diferente tipo se deberá usar un ValueConverter. Los ValueConventer convierten los valores del tipo de dato de la fuente al tipo de dato del destino o viceversa. Para generar clases convertidora personalizadas es necesario usar la interfase IValueConverter

Interfase IValueConverter Esta interfase permite generar clases que apliquen código de conversión de datos que pueden usarse en enlaces de datos. Para ellos cree una nueva clase e implemente la interfase IValueConverter. Esta interfase contiene dos métodos Convert y ConvertBack. Esta clase podrá convertir los datos de un tipo de dato a otro o modificar el aspecto de la presentación. Ambos métodos están asociados a culturas. Si el uso de culturas no es necesario en la aplicación con la cual se está trabajando este parámetro puede ignorarse. Por ejemplo si necesitamos enlazar un valor verdadero o falso a la propiedad Visibility debemos convertir el dato, ya que esta propiedad es una enumeración que contiene tres valores: Visible, Collapsed o Hidden. Como primer paso escribiremos una clase que implemente a la interfase IValueConverter y que implemente el método Convert de manera de generar la conversión necesaria. En este ejemplo no se está permitiendo la conversión inversa. using System.Windows.Data; using System.Globalization; using System.Windows; public class ConversionBooleanToVisibility: IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is Boolean) { return ((bool)value) ? Visibility.Visible : Visibility.Collapsed; } return value; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

Page 75: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

75

{ throw new NotImplementedException(); } } Luego crearemos un recurso que nos permita relacionar esta ventana con la clase. Al momento del enlace usando el atributo Converter podemos generar la llamada a nuestro convertidor. <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window2" Height="200" Width="300" xmlns:svc="clr-namespace:WpfCSharp" > <StackPanel> <StackPanel.Resources> <svc:ConversionBooleanToVisibility x:Key="boolToVisible" /> </StackPanel.Resources> <CheckBox x:Name="chkPrueba" Content="Prueba Visibilidad" /> <StackPanel x:Name="Detalle" Visibility="{Binding IsChecked, ElementName=chkPrueba, Converter={StaticResource boolToVisible}}"> <Button Height="23" Width="50" Content="Prueba"></Button> </StackPanel> </StackPanel> </Window>

En el siguiente ejemplo se crea una clase para controlar la validación y formateo de datos de tipo fecha. Al escribir una fecha sobre el TextBox, cuando reconoce que lo escrito tiene un formato tipo fecha la devuelve en formato dd/mm/aaaa en el TextBlock [ValueConversion(typeof(DateTime), typeof(String))] public class ConvierteFecha : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { DateTime fecha; if (value != null && DateTime.TryParse(value.ToString(), out fecha)) { return fecha.ToString("dd/MM/yyyy");

Page 76: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

76

} else return ""; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { string strValue = (string)value; DateTime fecha; if (DateTime.TryParse(strValue, out fecha)) return fecha; else throw new NotImplementedException(); } } <Window.Resources > <svc:ConvierteFecha x:Key="ConvFecha" /> </Window.Resources> <StackPanel> <TextBox Name="txtFecha" /> <TextBlock Name="tbFecha" Text="{Binding ElementName=txtFecha, Path=Text, Converter={StaticResource ConvFecha}}" /> <Button Height="20" Width="100" Content="Aceptar"></Button> </StackPanel>

El atributo ValueConversion permite especificar el tipo de dato de entrada y el de salida, es útil para documentar el tipo de conversión que estamos realizando, pero no es obligatorio su uso para que la conversión funcione correctamente.

4- Validar Datos ValidationRules La clase Binding cuenta con una propiedad llamada ValidationRules, que puede almacenar varias clases derivadas de ValidationRule. Todas esas reglas pueden contener cierta lógica que intenta comprobar si el valor enlazado es válido. Se pueden crear reglas personalizadas creando clases que deriven de ValidationRule o usar la clase ExceptionValidationRule que invalida el dato si existen excepciones durante el enlace.

Page 77: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

77

Clase Binding.ValidationRule Permite crear reglas personalizadas de manera de poder validar el ingreso de datos enlazados. En el siguiente ejemplo se creará una clase que valida el rango de edad aceptado en una aplicación. Valida que solo se ingresen números y que el rango esté entre dos valores que pueden establecerse a través de propiedades. public class ReglaEdad: ValidationRule { private int _minEdad; public int MinEdad { get { return _minEdad; } set { _minEdad = value; } } private int _maxEdad; public int MaxEdad { get { return _maxEdad; } set { _maxEdad = value; } } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { int iEdad = 0; try { if (((string)value).Length > 0) iEdad = Int32.Parse((String)value); } catch (Exception e) { return new ValidationResult(false, "Carácter incorrecto o " + e .Message); } if ((iEdad < MinEdad) || (iEdad > MaxEdad)) { return new ValidationResult(false, "Por favor ingrese la edad en el rango: " + MinEdad + " - " + MaxEdad + "."); } else { return new ValidationResult(true, null); } } } Se crea también una clase llamada GenerarPersonas que devuelve un objeto Persona (definido en el punto 2 de este mismo capítulo). La llamada a este método generará la fuente de datos para el enlace.

Page 78: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

78

public class GenerarPersonas { public Persona TraerPersona() { Persona oPersona = new Persona(); oPersona.Nombre = "Juan"; oPersona.Edad = 1; return oPersona; } } Enlazamos entonces la propiedad Edad del objeto Persona a un TextBox llamado tbEdad. También le asociamos la regla ReglaEdad y le damos valor a las propiedades MaxEdad y MinEdad de manera que establecer el rango. <TextBox Name="tbEdad" DataContext="{StaticResource Datos}" Width="100"> <TextBox.Text> <Binding Path="Edad" UpdateSourceTrigger="PropertyChanged" > <Binding.ValidationRules> <svc:ReglaEdad MinEdad="1" MaxEdad="80" /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> Creamos una plantilla y su estilo asociado para poder marcar los TextBox con error mostrando un punto rojo a la derecha del mismo y el mensaje de error en un ToolTip. <Window.Resources> <ObjectDataProvider x:Key="Datos" ObjectType="{x:Type svc:GenerarPersonas}" MethodName="TraerPersona"></ObjectDataProvider> <ControlTemplate x:Key="TextBoxErrorTemplate"> <DockPanel> <Ellipse DockPanel.Dock="Right" Margin="2,0" Width="10" Height="10"> <Ellipse.Fill> <LinearGradientBrush> <GradientStop Color="#11FF1111" Offset="0" /> <GradientStop Color="#FFFF0000" Offset="1" /> </LinearGradientBrush> </Ellipse.Fill> </Ellipse> <AdornedElementPlaceholder /> </DockPanel> </ControlTemplate> <Style x:Key="EstiloError" TargetType="TextBox"> <Setter Property="Margin" Value="4,4,10,4" /> <Setter Property="Validation.ErrorTemplate" Value="{StaticResource TextBoxErrorTemplate}" /> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="ToolTip"> <Setter.Value>

Page 79: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

79

<Binding Path="(Validation.Errors)[0].ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" /> </Setter.Value> </Setter> </Trigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel> <TextBox Name="tbEdad" DataContext="{StaticResource Datos}" Style="{StaticResource EstiloError}" Width="100"> <TextBox.Text> <Binding Path="Edad" UpdateSourceTrigger="PropertyChanged" > <Binding.ValidationRules> <svc:ReglaEdad MinEdad="1" MaxEdad="80" /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <Button Height="20" Width="100" Content="Aceptar"></Button> </StackPanel>

IDataErrorInfo Con la llegada de Microsoft .NET Framework 3.5, la compatibilidad de WPF para la validación de entradas ha mejorado significativamente. ValidationRule es de utilidad para las validaciones sencillas, pero las aplicaciones del mundo real se enfrentan a la complejidad de los datos y las reglas de negocio. La codificación de reglas de negocio en objetos ValidationRule no sólo vincula dicho código a la plataforma WPF, sino que además no permite que haya lógica de negocio ahí donde debe existir: en los objetos de negocios. Muchas aplicaciones tienen una capa de negocio, en la que la complejidad del procesamiento de reglas de negocio se incluye en un conjunto de objetos de negocios. Al compilar en Microsoft .NET Framework 3.5, puede usar la interfase IDataErrorInfo para que WPF pregunte a los objetos de negocios si están en un estado válido o no. De esta forma, se elimina la necesidad de agregar a los objetos una lógica de negocio independiente desde la capa de negocio, y permite crear objetos de negocios independientes de la plataforma de la interfase de usuario. Dado que la interfase IDataErrorInfo existe desde hace años, se facilita en gran medida el uso repetido de objetos de negocios de una aplicación heredada de Windows Forms o ASP.NET. IDataErrorInfo implementa 2 propiedades:

Error: Devuelve el mensaje de error indicando lo que no es correcto en el objeto

Page 80: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

80

Item: Devuelve el mensaje de error para la propiedad Para el ejemplo tomaremos la misma clase Persona del ejemplo anterior y en ella implementaremos la interfase IDataErrorInfo. using System.ComponentModel; public class Persona : IDataErrorInfo { private string _Nombre; public string Nombre { get { return _Nombre; } set { _Nombre = value; } } int _Edad; public int Edad { get { return _Edad; } set { _Edad = value; } } public Persona() { } public Persona(string pNombre, int pEdad) { Nombre = pNombre; Edad = pEdad; } public string Error { get { throw new NotImplementedException(); } } public string this[string columnName] { get { string result = null; if (columnName == "Nombre") { if (String.IsNullOrEmpty(Nombre)) result = "Debe ingresar el nombre"; else if (Nombre.Length < 3) result = "El nombre debe tener al menos 3 carácteres"; } else if (columnName == "Edad") { // Verifica rango if ((Edad < 1) || (Edad > 80)) { result="El edad debe estar entre 1 y 80"; }

Page 81: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

81

} return result; } } } Teniendo en cuenta las mismas fuentes de datos, plantilla y estilo del ejemplo anterior modificamos el código para que valide usando las propiedades de esta interfase. <StackPanel> <TextBox Name="txtNombre" DataContext="{StaticResource Datos}" Style="{StaticResource EstiloError}" Width="100"> <TextBox.Text> <Binding Path="Nombre" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <ExceptionValidationRule /> <DataErrorValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> <TextBox Name="txtEdad" DataContext="{StaticResource Datos}" Style="{StaticResource EstiloError}" Width="100"> <TextBox.Text> <Binding Path="Edad" UpdateSourceTrigger="PropertyChanged" ValidatesOnExceptions="true" ValidatesOnDataErrors="true" /> </TextBox.Text> </TextBox> <Button Height="20" Width="100" Content="Aceptar"></Button> </StackPanel>

ValidatesOnExceptions indica si debe incluirse o no ExceptionValidationRule. ValidatesOnDataErrors indica si debe incluirse o no DataErrorValidationRule, por lo tanto el código usado en ambos TextBox es idéntico, con diferente sintaxis. ExceptionValidationRule Representa la regla que verifica las excepciones que son disparadas durante las modificaciones de las propiedades enlazadas. DataErrorValidationRule Representa la regla que verifica los errores disparados por la implementación de IDataErrorInfo.

Page 82: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

82

Módulo 5

Enlace a Colecciones

Page 83: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

83

1- Enlace a Colecciones Enlace a Colecciones Un objeto de origen del enlace se puede tratar como un objeto único cuyas propiedades contienen los datos, o como una recolección de datos de objetos polimórficos que suelen estar agrupados (como el resultado de una consulta a una base de datos). Por ejemplo, es habitual utilizar ItemsControl como ListBox, ListView o TreeView para mostrar una recolección de datos. La propiedad que se utiliza es ItemsSource. Puede considerar la propiedad ItemsSource como el contenido del ItemsControl. El enlace será OneWay porque la propiedad ItemsSource admite el enlace OneWay de forma predeterminada.

Cómo implementar colecciones Es posible enumerar cualquier colección que implementa la interfase IEnumerable. Sin embargo, para configurar enlaces dinámicos de modo que las inserciones o eliminaciones que se realicen en la colección actualicen la interfase de usuario de forma automática, la colección debe implementar la interfase INotifyCollectionChanged. Esta interfase expone un evento que debe provocarse siempre que se realicen cambios en la colección subyacente. public event PropertyChangedEventHandler PropertyChanged; WPF proporciona la clase ObservableCollection<T>, que es una implementación integrada de una recolección de datos que expone la interfase INotifyCollectionChanged. Observe que para permitir totalmente la transferencia de valores de datos de los objetos de origen a los destinos, cada objeto de la colección que admite propiedades enlazables debe implementar también la interfase INotifyPropertyChanged. Antes de implementar su propia colección, considere la posibilidad de utilizar ObservableCollection<T> o una de las clases de colección existentes, como List<T>, Collection<T> y BindingList<T>, entre otras muchas. Si cuenta con un escenario avanzado y desea implementar su propia colección, considere la posibilidad de utilizar IList, que proporciona una colección no genérica de objetos a los que se puede obtener acceso individualmente por índice y, por consiguiente, proporciona el máximo rendimiento. En el siguiente ejemplo se muestra un ListBox enlazado a una objeto List<>. private void Window_Loaded(object sender, RoutedEventArgs e) { List<string> Lista = new List<string>(); Lista.Add("Buenos Aires"); Lista.Add("Córdoba"); Lista.Add("Mendoza"); stpProv.DataContext = Lista; }

Page 84: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

84

<StackPanel Name="stpProv"> <ListBox Name="lstProv" ItemsSource="{Binding}" /> </StackPanel>

En el siguiente ejemplo se implementa una clase personalizada que implementa la interfase INotifyPropertyChanged que se usará para armar una colección enlazable. using System.ComponentModel; using System.Collections.ObjectModel; public class Empleado : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _Nombre; public string Nombre { get { return _Nombre; } set { _Nombre = value; OnPropertyChanged("Nombre"); } } private string _Apellido; public string Apellido { get { return _Apellido; } set { _Apellido = value; OnPropertyChanged("Apellido"); } } public Empleado(string pNombre, string pApellido) { Nombre = pNombre; Apellido = pApellido; } protected void OnPropertyChanged(string info) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null)

Page 85: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

85

{ handler(this, new PropertyChangedEventArgs(info)); } } public override string ToString() { return Apellido.ToString() + ", " + Nombre.ToString(); } } Ahora creamos otra clase que deriva de ObservableCollection<> y desde el constructor ingresamos los datos a la colección. public class Empleados : ObservableCollection<Empleado> { public Empleados() { Add(new Empleado("Juan", "Perez")); Add(new Empleado("Jose", "Lopez")); Add(new Empleado("Maria", "Rodriguez")); } } Creamos un recurso a la clase que contiene los datos de la colección y generamos el enlace en un ListBox <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp" Title="Enlazar a una Colección" SizeToContent="WidthAndHeight"> <Window.Resources> <svc:Empleados x:Key="Empleados"/> </Window.Resources> <StackPanel> <TextBlock FontFamily="Verdana" FontSize="11" Margin="5,15,0,10" FontWeight="Bold">Empleados de la Empresa</TextBlock> <ListBox Width="200" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource Empleados}}"/> </StackPanel> </Window>

Page 86: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

86

2- Vistas de Colecciones Vistas de colecciones Una vez que ItemsControl esté enlazado a una recolección de datos, quizás desee ordenar, filtrar o agrupar los datos. Para ello, se utilizan vistas de colección, que son clases que implementan la interfase ICollectionView. Una vista de colección es un nivel situado encima de la colección de origen del enlace, que le permite navegar y mostrar la colección de origen en función de las consultas de ordenamiento, filtrado y agrupación, sin tener que cambiar la propia colección de origen subyacente. Una vista de colección también contiene un puntero al elemento actual de la colección. Si la colección de origen implementa la interfase INotifyCollectionChanged, los cambios provocados por el evento CollectionChanged se propagarán a las vistas. Dado que las vistas no cambian las colecciones de origen subyacente, cada colección de origen puede tener varias vistas asociadas. El uso de vistas le permite mostrar los mismos datos de formas diferentes. Por ejemplo, en el lado izquierdo de la página es posible que desee mostrar las tareas ordenadas por prioridad y, en el lado derecho, agrupadas por área. Cómo crear una vista Una manera de crear y utilizar una vista es crear directamente una instancia del objeto de vista y utilizar a continuación esa instancia como el origen del enlace. Para crear otra vista para la misma colección, puede crear otra instancia de CollectionViewSource y asignarle un nombre x:Key diferente. Especificar una vista de colección como origen de enlace es una forma de crear y utilizar una vista de colección. WPF también crea una vista de colección predeterminada para cada colección utilizada como origen de enlace. Si enlaza directamente a una colección, WPF enlaza a su vista predeterminada. Tenga en cuenta que todos los enlaces a una misma colección comparten esta vista predeterminada, de modo que si se realiza un cambio en una vista predeterminada a través de un control enlazado o mediante código (como un cambio de ordenación o en el puntero de elemento actual, que se describe más adelante), éste se refleja en el resto de los enlaces a la misma colección. Para obtener la vista predeterminada, se utiliza el método GetDefaultView. Ordenar Las vistas pueden aplicar un criterio de orden a una colección. Cuando este criterio existe en la colección subyacente, los datos pueden o no tener un orden relevante. La vista de la colección le permite aplicar un orden o cambiar el orden predeterminado, en función de los criterios de comparación especificados. Con las vistas, se puede aplicar ordenamientos controlados por el usuario, sin tener que realizar ningún cambio en la colección subyacente ni tener tampoco que volver a consultar el contenido de la colección. El ordenamiento se realiza usando la propiedad CollectionViewSource.SortDescriptions. Para mejorar el rendimiento, las vistas de colección para objetos DataTable o DataView de ADO.NET delegan el ordenamiento y el filtrado a DataView. Esto hace que todas las vistas de colección del origen de datos compartan el ordenamiento y el filtrado. Para habilitar el ordenamiento y el filtrado independientes de cada vista de colección, inicialice cada vista de este tipo con su propio objeto DataView. El siguiente ejemplo permite ordenar los datos de la colección Empleados del ejemplo anterior por el campo Apellido y mostrarlos en un ListBox <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Page 87: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

87

Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" Title="Enlazar a una Colección" SizeToContent="WidthAndHeight"> <Window.Resources> <svc:Empleados x:Key="Empleados"/> <CollectionViewSource Source="{StaticResource Empleados}" x:Key="EmplOrdenados"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="Apellido"/> </CollectionViewSource.SortDescriptions> </CollectionViewSource> </Window.Resources> <StackPanel> <TextBlock FontFamily="Verdana" FontSize="11" Margin="5,15,0,10" FontWeight="Bold">Empleados de la Empresa</TextBlock> <ListBox Width="200" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource EmplOrdenados}}"/> </StackPanel> </Window>

Agrupar Todas las vistas de colección admiten la funcionalidad de agrupación, que permite al usuario dividir la colección en la vista de colección en grupos lógicos. Los grupos pueden ser explícitos, donde el usuario proporciona una lista de grupos, o implícitos, donde los grupos se generan dinámicamente en función de los datos. La agrupación se realiza usando la propiedad CollectionViewSource.GroupDescriptions. Teniendo en cuenta el ejemplo anterior agregamos una nueva propiedad en la clase llamada Ciudad de manera de organizar a los empleados en su lugar de trabajo. El ejemplo permite mostrar a los empleados organizados por ciudad public class Empleado : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _Nombre; public string Nombre { get { return _Nombre; } set { _Nombre = value; OnPropertyChanged("Nombre"); }

Page 88: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

88

} private string _Apellido; public string Apellido { get { return _Apellido; } set { _Apellido = value; OnPropertyChanged("Apellido"); } } private string _Ciudad; public string Ciudad { get { return _Ciudad; } set { _Ciudad = value; OnPropertyChanged("Ciudad"); } } public Empleado(string pNombre, string pApellido, string pCiudad) { Nombre = pNombre; Apellido = pApellido; Ciudad = pCiudad; } protected void OnPropertyChanged(string info) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(info)); } } public override string ToString() { return Apellido.ToString() + ", " + Nombre.ToString(); } } public class Empleados : ObservableCollection<Empleado> { public Empleados() { Add(new Empleado("Juan", "Perez", "Buenos Aires")); Add(new Empleado("Jose", "Lopez","Mendoza")); Add(new Empleado("Maria", "Rodriguez", "Buenos Aires")); Add(new Empleado("Carlos", "Diaz", "Buenos Aires")); Add(new Empleado("Mariana", "Fernandez", "Mendoza"));

Page 89: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

89

} } <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" Title="Enlazar a una Colección" SizeToContent="WidthAndHeight"> <Window.Resources> <svc:Empleados x:Key="Empleados"/> <CollectionViewSource Source="{StaticResource Empleados}" x:Key="EmplOrdenados"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="Apellido"/> </CollectionViewSource.SortDescriptions> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName="Ciudad"/> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </Window.Resources> <StackPanel> <TextBlock FontFamily="Verdana" FontSize="11" Margin="5,15,0,10" FontWeight="Bold">Empleados de la Empresa</TextBlock> <ListBox Width="200" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource EmplOrdenados}}" DisplayMemberPath="Apellido" Name="lb"> <ListBox.GroupStyle> <x:Static Member="GroupStyle.Default"/> </ListBox.GroupStyle> </ListBox> </StackPanel> </Window>

Filtrar Las vistas pueden aplicar también un filtro a una colección. Esto significa que aunque un elemento pueda existir en la colección, esta vista en concreto está destinada a mostrar únicamente determinado subconjunto de la colección completa. Los datos se filtran en función a condiciones usando la propiedad Filter.

Page 90: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

90

El siguiente ejemplo aplica un filtro de manera de no mostrar todos los datos que están sobre el ListBox en base al valor del CheckBox. Si el CheckBox esta tildado solo se muestran los empleados cuyo apellido empieza con P, si está destildado muestra todos los empleados. La propiedad Filter del objeto CollectionViewSource se asocia al método que controla la condición del filtro. <Window x:Class="WpfCSharp.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="300" Width="500" xmlns:svc="clr-namespace:WpfCSharp" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" Title="Enlazar a una Colección" SizeToContent="WidthAndHeight"> <Window.Resources> <svc:Empleados x:Key="dsEmpleados" /> <CollectionViewSource Source="{StaticResource dsEmpleados}" x:Key="EmplFiltrados" Filter="filtroP" /> </Window.Resources> <StackPanel> <TextBlock FontFamily="Verdana" FontSize="11" Margin="5,15,0,10" FontWeight="Bold">Empleados de la Empresa</TextBlock> <CheckBox Name="chkFiltro" IsChecked="True" Checked="chkFiltro_Checked" Unchecked="chkFiltro_Unchecked" >Empleados con P</CheckBox> <ListBox Width="200" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource EmplFiltrados}}" /> </StackPanel> </Window> public partial class Window2 : Window { CollectionViewSource EmplFilter; public Window2() { InitializeComponent(); EmplFilter = (CollectionViewSource)(this.Resources["EmplFiltrados"]); } private void filtroP(object sender, FilterEventArgs e) { Empleado oItem = (Empleado) e.Item; if (oItem.Apellido.StartsWith("P")) e.Accepted = true; else e.Accepted = false; } private void chkFiltro_Checked(object sender, RoutedEventArgs e) { if (EmplFilter != null) EmplFilter.Filter += new FilterEventHandler(filtroP); } private void chkFiltro_Unchecked(object sender, RoutedEventArgs e) {

Page 91: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

91

if (EmplFilter != null) EmplFilter.Filter -= new FilterEventHandler(filtroP); } }

Punteros de elemento actual Las vistas admiten también la noción de elemento actual. Puede navegar por los objetos en una vista de colección. A medida que navega por los objetos, mueve un puntero de elemento que le permite recuperar el objeto ubicado concretamente en esa posición en la colección. Al enlazar a una vista, el carácter de barra diagonal ("/") de un valor Path designa el elemento actual de la vista. En el ejemplo siguiente, el contexto de datos es una vista de colección. La primera línea enlaza a la colección. La segunda línea enlaza al elemento actual de la colección. La tercera línea enlaza a la propiedad Description del elemento actual de la colección. <Button Content="{Binding }" /> <Button Content="{Binding Path=/}" /> <Button Content="{Binding Path=/Description}" /> La noción de elemento actual no es sólo útil para la navegación de elementos en una colección, sino también para el escenario de enlace Cabecera-Detalle. Navegación de Colecciones Cuando se enlaza datos a controles con propiedades que soportan un solo elemento de la colección es necesario poder navegar la misma. Este escenario es común cuando tengo una ventana que muestra datos por registro en Labels o TextBoxs. Dado que solo es posible ver un solo registro es necesario poder navegar la colección de manera de ver todos sus elementos. Para navegar por controles se usa la interfase ICollectionView que contiene métodos que permiten no solo la navegación, sino también el ordenado, filtrado, etc. En este ejemplo creamos un DataContext con la colección Empleados del ejemplo anterior y agregamos botones para poder navegar la colección. <StackPanel Name="stp" > <TextBlock Text="{Binding Nombre}" Width="100" Height="23"/> <TextBlock Text="{Binding Apellido}" Width="100" Height="23"/> <StackPanel Orientation="Horizontal" > <Button Content="&lt;&lt;" Name="btnPrimero" Width="30" Click="btnPrimero_Click" /> <Button Content="&lt;" Name="btnAnterior" Width="30" Click="btnAnterior_Click" /> <Button Content="&gt;" Name="btnSiguiente" Width="30" Click="btnSiguiente_Click" /> <Button Content="&gt;&gt;" Name="btnUltimo" Width="30" Click="btnUltimo_Click" />

Page 92: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

92

</StackPanel> </StackPanel> private void Window_Loaded(object sender, RoutedEventArgs e) { // Crea la colección como DataContext del StackPanel stp.DataContext = new Empleados(); } private void btnAnterior_Click(object sender, RoutedEventArgs e) { CollectionView Vista = (CollectionView)CollectionViewSource.GetDefaultView(stp.DataContext); Vista.MoveCurrentToPrevious(); if (Vista.IsCurrentBeforeFirst) { Vista.MoveCurrentToLast(); } } private void btnSiguiente_Click(object sender, RoutedEventArgs e) { CollectionView Vista = (CollectionView)CollectionViewSource.GetDefaultView(stp.DataContext); Vista.MoveCurrentToNext(); if (Vista.IsCurrentAfterLast) { Vista.MoveCurrentToFirst(); } } private void btnPrimero_Click(object sender, RoutedEventArgs e) { CollectionView Vista = (CollectionView)CollectionViewSource.GetDefaultView(stp.DataContext); Vista.MoveCurrentToFirst(); } private void btnUltimo_Click(object sender, RoutedEventArgs e) { CollectionView Vista = (CollectionView)CollectionViewSource.GetDefaultView(stp.DataContext); Vista.MoveCurrentToLast(); }

Page 93: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

93

Módulo 6

Administrar Documentos

Page 94: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

94

1- Documentos Definición Windows Presentation Foundation (WPF) proporciona una amplia gama de documentos que permiten la creación de contenido de alta fidelidad diseñado para facilitar su acceso y lectura con respecto a las generaciones anteriores de Windows. Además de las mejoras en las funciones y en la calidad, WPF proporciona servicios integrados para la presentación, empaquetado y seguridad de los documentos. Tipos de documentos WPF divide los documentos en dos categorías generales basándose en su uso previsto

Documentos Dinámicos

Documentos Fijos Los documentos fijos están diseñados para las aplicaciones que requieren una presentación "lo que ve es lo que imprime" (WYSIWYG) precisa, independiente del hardware de pantalla o de impresión utilizado. Los usos típicos para los documentos fijos incluyen la creación de publicaciones, el procesamiento de textos y el diseño de formularios, donde es vital que se respete el diseño de página original. Un documento fijo mantiene la colocación posicional precisa de los elementos de contenido con independencia del dispositivo de pantalla o de impresión utilizado. Por ejemplo, una página de un documento fijo presentada en una pantalla de 96 ppp aparecerá exactamente igual cuando se imprima en una impresora láser de 600 ppp o en una máquina tipográfica fotográfica de 4800 ppp. El diseño de la página permanece inalterado en todos los casos, aunque la calidad del documento se maximiza de acuerdo con las funciones de cada dispositivo. En comparación, los documentos dinámicos están diseñados para optimizar su presentación y legibilidad y son óptimos para su uso cuando la facilidad de lectura constituye el principal escenario de consumo del documento. En lugar de establecerse en un diseño predefinido, este tipo de documentos ajusta y recoloca dinámicamente su contenido basándose en las variables de tiempo de ejecución, tales como el tamaño de la ventana, la resolución del dispositivo y las preferencias opcionales del usuario. Una página web constituye un ejemplo sencillo de un documento dinámico donde se da formato al contenido de la página dinámicamente para ajustarlo a la ventana activa. Los documentos dinámicos optimizan la experiencia de visualización y lectura del usuario, basándose en el entorno de tiempo de ejecución. Por ejemplo, el mismo documento dinámico cambiará su formato dinámicamente para aportar una legibilidad óptima en una pantalla de 19 pulgadas de alta resolución o en la pequeña pantalla de un PDA de 2 x 3 pulgadas. Además, los documentos dinámicos tienen varias características integradas que incluyen la búsqueda, modos de presentación que optimizan la legibilidad y la capacidad de cambiar el tamaño y aspecto de las fuentes.

2- Documentos Dinámicos (FlowDocuments) Definición Los documentos dinámicos o FlowDocuments son documentos que pueden ser creados y mostrados en una aplicación WPF. Consisten primordialmente en textos, con figuras y otros elementos incluidos en el entorno. Consisten de dos diferentes tipos de elementos:

Elementos en bloque, los cuales definen bloques de secciones de texto, siempre tienen un salto de línea entre cada elemento

Elementos en línea, que proveen formatos y efectos de texto en línea. Para crearlos se usa el elemento FlowDocument. Estos documentos deben ser creados dentro de un contenedor, además los contenedores nos proveen de Zoom, Paginación, columnas y cuando se cambia de tamaño, el texto se adecua al tamaño del elemento.

Page 95: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

95

Contenedores para Documentos Dinámicos Existen 3 tipos de contenedores:

FlowDocumentScrollViewer: Este contenedor cuadra todo su contenido de acuerdo a su tamaño y agrega barras de desplazamiento. Es el contenedor más sencillo, aunque este también permite Zoom. Para añadir el Zoom al FlowDocumentScrollViewer, solo debemos dejar la propiedad de IsToolBarVisible a True.

FlowDocumentPageViewer: Automáticamente divide el contenido en páginas, el tamaño de la página está determinado por el tamaño del contenedor, incluye también un control para la paginación, y un elemento Slider para el Zoom

FlowDocumentReader: Es el contenedor que más opciones tiene. Nos permite cambiar las vistas para la paginación, adiciona barras de desplazamiento, columnas, una barra de búsqueda y Zoom.

FlowDocumentScrollViewer <FlowDocumentScrollViewer IsToolBarVisible="true"> <FlowDocument> <Paragraph> Este es una prueba de FlowDocument dentro de un FlowDocumentScrollViewer </Paragraph> </FlowDocument> </FlowDocumentScrollViewer>

FlowDocumentPageViewer <FlowDocumentPageViewer> <FlowDocument> <Paragraph> Este es una prueba de FlowDocument dentro de un FlowDocumentPageViewer </Paragraph> </FlowDocument> </FlowDocumentPageViewer>

Page 96: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

96

FlowDocumentReader <FlowDocumentReader > <FlowDocument> <Paragraph> Este es una prueba de FlowDocument dentro de un FlowDocumentReader </Paragraph> </FlowDocument> </FlowDocumentReader>

Formateando Documentos Dinámicos Todos los elementos en línea y en bloques tienen muchas propiedades que podemos usar para formatear el texto, como por ejemplo el fondo, el color, tipo, tamaño, estilo de la letra entre otras. Los cambios hechos a dichas propiedades son aplicados a todo el texto que esta encerrado en el elemento, hay otras propiedades que solo aplican para los elementos en bloque y son: color, grosor del borde, espaciamiento del texto, márgenes, alineación del texto. Si en el primer ejemplo cambiamos la siguiente línea a <Paragraph Background="yellow" BorderBrush="Red" BorderThickness="4" Foreground="Green" > El documento quedará:

Elementos en Bloque Como hemos visto, los elementos en bloque acomodan el texto dentro del documento, entre estos elementos tenemos:

Paragraph: Este es el más básico de los elementos en bloque y definen un bloque de texto dentro de un párrafo. Puede haber varios párrafos en un documento.

Page 97: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

97

List: El elemento List permite definir una lista de elementos. Cada elemento debe estar dentro de un elemento ListItem, y los ListItem deben contener otro elemento como por ejemplo un Paragraph.

Table: El elemento Table es muy parecido al Table de HTML, para crear una tabla, se crea un elemento Table, que tendrá como hijo un elemento TableRowGroup, en el TableRowGroup habrá una colección de elementos TableRow, y los elementos TableRow tendrán a su vez una colección de elementos TableCell el cuál tendrá el contenido de una celda, como por ejemplo un elemento Paragraph.

Section: El elemento Section es útil para agrupar otros elementos bloque, por ejemplo podemos tener una sección de muchos párrafos con un estilo y otra sección con otros estilos en el mismo documento.

BlockUIContainer: Permite incorporar otros elementos UIElement, como un Button, un ListBox y otros.

List <FlowDocumentScrollViewer> <FlowDocument> <List> <ListItem> <Paragraph>Buenos Aires</Paragraph> </ListItem> <ListItem> <Paragraph>Mendoza</Paragraph> </ListItem> <ListItem> <Paragraph>Córdoba</Paragraph> </ListItem> <ListItem> <Paragraph>San Juan</Paragraph> </ListItem> <ListItem> <Paragraph>San Luis</Paragraph> </ListItem> </List> </FlowDocument> </FlowDocumentScrollViewer>

La propiedad MarketStyle permite configurar las viñetas. Los valores posibles son: Box, Circle, Decimal, Disc, LowerLatin, LowerRoman, None, UpperLatin, UpperRoman. <List MarkerStyle="Decimal" >

Page 98: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

98

Tabla <FlowDocumentScrollViewer> <FlowDocument> <Table BorderBrush="Black"> <TableRowGroup> <TableRow> <TableCell ColumnSpan="4" TextAlignment="Center"> <Paragraph FontSize="16pt" FontWeight="Bold">Ejemplo tabla</Paragraph> </TableCell> </TableRow> <TableRow FontWeight="Bold" Foreground="Red" > <TableCell> <Paragraph>Visitas</Paragraph> </TableCell> <TableCell> <Paragraph>IP</Paragraph> </TableCell> </TableRow> <TableRow Background="White"> <TableCell> <Paragraph>100</Paragraph> </TableCell> <TableCell> <Paragraph>127.0.0.1</Paragraph> </TableCell> </TableRow> <TableRow> <TableCell> <Paragraph>100</Paragraph> </TableCell> <TableCell> <Paragraph>127.0.0.1</Paragraph> </TableCell> </TableRow> </TableRowGroup> </Table> </FlowDocument> </FlowDocumentScrollViewer>

Page 99: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

99

Section <FlowDocumentScrollViewer> <FlowDocument> <Section FontStyle="Italic"> <Paragraph>Escribimos este párrafo en letra italic</Paragraph> </Section> <Section Foreground="red"> <Paragraph>Este párrafo esta escrito en rojo</Paragraph> </Section> </FlowDocument> </FlowDocumentScrollViewer>

BlockUIContainer <FlowDocument> <Section FontStyle="Italic"> <Paragraph>Párrafo en letra italic para probar FlowDocuments.</Paragraph> </Section> <BlockUIContainer> <Button Width="500" Height="23" HorizontalAlignment="Center">clic para más información</Button> </BlockUIContainer> </FlowDocument>

Page 100: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

100

Elementos en Línea (Contenido dinámico) Los elementos dinámicos envuelven texto dentro de bloques, son usados para dar formato a los textos, como crear hipervínculos, aplicar propiedades como negrita a una parte del texto, y otras.

Run: El elemento run, contiene texto normal, cuando no se crea ningún elemento dinámico, el elemento Run es aplicado implícitamente al texto

Bold, Italic y Underline: Estos elementos aplicados a un texto dan el formato de negrita, cursiva y subrayado.

Hyperlink: Agrega un hipervínculo al texto

LineBreak: Provoca un salto de línea, este elemento no soporta contenido directo.

Floater: Permite crear una sección del documento que es paralela con el flujo principal de otro contenido, es útil para las imágenes.

InlineUIContainer: Permite insertar elementos UIElement, dentro del elemento dinámico, es parecido al BlockUIContainer.

<FlowDocument> <Paragraph>Un ejemplo del los elementos <Bold>Bold</Bold> , <Italic>Italic</Italic> y <Underline>Underline.</Underline> <LineBreak/> Aca sigue el párrafo <LineBreak/> </Paragraph> <Paragraph>Probando Hyperlink <Hyperlink>http://www.microsoft.com</Hyperlink> <InlineUIContainer> <Button Width="100" Height="23">Presionar</Button> </InlineUIContainer> </Paragraph> </FlowDocument>

<FlowDocument> <Paragraph> Este es un párrafo normal.

Page 101: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

101

<Floater FontFamily="TimesNewRoman" FontSize="12" Width="100" HorizontalAlignment="Left"> <Paragraph>Este párrafo esta escrito con Floater</Paragraph> </Floater> <LineBreak/> Y Esta parte del párrafo comparte el renglón con el párrafo armado con Floater. </Paragraph> </FlowDocument>

3- Documentos Fijos Definición Hospeda un documento portable, de formato fijo y alta fidelidad con acceso de lectura para la selección de texto de usuario, navegación mediante teclado y búsqueda. Para crearlos se usa el elemento FixedDocument que enlaza lógicamente una secuencia ordenada de páginas en un documento único, de varias páginas y diseño fijo. PageContent es el único elemento secundario permitido del elemento FixedDocument. Cada elemento PageContent hace referencia al origen del contenido para una página única. Los elementos PageContent deben estar en orden de marcado secuencial, coincidiendo con el orden de página del documento. FixedDocument está diseñado para aplicaciones "lo que ve es lo que imprime" (WYSIWYG) donde la aplicación define y controla el diseño del documento a fin de representar con la máxima exactitud la pantalla o el dispositivo de impresión. PageContent Proporciona información sobre los elementos FixedPage dentro de FixedDocument sin exigir a la aplicación que cargue páginas individuales. Los elementos PageContent son los únicos elementos secundarios permitidos de FixedDocument. El orden de los elementos PageContent dentro de FixedDocument define el orden de las páginas. La propiedad de dependencia Source especifica el identificador de recursos uniforme (URI) del objeto FixedPage correspondiente. Nota: El diseñador de WPF no soporta el ingreso del elemento <PageContent>. El programa ejecuta pero el diseñador genera un error que dice: Property 'Pages' does not support values of type 'PageContent'. Es un bug que está documentado y que probablemente va a ser solucionado en la versión 2010. FixedPage Proporciona el contenido de una página de formato fijo de alta fidelidad. FixedPage se utiliza normalmente para proporcionar el contenido de una página dentro de FixedDocument.

Page 102: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

102

FixedPage define automáticamente saltos de página al inicio y al final del contenido. Permite controlar el tamaño de la página usando las propiedades Width y Height. Tiene también la propiedad ContentBox que le permite establecer el área de la página durante la impresión. DocumentViewer Representa un control de visualización de documentos que puede hospedar contenido FixedDocument paginado como XpsDocument. En el ejemplo siguiente generamos una clase Persona con dos propiedades Nombre y Apellido. Luego una segunda clase que tiene un método que devuelve un objeto List<> que devuelve varias instancias de la clase Persona. Por último generamos una grilla para mostrar los datos y ponemos la grilla dentro de un documento fijo. public class Persona { public Persona() { } public Persona(string pNombre, string pApellido) { Nombre = pNombre; Apellido = pApellido; } private string _Nombre; public string Nombre { get { return _Nombre; } set { _Nombre = value; } } private string _Apellido; public string Apellido { get { return _Apellido; } set { _Apellido = value; } } } public class Personas { public List<Persona> TraerPersonas() { List<Persona> lista = new List<Persona>(); lista.Add(new Persona("Juan","Perez")); lista.Add(new Persona("Jose","Fernandez")); lista.Add(new Persona("Maria","Lopez")); lista.Add(new Persona("Pedro","Rodriguez")); return lista; } } <Window.Resources> <ObjectDataProvider x:Key="dsPersonas" ObjectType="{x:Type svc:Personas}"

Page 103: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

103

MethodName="TraerPersonas"/> </Window.Resources> <FixedDocument> <PageContent> <FixedPage> <TextBlock Text="Listado de Personas" HorizontalAlignment="Center" FontSize="14" FontWeight="Bold"></TextBlock> <ListView Height="150" Width="280" ItemsSource="{Binding Source={StaticResource dsPersonas}}" > <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Width="50" Header="Nombre" DisplayMemberBinding="{Binding Path=Nombre}"/> <GridViewColumn Width="200" Header="Apellido" DisplayMemberBinding="{Binding Path=Apellido}"/> </GridView.Columns> </GridView> </ListView.View> </ListView> </FixedPage> </PageContent> </FixedDocument>

Al igual que cualquier otro objeto puede crearse escribiendo código private void Window_Loaded(object sender, RoutedEventArgs e) { FixedDocument fd = new FixedDocument(); PageContent pc = new PageContent(); FixedPage fp = new FixedPage(); ((IAddChild)pc).AddChild(fp); fd.Pages.Add(pc); Canvas cv = new Canvas(); TextBlock tb = new TextBlock(); tb.Text = "Esta es una prueba del elemento FixDocument creado por código";

Page 104: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

104

tb.FontSize = 16; Canvas.SetLeft(tb, 10); Canvas.SetTop(tb, 10); cv.Children.Add(tb); fp.Children.Add(cv); // lo muestra en la ventana DocumentViewer dv = new DocumentViewer(); dv.Document = fd; ((IAddChild)this).AddChild(dv); }

4- Empaquetado e Impresión de Documentos Empaquetado Las API de System.IO.Packaging proporcionan un medio eficaz de organizar los datos de la aplicación, el contenido de los documentos y los recursos relacionados en un contenedor único de fácil acceso, portátil y sencillo de distribuir. Un archivo ZIP es un ejemplo de un tipo de Package capaz de contener varios objetos en una sola unidad. La API de empaquetado proporciona una implementación de ZipPackage predeterminada diseñada mediante una norma basada en la especificación Open Packaging Conventions (OPC, o Convenciones de empaquetado abierto) con arquitectura de archivo XML y ZIP. Las API de empaquetado de WPF facilitan la creación de paquetes, así como el almacenamiento y acceso de objetos en su interior. Un objeto almacenado en un Package se denomina PackagePart (elemento). Los paquetes también pueden incluir certificados digitales firmados que se pueden utilizar para identificar al originador de un elemento y comprobar que no se haya modificado el contenido de un paquete. Los paquetes también incluyen una característica PackageRelationship que permite agregar información adicional a un paquete o asociarla con elementos concretos sin que ello modifique el contenido de los elementos existentes. Los servicios de empaquetado también admiten Microsoft Windows Rights Management (RM). La arquitectura de paquetes de WPF constituye los cimientos de varias tecnologías fundamentales:

Documentos XPS que cumplen XML Paper Specification (XPS).

Documentos XML de formato abierto (.docx) de Microsoft Office "12".

Formatos de almacenamiento personalizados para su propio diseño de aplicaciones. Basándose en las API de empaquetado, XpsDocument está diseñado específicamente para almacenar documentos de contenido fijo de WPF. XpsDocument es un documento autónomo que se puede abrir en un visor, mostrar en un control DocumentViewer, enrutar a una cola de impresión o imprimir directamente en una impresora compatible con XPS.

Page 105: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

105

Empaquetar componentes Las API de empaquetado de WPF permiten organizar los datos y documentos de la aplicación en una sola unidad portátil. Un archivo ZIP es uno de los tipos más comunes de paquetes y constituye el tipo de empaquetado predeterminado proporcionado con WPF. Package es una clase abstracta desde la que se implementa ZipPackage mediante una arquitectura de archivos XML de norma abierta y ZIP. De manera predeterminada, el método Open utiliza ZipPackage para crear y utilizar los archivos ZIP. Un paquete puede contener tres tipos básicos de elementos:

PackagePart: Contenido de aplicaciones, datos, documentos y archivos de recursos. En un archivo ZIP, los elementos del paquete corresponden a los archivos individuales almacenados dentro del archivo ZIP. Gracias a las API de empaquetado de WPF, las aplicaciones pueden escribir, almacenar y leer varios objetos PackagePart utilizando un solo contenedor de archivos ZIP.

PackageDigitalSignatures: Certificado X.509 para la identificación, autenticación y validación. La firma digital no evita que se modifique un elemento, pero se produce un error en una comprobación de la validación en la firma digital si el elemento se ha modificado de alguna forma. La aplicación puede emprender la acción adecuada; por ejemplo, bloquear la apertura del elemento o notificar al usuario que se ha modificado el elemento y ya no es seguro.

PackageRelationships: Información agregada relacionada con el paquete o con un elemento concreto del mismo. Las relaciones de los paquetes proporcionan un medio reconocible de agregar y asociar información adicional a los elementos individuales o al paquete completo. Las relaciones de los paquetes se utilizan para dos funciones primarias, definir las relaciones de dependencia entre un elemento y otro y definir las relaciones de información que agregan notas u otros datos relacionados con el elemento.

Documentos XPS (XPSDocument) Un documento XML Paper Specification (XPS) es un paquete que contiene uno o más documentos fijos junto con todos los recursos y la información necesarios para su representación. XPS también es el formato de archivo nativo de cola de impresión de Windows Vista. XpsDocument se almacena en un conjunto de datos ZIP estándar y puede incluir una combinación de componentes XML y binarios, tales como archivos de imagen y de fuentes. Las relaciones PackageRelationships se utilizan para definir las dependencias entre el contenido y los recursos que se necesitan para representar totalmente el documento. El diseño de XpsDocument proporciona una solución de documento único de alta fidelidad que admite varios usos:

Lectura, escritura y almacenamiento de contenido y recursos de documentos fijos en un único archivo portátil y fácil de distribuir.

Presentación de documentos con la aplicación Visor de XPS.

Generación de documentos en el formato de salida de cola de impresión de Windows Vista.

Enrutamiento directo de documentos a las impresoras compatibles con XPS. XpsDocumentWriter Provee métodos para escribir en un documento XPS o en la cola de impresión. Esta clase no tiene constructor, para crearla se usa el método CreateXpsDocumentWriter de la clase XpsDocument o de la clase PrintQueue. Para el siguiente ejemplo de deberá agregar la referencia a System.Printing.dll using System.Windows.Xps;

Page 106: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

106

using System.Printing; PrintDocumentImageableArea area = null; XpsDocumentWriter xdw = PrintQueue.CreateXpsDocumentWriter(ref area); if (xdw != null) xdw.Write(fd); Nota: fd es un FixedDocument creado en un ejemplo anterior Impresión de Documentos La clase PrintDialog provee otra forma de imprimir documentos usando el método PrintDocument. Este método envía un DocumentPaginator a una cola de impresión. La clase DocumentPaginator provee una clase abstracta que admite la creación de elementos de varias páginas de un documento único, o sea que soporta paginado. Un objeto DocumentPaginator puede ser obtenido desde un documento WPF, tanto fijo o dinámico. <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <FlowDocumentReader Grid.Row="0"> <FlowDocument Name="DocPrueba" > <Paragraph>Escribiendo un párrafo en un documento dinámico para probar impresión</Paragraph> </FlowDocument> </FlowDocumentReader> <Button Grid.Row="1" Width="100" Height="23" Click="Imprimir_Click">Imprimir</Button> </Grid> private void Imprimir_Click(object sender, RoutedEventArgs e) { PrintDialog printDialog = new PrintDialog(); if (printDialog.ShowDialog() == true) { printDialog.PrintDocument(((IDocumentPaginatorSource) DocPrueba).DocumentPaginator, "Impresión Documento Dinámico"); } }

Page 107: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

107

Módulo 7

Gráficos, Animaciones y Multimedia

Page 108: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

108

1- Gráficos 2D Dibujos y formas WPF proporciona objetos Drawing y Shape para representar el contenido de los dibujos gráficos. Sin embargo, los objetos Drawing son estructuras más sencillas que los objetos Shape y proporcionan mejores características de rendimiento. Shape Un objeto Shape permite dibujar una forma gráfica en la pantalla. Se pueden utilizar dentro de los paneles y de la mayoría de los controles. Son fáciles de usar y proporcionan numerosas características útiles, tales como la administración del diseño y el control de eventos. WPF proporciona varios objetos de forma listos para usar. Todos los objetos de formas heredan de la clase Shape. Los objetos de formas disponibles incluyen

Ellipse: Borde elíptico.

Line: Dibuja una línea recta entre dos puntos.

Path: Dibuja una serie de líneas y curvas conectadas.

Polygon: Dibuja un polígono, que es una serie de líneas conectadas que crean una forma cerrada.

Polyline: Dibuja una serie de líneas rectas conectadas.

Rectangle: Obtiene un área rectangular que define los puntos inicial y final del degradado.

<Canvas> <Ellipse Canvas.Left="10" Canvas.Top="0" Height="50" Name="ellipse1" Stroke="Black" Width="100" Fill="Gray" /> <Rectangle Canvas.Left="80" Canvas.Top="20" Height="70" Name="rectangle1" Stroke="Blue" Width="150" Fill="Beige" /> <Line X1="20" Y1="20" X2="150" Y2="80" Stroke="Red" StrokeThickness="4" ></Line> <Polygon Canvas.Left="200" Canvas.Top="10" Points="50,30 60,80 40,55 30,60" Stroke="Purple" StrokeThickness="5"></Polygon> </Canvas>

Propiedades de las formas

Fill: Pinta el interior. Tipo de dato Brush

Stroke: Pinta el borde de la forma

StrokeThickness: Establece el espesor del borde

Page 109: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

109

Stretch: Determina como llena el espacio vacío del contenedor Drawing Por otro lado, los objetos Drawing proporcionan una implementación más ligera para representar formas, imágenes y texto. Hay cuatro tipos de objetos Drawing:

GeometryDrawing se utiliza para representar contenido de geometría. Los objetos de geometría se pueden utilizar para definir la región de un control, por ejemplo, o definir la región de recorte que se aplicará a una imagen. Los objetos de geometría pueden ser regiones simples, tales como rectángulos y círculos, o bien regiones compuestas creadas a partir de dos o más objetos de geometría. Las regiones de geometría más complejas se pueden crear combinando objetos derivados de PathSegment, como ArcSegment, BezierSegment y QuadraticBezierSegment.

ImageDrawing dibuja una imagen. proporciona menos características que Image para representar imágenes, sin embargo, ofrece ventajas de rendimiento que lo hace ideal para describir los fondos y las imágenes prediseñadas.

GlyphRunDrawing dibuja texto.

DrawingGroup dibuja otros dibujos. Utilice un grupo de dibujo para combinar otros dibujos en un único dibujo compuesto.

<Path Stroke="Black" StrokeThickness="1" > <Path.Data> <LineGeometry StartPoint="10,20" EndPoint="100,130" /> </Path.Data> </Path>

<Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry> <PathGeometry.Figures> <PathFigureCollection> <PathFigure StartPoint="1,10"> <PathFigure.Segments> <PathSegmentCollection> <QuadraticBezierSegment Point1="150,200" Point2="300,100" /> </PathSegmentCollection> </PathFigure.Segments> </PathFigure> </PathFigureCollection> </PathGeometry.Figures> </PathGeometry> </Path.Data> </Path>

Page 110: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

110

Aparentemente, la clase Geometry y la clase Shape son bastante similares. Ambas se utilizan para representar gráficos 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 geometría, deberá utilizarse otra clase, del tipo de DrawingContext, Drawing o Path (cabe destacar que Path es una forma) para realizar la operación de dibujo. Las propiedades de representación, tales como el relleno, el trazo y el grosor del trazo pertenecen a la clase que dibuja el objeto de geometría, mientras que un objeto de forma contiene estas propiedades. Podemos pensar en esta diferencia de la siguiente manera: un objeto de geometría define una región, un círculo por ejemplo, mientras que un objeto de forma define una región, define cómo se rellena y perfila esa región, y participa en el sistema de diseño. Puesto que los objetos Shape se derivan de la clase FrameworkElement, utilizarlos puede aumentar significativamente el consumo de memoria de la aplicación. Si realmente no necesita las características de FrameworkElement para el contenido gráfico, es conveniente utilizar los objetos Drawing, más ligeros. Propiedad Clip Obtiene o establece una región que limita la región de dibujo del gráfico. <Button Content="Aceptar" Height="100" Width="100"> <Button.Clip> <EllipseGeometry Center="50,50" RadiusX="50" RadiusY="20" /> </Button.Clip> </Button>

Brush Define los objetos usados para pintar objetos gráficos. Las clases que se derivan de Brush describen cómo se pinta el área. Un objeto Brush "pinta" o "rellena" un área con sus resultados. Los distintos pinceles tienen tipos de resultados diferentes. Algunos pinceles pintan un área con un color sólido, otros con un degradado, una trama, una imagen o un dibujo. La lista siguiente describe los distintos tipos de pinceles de WPF:

SolidColorBrush: pinta un área con un color (Color) sólido.

LinearGradientBrush: pinta un área con un degradado lineal.

RadialGradientBrush: pinta un área con un degradado radial.

ImageBrush: pinta un área con una imagen (representada por un objeto ImageSource).

Page 111: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

111

DrawingBrush: pinta un área con un objeto Drawing. El dibujo puede incluir vectores y objetos de mapa de bits.

VisualBrush: pinta un área con un objeto Visual. VisualBrush permite duplicar el contenido de una parte de la aplicación en otra área; es muy útil para crear efectos de reflexión y ampliar partes de la pantalla.

<StackPanel> <Rectangle Width="50" Height="20" Fill="#FF0000FF" /> <Rectangle Width="50" Height="20"> <Rectangle.Fill> <SolidColorBrush> <SolidColorBrush.Color> <!-- Usa RGB. Cada valor tiene un rango de 0-255. R red, G green, B blue. A controla transparencia --> <Color A="255" R="255" G="0" B="255" /> </SolidColorBrush.Color> </SolidColorBrush> </Rectangle.Fill> </Rectangle> <Rectangle Width="200" Height="50"> <Rectangle.Fill> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="Yellow" Offset="0.0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1.0" /> </LinearGradientBrush> </Rectangle.Fill> </Rectangle> <Rectangle Width="200" Height="100"> <Rectangle.Fill> <RadialGradientBrush GradientOrigin="0.5,0.5" Center="0.5,0.5" RadiusX="0.5" RadiusY="0.5"> <RadialGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1" /> </RadialGradientBrush.GradientStops> </RadialGradientBrush> </Rectangle.Fill> </Rectangle> </StackPanel>

Page 112: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

112

2- Imágenes Imágenes La creación de imágenes de WPF proporciona una mejora significativa con respecto a las funciones de creación de imágenes de las versiones anteriores de Windows. Las funciones de creación de imágenes, tales como la presentación de mapas de bits o el uso de imágenes en controles comunes, se administraban principalmente por las interfases de programación de aplicaciones (API) de la interfaz de dispositivo gráfico (GDI) o GDI+ de Microsoft Windows. Estas API proporcionaban la funcionalidad básica para la creación de imágenes, pero carecían de características tales como compatibilidad con la extensibilidad de códec y con imágenes de alta fidelidad. La API de creación de imágenes de WPF se ha rediseñado para superar las limitaciones de GDI y GDI+ y proporcionar un nuevo conjunto de API para mostrar y utilizar imágenes en las aplicaciones. Al utilizar imágenes, tenga en cuenta las recomendaciones siguientes para obtener el mejor rendimiento:

Si su aplicación le exige que muestre imágenes en miniatura, puede ser conveniente crear una versión de dimensiones reducidas de la imagen. De manera predeterminada, WPF carga la imagen y la decodifica a su tamaño completo. Si sólo desea una versión en miniatura de la imagen, WPF decodifica innecesariamente la imagen a su tamaño completo y, a continuación, la reduce a la escala en miniatura. Para evitar este consumo de recursos innecesario, puede solicitar a WPF que decodifique la imagen a un tamaño en miniatura o bien solicitar a WPF que cargue una imagen en miniatura.

Siempre decodifique la imagen al tamaño deseado y no al tamaño predeterminado. De este modo, no sólo mejorará el espacio de trabajo de la aplicación, sino también la velocidad de ejecución.

Si es posible, combine las imágenes en una imagen única, como una tira cinematográfica creada de varias imágenes.

Se utiliza un códec para descodificar o codificar cada formato multimedia concreto. Las imágenes WPF incluyen un códec para los formatos de imagen BMP, JPEG, PNG, TIFF, Windows Media Photo, GIF y de icono. Cada uno de estos códecs permite a las aplicaciones decodificar y, con la excepción de los iconos, codificar sus formatos de imagen respectivos. La selección del códec es automática a menos que se especifique un descodificador concreto. Control Image Hay varias maneras de mostrar una imagen en una aplicación de Windows Presentation Foundation (WPF). Las imágenes se pueden mostrar mediante un control Image, pintado en un objeto visual con un objeto ImageBrush, o dibujado con un objeto ImageDrawing. Image es un elemento de marco de trabajo y la manera principal de mostrar imágenes en aplicaciones. En muchos casos se utiliza un objeto BitmapImage para hacer referencia a un archivo de imagen. BitmapImage es un BitmapSource especializado que se optimiza para la carga en Lenguaje de marcado de aplicaciones extensible (XAML) y constituye una manera fácil de mostrar imágenes como la propiedad Source de un control Image. El uso de las propiedades DecodePixelWidth o DecodePixelHeight ahorra memoria de la aplicación. <StackPanel> <Image Width="150" Source="mslogo.jpg"/> <Image Width="130"> <Image.Source> <BitmapImage DecodePixelWidth="130" UriSource="mslogo.jpg" /> </Image.Source> </Image> </StackPanel>

Page 113: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

113

Girar, Convertir y Recortar Imágenes WPF permite a los usuarios transformar imágenes utilizando las propiedades de BitmapImage o mediante objetos BitmapSource adicionales, tales como CroppedBitmap o FormatConvertedBitmap. Estas transformaciones de imagen pueden girar una imagen, ajustar su escala, cambiar su formato de píxel o recortarla. Los giros de imagen se realizan mediante la propiedad Rotation de BitmapImage. Los giros sólo se pueden hacer en incrementos de 90 grados. En el siguiente ejemplo vemos como rotar la imagen 90º <Image Height ="150"> <Image.Source> <TransformedBitmap Source="mslogo.jpg" > <TransformedBitmap.Transform> <RotateTransform Angle="90"/> </TransformedBitmap.Transform> </TransformedBitmap> </Image.Source> </Image>

En este ejemplo convertimos la imagen a tonos de gris. <Image Width="150" > <Image.Source> <FormatConvertedBitmap Source="mslogo.jpg" DestinationFormat="Gray2" /> </Image.Source> </Image>

Page 114: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

114

En este ejemplo recortamos la imagen. <Image Width="200" Source="mslogo.jpg"> <Image.Clip> <EllipseGeometry Center="75,10" RadiusX="40" RadiusY="15" /> </Image.Clip> </Image>

Expandir imágenes La propiedad Stretch controla cómo se expande una imagen para rellenar su contenedor. La propiedad Stretch acepta los valores siguientes, definidos por la enumeración Stretch:

None: la imagen no se expande para rellenar el área de salida. Si la imagen es mayor que el área de salida, la imagen se dibuja en el área de salida, y se recorta lo que sobra.

Fill: se ajusta la escala de la imagen al área de salida. Dado que la escala se aplica de manera independiente al alto y al ancho de la imagen, puede que no se conserve su relación de aspecto original. Es decir, es posible que la imagen se distorsione para rellenar totalmente el contenedor de salida.

Uniform: se cambia la escala de la imagen de modo que se ajuste completamente al área de salida. Se conserva la relación de aspecto de la imagen.

UniformToFill: la escala de la imagen se ajusta hasta rellenar completamente el área de salida y se conserva la relación de aspecto original de la imagen.

<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="100"/> <ColumnDefinition Width="100"/> <ColumnDefinition Width="100"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="50"/> </Grid.RowDefinitions> <Image Grid.Row="0" Grid.Column="0" Source="mslogo.jpg" Stretch="None" /> <Image Grid.Row="0" Grid.Column="1" Source="mslogo.jpg" Stretch="Fill" /> <Image Grid.Row="0" Grid.Column="2" Source="mslogo.jpg" Stretch="Uniform" /> <Image Grid.Row="0" Grid.Column="3" Source="mslogo.jpg" Stretch="UniformToFill" /> </Grid>

Page 115: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

115

Pintar con imágenes Las imágenes también se pueden mostrar en una aplicación pintándolas con un objeto Brush. Los pinceles permiten pintar los objetos de una interfase de usuario con cualquier cosa desde simples colores sólidos hasta conjuntos complejos de tramas e imágenes. Para pintar con imágenes, utilice un ImageBrush. Un ImageBrush es un tipo de TileBrush que define su contenido como una imagen de mapa de bits. Un ImageBrush muestra una imagen única, que se especifica mediante su propiedad ImageSource. Puede controlar cómo se expande, alinea o coloca en mosaico la imagen, a fin de evitar la distorsión y crear tramas y otros efectos. <Button Height="50" Width="100" Foreground="White" FontWeight="Bold" FontSize="14" > Aceptar <Button.Background> <ImageBrush ImageSource="Flower2.jpg" /> </Button.Background> </Button>

3- Gráficos 3D La implementación de 3D en WPF permite a los programadores dibujar, transformar y animar gráficos 3D en el marcado y en el código de procedimientos, utilizando las mismas funciones permitidas por la plataforma a los gráficos 2D. Los programadores pueden combinar gráficos 2D y 3D para crear controles enriquecidos, proporcionar ilustraciones complejas de datos o mejorar la experiencia del usuario con la interfaz de una aplicación. La compatibilidad con 3D de WPF no está diseñada para proporcionar una plataforma con todas las funciones para la programación de juegos. Viewport3D El contenido de los gráficos 3D de WPF se encapsula en un elemento, Viewport3D, que puede participar en la estructura de elementos bidimensionales. El sistema de gráficos trata Viewport3D como un elemento visual bidimensional como tantos en WPF. Viewport3D actúa como una ventana, un área de visualización, a una escena tridimensional. Expresado de modo más preciso, es la superficie sobre la que se proyecta una escena 3D. En una aplicación 2D convencional, utilice Viewport3D como cualquier otro elemento contenedor, como Grid o Canvas. Aunque puede utilizar Viewport3D con otros objetos de dibujo 2D en el mismo gráfico de escena, no puede combinar objetos 2D y 3D dentro de Viewport3D.

Page 116: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

116

Espacio de coordenadas 3D El sistema de coordenadas de WPF para gráficos 2D localiza el origen en la parte superior izquierda del área de representación (que suele ser la pantalla). En el sistema 2D, los valores positivos del eje X se extienden hacia la derecha, y los valores positivos del eje Y extienden hacia abajo. En el sistema de coordenadas 3D, sin embargo, el origen se encuentra en el centro del área de representación, los valores positivos del eje X se extienden hacia la derecha, los valores positivos del eje Y se extienden hacia arriba (no hacia abajo) y los valores positivos del eje Z se extienden hacia el exterior partiendo del origen, es decir, hacia el espectador.

Cámaras y proyecciones Los programadores que trabajan en 2D están acostumbrados a colocar los elementos de dibujo primitivos en una pantalla bidimensional. Al crear una escena 3D, es importante recordar que, en realidad, se está creando una representación 2D de los objetos 3D. Dado que una escena 3D tiene un aspecto diferente dependiendo del punto de vista del espectador, debe especificar ese punto de vista. La clase Camera permite especificar este punto de vista para una escena 3D. Otra manera de entender cómo se representa una escena 3D en una superficie 2D consiste en describir dicha escena como una proyección sobre la superficie de visualización. ProjectionCamera permite especificar proyecciones diferentes y sus propiedades para cambiar la manera en que el espectador ve los modelos 3D. PerspectiveCamera proporciona una perspectiva de punto de fuga. Puede especificar la posición de la cámara en el espacio de coordenadas de la escena, la dirección y el campo de visión de la cámara, y un vector que define la dirección "hacia arriba" en la escena. Las propiedades NearPlaneDistance y FarPlaneDistance de ProjectionCamera limitan el intervalo de proyección de la cámara. Dado que las cámaras se pueden ubicar en cualquier parte de la escena, es posible situarlas dentro de un modelo o muy cerca de él, con lo que resultaría difícil distinguir correctamente los objetos. NearPlaneDistance permite especificar una distancia mínima a la cámara a partir de la cual no se dibujarán objetos. A la inversa, FarPlaneDistance permite especificar una distancia máxima a la cámara, más allá de la que no se dibujarán objetos, lo que garantice que no se incluyan en la escena aquellos objetos que estén demasiado lejos para ser reconocibles. OrthographicCamera especifica una proyección ortogonal de un modelo 3D sobre una superficie visual 2D. Al igual que otras cámaras, especifica una posición, dirección de visualización y dirección "hacia arriba". OrthographicCamera describe un cuadro de vista cuyos lados son paralelos, en lugar de uno cuyos lados convergen en un punto de la cámara.

Page 117: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

117

Elementos primitivos de modelo y malla Model3D es la clase base abstracta que representa un objeto 3D genérico. Para generar una escena 3D, necesita algunos objetos que ver; los objetos que componen el gráfico de escena se derivan de la clase Model3D. En la actualidad, WPF permite geometrías de modelado con GeometryModel3D. Para crear un modelo, comience por crear un elemento primitivo, o malla. Un elemento 3D primitivo es una colección de vértices que constituyen una entidad 3D única. La mayoría de los sistemas 3D proporcionan elementos primitivos modelados a partir de la figura cerrada más simple: un triángulo definido por tres vértices. Dado que los tres puntos de un triángulo son coplanares, puede seguir agregando triángulos para modelar formas más complejas, denominadas mallas. El sistema 3D de WPF proporciona actualmente la clase MeshGeometry3D, que permite especificar cualquier geometría; en este momento, no admite elementos 3D primitivos predefinidos, tales como esferas o formas cúbicas. Empiece por crear MeshGeometry3D especificando una lista de vértices de triángulos como su propiedad Positions. Cada vértice se especifica como un Point3D. (En Lenguaje de marcado de aplicaciones extensible (XAML), especifique esta propiedad como una lista de números agrupados en ternas, que representan las coordenadas de cada vértice.) Según cuál sea la geometría, la malla puede estar compuesta de muchos triángulos, algunos de los cuales compartirán las mismas esquinas (vértices). WPF necesita información sobre qué triángulos comparten qué vértices para dibujar la malla correctamente. Esta información se proporciona especificando una lista de índices de triángulos con la propiedad TriangleIndices. Esta lista especifica el orden en el que los puntos especificados en la lista Positions determinarán un triángulo. Puede seguir definiendo el modelo especificando valores para las propiedades Normals y TextureCoordinates. Para representar la superficie del modelo, el sistema de gráficos necesita información sobre en qué dirección mira la superficie de cualquier triángulo dado. Utiliza esta información para realizar los cálculos de iluminación del modelo: las superficies que miran directamente hacia una fuente de luz parecen más luminosas que las que tienen un ángulo que las oculta de la luz. Aunque WPF puede determinar los vectores normales predeterminados utilizando las coordenadas de posición, también es posible especificar vectores normales diferentes para crear un aspecto más aproximado de las superficies curvas. La propiedad TextureCoordinates especifica una colección de puntos (Point) que indica al sistema de gráficos cómo asignar las coordenadas que determinan cómo trazar una textura en los vértices de la malla. Las TextureCoordinates se especifican como un valor comprendido entre cero y 1, incluidos. Como sucede con la propiedad Normals, el sistema de gráficos puede calcular las coordenadas de textura predeterminadas, pero si lo desea puede establecer coordenadas de textura diferentes a fin de controlar la asignación de una textura que incluya parte de un patrón repetitivo.

Page 118: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

118

Materiales del Modelo Para que una malla parezca un objeto tridimensional, debe tener una textura aplicada que cubra la superficie definida por sus vértices y triángulos, de manera que se pueda iluminar y proyectar por la cámara. En 2D, se utiliza la clase Brush para aplicar colores, patrones, degradados y otro contenido visual a las áreas de la pantalla. El aspecto de los objetos 3D, sin embargo, depende del modelo de iluminación, no sólo del color o del patrón que se les aplica. Los objetos reales reflejan la luz de manera distinta según la calidad de su superficie: las superficies satinadas y brillantes no tienen el mismo aspecto que las superficies ásperas o mates, y algunos objetos parecen absorber la luz, mientras que otros la emiten. Puede aplicar a los objetos 3D los mismos pinceles que a los objetos 2D, pero no directamente. Para definir las características de la superficie de un modelo, WPF utiliza la clase abstracta Material. Las subclases concretas de Material determinan algunas de las características del aspecto de la superficie del modelo y, además, cada una de ellas proporciona una propiedad Brush a la que puede pasar SolidColorBrush, TileBrush o VisualBrush.

DiffuseMaterial especifica que el pincel se aplicará al modelo como si estuviera iluminado con una luz difusa. Utilizar DiffuseMaterial es lo que más se parece al uso directo de pinceles en los modelos 2D; las superficies del modelo no reflejan la luz como si brillasen.

SpecularMaterial especifica que el pincel se aplicará al modelo como si la superficie del modelo fuese dura o brillante, capaz de reflejar la iluminación. Puede establecer el grado en que la textura sugerirá esta cualidad de reflexión, o "brillo", especificando un valor para la propiedad SpecularPower.

EmissiveMaterial permite especificar que la textura se aplicará como si el modelo estuviera emitiendo luz del mismo color que el pincel. Esto no convierte el modelo en una luz; sin embargo, participará de manera diferente en el sombreado que si se aplica textura con DiffuseMaterial o SpecularMaterial.

Para mejorar rendimiento, las caras ocultas de GeometryModel3D (aquéllas que están fuera de la vista porque se encuentran en el lado del modelo opuesto a la cámara) se seleccionan de la escena. Para especificar el Material que se aplicará a la cara oculta de un modelo, como un plano, establezca la propiedad BackMaterial del modelo. Para lograr algunas cualidades de la superficie, como el brillo o los efectos de reflejo, puede ser conveniente aplicar sucesivamente varios pinceles diferentes a un modelo. Puede aplicar y reutilizar varios materiales mediante la clase MaterialGroup. Los elementos secundarios de MaterialGroup se aplican del primero al último en varias pasadas de representación. Iluminar la escena Las luces de los gráficos 3D hacen lo mismo que las luces en el mundo real: permiten ver las superficies. Más concretamente, las luces determinan qué parte de una escena se incluye en la proyección. Los objetos de luz en WPF crean gran variedad de efectos de luz y sombra y siguen el modelo de comportamiento de diversas luces del mundo real. Debe incluir por lo menos una luz en la escena, pues de lo contrario no habrá ningún modelo visible. Las luces siguientes se derivan de la clase base Light:

AmbientLight: proporciona iluminación de ambiente que ilumina uniformemente todos los objetos sin tener en cuenta su ubicación u orientación.

DirectionalLight: ilumina como una fuente de luz distante. Las luces direccionales tienen Direction, que se especifica como Vector3D, pero ninguna ubicación concreta.

PointLight: ilumina como una fuente de luz cercana. Las luces puntuales tienen posición y emiten la luz desde esa posición. Los objetos de la escena se iluminan dependiendo de su posición y distancia con respecto a la luz. PointLightBase expone una propiedad Range, que determina una distancia más allá de la cual la luz no iluminará los modelos. PointLight también expone propiedades de atenuación que

Page 119: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

119

determinan cómo disminuye la intensidad de la luz con la distancia. Puede especificar interpolaciones constantes, lineales o cuadráticas para la atenuación de la luz.

SpotLight: hereda de PointLight. Los focos de luz iluminan como las luces puntuales, y tienen posición y dirección. Proyectan la luz en un área cónica establecida por las propiedades InnerConeAngle y OuterConeAngle, especificada en grados.

Las luces son objetos Model3D, por lo que puede transformar y animar las propiedades de la luz, incluidas su posición, posición, color, dirección y alcance. El siguiente ejemplo arma un gráfico 3D aplicando los objetos vistos <Canvas Width="200" Height="201"> <!-- Viewport3D provee la superficie --> <Viewport3D ClipToBounds="True" Width="150" Height="150" Canvas.Left="0" Canvas.Top="10"> <!-- Define la cámara --> <Viewport3D.Camera> <PerspectiveCamera Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <!-- ModelVisual3D define la luz de la escena. sin luz los objetos 3D no pueden verse. La dirección de la luz define las sombras. Se pueden crear múltiples luces con diferentes colores que brillen en distintas direcciones --> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <!-- La geometría especifica la forma del plano 3D. --> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 - 0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <!-- El material especifica el material aplicado al objeto 3D. --> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5"> <LinearGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial>

Page 120: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

120

</MaterialGroup> </GeometryModel3D.Material> <!-- Se puede aplicar transformaciones al objeto. --> <GeometryModel3D.Transform> <RotateTransform3D> <RotateTransform3D.Rotation> <AxisAngleRotation3D Axis="0,3,0" Angle="40" /> </RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> </Canvas>

Transformar modelos Al crear modelos, éstos tienen una ubicación determinada en la escena. Para mover esos modelos por la escena, girarlos o cambiar su tamaño, no es práctico cambiar los vértices que definen los propios modelos. En lugar de ello, al igual que en 2D, se aplican transformaciones a los modelos. Cada objeto de modelo tiene una propiedad Transform con la que puede mover, reorientar o cambiar el tamaño del modelo. Al aplicar una transformación, en realidad lo que se hace es desplazar todos los puntos del modelo según un vector o valor especificado por la transformación. En otras palabras, se transforma el espacio de coordenadas en el que se ha definido el modelo ("espacio del modelo"), pero no se cambian los valores que constituyen la geometría del modelo en el sistema de coordenadas de la escena completa ("espacio universal"). Animar modelos La implementación de 3D en WPF utiliza el mismo sistema de control de tiempo y animación que los gráficos 2D. En otras palabras, para animar una escena 3D, se animan las propiedades de sus modelos. Es posible animar directamente las propiedades de los elementos primitivos, pero suele ser más fácil de animar las transformaciones que cambian la posición o el aspecto

Page 121: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

121

de los modelos. Dado que las transformaciones se pueden aplicar a los objetos Model3DGroup así como a los modelos individuales, es posible aplicar un conjunto de animaciones a un elemento secundario de Model3DGroup y otro conjunto de animaciones a un grupo de objetos secundarios. También puede lograr gran variedad de efectos visuales animando las propiedades de iluminación de la escena. Finalmente, si lo desea puede animar la propia proyección, animando la posición de la cámara o el campo de visión. Para animar un objeto en WPF, se crea una escala de tiempo, se define una animación (que, en realidad, es un cambio de algún valor de propiedad a lo largo del tiempo) y se especifica la propiedad a la que aplicar la animación. Dado que todos los objetos de una escena 3D son elementos secundarios de Viewport3D, las propiedades de destino de cualquier animación que desea aplicar a la escena son propiedades de propiedades de Viewport3D. La clase Storyboard controla las animaciones con una escala de tiempo y proporciona información de destino de objetos y propiedades para sus animaciones secundarias. Un objeto Storyboard puede considerarse como un contenedor de otros objetos de animación (por ejemplo, DoubleAnimation) y de otros objetos Storyboard. Es decir, se pueden anidar objetos Storyboard unos dentro de otros y especificar valores de BeginTime para cada Storyboard por separado. El uso de guiones gráficos anidados puede ayudarle a orquestar secuencias de animación detalladas. Cada Storyboard secundario esperará hasta que comience su Storyboard primario y, a continuación, iniciará la cuenta atrás antes de que comience a su vez. La Clase DoubleAnimation anima el valor de una propiedad Double entre dos valores de destino usando la interpolación lineal en una propiedad Duration especificada. Una animación actualiza el valor de una propiedad durante un período de tiempo. Un efecto de animación puede ser sutil, como mover un Shape unos cuantos píxeles a la izquierda o a la derecha, o espectacular, como ampliar el tamaño original de un objeto 200 veces mientras gira y cambia de color. Para crear una animación, se asocia una animación al valor de propiedad de un objeto. La clase DoubleAnimation crea una transición entre dos valores de destino. Para establecer sus valores de destino, use sus propiedades From, To y By. La animación progresa desde el valor From hasta el valor especificado por la propiedad To. By permite sumar valores. Transformaciones de Traslación Las transformaciones 3D heredan de la clase base abstracta Transform3D; se incluyen las clases de transformaciones afines TranslateTransform3D, ScaleTransform3D y RotateTransform3D. El sistema 3D de Windows Presentation Foundation (WPF) también proporciona una clase MatrixTransform3D que permite especificar las mismas transformaciones en operaciones de matrices más precisas. TranslateTransform3D translada objetos en un plazo tridimensional (x-y-z). El siguiente ejemplo genera que el rectángulo se mueva a derecha e izquierda. <Canvas Width="300" Height="201"> <Viewport3D Name="MyAnimatedObject" ClipToBounds="True" Width="300" Height="150" Canvas.Left="0" Canvas.Top="10"> <Viewport3D.Camera> <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" /> </ModelVisual3D.Content>

Page 122: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

122

</ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <SolidColorBrush Color="Cyan" Opacity="0.3"/> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <!-- La propiedad OffsetX esta animada por el Storyboard de abajo. --> <GeometryModel3D.Transform> <TranslateTransform3D x:Name="myTranslateTransform3D" OffsetX="0" OffsetY="0" OffsetZ="0" /> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> <!-- Dispara la transformación de traslación --> <Viewport3D.Triggers> <EventTrigger RoutedEvent="Viewport3D.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="myTranslateTransform3D" Storyboard.TargetProperty="OffsetX" To="-0.8" AutoReverse="True" RepeatBehavior="Forever" /> <!-- Si se desea animar OffsetY y/o OffsetZ crear un código similar--> </Storyboard> </BeginStoryboard> </EventTrigger> </Viewport3D.Triggers> </Viewport3D> </Canvas>

Page 123: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

123

Transformaciones de Escala ScaleTransform3D cambia la escala del modelo mediante un vector de escala especificado respecto a un punto central. Especifique una escala uniforme, que escala el modelo mediante el mismo valor en los ejes X, Y y Z, para cambiar proporcionalmente el tamaño del modelo. Por ejemplo, si se establece el valor de las propiedades ScaleX, ScaleY y ScaleZ de la transformación en mitades de 0,5 del tamaño del modelo; al establecer el valor de las mismas propiedades en 2 se duplica su escala en los tres ejes.

Si se especifica una transformación de escala no uniforme (una transformación de escala cuyos valores X, Y y Z no son iguales), se puede provocar el estiramiento o la contracción del modelo en una o dos dimensiones sin afectar el resto. Por ejemplo, si se establece el valor de ScaleX en 1, de ScaleY en 2 y de ScaleZ en 1, se provocaría la duplicación del alto del modelo transformado pero los ejes X y Z permanecerían iguales. De forma predeterminada, ScaleTransform3D provoca la expansión o contracción de los vértices en el origen (0,0,0). Si el modelo que desea transformar no se dibuja partiendo del origen, sin embargo, al escalar el modelo a partir del origen, no se escalará el modelo "en contexto". En su lugar, cuando se multiplican los vértices del modelo por el vector de escala, la operación de la escala tendrá el efecto de trasladar y escalar el modelo.

Page 124: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

124

Para escalar un modelo "en contexto", especifique el centro del mismo estableciendo el valor de las propiedades CenterX, CenterY y CenterZ de ScaleTransform3D. De esta forma, se asegura de que el sistema de gráficos escala el espacio del modelo y, a continuación, lo traslada para centrarse en el objeto Point3Despecificado. A la inversa, si ha generado el modelo en el origen y ha especificado un punto central diferente, espere ver el modelo trasladado fuera del origen. Para ver la transformación de escala prueba el código siguiente con y la parte de código en negrita y observe la transformación. <Canvas Width="321" Height="201"> <Viewport3D ClipToBounds="True" Width="150" Height="150" Canvas.Left="0" Canvas.Top="10"> <Viewport3D.Camera> <PerspectiveCamera Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry> <MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5"> <LinearGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <GeometryModel3D.Transform> <ScaleTransform3D ScaleX="2" ScaleY="0.2" ScaleZ="1" CenterX="0" CenterY="0" CenterZ="0" /> </GeometryModel3D.Transform> </GeometryModel3D>

Page 125: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

125

</ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> </Viewport3D> </Canvas>

Transformaciones de Giro Puede girar un modelo 3D de varias maneras diferentes. Una transformación de giro típica especifica un eje y un ángulo de giro alrededor de ese eje. La clase RotateTransform3D permite definir un objeto Rotation3D con su propiedad Rotation. Después especifique las propiedades Axis y Angle en Rotation3D, en este caso un objeto AxisAngleRotation3D, para definir la transformación. El siguiente ejemplo genera la rotación de la figura. <Canvas Width="321" Height="201"> <Viewport3D Name="MyAnimatedObject" ClipToBounds="True" Width="150" Height="150" Canvas.Left="0" Canvas.Top="10"> <Viewport3D.Camera> <PerspectiveCamera x:Name="myPerspectiveCamera" Position="0,0,2" LookDirection="0,0,-1" FieldOfView="60" /> </Viewport3D.Camera> <Viewport3D.Children> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="#FFFFFF" Direction="-0.612372,-0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <DirectionalLight Color="#FFFFFF" Direction="0.612372,-0.5,-0.612372" /> </ModelVisual3D.Content> </ModelVisual3D> <ModelVisual3D> <ModelVisual3D.Content> <GeometryModel3D> <GeometryModel3D.Geometry>

Page 126: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

126

<MeshGeometry3D TriangleIndices="0,1,2 3,4,5 " Normals="0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 0,0,1 " TextureCoordinates="0,0 1,0 1,1 1,1 0,1 0,0 " Positions="-0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,0.5 " /> </GeometryModel3D.Geometry> <GeometryModel3D.Material> <MaterialGroup> <DiffuseMaterial> <DiffuseMaterial.Brush> <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5"> <LinearGradientBrush.GradientStops> <GradientStop Color="Yellow" Offset="0" /> <GradientStop Color="Red" Offset="0.25" /> <GradientStop Color="Blue" Offset="0.75" /> <GradientStop Color="LimeGreen" Offset="1" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </DiffuseMaterial.Brush> </DiffuseMaterial> </MaterialGroup> </GeometryModel3D.Material> <!-- La propiedad Rotation del objeto esta animada para causar la rotación del mismo --> <GeometryModel3D.Transform> <RotateTransform3D> <RotateTransform3D.Rotation> <AxisAngleRotation3D x:Name="myAngleRotation" Axis="0,3,0" Angle="40" /> </RotateTransform3D.Rotation> </RotateTransform3D> </GeometryModel3D.Transform> </GeometryModel3D> </ModelVisual3D.Content> </ModelVisual3D> </Viewport3D.Children> <!-- Dispara la animación de rotación--> <Viewport3D.Triggers> <EventTrigger RoutedEvent="Viewport3D.Loaded"> <BeginStoryboard> <Storyboard> <!-- Esta animación anima la propiedad Angle de AxisAngleRotation3D haciendo que el objeto rote de -60 a 60 --> <DoubleAnimation Storyboard.TargetName="myAngleRotation" Storyboard.TargetProperty="Angle" From="-60" To="60" Duration="0:0:4" AutoReverse="True" RepeatBehavior="Forever"/> <!-- Esta animación anima la propiedad Axis de AxisAngleRotation3D haciendo que el objeto se tambalee mientras rota --> <Vector3DAnimation

Page 127: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

127

Storyboard.TargetName="myAngleRotation" Storyboard.TargetProperty="Axis" From="0,3,0" To="1,0,1" Duration="0:0:4" AutoReverse="True" RepeatBehavior="Forever"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Viewport3D.Triggers> </Viewport3D> </Canvas>

4- Multimedia Multimedia permite a Windows Presentation Foundation (WPF) integrar Audio y Video a las aplicaciones. Media API Las clases MediaElement y MediaPlayer se usan para presentar Audio y Video. Estas clases pueden ser controladas interactivamente o por reloj. Se pueden usar con el control Microsoft Windows Media Player 10. MediaElement es un elemento que puede ser utilizado como contenido de varios controles. Puede usarse desde XAML o por código. MediaPlayer, en cambio, está diseñado para objetos Drawing. Solo puede ser presentado usando VideoDrawing o directamente interactuando con DrawingContext. No puede usarse en XAML.

<StackPanel Margin="20"> <MediaElement Source="media/numbers-aud.wmv" /> </StackPanel> MediaPlayer player = new MediaPlayer(); player.Open(new Uri(@"sampleMedia\xbox.wmv", UriKind.Relative)); VideoDrawing aVideoDrawing = new VideoDrawing(); aVideoDrawing.Rect = new Rect(0, 0, 100, 100); aVideoDrawing.Player = player; player.Play();

Modos Media Playback Controla los diferentes modos que un medio puede ser reproducido. Tanto MediaElement como MediaPlayer pueden usar ambos modos. Si Clock está en nulo el medio se reproduce en forma independiente.

Page 128: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

128

Modo Independiente: Predeterminado. Se puede especificar la URI del medio, controlar su reproducción, etc. Permite usar los métodos Play, Pause, Close y Stop.

Modo Reloj: La reproducción se controla con MediaTimeline. Los métodos Play, Pause, Close y Stop está inhabilitados.

<MediaElement Name="myMediaElement" > <MediaElement.Triggers> <EventTrigger RoutedEvent="MediaElement.Loaded"> <EventTrigger.Actions> <BeginStoryboard> <Storyboard> <!-- La MediaTimeline tiene RepeatBehavior="Forever" que genera que se repita eternamente--> <MediaTimeline Source="media\tada.wav" Storyboard.TargetName="myMediaElement" RepeatBehavior="Forever" /> </Storyboard> </BeginStoryboard> </EventTrigger.Actions> </EventTrigger> </MediaElement.Triggers> </MediaElement>

SoundPlayer Controla la reproducción del sonido de un archivo .wav. Proporciona una interfaz simple para cargar y reproducir un archivo .wav. Permite cargar un archivo .wav desde una ruta de acceso de archivo, una dirección URL, un Stream que contiene un archivo .wav o un recurso incrustado que contiene un archivo .wav. Para reproducir un sonido mediante la clase SoundPlayer, configure un SoundPlayer con una ruta de acceso al archivo .wav y llame a uno de los métodos de reproducción. Para identificar el archivo .wav que desee reproducir, utilice uno de los constructores o establezca el valor de la propiedad SoundLocation o Stream. El archivo se puede cargar antes de reproducirlo utilizando uno de los métodos de carga, o bien, se puede diferir la carga hasta que se llame a uno de los métodos de reproducción. El objeto SoundPlayer configurado para cargar un archivo .wav desde una Stream o una dirección URL debe cargar el archivo en la memoria antes de que comience la reproducción. private void Window_Loaded(object sender, RoutedEventArgs e) { System.Media.SoundPlayer sp = new System.Media.SoundPlayer(); sp.SoundLocation = txtArchivo.Text; sp.Play(); }

Page 129: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

129

Módulo 8

Configuración y Distribución

Page 130: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

130

1- Configuración Configurar Aplicaciones La configuración de la aplicación le permite almacenar y recuperar dinámicamente la configuración de propiedades y cualquier otra información de la aplicación, así como mantener las preferencias de usuario y de la aplicación personalizada en el equipo cliente. Con frecuencia son datos necesarios, como una cadena de conexión, para ejecutar la aplicación que no desea incluir directamente en el código. Quizá desee almacenar dos cadenas de conexión a bases de datos diferentes y recuperar una de ellas en función de la ubicación del equipo en tiempo de ejecución. O bien, puede almacenar las preferencias de color de un usuario y, a continuación, recuperarlas la siguiente vez que ejecute la aplicación. Cada configuración debe tener un nombre único; el nombre puede ser cualquier combinación de letras, números o un carácter de subrayado que no empiece por un número y sin espacios. Se puede cambiar el nombre mediante la propiedad Name. La configuración de la aplicación se puede almacenar como cualquier tipo de datos que sea XML serializable o que tenga un TypeConverter que implemente ToString/FromString. Los tipos más comunes son String, Integer y Boolean, pero también puede almacenar valores como Color, Object, o bien como una cadena de conexión. La configuración de la aplicación también contiene un valor. El valor se establece mediante la propiedad Value y debe coincidir con el tipo de datos de la configuración. Además, la configuración de la aplicación se puede enlazar directamente a una propiedad de un formulario o de un control en tiempo de diseño. Hay dos tipos de configuración de la aplicación, en función del ámbito:

La configuración de ámbito de aplicación se puede utilizar para obtener información como una dirección URL para un servicio Web o una cadena de conexión a bases de datos. Estos valores se asocian a la aplicación; por tanto, los usuarios no pueden cambiarlos en tiempo de ejecución.

La configuración de ámbito de usuario se puede utilizar para obtener información como recordar la última posición de un formulario o una preferencia de fuente. Los usuarios pueden modificar estos valores en tiempo de ejecución.

Puede cambiar el tipo de una configuración con la propiedad Scope. App.config Este archivo XML permite configurar las aplicaciones WPF. Si la aplicación no contiene este archivo puede agregarse con la opción Agregar Nuevo Elemento – Archivo de Configuración de Aplicaciones. En tiempo de diseño, existen dos maneras de crear la configuración de la aplicación: mediante la página Configuración del Diseñador de proyectos o desde la ventana Propiedades de un formulario o un control, lo que le permite enlazar una configuración directamente a una propiedad. Cuando crea una configuración con ámbito de aplicación (por ejemplo, una cadena de conexión a bases de datos o una referencia a los recursos del servidor), Visual Studio la guarda en un archivo app.config con la etiqueta <applicationSettings> (las cadenas de conexión se guardan en la etiqueta <connectionStrings>). Cuando crea una configuración con ámbito de usuario (por ejemplo, fuente predeterminada, página principal o tamaño de la ventana), Visual Studio la guarda en un archivo app.config con la etiqueta <userSettings>.

<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >

Page 131: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

131

<section name="WpfCSharp.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" /> </sectionGroup> </configSections> <connectionStrings> <add name="WpfCSharp.Properties.Settings.AdvWorks" connectionString="Data Source=.;Initial Catalog=AdventureWorks;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings> <userSettings> <WpfCSharp.Properties.Settings> <setting name="miClave" serializeAs="String"> <value>ElValor</value> </setting> </WpfCSharp.Properties.Settings> </userSettings> </configuration>

La configuración de aplicación consta de cuatro valores:

Nombre: El nombre o identificación del valor configurado. Se lo usa para acceder al valor.

Tipo: El tipo de dato

Ámbito: Puede ser Usuario o Aplicación

Page 132: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

132

Valor: El valor a devolver al leer la configuración

Recuperando información de app.config Durante la ejecución de la aplicación necesitará acceder a los valores configurados en el archivo app.config. Para ello podrá hacerlo desde el código escribiendo un código similar al siguiente, siendo AdvWorks el nombre del valor configurado: string sc = Properties.Settings.Default.AdvWorks; Almacenar información en app.config en run-time Se puede almacenar información en el archivo de configuración durante la ejecución solo para valores configurados de ámbito de usuario. Para cambiar el valor simplemente asígnele un nuevo valor y luego llame el método Save. Properties.Settings.Default.miValor = "Otro Valor"; Properties.Settings.Default.Save();

2- Distribución de Aplicaciones WPF Una vez generadas las aplicaciones de Windows Presentation Foundation (WPF), es preciso implementarlas. Windows y .NET Framework incluyen varias tecnologías de implementación:

XCopy.

Microsoft Windows Installer.

Implementación de ClickOnce. XCopy La implementación de XCopy se refiere al uso del programa de línea de comandos XCopy para copiar los archivos de una ubicación a otra. La implementación de XCopy es adecuada en las siguientes circunstancias:

Una aplicación es autónoma; no necesita actualizar el cliente para ejecutarse.

Los archivos la aplicación se deben mover de una ubicación a otra; por ejemplo, de la ubicación de compilación (disco local, recurso compartido de archivos UNC, etc.) a la ubicación de publicación (sitio web, recurso compartido de archivos UNC, etc.).

Una aplicación no requiere la integración en el shell (acceso directo del menú de Inicio, icono de escritorio, etc.).

Aunque XCopy es adecuado para escenarios de implementación simples, presenta limitaciones cuando se requieren funciones de implementación más complejas. En particular, al utilizar Xcopy se provoca una sobrecarga al crear, ejecutar y mantener los scripts necesarios para administrar la implementación de una manera robusta. Además, XCopy no admite el control de versiones, la desinstalación ni la reversión. Microsoft Windows Installer Windows Installer permite empaquetar las aplicaciones como aplicaciones ejecutables autónomas que se pueden distribuir con facilidad a los clientes y ejecutar. Además, Windows Installer se instala con Windows y habilita la integración con el escritorio, el menú Inicio, y el panel de control Agregar o quitar programas. Windows Installer simplifica la instalación y desinstalación de aplicaciones, pero no proporciona los medios para asegurarse de que las aplicaciones instaladas se mantengan actualizadas desde el punto de vista de su versión.

Page 133: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

133

ClickOnce ClickOnce habilita la implementación 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 características de cliente que sí poseen las aplicaciones instaladas con Windows Installer, admite un subconjunto que incluye lo siguiente:

Integración con el menú Inicio y el panel de control Agregar o Quitar Programas, para aplicaciones independientes.

Control de versiones, reversión y desinstalación.

Modo de instalación en línea, que siempre inicia una aplicación desde la ubicación de implementación.

Para hacer que una aplicación ClickOnce esté disponible para los usuarios, deberá publicarla en un servidor Web, recurso compartido de archivo o en medios extraíbles. Puede publicar la aplicación utilizando el Asistente para publicación. Antes de ejecutar el Asistente para publicación, debe establecer las propiedades de publicación adecuadamente. Publicación ClickOnce Dentro de las propiedades del proyecto WPF tenemos una solapa Publicar. Podemos usar esta solapa para configurar la publicación. Podemos elegir la ubicación predetermina para la publicación, el modo de instalación, los archivos que forman parte de la aplicación, cuales serán lo requisititos previos a la instalación (verificación de componentes que deberán estar previamente instalados), si la instalación soportará actualizaciones automáticas, versionado, etc.

Page 134: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

134

Como Publicar

1. En el Explorador de soluciones, seleccione el proyecto de la aplicación. 2. Haga clic con el botón secundario en el nodo del proyecto y haga clic en Publicar. Aparecerá el Asistente para publicación. También puede llamar al asistente de publicación desde la solapa Publicar explicada anteriormente. Publicar en Web 3. En la página ¿Dónde desea publicar la aplicación?, escriba una dirección URL válida con el formato http://www.microsoft.com/foldername y, a continuación, haga clic en Siguiente. 4. En la página ¿La aplicación estará disponible sin conexión?, haga clic en la opción adecuada: - Si desea permitir que se ejecute la aplicación cuando el usuario esté desconectado de la red, haga clic en Sí, esta aplicación va a estar disponible con conexión o sin ella. Se creará un acceso directo en el menú Inicio para la aplicación. - Si desea ejecutar la aplicación directamente desde la ubicación de publicación, haga clic en No, esta aplicación sólo está disponible en línea. No se creará un acceso directo en el Menú Inicio. Haga clic en Siguiente para continuar. 5. Haga clic en Finalizar para publicar la aplicación. El estado de la publicación se muestra en el área de notificación de estado. Recurso compartido de archivos 3. En la página ¿Dónde desea publicar la aplicación?, escriba una ruta de acceso válida con el formato \\computername\applicationname y, a continuación, haga clic en Siguiente. 4. En la página Instalación de la aplicación, seleccione la ubicación donde los usuarios instalarán la aplicación: - Si los usuarios van a instalar la aplicación desde un sitio web, haga clic en Desde un sitio web y escriba una dirección URL que corresponda a la ruta de acceso del archivo escrita en el paso anterior. Haga clic en Siguiente. (Normalmente, se utiliza esta opción

Page 135: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

135

cuando se especifica una dirección FTP como la ubicación de la publicación. No se admite la descarga directa desde FTP. Por lo tanto, aquí debe escribir una dirección URL.) - Si los usuarios instalan la aplicación directamente desde el recurso compartido de archivos, haga clic en Desde una ruta de acceso UNC o un recurso compartido de archivos y luego haga clic en Siguiente. (Esto es para ubicaciones de publicación en el formato c:\deploy\myapp o \\server\myapp.) - Si los usuarios van a instalar la aplicación desde medios extraíbles, haga clic en Desde un CD-ROM o un DVD-ROM y, a continuación, haga clic en Siguiente. 5. En la página ¿La aplicación estará disponible sin conexión?, haga clic en la opción adecuada: - Si desea permitir que se ejecute la aplicación cuando el usuario esté desconectado de la red, haga clic en Sí, esta aplicación va a estar disponible con conexión o sin ella. Se creará un acceso directo en el menú Inicio para la aplicación. - Si desea ejecutar la aplicación directamente desde la ubicación de publicación, haga clic en No, esta aplicación sólo está disponible en línea. No se creará un acceso directo en el Menú Inicio. Haga clic en Siguiente para continuar. 6. Haga clic en Finalizar para publicar la aplicación. El estado de la publicación se muestra en el área de notificación de estado. CD-ROM o DVD-ROM 3. En la página ¿Dónde desea publicar la aplicación?, escriba la ruta de acceso del archivo o ubicación del FTP donde se publicará la aplicación, por ejemplo d:\deploy. A continuación, haga clic en Siguiente. 4. En la página Instalación de la aplicación, haga clic en Desde un CD-ROM o un DVD-ROM y, a continuación, haga clic en Siguiente. 5. Si distribuye la aplicación en CD-ROM, puede que desee proporcionar actualizaciones desde un sitio Web. En la página ¿Dónde buscará la aplicación las actualizaciones?, elija una opción de actualización: - Si la aplicación comprueba las actualizaciones, haga clic en la opción La aplicación buscará actualizaciones en la siguiente ubicación y escriba la ubicación donde se enviarán las actualizaciones. Puede ser una ubicación de archivo, un sitio web o un servidor FTP. - Si la aplicación no comprueba las actualizaciones, haga clic en la opción La aplicación no buscará actualizaciones. Haga clic en Siguiente para continuar. 6. Haga clic en Finalizar para publicar la aplicación. El estado de la publicación se muestra en el área de notificación de estado. Comparación entre ClickOnce y Microsoft Windows Installer

Característica ClickOnce Windows Installer

Actualización automática SI SI

Deshacer cambios tras la instalación SI NO

Actualizar desde el Web SI NO

No afecta a componentes compartidos u otras aplicaciones

SI NO

Se conceden permisos de seguridad Sólo concede los permisos necesarios

para la aplicación (más seguro)

Concede plena confianza de forma

predeterminada (menos seguro)

Permisos de seguridad requeridos Zona Internet o intranet (plena

Administrador

Page 136: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

136

confianza para la instalación de CD-

ROM)

Firma de manifiestos de aplicación e implementación

SI NO

Interfaz de usuario del proceso de instalación Indicador único

Asistente de varias partes

Instalación de ensamblados a petición SI NO

Instalación de archivos compartidos NO SI

Instalación de controladores NO

Sí (con acciones personalizadas)

Instalación en la caché de ensamblados global NO SI

Instalación para varios usuarios NO SI

Agregar la aplicación al menú Inicio SI SI

Agregar la aplicación al grupo Inicio NO SI

Agregar la aplicación al menú Favoritos NO SI

Registrar tipos de archivos NO SI

Acceso al Registro durante la instalación Limitado SI

Revisión de archivos binarios NO SI

Ubicación de instalación de aplicaciones Caché de aplicaciones de

ClickOnce

Carpeta Archivos de programa

Page 137: Programación en .Net (Avanzado) - Manual WPF - V_DIGITAL

137

Links Relacionados Introducción a WPF http://msdn.microsoft.com/es-ar/library/aa970268.aspx Ejemplos Aplicaciones WPF: http://msdn.microsoft.com/es-ar/library/ms771449.aspx http://msdn.microsoft.com/es-ar/library/ms771542.aspx Información sobre controles http://msdn.microsoft.com/es-es/library/ms590941(v=VS.90).aspx Eventos y Comandos enrutados http://msdn.microsoft.com/es-es/magazine/cc785480.aspx Enlace a Datos http://msdn.microsoft.com/es-ar/magazine/cc163299.aspx http://channel9.msdn.com/posts/eliseta/WPF-para-desarrolladores/ http://www.c-sharpcorner.com/UploadFile/mahesh/GridViewWpf11082009182813PM/GridViewWpf.aspx http://www.elguille.info/colabora/2007/juanpablogc_wpf_gridview.htm Enlace a Colecciones http://msdn.microsoft.com/es-ar/library/ms752347.aspx#binding_to_collections Documentos http://msdn.microsoft.com/es-es/library/ms748388(VS.90).aspx http://msdn.microsoft.com/es-es/library/ms771612.aspx Graficos y multimedia http://msdn.microsoft.com/es-es/library/ms742562.aspx http://msdn.microsoft.com/es-es/library/ms748873.aspx http://msdn.microsoft.com/es-es/library/ms747437(v=VS.90).aspx http://msdn.microsoft.com/es-es/library/ms753347(VS.90).aspx http://msdn.microsoft.com/en-us/library/ms748248.aspx ClickOnce http://msdn.microsoft.com/es-es/library/142dbbz4(v=VS.90).aspx