Post on 15-Jun-2015
description
Desarrollo de aplicaciones con WPF
(Windows Presentation Foundation)José Alberto Rubalcaba Velázquez
Es un framework de nueva generación que cuenta con la integración de varios frameworks como GDI (Graphic Device Interface) y GDI+, influenciado fuertemente por kits de herramientas para Web, como lo son Adobe Flash
Podemos crear aplicaciones con experiencia de usuario visualmente satisfactoria
Que es WPF?
WPF existe como una gran parte del framework de .NET que están ubicados en su mayor parte en el espacio de nombres de System.Windows
Si se cuenta con experiencia en ASP.NET o Windows Forms, la programación con WPF te sonará familiar; se instancian clases, asignas propiedades, mandas a llamar métodos y manejar eventos, todo por medio de tu lenguaje de programación favorito: C# o VB
Programando con WPF
Podemos crear una separación entre la lógica y la apariencia de nuestra aplicación, obteniendo los siguientes beneficios:
Costos de desarrollo y mantenimiento son reducidos, ya que la apariencia no esta fuertemente ligada con el comportamiento de la aplicación.
Programando con WPF
El desarrollo es mas eficiente, ya que los diseñadores pueden estar trabajando en la apariencia de la aplicación mientras desarrolladores trabajan en el comportamiento.
Podemos usar múltiples herramientas de diseño para nuestras aplicaciones como Microsoft Expression.
Globalizacion y localización para aplicaciones con WPF se ha simplificado (Globalización y Localización con WPF)
Programando con WPF
Es un lenguaje de marcado basado en XML para implementar la apariencia de una aplicación declarativamente.
Se usa para crear ventanas, diálogos, páginas, controles de usuario, dibujos y/o gráficas.
Se usa para el diseño de vistas para Workflow markup, Windows Phone 7 y 8, Aplicaciones para Windows Store, y mas !
XAML (eXtensible Application Markup Language)
Mismas reglas que en XML
oDebe de existir un nodo raízoTodo elemento debe de cerraroSensible a mayúsculas y minúsculas oExisten elementos y subelementosoExisten atributos para cada elemento
Reglas básicas de XAML
Los elementos instancian un objeto<Rectangle />
Los atributos cambian las características de los objetos<Rectangle Width=“100” Height=“100” />
El anidamiento implica pertenencia <Grid>
<Rectangle /> </Grid>
Reglas básicas de XAML
A todo elemento declarado en XAML, le debe de corresponder a una clase dentro del espacio de nombres de la API de .NET◦ Por ejemplo
Reglas basicas XAML
Elemento XAML Clase
<Rectangle /> System.Windows.Shapes.Rectangle
<Button /> System.Windows.Controls.Button
<ListBox /> System.Windows.Controls.ListBox
Se usan para organizar lógicamente las claseshttp://schemas.microsoft.com/winfx/2006/xaml/presentation◦ Espacio de nombres base. Abarca todos los
espacios de nombres CLR (Common Language Runtime)
http://schemas.microsoft.com/winfx/2006/xamlEspacio de nombres de XAML
Espacios de nombres en XAML
El atributo xmlns importa un espacio de nombres XML para dejar a nuestro alcance todos los miembros incluidos en el
Es similar a una sentencia using en C# o Imports en VB
Podemos asignar de manera opcional un alias a nuestros espacios de nombres (xmlns:alias)
Espacios de nombres en XAML
Se puede establecer el atributo xmlns en cualquier nivel de nuestra aplicación
Lo mas conveniente es colocar el espacio de nombres en la raíz de la página o ya sea de la aplicación
<Grid xmlns:ans=http://schemas.microsoft.com/winfx/2006/xaml/presentation>
<ans:Button Width=“200” Height=“100” Content=“Click me!” />
</Grid>
Espacios de nombres en XAML
Todas las propiedades se pueden establecer como subelementos dentro de un documento XAML
Es necesario únicamente cuando el valor de una propiedad es un objeto complejo y no se cuenta con un convertidor de tipo
<Rectangle Width=“100” Height=“100” Fill=“Yellow” />
es lo mismo que:
<Rectangle><Rectangle.Width>100</Rectangle.Width><Rectangle.Height>100</Rectangle.Height><Rectangle.Fill>Yellow</Rectangle.Fill>
</Rectangle>
Sintaxis de subelementos
Son clases que permiten al intérprete de XAML el evaluar de distintas maneras sus valores◦ {StaticResource}◦ {Binding}◦ {TemplateBinding}◦ {RelativeSource}◦ {x:Null}
Sintáxis:<Element property=“{Extensión [Properties]}” />
Extensiones de marcado
Se refieren a una bolsa de propiedades La clase FrameworkElement implementa la
propiedad Resources◦ Permite guardar cualquier tipo de objeto para
reutilizarlo◦ Se identifican por medio de una cláve única
(atributo x:Key)
<Grid.Resources><SolidColorBrush x:Key=“myBrush”
Color=“Red” /></Grid.Resources>
Recursos
Se referencían en XAML por medio de la extensión {StaticResource}
{StaticResource} puede ser usada en propiedades regulares CLR<Window.Resources>
<SolidColorBrush x:Key=“myBrush”Color=“Red” />
</Window.Resources><Rectangle Width=“100” Height=“100”
Fill=“{StaticResource myBrush}” />
Recursos
Recursos via código◦ Dentro del código de la aplicación usamos la propiedad
Resources para leer o agregar objetos al diccionario de recursos
◦ La propiedad Resources es un diccionario del tipo <object,object>
Private void Button_Click(object sender, RoutedEventArgs e){
if(this.Resources.Contains(“myBrush”)// obtenemos el recursovar brush = this.Resources[“myBrush”] as
SolidColorBrush;//agregamos un recurso this.Resources.Add(“resource”, resourceObject);
}
Recursos
Tipo especial de propiedad dependiente
Notifican al elemento padre que se requiere cierto valor
Sintáxis XAML
<ParentClass>
<Element ParentClass.Property = “Value” /></ParentClass>
Propiedades adjuntas
Se pueden utilizar los métodos SetValue() y GetValue() como en cualquier otra propiedad dependienteif ((double) rect.GetValue(Grid.Column) == 1){
rect.SetValue(Grid.Column, 2);}
Se pueden usar los métodos para leer o establecer los valores de las propiedades adjuntas
if (Grid.GetColumn(rect) == 1){
Grid.SetColumn(rect, 2);}
Propiedades adjuntas
Contenedores visuales
Clases que heredan de la clase base Panel◦ Canvas ◦ StackPanel◦ Grid
Otros◦ Border◦ ScrollViewer
Contenedores
Contenedor básico de posicionamiento absoluto
Propiedades adjuntas◦ Left◦ Right◦ Top◦ Bottom
Canvas
Véase el siguiente fragmento de código:<Canvas>
<Rectangle Width=”100” Height=“100”Canvas.Left=“50” Canvas.Top=“50” Fill=“Blue” />
<Rectangle Width=”100” Height=“100”Canvas.Left=“50” Canvas.Top=“50”
Fill=“Orange”/></Canvas>
Ejemplo Canvas
¿Qué obtenemos?
Contenedor para apilar elementos de manera horizontal o vertical
Útil en escenarios donde necesites alinear controles◦ Casos como un menú, una barra de botones, etc
StackPanel
Véase el siguiente fragmento de código:<StackPanel>
<Rectangle Width=”150” Height=“150”Fill=“Blue” />
<Rectangle Width=”150” Height=“150”Fill=“Orange”/>
</StackPanel>
Ejemplo StackPanel
¿Qué obtenemos?
Contenedor de tipo tabla
Es el más flexible de todos los contenedores
Permite definir columnas y filas
Propiedades adjuntas:◦ Column◦ Row◦ ColumnSpan◦ RowSpan
Grid
Los altos y anchos de filas y columnas pueden ser de 3 tipos:
◦ Fijo Se mide en pixeles
◦ Automático En función de su contenido
◦ Proporcional(*) Predeterminado
Grid
Véase el siguiente fragmento de código<Grid> <Grid.RowDefinitions> <RowDefinition Height="110"/> <RowDefinition Height=“Auto"/> <RowDefinition Height=“*"/> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <ColumnDefinition Height=“110”/> <ColumnDefinition Height=“Auto”/> <ColumnDefinition Height=“*”/> </Grid.ColumnDefinitions>
<Rectangle Width="100" Height="100" Fill="Blue" Grid.Column="0" Grid.Row="0"/>
<Rectangle Width="100" Height="100" Fill="Blue" Grid.Column="1" Grid.Row="1"/>
<Rectangle Width="100" Height="100" Fill="Blue" Grid.Column="2" Grid.Row="2"/>
</Grid>
Ejemplo Grid
¿Qué obtenemos?
Propiedades de distribución dinámica para contenedores excepto Canvas
◦ HorizontalAlignment y VerticalAlignment◦ Margin◦ MaxWidth◦ MaxHeight◦ MinWidth◦ MinHeight
Propiedades de distribución
System.Windows.Shapes Propiedades
◦ Fill◦ Stroke◦ StrokeThickness◦ StrokeDashCap◦ StrokeDashOffset
Clase Shape
System.Windows.Shapes◦ Ellipse◦ Rectangle◦ Line◦ Polyline◦ Polygon◦ Path
Formas básicas
System.Windows.Controls Clase para representar una imagen Similar al elemento <img> de HTML Puede tener una fuente absoluta o relativa Soporta solo imágenes png y jpg
<Image Source=“someImg.png”/>
<Image Source=“http://www.somepage.com/someImg.jpg” />
Image
System.Windows.Controls Elemento principal para mostrar texto en
las aplicaciones XAML Soporta cambiar el tamaño de la fuente, el
tipo, las decoraciones, alineaciones, etc Run
◦ Permite estilizar partes del texto de un TextBlock LineBreak
◦ Salto de línea explícito
TextBlock
Véase el siguiente fragmento de código
<TextBlock FontSize="50" TextWrapping="Wrap"> <Run Foreground="Blue">Taller</Run> de desarrollo de aplicaciones
<LineBreak /> con <Run Foreground="Gold">WPF</Run>
<LineBreak /> <Run Foreground="Red">Semana ISW</Run>
</TextBlock>
Ejemplo
¿Qué se obtiene?
Enlace de datos
Enlace de datos
Modelo robusto◦ Objeto fuente
Propiedad en el objeto fuente
◦ Control destino Propiedad en el control destino
Se expresan a través de la extensión del Markup {Binding}
<TextBlock Text=“{Binding Source={StaticResource User}, Path=UserName}” />
Enlace de datos
Parámetros principales de {Binding}◦ Source
Indica el objeto fuente
◦ Path Indica una ruta a la propiedad en el objeto fuente Parámetro predeterminado
◦ Mode Indica el modo para el enlace
Enlace de datos
OneTime◦ El enlace se establece y el objeto fuente y el
control destino no se vuelven a comunicar entre sí OneWay
◦ El enlace se establece y cuaquier cambio que suceda en el objeto fuente le avisará al control destino
TwoWay◦ El enlace se establece y cuaquier cambio que
suceda en el objeto fuente le avisará al control destino y viceversa (bi-direccional)
Modos de enlace
Se expresan a través del atributo Mode
<TextBlock Text=“{Binding
Source={StaticResource User},Path=UserName,Mode=TwoWay}” />
Modos de enlace
Los modos OneWay y TwoWay requieren que el objeto fuente implemente alguna de las interfaces INotifyPropertyChanged o INotifyCollectionChanged◦ Implementan un evento, el cual es escuchado en
la infraestructura de enlace de datos◦ INotifyPropertyChanged en objetos
individuales, para notifucar que una propiedad ha cambiado
◦ INotifyCollectionChanged en colecciones, para notificar que una colección ha cambiado
Interfaces
Windows Presentation Foundation soporta el atributo CallerMemberName
◦ Obtiene automáticamente el nombre del método o propiedad que mandó a llamar al método en cuestión
◦ Se evita el uso de “cadenas mágicas”, lo cual no dificulta el dar mantenimiento a las aplicaciones
◦ Disponible en System.Runtime.CompilerServices
Interfaces
Clase base que implementa INotifyPropertyChanged
protected virtual void OnPropertyChanged([CallerMemberName]
string propertyName = null)
{
If(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Interfaces
Colección genérica recomendada para escenarios de enlace de datos
Implementa INotifyPropertyChanged y INotifyCollectionChanged
Automáticamente actualiza el control de lista que esté enlazada
Disponible en System.Collections.ObjectModel
ObservableCollection<User> …
ObservableCollection<T>
Expresan el XAML que representa a cada uno de los elementos en un control, lo podemos usar en listas, botones, etc
Se expresan con el elemento DataTemplate o ControlTemplate
Se declaran en linea junto con el elemento a personalizar, o dentro del diccionario de recursos de la pagina o aplicación
Plantillas de datos
<Button > <Button.Template> <ControlTemplate> <StackPanel Orientation="Horizontal"> <Image Source="BB.jpg" /> <StackPanel> <TextBlock Text="Click me"/> <TextBlock Text="Right now!"/> </StackPanel> </StackPanel> </ControlTemplate> </Button.Template> </Button>
Plantillas de datos
Clases que implementan la interfaz IValueConverter
La interfaz IValueConverter incluye dos métodos a implementar:
◦ Convert Método que se ejecuta cuando el valor fluye del
objeto fuente hacia el control destino◦ ConvertBack
Método que se ejecuta cuando el valor fluye de regreso: del control destino hacia el objeto fuente
Convertidores de valor
Son “funcionalidad enlazable” Clases que implementan la interfaz
ICommand Soportados por la familia de clases
ButtonBase Miembros:
◦ Execute: Indica qué acción se realizará◦ CanExecute: Determina si el comando puede
ejecutar◦ CanExecuteChanged: Re-evalúa CanExecute
Comandos
Model-View-ViewModel
Patrón de diseño natural para plataformas XAML◦ Aprovecha al máximo el enlace de datos {Binding}
Ventajas◦ Separacion de concerns (preocupaciones)◦ Pruebas unitarias ◦ Mantenimiento de código◦ Consistencia◦ Desacoplamiento◦ Flujo de trabajo entre diseñadores y desarrolladores◦ Reutilización de código◦ ..y muchos beneficios mas..
¿Qué es MVVM?
¿Cómo trabaja MVVM?
View100% Declarative via XAML
ViewModelExposes Model to View for data binding
Exposes logic to user via data bound ICommandsApplication-specific state and logic
ModelDomain specific entities and operationsContains no knowledge of specific usage
Data binding of commands
Data binding of properties
Direct access via code
View◦ Define la interfaz de usuario◦ Define la estructura y apariencia de lo que el
usuario ve en la pantalla◦ Estilos, recursos◦ El contexto de datos es el ViewModel◦ Poco o nada de code-behind
Solo código que no necesite pruebas unitarias◦ Comportamientos◦ Actualizada a través de Bindings
MVVM
ViewModel◦ Es una abstracción de la Vista◦ Implementa la lógica de presentación◦ Adapta el modelo a la vista◦ Mantiene el estado◦ Expone propiedades a las que se enlaza la vista
(datos y comandos)◦ Expone metodos que los comportamientos de una
vista puede invocar◦ Desacoplamiento y Testability es el objetivo
principal del ViewModel
MVVM
Model
◦ Tu dominio◦ Objetos de datos
DTO, POCO Modelo de datos generado Modelo de proxy generado
◦ Capa de servicios Repositorios Objetos negocio
MVVM
Cardinalidad
◦ Generalmente, una vista solo tiene un ViewModel
◦ Un ViewModel puede ser usado en una o más vistas
◦ Un Model puede ser usado en uno o mas ViewModels
MVVM
Estrategias para relacionar View con ViewModel◦ Primero la vista (View first)
La vista creal el ViewModel (en XAML o code-behind) La vista tiene inyectado el ViewModel (propiedad o
constructor)
◦ Primero el ViewModel (ViewModel first) El ViewModel crea la vista, se enlaza a sí mismo a la
vista
MVVM
Para cambiar una vista, siempres se debe de implementar una propiedad en el ViewModel◦ Para deshabilitar un boton: enlaza una propiedad◦ Para cambiar el estado de la vista: enlaza una
propiedad◦ Para iniciar alguna animación: enlaza una propiedad◦ Para mostrar errores de validación: enlaza una
propiedad Para que la vista ejecute código
◦ Los controles de la vista se enlazan a propiedades de tipo ICommand
◦ Los comportamientos de la vista pueden invocar métodos o enlazar un evento a un comando
MVVM
Arquitectura de tu aplicación
MVVM
Si recapitulamos◦ La vista es XAML◦ La vista puede tener code-behind
Solo el código relacionado con la UI◦ La vista mantiene una referencia al ViewModel◦ La vista se enlaza al ViewModel◦ La vista utiliza comandos para invocar métodos
en el ViewModel◦ La vista utiliza comportamientos para invocar
metodos en el ViewModel◦ El ViewModel mantiene una referencia al Model
MVVM
Crea un proyecto nuevo de Visual Studio 2012
Construyamos una app !!
Dale el nombre WorkshopApp
Observa la arquitectura de tu proyecto
Construyamos una app !!
Agrega 3 folders con los nombres Models, ViewModels y Views, la vista llamada MainWindow arrástrala al folder Views
Ahora abre tu documento
App.xaml
Construyamos una app !!
Cambia el StartupUri de la aplicación al de la vista que está en el folder Views
Construyamos una app !!
Da click derecho sobre el proyecto y selecciona la opción Manage NuGet Packages ◦ Busca el paquete llamado HttpClient e instálalo,
aceptando los términos y condiciones
Construyamos una app !!
Model◦ Crea una clase pública llamada New con las
siguientes propiedades
Construyamos una app !!
Model◦ Crea una clase pública llamada NewsEventArgs
que herede de la clase base EventArgs.◦ Este evento debe de guardar una lista de noticias,
resultado de un consumo de datos de una API de noticias
Construyamos una app !!
Model◦ Crea una clase llamada NewsService y agrega un
manejador de eventos para NewsEventArgs
◦ Agrega una constante llamada NewsUriFormat con la siguiente cadena
“http://apiservice.univision.com/rest/feed/getFeed?url=%2Fsearch%2Farticles%3Fcount%3D{1}%26site%3Dnoticias%26tags%3D{0}%26outputMode%3Dxml&api_key={2}”
Construyamos una app !!
Model◦ Crea una funcion llamada GetNews que reciba una cadena como
parámetro.◦ Usaremos la clase XDocument para procesar la respuesta en formato
XML por medio de un query
Construyamos una app !!
ViewModel◦ Crea una clase llamada ActionCommand que
implemente las funciones de ICommand.◦ Crea una propiedad a nivel de clase del tipo
Action y que sea recibida por medio del constructor.
◦ La función CanExecute devolverá un valor verdadero
◦ La función Execute debera ejecutar la acción definida como propiedad
Construyamos una app !!
ViewModel◦ Crea una clase pública llamada BaseViewModel
que implemente la interface INotifyPropertyChanged, ésta clase sera la base para todos los ViewModels, recuerda usar el atributo CallerMemberName
Construyamos una app !!
ViewModel◦ Ahora crea una clase pública llamada NewsViewModel, ésta debe de
heredar de la clase base BaseViewModel
◦ Encapsula las propiedades que desees enlazar a la vista de la aplicación (en este caso crearás una propiedad llamada city y en el accesor set llama a la función OnPropertyChanged para notificar el cambio)
◦ Sigue el mismo procedimiento con con una propiedad del tipo ObservableCollection<New>
Construyamos una app !!
ViewModel◦ Crea una propiedad privada de la clase
NewsService, e inicializala dentro del constructor del ViewModel junto con el manejador del evento GetNewsCompleted
Construyamos una app !!
ViewModel◦ Crea una propiedad de la clase ActionCommand y encapsúlala, se debe
de crear una clase por cada comando deseado dentro de la vista
◦ Dentro del accesor get, checa que si el campo no es nulo, de ser así, crea una nueva instancia del campo getNewsCommand, asignandole una acción por medio de una expresión lambda
◦ Dentro del cuerpo de la acción, manda a llamar la funcion GetNews, que pertenece a la propiedad del tipo NewsService
Construyamos una app !!
View◦ Importemos el espacio de nombres de
ViewModels a la ventana XAML
◦ Creemos una instancia de NewsViewModel dentro del diccionario de recursos de la ventana
Construyamos una app !!
View◦ Dividimos en dos filas nuestro Grid principal, y le
asigamos a la propiedad DataContext el ViewModel alojado en el diccionario de recursos
Construyamos una app !!
View◦ A la primera fila le agregamos una caja de búsqueda y un botón para
iniciar una búsqueda de noticias, enlazandolo a nuestro comando de noticas; podemos usar algún DataTemplate para darle estilo a nuestro botón
Construyamos una app !!
View◦ A la segunda fila le agregamos un elemento
ListBox, el cual estará enlazado a nuestra lista de noticias en el ViewModel, creando un ItemTemplate para cada elemento en el ListBox
Construyamos una app !!
Resultado