Documentos de Académico
Documentos de Profesional
Documentos de Cultura
UNIDAD I
MICROSOFT WINDOWS
PRESENTATION FOUNDATION
Image
IZADOR
ES
1.7.
WPF OS
WPF
1.4.
Eventos de cambios de
propiedades
1
1/9/2023
1.1. XAML
2
1/9/2023
3
1/9/2023
XAML
El significado de XAML proviene del inglés "eXtensible Application Markup Language" o
"Lenguaje de marcado extensible de aplicación". Esta técnología es una variante
provista por Microsoft para describir un GUI. En Frameworks GUI previos, como
WinForms, el GUI era generado en el mismo lenguaje que se utilizaba para interactuar
con el GUI, como por ejemplo C# o VB.NET, y usualmente mantenido por el diseñador
(Generalmente Visual Studio). El enfoque de Microsoft cambió con la implementación de
XAML, siendo mucho mas parecido a código HTML, permitiendo editar y escribir la GUI
fácilmente.
XAML es una parte esencial de WPF. Sin importar lo que se crea, una Ventana o una
Página, WPF consiste en un archivo XAML y un archivo CodeBehind(.cs), los cuales en
conjunto crean la Ventana/Página. El archivo XAML define la interfaz con todos sus
elementos, mientras que el CodeBehind maneja todos los eventos y puede manipularlos
mediante los controles XAML.
8
4
1/9/2023
</Grid>
</Window>
10
10
5
1/9/2023
Las etiquetas XAML tienen que ser cerradas, escribiendo un etiqueta de cierre o
insertando una barra diagonal al final del nombre de la etiqueta y antes que el
signo mayor de cierre:
<Button>Presiona aqui</Button>
11
11
<Window x:Class="InicioWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:InicioWPF"
mc:Ignorable="d"
Title="MainWindow" Height="150" Width="600">
<Grid>
<Button>Presiona aqui</Button>
</Grid>
</Window>
12
6
1/9/2023
<Button>
<Button.FontWeight>Bold</Button.FontWeight>
<Button.Content>Boton</Button.Content>
</Button>
13
13
<Button>
<Button.FontWeight>Bold</Button.FontWeight>
<Button.Content>
<WrapPanel>
<TextBlock Foreground="Blue">Multi</TextBlock>
<TextBlock Foreground="Red">Color</TextBlock>
<TextBlock>Button</TextBlock>
</WrapPanel>
</Button.Content>
</Button>
14
14
7
1/9/2023
<Button FontWeight="Bold">
<WrapPanel>
<TextBlock Foreground="Blue">Multi</TextBlock>
<TextBlock Foreground="Red">Color</TextBlock>
<TextBlock>Button</TextBlock>
</WrapPanel>
</Button>
15
15
➢ CÓDIGO SUBYACENTE
El comportamiento principal de una aplicación consiste en implementar la
funcionalidad que responde a las interacciones del 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 al
acceso a los datos. En WPF, este comportamiento se implementa en el código
que está asociado a XAML. Este tipo de código se conoce como código
subyacente.
16
16
8
1/9/2023
17
17
18
18
9
1/9/2023
Contenido basado en la
Etiqueta o TAG definida
etiqueta
<ETIQUETA> </ETIQUETA>
19
19
➢ ATRIBUTOS
20
20
10
1/9/2023
2.1. 3. VENTAJAS
Es más nuevo y, por lo tanto, está más en consonancia con los estándares actuales
Microsoft lo está utilizando para muchas aplicaciones nuevas, por ejemplo, Visual
Studio
Es más flexible, por lo que puede hacer más cosas sin tener que escribir o comprar
nuevos controles
Cuando necesite utilizar controles de terceros, es probable que los desarrolladores
de estos controles se enfoquen más en WPF porque es más reciente
XAML hace que sea fácil crear y editar su GUI, y permite que el trabajo se divida
entre un diseñador (XAML) y un programador (C#, VB.net etc.)
Enlace de datos (Databinding), le permite obtener una separación más limpia de los
datos y el diseño
Utiliza la aceleración de hardware para dibujar la GUI, para un mejor rendimiento
Permite realizar interfaces de usuario tanto para aplicaciones Windows como para
aplicaciones web (Silverlight/XBAP)
21
21
xmlns="http://schemas.microsoft.com/winfx/20 <Button.FontWeight>Bold</Button.FontWeight>
06/xaml/presentation" <Button.Content>
<WrapPanel>
xmlns:x="http://schemas.microsoft.com/winfx/ <TextBlock
2006/xaml" Foreground="Blue">Boton</TextBlock>
<TextBlock
xmlns:d="http://schemas.microsoft.com/expres Foreground="Red">Multi</TextBlock>
sion/blend/2008"
<TextBlock>Color</TextBlock>
xmlns:mc="http://schemas.openxmlformats.org/ </WrapPanel>
markup-compatibility/2006" </Button.Content>
xmlns:local="clr- </Button>
namespace:Ejemplo1WPF" </Grid>
mc:Ignorable="d" </Window>
Title="MainWindow" Height="450"
Width="800">
<Grid>
22
22
11
1/9/2023
23
23
➢ EVENTOS XAML
La mayoría de los marcos (frameworks) de UI modernos al igual que WPF,
están impulsados por eventos. Todos los controles, incluida la ventana
(Window) (que también hereda la clase control) exponen un rango de
eventos a los que puede suscribirse, lo que significa que la aplicación será
notificada cuando ocurran y se podrá entonces reaccionar a ellos.
Hay muchos tipos de eventos, pero algunos de los más comúnmente
utilizados están hechos para responder a la interacción del usuario con su
aplicación, con el ratón o el teclado. En la mayoría de los controles se
encuentran eventos como KeyDown, KeyUp, MouseDown, MouseEnter,
MouseLeave, MouseUp y otros.
El funcionamiento de los eventos en WPF es un tema complejo, pera para
empezar es necesario conocer cómo vincular un evento de control en XAML
con un fragmento de código en su archivo de código subyacente (Code-
behind).
24
24
12
1/9/2023
<Window x:Class="WpfTutorialSamples.XAML.EventsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="EventsSample" Height="300" Width="300">
<Grid Name="pnlMainGrid" MouseUp=“Evento1”
Background="LightBlue">
</Grid>
</Window>
25
26
26
13
1/9/2023
27
27
28
14
1/9/2023
Una vez más, es necesario conocer que delegado utilizar, y una vez más, Visual
Studio puede ayudar. Apenas se escribe:
Simplemente se presiona la tecla [Tab] dos veces para que Visual Studio genere el
gestor de evento de manera automática, directamente debajo del método actual,
listo para ser implementado. Cuando se suscribe a los eventos de esta manera, no
es necesario hacerlo en XAML.
29
29
➢ LAYOUTS
Layout es un término de la lengua inglesa que no forma parte del diccionario de
la Real Academia Española. El concepto puede traducirse como “disposición” o
“plan” y tiene un uso extendido en el ámbito de la tecnología.
La noción de layout suele utilizarse para nombrar al esquema de distribución
de los elementos dentro un diseño. Es habitual que un diseñador que se dedica
a la creación de páginas web desarrolle un layout y se lo presente a su cliente
para que éste lo apruebe y decida sobre la distribución de los contenidos.
30
30
15
1/9/2023
31
31
➢ GRID LAYOUT
Por defecto se tiene el Grid Layout, el cual añade los diferentes componentes
en la parte central, los cuales pueden ser reubicados.
32
32
16
1/9/2023
➢ FRAME LAYOUT
Este es el Layout más básico, en donde todos los controles hijos quedan
ubicados en la esquina superior izquierda, además, si se colocan más objetos
van a quedar uno encima de otro en la misma posición ocultando al anterior.
33
33
➢ LINEAR LAYOUT
Este Layout es uno de los más comunes junto al Relative Layout, dispone los
elementos uno debajo o al lado del otro hijo, dependiendo de su orientación
vertical u horizontal.
34
34
17
1/9/2023
➢ RELATIVE LAYOUT
Este Layout permite posicionar los elementos de forma relativa a su Layout
contenedor o a cualquiera de sus elementos incluidos en él. Permite por
ejemplo, ubicar un texto a la derecha del botón, los cuales están debajo de una
imagen.
35
35
PANEL DESCRIPCIÓN
Canvas Define un área dentro de la cual puede colocar explícitamente
elementos secundarios por coordenadas relativas al área del canvas
.
DockPanel Define un área dentro de la cual puede organizar los elementos
secundarios, ya sea horizontal o verticalmente, entre sí..
Grid Define un área de cuadrícula flexible que consta de columnas y filas.
StackPanel Organiza los elementos secundarios en una sola línea que se puede
orientar horizontal o verticalmente.
VirtualizingPanel Proporciona un marco para los elementos del Panel que virtualizan
su recopilación de datos secundarios. Esto es una clase abstracta..
WrapPanel Coloca los elementos secundarios en una posición secuencial de
izquierda a derecha, dividiendo el contenido en la siguiente línea en
el borde del cuadro contenedor. El orden posterior ocurre
secuencialmente de arriba a abajo o de derecha a izquierda, según
el valor de la propiedad Orientación .
36
36
18
1/9/2023
➢ MARGIN Y PADDING
37
37
38
38
19
1/9/2023
<Window x:Class="IniciandoWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IniciandoWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
39
39
40
40
20
1/9/2023
41
42
42
21
1/9/2023
43
➢ APP.XML
App.xaml es el punto declarativo inicial de una aplicación. Visual Studio
automáticamente crea este archivo cuando se crea una nueva aplicación WPF,
incluyendo un archivo Code-behind llamado App.xaml.cs. Estas clases trabajan
similarmente a la de una Ventana, donde hay dos archivos que son clases
parciales, trabajando en conjunto para permitir tanto texto de marcado(XAML) y
Code-behind.
App.xaml.cs extiende la clase Application, la cual es una clase central en una
aplicación de WPF de Windows. .NET también busca esta clase para obtener
sus instrucciones iniciales para luego iniciar la ventana o página deseada desde
esta. Este también es el lugar para subscribir eventos importantes de aplicación
tales como, inicio de aplicación, excepciones sin manejar y otras. Una de las
características utilizadas con mayor frecuencia de un archivo App.xaml es la
definición de recursos globales que pueden ser utilizadas en toda la aplicación,
por ejemplo estilos globales.
44
44
22
1/9/2023
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace IniciandoWPF
{
/// <summary>
/// Lógica de interacción para App.xaml
/// </summary>
public partial class App : Application
{
}
}
45
45
46
23
1/9/2023
➢ EL CONTROL TEXTBLOCK
Aunque el control TextBlock es uno de los más básicos de WPF, es uno de
mucha utilidad. Permite colocar texto en la pantalla, de manera similar a como
lo hace el control Label, pero más simple y consumiendo menos recursos.
Normalmente se usa Label para textos cortos de una línea (que pueden
contener, por ejemplo, una imagen), por otra parte, TextBlock trabaja muy bien
con cadenas de texto de varias líneas, pero solo puede contener texto(strings).
Tanto el Label como el TextBlock ofrecen cada uno ventajas únicas, por lo que
su uso depende mucho de la situación.
47
47
<Window x:Class="IniciandoWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:IniciandoWPF"
mc:Ignorable="d"
Title="MainWindow" Height="100" Width=“100">
<Grid>
<TextBlock>Hola WPF</TextBlock>
</Grid>
</Window>
48
48
24
1/9/2023
<Window x:Class="IniciandoWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-
compatibility/2006"
xmlns:local="clr-namespace:IniciandoWPF"
mc:Ignorable="d"
Title="MainWindow" Height="100" Width=“100">
<Grid>
<TextBlock Margin="15">Este es un TEXTBLOCK con una gran línea
de código</TextBlock>
</Grid>
</Window>
49
49
50
50
25
1/9/2023
✓ HIPERLINK
El elemento Hyperlink permite introducir enlaces en los textos, con un aspecto
visual acorde con el tema de Windows activo, lo que suele ser alguna tonalidad
de color azul cambiando a rojo cuando el cursor se coloca encima y teniendo
este último forma de mano. Puede usar la propiedad NavigateUri para definir la
URL a la que desea navegar
51
51
<Window x:Class="IniciandoWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IniciandoWPF"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="400">
<StackPanel>
<TextBlock Margin="10" Foreground="Red">Este es un TEXTBLOCK
<LineBreak/>con una gran línea de código</TextBlock>
<TextBlock Margin="10" TextTrimming="CharacterEllipsis"
Foreground="Green">Este es un TEXTBLOCK con una gran línea de código</TextBlock>
<TextBlock Margin="10" TextWrapping="Wrap" Foreground="Blue">Este es un
TEXTBLOCK con una gran línea de código</TextBlock>
</StackPanel>
</Window>
52
52
26
1/9/2023
<Window x:Class="Wpf_AulaV.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_AulaV"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="250">
<StackPanel>
<TextBlock Margin="10" Foreground="Red">
Este es un control Textblock<LineBreak />con muchas líneas de texto.
</TextBlock>
<TextBlock Margin="10" TextTrimming="CharacterEllipsis"
Foreground="Green">
Este es un control TextBlock con texto que puede que no se muestre por completo,
lo que se indicará con puntos suspensivos.
</TextBlock>
<TextBlock Margin="10" TextWrapping="Wrap" Foreground="Blue">
Este es un control TextBlock con texto ajustado automáticamente,
usando la propiedad TextWrapping.
</TextBlock>
</StackPanel>
53
</Window>
53
54
54
27
1/9/2023
<Window x:Class="Wpf_AulaV.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_AulaV"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="250">
<Grid>
<TextBlock Margin="10" TextWrapping="Wrap">
TextBlock con texto en <Bold>Negrita</Bold>, <Italic>Cursiva</Italic> y
<Underline>Subrayado</Underline> texto.
</TextBlock>
</Grid>
</Window>
55
55
<Window x:Class="Wpf_AulaV.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_AulaV"
mc:Ignorable="d"
Title="MainWindow" Height="200" Width="250">
<Grid>
<TextBlock Margin="10" TextWrapping="Wrap">
<Hyperlink NavigateUri="http://www.google.com"
RequestNavigate="Hyperlink_RequestNavigate">google.com</Hyperlink>
</TextBlock>
</Grid>
</Window> private void
Hyperlink_RequestNavigate(object sender,
RequestNavigateEventArgs e)
{
Process.Start(new
ProcessStartInfo(e.Uri.AbsoluteUri) {
UseShellExecute = true });
using System.Diagnostics; }
56
using System.Windows.Navigation;
56
28
1/9/2023
✓ RUN
El atributo Run permite dar formato a una cadena de texto utilizando todas las
propiedades disponibles en el elemento Span, pero mientras que éste puede
contener en su interior otros elementos en línea, un elemento Run solo puede
contener texto. Eso hace del elemento Span más flexible y, por tanto, la elección
más lógica en la mayor parte de los casos
✓ SPAN
El elemento Span no tiene un formato específico predefinido, pero le permite
especificar casi cualquier tipo de formato, incluyendo el tamaño, estilo y grosor de
la fuente, los colores de fondo y del texto, etc. Lo mejor del elemento Span es que
permite contener otros elementos en línea en su interior, facilitando la
construcción de combinaciones avanzadas de textos y estilos.
57
57
<StackPanel>
<TextBlock Margin="10" TextWrapping="Wrap">
Este <Span FontWeight="Bold">es</Span> un
<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
con <Span TextDecorations="Underline">muchos</Span>
<Span FontStyle="Italic">Span</Span> elementos,
<Span Foreground="Blue"> usando una <Bold>gran variedad</Bold>
de <Italic>estilos</Italic></Span>.
</TextBlock>
</StackPanel>
58
58
29
1/9/2023
</Grid>
</Window>
59
59
namespace Wpf_AulaV
{
/// <summary>
/// Lógica de interacción para MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TextBlock tb = new TextBlock();
tb.TextWrapping = TextWrapping.Wrap;
tb.Margin = new Thickness(10);
tb.Inlines.Add("Un ejemplo de ");
tb.Inlines.Add(new Run("un control TextBlock ") { FontWeight = FontWeights.Bold });
tb.Inlines.Add("usando ");
tb.Inlines.Add(new Run("texto en línea ") { FontStyle = FontStyles.Italic });
tb.Inlines.Add(new Run("con formato ") { Foreground = Brushes.Blue });
tb.Inlines.Add("desde ");
tb.Inlines.Add(new Run("Código Subyacente") { TextDecorations =
TextDecorations.Underline });
tb.Inlines.Add(".");
this.Content = tb;
}
}
} 60
60
30
1/9/2023
➢ EL CONTROL LABEL
El control Label, en su forma más simple, es muy similar al control TextBlock.
Sin embargo, rápidamente se notará que en lugar de una propiedad Text, tiene
una propiedad Content. La razón de esto es que Label puede alojar cualquier
otro tipo de control directamente dentro de él, en lugar de solo texto. Este
contenido también puede ser una cadena.
<Grid>
<Label Content="Este es un control Label."/>
</Grid>
Es posible notar que el control Label, por defecto, tiene un poco de padding,
permitiendo al texto ser renderizado a pocos pixels del alto y de la esquina
izquierda. En un caso sencillo como este, donde el contenido es
simplemente una cadena de texto, el Label creará un TextBlock
61
internamente y mostrará la cadena en él.
61
Desde esta perspectiva, la pregunta necesaria es: ¿Por qué usar el control
Label? Bien, hay pocas diferencias importantes entre el Label y el TextBlock. El
TextBlock sólo permite renderizar una cadena de texto, mientras que el Label
permite:
Especificar un borde
Renderizar otros controles, por ejemplo, una imagen.
Usar templates a través de la propiedad ContentTemplate
Usar teclas de acceso para posicionar el foco en el control relacionado.
El último punto es uno de los principales motivos para usar el Label en vez del
control TextBlock. Cuando se quiera renderizar texto sencillo, se debe usar el
TextBlock, ya que es más ligero y funciona mejor que el Label en la mayoría de
los casos.
62
62
31
1/9/2023
63
63
64
32
1/9/2023
<StackPanel Margin="10">
<Label Target="{Binding ElementName=txtName}">
<StackPanel Orientation="Horizontal">
<Image Source=“F:\Univalle 2022\Semestre 2-2022\Programacion
II\Iconos_C\windows_security_21075.png" Height="10" />
<AccessText Text="_Name:" />
</StackPanel>
</Label>
<TextBox Name="txtName" />
<Label Target="{Binding ElementName=txtMail}">
<StackPanel Orientation="Horizontal">
<Image Source=“F:\Univalle 2022\Semestre 2-2022\Programacion
II\Iconos_C\Windows_Security_25875.png" Height="10"/>
<AccessText Text="_Mail:" />
</StackPanel>
</Label>
<TextBox Name="txtMail" />
</StackPanel>
65
65
66
66
33
1/9/2023
➢ EL CONTROL TEXTBOX
El control TextBox es el control más básico para introducir texto en WPF,
permitiendo al usuario final escribir texto plano en una sola línea para un
formulario o como múltiples líneas como en un editor de texto.
<StackPanel Margin="10">
<TextBox />
</StackPanel>
<StackPanel Margin="10">
<TextBox Text=“Hola Mundo!" />
</StackPanel>
67
67
<Grid Margin="10">
<TextBox AcceptsReturn="True"
TextWrapping="Wrap" />
</Grid>
68
68
34
1/9/2023
69
69
<Grid Margin="10">
<TextBox AcceptsReturn="True" TextWrapping="Wrap"
SpellCheck.IsEnabled="True" Language="es" />
</Grid>
70
35
1/9/2023
71
71
72
36
1/9/2023
73
73
➢ EL CONTROL BUTTON
El último de los componentes básicos es el control Button (botón), WPF tiene
incluido uno muy agradable, y como el resto de los controles de framework, es
muy flexible y permitirá lograr casi cualquier cosa.
<DockPanel>
<Button Click="Button_Click">Saludo!</Button>
</DockPanel>
74
74
37
1/9/2023
75
75
76
76
38
1/9/2023
77
77
78
78
39
1/9/2023
<Grid>
<Button Padding="5">
<StackPanel Orientation="Horizontal">
<Image Source="E:\Univalle 2022\Semestre 2-2022\Programacion
II\Iconos_C\search_14765.png" Height="15"/>
<TextBlock Margin="5,0">Buscar</TextBlock>
</StackPanel>
</Button>
</Grid>
79
79
✓ ATRIBUTOS GLOBALES
En algunas ocasiones puede ser un trabajo moroso y aburrido, ir colocando
atributos a los componentes wpf, cuando los mismos tienen los mismos valores,
por ejemplo, tratar de aplicar padding de 5px superior e inferior y 2px izquierda y
derecha, sin embargo, se puede aplicar el relleno globalmente, ya sea en toda la
aplicación o solo en una ventana específica, usando un estilo, aplicando la
propiedad Window.Resources
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Padding" Value="5,2"/>
</Style>
</Window.Resources>
80
80
40
1/9/2023
➢ EL CONTROL CHECKBOX
El control CheckBox permite al usuario final alternar una opción entre
verdadero y falso. Usualmente refleja un valor Boolean en el código subyacente.
<StackPanel Margin="10">
<Label FontWeight="Bold">Opciones de Aplicación</Label>
<CheckBox>Opción 1</CheckBox>
<CheckBox IsChecked="True">Opción 2</CheckBox>
<CheckBox>Opción 3</CheckBox>
</StackPanel>
81
81
✓ CHECKBOX PERSONALIZADOS
El control CheckBox hereda de la clase ContentControl, lo que significa que
puede tomar contenido personalizado y mostrarlo junto a él. Si se especifica un
trozo de texto, WPF lo pondrá dentro de un control de tipo TextBlock y lo
mostrará, pero es posible utilizar cualquier tipo de control dentro de él.
82
82
41
1/9/2023
<StackPanel Margin="10">
<Label FontWeight="Bold">Opciones de Aplicación</Label>
<CheckBox>
<TextBlock>
Opción <Run Foreground="Green" FontWeight="Bold">ABC</Run>
</TextBlock>
</CheckBox>
<CheckBox IsChecked="True">
<WrapPanel>
<TextBlock>
Opción <Run FontWeight="Bold">XYZ</Run>
</TextBlock>
<Image Source="F:\Univalle 2022\Semestre 2-2022\Programacion II\Iconos_C/carpeta.png"
Width="16" Height="16" Margin="5,0" />
</WrapPanel>
</CheckBox>
<CheckBox>
<TextBlock>
Opción <Run Foreground="Blue" TextDecorations="Underline" FontWeight="Bold">WWW</Run>
</TextBlock>
</CheckBox>
</StackPanel>
83
83
✓ LA PROPIEDAD ISTHREESTATE
El CheckBox normalmente corresponde a un valor lógico, lo que significa que
tiene sólo dos estados: true o false (verdadero o falso). En cualquier caso,
puesto que un tipo de datos boolean podría ser nullable, permitiendo de hecho
una tercera opción (true, false o null) el control CheckBox también permite este
escenario. Poniendo la propiedad IsThreeState a true, el CheckBox podrá
adquirir el tercer estado llamado el estado intermedio.
Una utilización habitual para esto es disponer de un CheckBox que habilite todo,
que puede controlar un conjunto de Checkboxes hijos así como mostrar su
estado colectivo.
84
84
42
1/9/2023
<StackPanel Margin="10">
<Label FontWeight="Bold">Opciones</Label>
<StackPanel Margin="10,5">
<CheckBox IsThreeState="True" Name="cbOpciones"
Checked="cbOpciones_CheckedChanged"
Unchecked="cbOpciones_CheckedChanged">Seleccionar todo</CheckBox>
<StackPanel Margin="20,5">
<CheckBox Name="cbOpcion1" Checked="cbOpcion_CheckedChanged"
Unchecked="cbOpcion_CheckedChanged">Opción ABC</CheckBox>
<CheckBox Name="cbOpcion2" IsChecked="True"
Checked="cbOpcion_CheckedChanged" Unchecked="cbOpcion_CheckedChanged">Opción
XYZ</CheckBox>
<CheckBox Name="cbOpcion3" Checked="cbOpcion_CheckedChanged"
Unchecked="cbOpcion_CheckedChanged">Opción WWW</CheckBox>
</StackPanel>
</StackPanel>
</StackPanel>
85
85
86
86
43
1/9/2023
87
87
➢ EL CONTROL RADIOBUTTON
El control RadioButton permite dar al usuario una lista de posibles opciones,
con solo un elemento seleccionado al mismo tiempo.
<StackPanel Margin="10">
<Label FontWeight="Bold">Estas listo?</Label>
<RadioButton>Si</RadioButton>
<RadioButton>No</RadioButton>
<RadioButton IsChecked="True">Tal vez</RadioButton>
</StackPanel>
88
88
44
1/9/2023
✓ AGRUPAMIENTO DE RADIOBUTTON
<StackPanel Margin="10">
<Label FontWeight="Bold">Estas listo?</Label>
<RadioButton GroupName="listo">Si</RadioButton>
<RadioButton GroupName="listo">No</RadioButton>
<RadioButton GroupName="listo" IsChecked="True">Tal vez</RadioButton>
<Label FontWeight="Bold">Género?</Label>
<RadioButton GroupName="sexo">Masculino</RadioButton>
<RadioButton GroupName="sexo">Femenino</RadioButton>
<RadioButton GroupName="sexo" IsChecked="True">No estoy seguro</RadioButton>
</StackPanel>
89
89
✓ PERSONALIZACIÓN DE RADIOBUTTON
90
90
45
1/9/2023
➢ EL CONTROL PASSWORDBOX
Para editar texto normal, se utiliza un TextBox. Pero, ¿qué hay de la edición de
contraseñas? Si se requiere la misma funcionalidad básica, escondiendo los
caracteres ingresados para proteger las contraseñas. Para este propósito, WPF
provee el control de PasswordBox , que resulta tan fácil de usar como un
TextBox.
<StackPanel Margin="10">
<Label>Usuario:</Label>
<TextBox />
<Label>Contraseña:</Label>
<PasswordBox />
</StackPanel>
91
92
92
46
1/9/2023
1.5. CONTROLES
CONTENEDORES
93
Paneles
Para el trabajo con WPF, es necesario contar con controles contenedores, que
permitan el posicionamiento de los diferentes controles o elementos.
Los paneles son uno de los tipos de controles más importantes de WPF. Actúan
como contenedores para otros controles, y manejan el layout de las ventanas o
páginas. A diferencia de una ventana, que sólo puede contener un control hijo;
un panel es usado comúnmente para dividir el espacio en áreas, donde cada área
puede contener un control u otro panel (que es, al fin y al cabo, otro control).
Los paneles presentan diferentes características, con cada uno de ellos
teniendo su propio modo de lidiar con el diseño y los controles hijos. Elegir el
panel correcto es esencial para obtener el comportamiento y el diseño que se
desea.
94
94
47
1/9/2023
➢ TIPOS DE PANELES
Los paneles que se encuentran a disposición en WPF son:
Canvas
Un panel simple, que imita la forma de hacer las cosas de WinForms. Permite
asignar coordenadas específicas a cada uno de los controles secundarios, lo
que te da un control total del diseño. Sin embargo, esto no es muy flexible,
porque se debe mover manualmente los controles secundarios y asegurarse de
que se alineen de la forma deseada. Se recomienda usarlo (solo) cuando se
desee un control completo de las posiciones de los controles hijos.
WrapPanel
El WrapPanel colocará cada uno de sus controles hijos uno junto al otro,
horizontalmente (predeterminado) o verticalmente, hasta que no haya más
espacio, donde se ajustará a la siguiente línea y luego continuará. Debe usarse
cuando se desee un control de lista vertical u horizontal que se ajusta
automáticamente cuando no hay más espacio.
95
95
StackPanel
El StackPanel actúa de manera muy parecida al WrapPanel, pero en lugar de
adaptarse si los controles secundarios ocupan demasiado espacio,
simplemente se expande, si es posible. Al igual que con WrapPanel, la
orientación puede ser horizontal o vertical, pero en lugar de ajustar el ancho o la
altura de los controles hijos en función del elemento más grande, cada elemento
se estira para abarcar todo el ancho o la altura. Se debe usar el StackPanel
cuando se desee una lista de controles que ocupe todo el cuadrante disponible,
sin adaptarlos.
DockPanel
El DockPanel permite acoplar los controles hijos a la parte superior, inferior,
izquierda o derecha. Por defecto, el último control, si no tiene una posición de
acoplamiento específica, llenará el espacio restante. Se puede lograr lo mismo
con el panel Cuadrícula (Grid), pero para las situaciones más simples, DockPanel
será más fácil de usar. Usar DockPanel siempre que se necesite acoplar uno o
varios controles a uno de los lados, como dividir la ventana en áreas específicas.
96
96
48
1/9/2023
Cuadrícula (Grid)
La Cuadrícula (Grid) es probablemente el más complejo de los tipos de paneles.
Una cuadrícula puede contener múltiples filas y columnas. Se define una altura
para cada una de las filas y un ancho para cada una de las columnas, ya sea en
una cantidad absoluta de píxeles, en un porcentaje del espacio disponible o
como automático, donde la fila o columna ajustará automáticamente su tamaño
según el contenido. Se usa la cuadrícula cuando los otros paneles no hagan el
trabajo, por ejemplo: cuando se necesitan varias columnas y, a menudo, en
combinación con los otros paneles.
Cuadrícula uniforme (UniformGrid)
UniformGrid es como la Cuadrícula (Grid), con la posibilidad de filas y columnas
múltiples, pero con una diferencia importante: todas las filas y columnas
tendrán el mismo tamaño. Se debe usar cuando se necesite el comportamiento
de cuadrícula sin la necesidad de especificar diferentes tamaños para las filas y
columnas.
97
97
✓ CANVAS
El panel Canvas es probablemente el panel más simple de todos. Realmente no
hace nada por defecto, solo permite poner controles en él y posicionarlos de
acuerdo al criterio del desarrollador usando coordenadas específicas. El panel
Canvas otorga control completo de las posiciones, no le preocupa realmente si
hay suficiente espacio para todos los controles o si uno está encima de otro
Si se tiene experiencia en IU como Windows Forms, Canvas será lo mismo, pero
si bien puede ser tentador tener control de todos los controles hijos, esto
también significa que el Panel no hará nada para mantener el diseño una vez que
el usuario comience a cambiar el tamaño de la ventana, si se coloca texto
posicionado de manera absoluta o si el contenido está escalado.
98
98
49
1/9/2023
<Canvas>
<Button>Boton 1</Button>
<Button>Boton 2</Button>
</Canvas>
<Canvas>
<Button Canvas.Left="10">Superior izquierda</Button>
<Button Canvas.Right="10">Superior derecha</Button>
<Button Canvas.Left="10" Canvas.Bottom="10">Inferior izquierda</Button>
<Button Canvas.Right="10" Canvas.Bottom="10">Inferior derecha</Button>
</Canvas>
99
99
Z-Index
<Canvas>
<Ellipse Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
<Rectangle Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
<Rectangle Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
<Rectangle Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
</Canvas>
<Canvas>
<Ellipse Panel.ZIndex="2" Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200"
Height="200" />
<Rectangle Panel.ZIndex="3" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50"
Height="50" />
<Rectangle Panel.ZIndex="2" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50"
Height="50" />
<Rectangle Panel.ZIndex="4" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50"
Height="50" />
</Canvas>
100
100
50
1/9/2023
✓ WRAPPANEL
El control WrapPanel colocará cada uno de sus controles hijos uno al lado del
otro, horizontalmente (predeterminado) o verticalmente, hasta que no haya más
espacio, donde se ajustará a la siguiente línea y luego continuará. Su mejor uso
se da al buscar una lista de controles que se alineen vertical u horizontal de
forma automática cuando ya no tenga mas espacio.
Cuando el control WrapPanel use la orientación horizontal, los controles hijos
tomarán la misma altura, basado en el elemento mas alto. Cuando el control
WrapPanel tenga una orientación vertical, los controles hijos tomarán el mismo
ancho, basado en el elemento mas ancho.
101
101
<WrapPanel>
<Button>Boton de prueba 1</Button>
<Button>Boton de prueba 2</Button>
<Button>Boton de prueba 3</Button>
<Button Height="40">Boton de prueba 4</Button>
<Button>Boton de prueba 5</Button>
<Button>Boton de prueba 6</Button>
</WrapPanel>
<WrapPanel Orientation="Vertical">
<Button>Boton de prueba 1</Button>
<Button>Boton de prueba 2</Button>
<Button>Boton de prueba 3</Button>
<Button Height="40" Width="44">Boton de prueba 4</Button>
<Button>Boton de prueba 5</Button>
<Button>Boton de prueba 6</Button>
</WrapPanel>
102
102
51
1/9/2023
✓ STACKPANEL
El StackPanel es muy similar al WrapPanel, pero con al menos una diferencia
importante: El StackPanel no adapta el contenido. En lugar de eso lo estira en
una dirección, permitiendo apilar ítem tras ítem uno encima de otro. Siendo su
orientación por defecto Vertical.
<StackPanel>
<Button>Boton 1</Button>
<Button>Boton 2</Button>
<Button>Boton 3</Button>
<Button>Boton 4</Button>
<Button>Boton 5</Button>
<Button>Boton 6</Button>
</StackPanel>
103
103
<StackPanel Orientation="Horizontal">
<Button>Boton 1</Button>
<Button>Boton 2</Button>
<Button>Boton 3</Button>
<Button>Boton 4</Button>
<Button>Boton 5</Button>
<Button>Boton 6</Button>
</StackPanel>
104
104
52
1/9/2023
✓ DOCKPANEL
El DockPanel simplifica la tarea de acoplar contenido en función a los lados de la
ventana: arriba, abajo, izquierda y derecha. Esto lo convierte en una gran opción
en muchas situaciones donde se quiera dividir la ventana en áreas específicas
especialmente porque, por defecto, el último elemento dentro del DockPanel (a
no ser que esta funcionalidad esté específicamente deshabilitada) va a llenar el
resto del espacio (desde el centro), es decir, la propiedad DockPanel.Dock,
decide en que dirección se quiere que el control hijo se coloque. Si no se usa
esta propiedad, el primer control se colocará desde la izquierda, y el último
tomará todo el espacio sobrante.
<DockPanel>
<Button DockPanel.Dock="Left">Izquierda</Button>
<Button DockPanel.Dock="Top">Arriba</Button>
<Button DockPanel.Dock="Right">Derecha</Button>
<Button DockPanel.Dock="Bottom">Abajo</Button>
<Button>Centro</Button>
</DockPanel>
105
105
<DockPanel>
<Button DockPanel.Dock="Top" Height="50">Arriba</Button>
<Button DockPanel.Dock="Bottom" Height="50">Abajo</Button>
<Button DockPanel.Dock="Left" Width="50">Izquierda</Button>
<Button DockPanel.Dock="Right" Width="50">Derecha</Button>
<Button>Centro</Button>
</DockPanel>
106
106
53
1/9/2023
Propiedad LastChildFill
El comportamiento por defecto, es que el último elemento del DockPanel utilice
todo el espacio remanente, pero esto puede deshabilitarse usando la propiedad
LastChildFill, además es posible acoplar más de un control en el mismo lado.
<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Top" Height="50">Arriba</Button>
<Button DockPanel.Dock="Bottom" Height="50">Abajo</Button>
<Button DockPanel.Dock="Left" Width="50">Izquierda</Button>
<Button DockPanel.Dock="Left" Width="50">Izquierda</Button>
<Button DockPanel.Dock="Right" Width="50">Derecha</Button>
<Button DockPanel.Dock="Right" Width="50">Derecha</Button>
</DockPanel>
107
107
✓ GRID
El control Grid es probablemente el más complejo de los controles tipo panel.
Puede contener múltiples filas y columnas. Se debe definir la altura para cada
fila y el ancho de cada columna. Esas dimensiones pueden establecerse tanto
en forma absoluta en cantidad de pixels, como porcentaje del espacio
disponible o en forma automática Auto, en la cual la fila o columna ajustará su
tamaño automáticamente dependiendo del contenido. Se utiliza un control Grid
cuando otro tipo de paneles no sean adecuados para el formato deseado. Por
ejemplo, cuando se requiere de varias filas y/columnas, a menudo en
combinación con otro tipo de paneles.
En su forma más simple, una Grid tomará todos los controles que se coloquen
dentro de ella, aumentará su tamaño hasta que usen todo el espacio disponible,
y los ubicará uno encima de otro.
<Grid>
<Button>Boton 1</Button>
<Button>Boton 2</Button>
</Grid> 108
108
54
1/9/2023
El último control toma la posición superior, lo cual significa que no es posible ver
el primer botón. Pero es posible dividir el espacio, que es lo que la grilla hace tan
bien. Para lo cual se utilizan las propiedades ColumnDefinitions y
RowDefinitions.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button>Boton 1</Button>
<Button Grid.Column="1">Boton 2</Button>
</Grid>
Como se puede comprobar, los controles toman todo el espacio disponible, el cual
es el comportamiento por defecto cuando el Grid organiza sus controles hijos. Lo
hace estableciendo las propiedades HorizontalAlignment y VerticalAlignment de
los mismos a Stretch.
109
109
110
110
55
1/9/2023
Filas y columnas
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Boton 2</Button>
<Button Grid.Column="2">Boton 3</Button>
<Button Grid.Row="1">Boton 4</Button>
<Button Grid.Column="1" Grid.Row="1">Boton 5</Button>
<Button Grid.Column="2" Grid.Row="1">Boton 6</Button>
<Button Grid.Row="2">Boton 7</Button>
<Button Grid.Column="1" Grid.Row="2">Boton 8</Button>
<Button Grid.Column="2" Grid.Row="2">Boton 9</Button>
</Grid> 111
111
Un total de nueve botones, cada uno ubicado en su propia celda, en una grilla
que contiene tres filas y tres columnas, configurando el ancho basado en *,
además de asignar números. Se podrá notar el uso de las propiedades Attached
Grid.Row y Grid.Column para ubicar los controles en la grilla, omitiendo las
mismas en los controles de la primera y/o segunda fila.
112
112
56
1/9/2023
Unidades
Además del uso del *, que indica que una columna o fila debería tomar cierto
porcentaje del espacio combinado, existen otras dos formas de especificar el
ancho y altura de una columna o fila: Unidades absolutas y el ancho y altura
automáticos (Auto).
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Button>Boton 1</Button>
<Button Grid.Column="1">Boton 2 con texto largo</Button>
<Button Grid.Column="2">Boton 3</Button>
</Grid>
113
113
Extendiendo el Grid
El comportamiento por defecto es que cada control utilice una celda, pero a
veces se requiere que un control ocupe múltiples filas o columnas.
Afortunadamente, el Grid lo permite fácilmente con las propiedades
ColumnSpan y RowSpan. El valor por defecto de esa propiedad es 1, pero es
posible cambiarlo por un número más grande para que el control abarque varias
filas o columnas.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button>Boton 1</Button>
<Button Grid.Column="1">Boton 2</Button>
<Button Grid.Row="1" Grid.ColumnSpan="2">Boton 3</Button> 114
</Grid>
114
57
1/9/2023
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.ColumnSpan="2">Boton 1</Button>
<Button Grid.Column="3">Boton 2</Button>
<Button Grid.Row="1">Boton 3</Button>
<Button Grid.Column="1" Grid.Row="1" Grid.RowSpan="2"
Grid.ColumnSpan="2">Boton 4</Button>
<Button Grid.Column="0" Grid.Row="2">Boton 5</Button>
</Grid>
115
115
GridSplitter
El panel Grid permite facilitar el trabajo de dividir el espacio disponible en
celdas individuales. Usando definiciones de columnas y filas es posible definir
el espacio que ocuparán en pantalla, pero en ocasiones se vuelve necesario que
el usuario cambie estas medidas. Esto puede realizarse con la propiedad
GridSplitter, aplicándola a una columna o una fila en un Grid, con la cantidad
adecuada de espacio para ello.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock FontSize="55" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="Wrap">Lado izquierdo</TextBlock>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<TextBlock Grid.Column="2" FontSize="55" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="Wrap">Lado derecho</TextBlock>
</Grid> 116
116
58
1/9/2023
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="5" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock FontSize="55" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="Wrap">Arriba</TextBlock>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" />
<TextBlock Grid.Row="2" FontSize="55" HorizontalAlignment="Center"
VerticalAlignment="Center" TextWrapping="Wrap">Abajo</TextBlock>
</Grid>
117
117
Ejemplo
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox>Nombre</TextBox>
<TextBox Grid.Row="1">E-mail</TextBox>
<TextBox Grid.Row="2" AcceptsReturn="True">Observación</TextBox>
</Grid>
118
118
59
1/9/2023
Ejercicio
119
119
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label>Nombre:</Label>
<TextBox Grid.Column="1" Margin="0,0,0,10" />
<Label Grid.Row="1">E-mail:</Label>
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" />
<Label Grid.Row="2">Observación:</Label>
<TextBox Grid.Row="2" Grid.Column="1" AcceptsReturn="True" />
</Grid>
120
120
60
1/9/2023
El control Image
El control de WPF Image permite mostrar imágenes en aplicaciones. Es un control
muy versátil con muchas opciones y métodos útiles.
<Grid>
<Image Source="https://empresas.blogthinkbig.com/wp-content/uploads/2019/11/Imagen3-245003649.jpg?fit=960%2C720" />
</Grid>
121
121
<Grid>
<Image Source="F:\Univalle 2023\Semestre 2-2023\Programacion
II\Imagenes\Color_picker_35275.png" />
</Grid>
122
122
61
1/9/2023
123
✓ LA PROPIEDAD STRETCH
La propiedad Stretch
(estiramiento), controla lo
que ocurre cuando las
dimensiones de la imagen
cargada no encajan
completamente las
dimensiones del control
Image. Esto suele pasar
todo el tiempo, ya que el
tamaño de la ventana
puede ser controlada por el
usuario y, a menos que el
diseño sea estático, esto
significa que el tamaño del
control Image va a cambiar
también. 124
124
62
1/9/2023
125
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Column="0" HorizontalAlignment="Center" FontWeight="Bold">Uniform</Label>
<Label Grid.Column="1" HorizontalAlignment="Center"
FontWeight="Bold">UniformToFill</Label>
<Label Grid.Column="2" HorizontalAlignment="Center" FontWeight="Bold">Fill</Label>
<Label Grid.Column="3" HorizontalAlignment="Center" FontWeight="Bold">None</Label>
<Image Source="E:\Univalle 2022\Semestre 2-2022\Programacion II\Imagenes\tigre.jpg"
Stretch="Uniform" Grid.Column="0" Grid.Row="1" Margin="5" />
<Image Source="E:\Univalle 2022\Semestre 2-2022\Programacion II\Imagenes\tigre.jpg"
Stretch="UniformToFill" Grid.Column="1" Grid.Row="1" Margin="5" />
<Image Source="E:\Univalle 2022\Semestre 2-2022\Programacion II\Imagenes\tigre.jpg"
Stretch="Fill" Grid.Column="2" Grid.Row="1" Margin="5" />
<Image Source="E:\Univalle 2022\Semestre 2-2022\Programacion II\Imagenes\tigre.jpg"
Stretch="None" Grid.Column="3" Grid.Row="1" Margin="5" />
</Grid>
126
126
63
1/9/2023
CLASES BASES
Un alto porcentaje de las clases en WPF se derivan de cuatro clases que se
conocen comúnmente como las clases de elemento base. Estas clases son:
UIElement, ContentElement, FrameworkElementy FrameworkContentElement. La
clase DependencyObject también está relacionada, porque es una clase base de
UIElement y ContentElement.
127
127
2.2.1. UIELEMENT
UIElement es una clase base para implementaciones de nivel de núcleo de WPF
que se compila a partir de características básicas de presentación y elementos
de Windows Presentation Foundation (WPF). Proviene del espacio de nombres:
System.Windows y genera el ensamblado: PresentationCore.dll.
[System.Windows.Markup.UidProperty("Uid")]
public class UIElement : System.Windows.Media.Visual,
System.Windows.IInputElement, System.Windows.Media.Animation.IAnimatable
128
128
64
1/9/2023
129
130
130
65
1/9/2023
✓ FRAMEWORKELEMENT
FrameworkElement es la clase de implementación de nivel de marco de WPF
que se basa en UIElement y agrega interacciones específicas con el nivel marco
de WPF. FrameworkElement agrega y define las siguientes capacidades:
Características de diseño específicas del marco de trabajo adicionales
Compatibilidad con informes de metadatos más completos en propiedades
Implementación específica de la clase de determinadas clases base de
entrada y sus propiedades adjuntas o eventos adjuntos
Compatibilidad de estilo
Mayor compatibilidad con animaciones
[System.Windows.Markup.RuntimeNameProperty("Name")]
[System.Windows.Markup.UsableDuringInitialization(true)]
[System.Windows.Markup.XmlLangProperty("Language")]
[System.Windows.StyleTypedProperty(Property="FocusVisualStyle",
StyleTargetType=typeof(System.Windows.Controls.Control))] public class
FrameworkElement: System.Windows.UIElement,
System.ComponentModel.ISupportInitialize,
System.Windows.IFrameworkInputElement, System.Windows.Markup.IQueryAmbient 131
131
2.2.2. CONTENELEMENT
La clase CONTENELEMENT proporciona una clase base de nivel principal de
WPF para los elementos de contenido. Los elementos de contenido están
diseñados para la presentación del estilo de flujo, mediante un modelo de
diseño orientado a marcado intuitivo y un modelo de objetos deliberadamente
simple.
public class ContentElement : System.Windows.DependencyObject,
System.Windows.IInputElement, System.Windows.Media.Animation.IAnimatable
132
132
66
1/9/2023
133
133
134
134
67
1/9/2023
✓ FRAMEWORKCONTENTELEMENT
FrameworkContentElement es la implementación de nivel de marco de WPF y la
expansión de la clase base ContentElement. FrameworkContentElement agrega
compatibilidad para las API de entrada adicionales (incluye información sobre
herramientas y menús contextuales), guiones gráficos, el contexto de datos para
el enlace de datos, la compatibilidad de estilos y las API del asistente del árbol
lógico.
[System.Windows.Markup.RuntimeNameProperty("Name")]
[System.Windows.Markup.UsableDuringInitialization(true)]
[System.Windows.Markup.XmlLangProperty("Language")]
[System.Windows.StyleTypedProperty(Property="FocusVisualStyle",
StyleTargetType=typeof(System.Windows.Controls.Control))] public
class FrameworkContentElement : System.Windows.ContentElement,
System.ComponentModel.ISupportInitialize,
System.Windows.IFrameworkInputElement,
System.Windows.Markup.IQueryAmbient
135
135
2.2.3. DEPENDENCYOBJECT
La clase DependencyObject representa un objeto que forma parte del sistema
de propiedades de dependencia.
[System.Windows.Markup.NameScopeProperty("NameScope",
typeof(System.Windows.NameScope))] public class DependencyObject :
System.Windows.Threading.DispatcherObject
136
68
1/9/2023
137
ARQUITECTURA WPF
La arquitectura de WPF representa la jerarquía de clases de Windows
Presentation Foundation (WPF). Abarca la mayoría de los subsistemas
principales de WPF y describe cómo interactúan.
✓ SYSTEM.OBJECT
El modelo principal de programación de WPF se expone a través del código
administrado. Al principio de la fase de diseño de WPF, había una serie de
debates sobre dónde se debe dibujar la línea entre los componentes
administrados del sistema y los no administrados. CLR proporciona una serie de
características que hacen que el desarrollo sea más productivo y robusto
(incluida la administración de la memoria, el control de errores, el sistema de
tipos común, etc.), pero tienen un costo.
138
138
69
1/9/2023
139
140
70
1/9/2023
Eventos WPF
La mayoría de los marcos (frameworks) de UI modernos al igual que WPF, están
impulsados por eventos. Todos los controles, incluida la ventana (Window) (que
también hereda de la clase control) exponen un rango de eventos a los que es
posible suscribirse, lo que significa que la aplicación será notificada cuando
ocurran y podrá reaccionar a ellos.
Hay muchos tipos de eventos, pero algunos de los más comúnmente utilizados
están hechos para responder a la interacción del usuario con su aplicación, con el
ratón o el teclado. En la mayoría de los controles se encuentran eventos como
KeyDown, KeyUp, MouseDown, MouseEnter, MouseLeave, MouseUp y varios otros.
141
141
<Grid>
<Button Padding="5“Click="Button_Click">
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE
Programacion II\Iconos\search_14765.png" Height="15"/>
<TextBlock Margin="5,0">Buscar</TextBlock>
</StackPanel>
</Button>
</Grid>
142
142
71
1/9/2023
EVENTOS ENRUTADOS
Para entender lo que representan los eventos enrutados se pueden ver desde una
perspectiva funcional o de implementación.
Definición funcional: un evento enrutado es un tipo de evento que puede invocar
controladores en múltiples oyentes en un árbol de elementos, en lugar de solo en
el objeto que generó el evento.
Definición de implementación: un evento enrutado es un evento CLR (Common
Language Runtime) respaldado por una instancia de la clase RoutedEvent y
procesado por el sistema de eventos de Windows Presentation Foundation
(WPF).
Una aplicación típica de WPF contiene muchos elementos. Ya sea que se creen en
código o se declaren en XAML, estos elementos existen en una relación de árbol de
elementos entre sí. La ruta del evento puede viajar en una de dos direcciones
dependiendo de la definición del evento, pero generalmente la ruta viaja desde el
elemento de origen y luego burbujea hacia arriba a través del árbol de elementos
hasta que alcanza la raíz del árbol de elementos (generalmente una página o una
ventana) . 143
143
72
1/9/2023
145
145
146
146
73
1/9/2023
✓ MANEJO DE CLASES
Los eventos enrutados permiten un manejador estático definido por la clase.
Este controlador de clase tiene la oportunidad de manejar un evento antes que
cualquier controlador de instancia adjunto.
✓ HACER REFERENCIA A UN EVENTO SIN REFLEXIÓN
Ciertos códigos y técnicas de marcado requieren una forma de identificar un
evento específico. Un evento enrutado crea un campo RoutedEvent como
identificador, que proporciona una técnica sólida de identificación de eventos
que no requiere reflexión estática en tiempo de ejecución.
147
147
EVENTOS ADJUNTOS
El lenguaje XAML, define un componente de lenguaje y un tipo de evento
llamado evento adjunto. El concepto de evento adjunto permite agregar un
controlador para un evento en particular a un elemento arbitrario en lugar de a
un elemento específico. En este caso, ni el objeto que potencialmente genera el
evento ni la instancia de manejo de destino define o posee el evento.
Los eventos adjuntos tienen una sintaxis XAML y un patrón de codificación que
debe usar el código de respaldo para admitir el uso del evento adjunto.
En la sintaxis XAML, el evento adjunto se especifica no solo por su nombre de
evento, sino por su tipo propietario más el nombre del evento, separados por un
punto (.). Debido a que el nombre del evento se establece con el nombre de su
tipo propietario, la sintaxis del evento adjunto permite aplicar cualquier evento
adjunto a cualquier elemento del que se pueda crear una instancia.
148
148
74
1/9/2023
<Grid Button.Click="botones_Click">
<Button Name="button1" Content="Botón 1" Height="25" Margin="0,10,0,81"/>
<Button Name="button2" Content="Botón 2" Height="25" Margin="0,40,0,51"/>
<Button Name="button3" Content="Botón 3" Height="25" Margin="0,70,0,21"/>
</Grid>
149
150
150
75
1/9/2023
151
152
76
1/9/2023
154
154
77
1/9/2023
155
155
156
156
78
1/9/2023
157
157
158
79
1/9/2023
Estilos WPF
En WPF, un estilo define los valores de una o más propiedades de dependencia
para un elemento visual dado. Los estilos se utilizan en toda la aplicación para
hacer que la interfaz de usuario sea más consistente (por ejemplo, para que todos
los botones de diálogo tengan un tamaño uniforme) y para hacer que los cambios
masivos sean más fáciles (por ejemplo, para cambiar el ancho de todos los
botones).
Normalmente, los estilos se definen en un ResourceDictionary a un alto nivel en la
aplicación (por ejemplo, en App.xaml o en un tema), por lo que está disponible
para toda la aplicación, pero también pueden definirse para un solo elemento y
sus elementos secundarios , por ejemplo, aplicar un Estilo a todos los elementos
TextBlock dentro de un StackPanel .
159
159
<StackPanel Margin="10">
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
</StackPanel.Resources>
<TextBlock>Texto 1</TextBlock>
<TextBlock>Texto 2</TextBlock>
<TextBlock Foreground="Blue">Texto 3</TextBlock>
</StackPanel>
160
80
1/9/2023
161
161
➢ ESTILO IMPLÍCITO
Un estilo implícito se aplica a todos los elementos de un tipo dado dentro del
alcance. Un estilo implícito puede omitir x:Key ya que es implícitamente lo
mismo que la propiedad TargetType del estilo.
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</StackPanel.Resources>
162
162
81
1/9/2023
163
163
164
164
82
1/9/2023
➢ ESTILO DE VENTANA
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock>Texto 1</TextBlock>
<TextBlock>Texto 2</TextBlock>
<TextBlock Foreground="Blue">Texto 3</TextBlock>
</StackPanel>
165
165
➢ ESTILO ANCHO
Es posible aplicar los estilos en toda la aplicación, en diferentes ventanas. Esto
se hace en el archivo App.xaml que Visual Studio ha creado, y se hace como en
el ejemplo de toda la ventana:
<Application x:Class="Aula1WPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Aula1WPF"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
</Application.Resources>
</Application>
166
166
83
1/9/2023
<StackPanel Margin="10">
<TextBlock>Texto 1</TextBlock>
<TextBlock>Texto 2</TextBlock>
<TextBlock Foreground="Blue">Texto 3</TextBlock>
</StackPanel>
167
167
➢ ESTILO EXPLÍCITO
<Window.Resources>
<Style x:Key="EstiloTexto" TargetType="TextBlock">
<Setter Property="Foreground" Value="Gray" />
<Setter Property="FontSize" Value="24" />
</Style>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock>Texto 1</TextBlock>
<TextBlock Style="{StaticResource EstiloTexto}">Texto 2</TextBlock>
<TextBlock>Texto 3</TextBlock>
</StackPanel>
168
168
84
1/9/2023
TRIGGERS (DISPARADORES)
Hasta el momento, se ha trabajado con estilos estableciendo valores estáticos
en una propiedad determinada. Sin embargo, mediante el uso de disparadores
(Triggers), se puede modificar los valores de las propiedades ante cierta
condición. Existe varios tipos de triggers: de propiedad, de evento, y de datos.
Los triggers permiten realizar tareas que normalmente se realizarían en code
behind, como parte del proceso constante de separar la presentación de la
lógica de negocios.
169
169
➢ TRIGGERS DE PROPIEDAD
El tipo más común de trigger es el de propiedad, el cual, simplemente se define
con un elemento <Trigger>. Este tipo de trigger observa a una propiedad dada
en el control contenedor, y cuando esa propiedad toma un valor determinado, la
propiedad cambia.
<Grid>
<TextBlock Text="Hola, mundo con estilo!" FontSize="28"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Blue"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="TextDecorations" Value="Underline" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
170
</Grid>
170
85
1/9/2023
➢ TRIGGERS DE DATOS
Los triggers de datos, que se representan mediante el elemento <DataTrigger>,
se usan para propiedades que no necesariamente son propiedades de
dependencia. Funcionan mediante la creación de un binding a una propiedad
corriente, la cual se monitorea después en espera de cambios. Esto también
abre la posibilidad de vincular el trigger a una propiedad de otro control distinto.
171
171
✓ BINDING
172
86
1/9/2023
173
173
➢ TRIGGERS DE EVENTOS
Los triggers de evento, que se representan mediante el elemento
<EventTrigger> se usan mayormente para disparar una animación en respuesta
a un evento.
174
174
87
1/9/2023
<Grid> </EventTrigger>
<TextBlock Name="lblEstilo" Text="Hola, <EventTrigger
mundo con estilos!" FontSize="18" RoutedEvent="MouseLeave">
HorizontalAlignment="Center"
VerticalAlignment="Center"> <EventTrigger.Actions>
<TextBlock.Style>
<Style TargetType="TextBlock"> <BeginStoryboard>
<Style.Triggers>
<EventTrigger <Storyboard>
RoutedEvent="MouseEnter">
<DoubleAnimation Duration="0:0:0.800"
<EventTrigger.Actions> Storyboard.TargetProperty="FontSize" To="18" />
<BeginStoryboard> </Storyboard>
<Storyboard> </BeginStoryboard>
175
➢ DISPARADORES MÚLTIPLES
Se pudo ver disparadores basados en una sola propiedad, pero WPF también es
compatible con múltiples disparadores, que pueden monitorear dos o más
condiciones de propiedad y solo desencadenarse una vez que todas se
cumplan.
Hay dos tipos de disparadores múltiples: el MultiTrigger , que al igual que el
activador normal funciona en las propiedades de dependencia, y luego
el MultiDataTrigger, que se vincula a cualquier tipo de propiedad.
176
176
88
1/9/2023
➢ MULTITRIGGER
<Grid>
<TextBox VerticalAlignment="Center" HorizontalAlignment="Center" Text="Haz clic aqui"
Width="150">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsKeyboardFocused" Value="True" />
<Condition Property="IsMouseOver" Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="Background" Value="LightGreen" />
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
177
177
➢ MULTIDATATRIGGER
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<CheckBox Name="cbSi" Content="Si" />
<CheckBox Name="cbSeguro" Content="Estoy seguro" />
<TextBlock HorizontalAlignment="Center" Margin="0,20,0,0" FontSize="28">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Sin verificar" />
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=cbSi, Path=IsChecked}"
Value="True" />
<Condition Binding="{Binding ElementName=cbSeguro,
Path=IsChecked}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="Text" Value="Verificado" />
<Setter Property="Foreground" Value="Green" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock> 178
</StackPanel>
178
89
1/9/2023
Plantillas WPF
Una plantilla describe el aspecto general y el aspecto visual de un control. Para cada
control, hay una plantilla predeterminada asociada que le da al control su apariencia.
En las aplicaciones de WPF, es posible crear fácilmente plantillas propias cuando se
desee personalizar el comportamiento visual y la apariencia visual de un control. La
conectividad entre la lógica y la plantilla se puede lograr mediante el enlace de datos.
Las principales diferencias entre estilos y plantillas son:
Los estilos solo pueden cambiar la apariencia de su control con las propiedades
predeterminadas de ese control.
Con las plantillas, puede acceder a más partes de un control que en estilos.
También puede especificar el comportamiento nuevo y existente de un control.
Hay dos tipos de plantillas que se utilizan con más frecuencia:
Plantilla de control
Plantilla de datos
179
179
➢ PLANTILLA DE CONTROL
La plantilla de control define la apariencia visual de un control. Todos los
elementos de la interfaz de usuario tienen algún tipo de apariencia y
comportamiento, por ejemplo, Button tiene apariencia y comportamiento. El
evento de clic o el evento de desplazamiento del mouse son los
comportamientos que se activan en respuesta a un clic y al pasar el mouse, y
también hay una apariencia predeterminada del botón que se puede cambiar
mediante la plantilla de Control.
180
180
90
1/9/2023
<Window.Resources>
<ControlTemplate x:Key = "PlantillaBoton" TargetType = "Button">
<Grid>
<Ellipse x:Name = "Elipse" Height = "100" Width = "150" >
<Ellipse.Fill>
<LinearGradientBrush StartPoint = "0,0.2" EndPoint = "0.2,1.4">
<GradientStop Offset = "0" Color = "Red" />
<GradientStop Offset = "1" Color = "Orange" />
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<ContentPresenter Content = "{TemplateBinding Content}" HorizontalAlignment = "Center" VerticalAlignment = "Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property = "IsMouseOver" Value = "True">
<Setter TargetName = "Elipse" Property = "Fill" >
<Setter.Value>
<LinearGradientBrush StartPoint = "0,0.2" EndPoint = "0.2,1.4">
<GradientStop Offset = "0" Color = "YellowGreen" />
<GradientStop Offset = "1" Color = "Gold" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property = "IsPressed" Value = "True">
<Setter Property = "RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX = "0.8" ScaleY = "0.8" CenterX = "0" CenterY = "0" />
</Setter.Value>
</Setter>
<Setter Property = "RenderTransformOrigin" Value = "0.5,0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources> 181
181
<StackPanel>
<Button Content = "Boton circular!“ Template = "{StaticResource PlantillaBoton}"
Width = "150" Margin = "50" />
<Button Content = "Boton por defecto!" Height = "40 Width = "150" Margin = "5" />
</StackPanel>
182
182
91
1/9/2023
➢ PLANTILLA DE DATOS
Una plantilla de datos define y especifica la apariencia y estructura de una
colección de datos. Proporciona la flexibilidad de formatear y definir la
presentación de los datos en cualquier elemento de la interfaz de usuario. Se
utiliza principalmente en controles de elementos relacionados con datos, como
ComboBox, ListBox, etc.
183
183
184
92
1/9/2023
185
186
186
93
1/9/2023
➢ DICCIONARIO DE RECURSOS
Los recursos pueden establecerse como definiciones relacionadas con algún objeto
que se usarán más de una vez. ”Es la capacidad de almacenar datos localmente para
controles o para la ventana actual o globalmente para todas las aplicaciones”.
Definir un objeto como recurso permite acceder a él desde otro lugar. Lo que
significa que el objeto se puede reutilizar. Los recursos se definen en diccionarios de
recursos y cualquier objeto se puede definir como un recurso, lo que lo convierte en
un activo que se puede compartir. Se especifica una clave única para un recurso
XAML y, con esa clave, se puede hacer referencia a ella mediante una extensión de
marcado StaticResource. Los recursos pueden ser de dos tipos:
StaticResource
DynamicResource
Un StaticResource es una búsqueda única, mientras que un DynamicResource
funciona más como un enlace de datos. Se debe recordar que una propiedad está
asociada con una clave de recurso en particular. Si el objeto asociado con esa clave
cambia, el recurso dinámico actualizará la propiedad de destino.
187
187
<Window.Resources>
<SolidColorBrush x:Key = "Recurso1" Color = "Bisque" />
</Window.Resources>
<StackPanel>
<Rectangle Height = "50" Margin = "20" Fill = "{StaticResource Recurso1}" />
<Rectangle Height = "50" Margin = "20" Fill = "{DynamicResource Recurso1}" />
</StackPanel>
188
188
94
1/9/2023
189
189
✓ DICCIONARIO DE RECURSOS
Los diccionarios de recursos en aplicaciones XAML implican que los
diccionarios de recursos se guardan en archivos separados. Se sigue en casi
todas las aplicaciones XAML. La definición de recursos en archivos separados
puede tener las siguientes ventajas:
Separación entre la definición de recursos en el diccionario de recursos y el
código relacionado con la interfaz de usuario.
La definición de todos los recursos en un archivo separado, como App.xaml,
los haría disponibles en toda la aplicación.
190
190
95
1/9/2023
<StackPanel>
<Rectangle Height = "50" Margin = "20" Fill="{StaticResource Recurso1}"/>
<Rectangle Height = "50" Margin = "20" Fill="{DynamicResource Recurso1}"/>
</StackPanel>
191
191
192
96
1/9/2023
Enlazar Comandos
Realmente, los comandos no hacen nada por sí mismos. En esencia consisten en
la interfaz ICommand, que únicamente define un evento y dos métodos: Execute()
y CanExecute(). El primero se encarga de realizar la acción, mientras que el
segundo determina si la acción está disponible. Para lograr realizar la acción
asociada al comando, se necesita enlazar el comando con el código que define la
acción, y aquí es donde entra en juego el CommandBinding.
Un CommandBinding se define típicamente en Window o en un UserControl, y
contiene una referencia al comando que controla, así como los controladores
para tratar los eventos Execute() y CanExcute() del comando.
193
193
➢ COMANDOS PREDEFINIDOS
Obviamente es posible implementar comandos propios, pero por facilidad, WPF
trae predefinidos más de 100 comandos típicos que son necesarios. Éstos se
dividen en 5 categorías: ApplicationCommands, NavigationCommands,
MediaCommands, EditingCommands y ComponentCommands. En especial
ApplicationCommands contiene comandos para multitud de acciones muy
comunes como Nuevo, Abrir, Guardar, Cortar, Copiar o Pegar.
194
194
97
1/9/2023
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.New"
Executed="NewCommand_Executed" CanExecute="NewCommand_CanExecute" />
</Window.CommandBindings>
195
196
98
1/9/2023
➢ COMANDO CANEXECUTE
Al implementar un evento CanExecute que sólo devuelve verdadero, el botón
estaría disponible todo el tiempo. Sin embargo, esto, por supuesto, no es cierto
para todos los botones; en muchos casos, se desea que el botón se habilite o
deshabilite dependiendo de algún tipo de estado de la aplicación.
Un ejemplo muy común de esto es alternar botones para usar el Portapapeles de
Windows, donde se desea que los botones Cortar y Copiar estén habilitados solo
cuando se selecciona texto, y el botón Pegar solo se habilita cuando el texto
está presente en el portapapeles.
197
197
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Cut"
CanExecute="CutCommand_CanExecute" Executed="CutCommand_Executed" />
<CommandBinding Command="ApplicationCommands.Paste"
CanExecute="PasteCommand_CanExecute" Executed="PasteCommand_Executed" />
</Window.CommandBindings>
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Margin="3">
<Button Command="ApplicationCommands.Cut"
Width="60">_Cortar</Button>
<Button Command="ApplicationCommands.Paste" Width="60"
Margin="3,0">_Pegar</Button>
</WrapPanel>
<TextBox AcceptsReturn="True" Name="txtEditor" />
</DockPanel>
198
198
99
1/9/2023
199
199
Se tiene esta interfaz muy simple con un par de botones y un control TextBox. El
primer botón se cortará en el portapapeles y el segundo pegará desde allí.
La parte interesante de esto es que no se tiene que llamar a esos métodos para
tener los botones actualizados, WPF hace esto automáticamente cuando la
aplicación tiene un momento libre, asegurándose que la interfaz se mantiene
actualizada todo el tiempo.
200
200
100
1/9/2023
Control Menú
Una de las partes más comunes de una Aplicación de Windows es el menú,
algunas veces se refiere a él como el Menú Principal porque usualmente solo
existe uno en la aplicación. El menú es práctico porque ofrece muchas opciones,
usando solo un poco de espacio, aunque Windows está tratando de fomentar el
uso de la Cinta de Opciones (the Ribbon) como reemplazo, viejos menús y barras
de herramientas, definitivamente aún tienen su lugar en cada Caja de
Herramientas de un buen Desarrollador.
WPF viene con un control preciso para crear menús llamado... Menu.
Agregaritems, es muy simple – solo se agrega los elementos del MenuItem a el, y
cada MenuItem puede tener una gama de Sub-Items, permitiendo crear menús
jerárquicos como en muchas aplicaciones de Windows.
201
201
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Archivo">
<MenuItem Header="_Nuevo" />
<MenuItem Header="A_brir" />
<MenuItem Header="_Guardar" />
<Separator />
<MenuItem Header="_Salir" />
</MenuItem>
</Menu>
<TextBox AcceptsReturn="True" />
</DockPanel>
202
202
101
1/9/2023
203
203
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Archivo">
<MenuItem Header="_Salir">
<MenuItem.Icon>
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE
Programacion II\Iconos\salir.png" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
<MenuItem Header="_Herramientas">
<MenuItem Header="_Administracion Usuarios">
<MenuItem.Icon>
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE
Programacion II\Iconos\user.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Mostrar Grupos" IsCheckable="True" IsChecked="True" />
</MenuItem>
</Menu>
<TextBox AcceptsReturn="True" />
</DockPanel>
204
204
102
1/9/2023
205
205
206
103
1/9/2023
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="NewCommand_CanExecute"
Executed="NewCommand_Executed" />
</Window.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Archivo">
<MenuItem Command="New" />
<Separator />
<MenuItem Header="_Salir" />
</MenuItem>
<MenuItem Header="_Editar">
<MenuItem Command="Cut" />
<MenuItem Command="Copy" />
<MenuItem Command="Paste" />
</MenuItem>
</Menu>
207
207
208
208
104
1/9/2023
209
209
<Window.CommandBindings>
<CommandBinding Command="New" CanExecute="CommonCommandBinding_CanExecute" />
<CommandBinding Command="Open" CanExecute="CommonCommandBinding_CanExecute" />
<CommandBinding Command="Save" CanExecute="CommonCommandBinding_CanExecute" />
</Window.CommandBindings>
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="New" Content="Nuevo" />
<Button Command="Open" Content="Abrir" />
<Button Command="Save" Content="Guardar" />
</ToolBar>
<ToolBar>
<Button Command="Cut" Content="Cortar" />
<Button Command="Copy" Content="Copiar" />
<Button Command="Paste" Content="Pegar" />
</ToolBar>
</ToolBarTray>
<TextBox AcceptsReturn="True" />
</DockPanel>
210
105
1/9/2023
➢ MANEJO DE IMÁGENES
Mientras que el texto de los botones de la barra de herramientas está
perfectamente bien, el enfoque normal es tener iconos o al menos una
combinación de un icono y un trozo de texto. Dado que WPF utiliza controles de
botón regulares, agregar iconos a los elementos de la barra de herramientas es
muy fácil.
211
211
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="Cut" ToolTip="Corta y coloca una selección en el prtapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion
II\Iconos\cortar.png" />
</Button>
<Button Command="Copy" ToolTip="Copia una selección en el Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion
II\Iconos\copiar.png" />
</Button>
<Button Command="Paste" ToolTip="Pega contenido del Portapapeles">
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE
Programacion II\Iconos\pegar.png" />
<TextBlock Margin="3,7,0,0">Pegar</TextBlock>
</StackPanel>
</Button>
</ToolBar>
</ToolBarTray>
<TextBox AcceptsReturn="True" />
</DockPanel>
212
212
106
1/9/2023
➢ DESBORDE
Una buena razón para utilizar el control ToolBar en lugar de un panel de botones,
es el manejo automático del desborde. Esto significa que si no hay lugar
suficiente para mostrar todos los botones de la barra de herramientas, WPF lo
pondrá en un menú accesible presionando en la flecha a la derecha de la barra.
<ToolBar>
<Button Command="Cut" Content="Cortar" ToolBar.OverflowMode="Always" />
<Button Command="Copy" Content="Copiar" ToolBar.OverflowMode="AsNeeded" />
<Button Command="Paste" Content="Pegar" ToolBar.OverflowMode="Never" />
</ToolBar>
213
213
➢ POSICIÓN
Si bien es cierto que la posición más común de una barra de herramientas es a
lo alto de la pantalla, las barras de herramientas también pueden encontrarse
en el fondo de la ventana de la aplicación o incluso a los lados. Por supuesto, la
barra de herramientas de WPF permite todo esto, y mientras que situarla al
fondo simplemente requiere cambiar la propiedad Dock del DockingPanel, una
barra vertical requiere también el uso de la propiedad Orientation (Orientación)
de la ToolbarTray.
214
214
107
1/9/2023
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="Cut" ToolTip="Corta una selección y pega al Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\cortar.png" />
</Button>
<Button Command="Copy" ToolTip="Copia una selección en el Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\copiar.png" />
</Button>
<Button Command="Paste" ToolTip="Pega contenido del portapapeles">
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\pegar.png" />
<TextBlock Margin="3,7,0,0">Pegar</TextBlock>
</StackPanel>
</Button>
</ToolBar>
</ToolBarTray>
<ToolBarTray DockPanel.Dock="Right" Orientation="Vertical">
<ToolBar>
<Button Command="Cut" ToolTip="Corta una selección y pega al Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\cortar.png" />
</Button>
<Button Command="Copy" ToolTip="Copia una selección en el Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\copiar.png" />
</Button>
<Button Command="Paste" ToolTip="Pega contenido del portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\pegar.png" />
</Button>
</ToolBar>
</ToolBarTray>
<TextBox AcceptsReturn="True" /> 215
</DockPanel>
215
➢ CONTROLES PERSONALIZADOS
<DockPanel>
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<Button Command="Cut" ToolTip="Corta una selección y pega al Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\cortar.png" />
</Button>
<Button Command="Copy" ToolTip="Copia una selección en el Portapapeles">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\copiar.png" />
</Button>
<Button Command="Paste" ToolTip="Pega contenido del portapapeles">
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion II\Iconos\pegar.png" />
<TextBlock Margin="3,7,0,0">Pegar</TextBlock>
</StackPanel>
</Button>
<Separator />
<Label Margin="0,7,0,0">Tamaño:</Label>
<ComboBox>
<ComboBoxItem>10</ComboBoxItem>
<ComboBoxItem IsSelected="True">12</ComboBoxItem>
<ComboBoxItem>14</ComboBoxItem>
<ComboBoxItem>16</ComboBoxItem>
</ComboBox>
</ToolBar>
</ToolBarTray>
<TextBox AcceptsReturn="True" />
</DockPanel>
216
216
108
1/9/2023
1.7. CONTROLES
AVANZADOS
217
Control Border
El control Border es un control Decorador que puede ser usado para dibujar un
borde, un fondo o inclusive ambos, alrededor de otro elemento. Ya que los
paneles WPF no tienen la capacidad de dibujar un borde alrededor de sus
esquinas, el control Border puede ayudar a lograr exactamente eso, simplemente
rodeando el mismo.
<Grid Margin="10">
<Border Background="GhostWhite" BorderBrush="Gainsboro"
BorderThickness="1">
<StackPanel Margin="10">
<Button>Boton 1</Button>
<Button Margin="0,10">Boton 2</Button>
<Button>Boton 3</Button>
</StackPanel>
</Border>
</Grid> 218
218
109
1/9/2023
<Grid Margin="10">
<Border Background="GhostWhite" BorderBrush="Silver" BorderThickness="1"
CornerRadius="8,8,3,3">
<StackPanel Margin="10">
<Button>Boton 1</Button>
<Button Margin="0,10">Boton 2</Button>
<Button>Boton 3</Button>
</StackPanel>
</Border>
</Grid>
<Grid Margin="10">
<Border Background="GhostWhite" BorderBrush="DodgerBlue"
BorderThickness="1,3,1,5">
<StackPanel Margin="10">
<Button>Boton 1</Button>
<Button Margin="0,10">Boton 2</Button>
<Button>Boton 3</Button>
</StackPanel>
</Border>
</Grid> 219
219
<Grid Margin="10">
<Border BorderBrush="Navy" BorderThickness="1,3,1,5">
<Border.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="LightCyan" Offset="0.0" />
<GradientStop Color="LightBlue" Offset="0.5" />
<GradientStop Color="DarkTurquoise" Offset="1.0" />
</LinearGradientBrush>
</Border.Background>
<StackPanel Margin="10">
<Button>Boton 1</Button>
<Button Margin="0,10">Boton 2</Button>
<Button>Boton 3</Button>
</StackPanel>
</Border>
</Grid>
220
220
110
1/9/2023
Control Slider
221
222
222
111
1/9/2023
223
224
224
112
1/9/2023
Control ProgressBar
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Value="75" />
</Grid>
225
ContentRendered="Window_ContentRendered">
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Name="pbStatus" />
</Grid>
using System.Threading;
226
113
1/9/2023
using System.Threading;
using System.ComponentModel;
worker.RunWorkerAsync();
}
227
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Name="pbStatus" IsIndeterminate="True" />
</Grid>
<Grid Margin="20">
<ProgressBar Minimum="0" Maximum="100" Value="75" Name="pbStatus" />
<TextBlock Text="{Binding ElementName=pbStatus, Path=Value, StringFormat={}{0:0}%}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
228
228
114
1/9/2023
Control GroupBox
El control GroupBox permitirá agrupar de forma visual un grupo de controles.
Obviamente esto también podría realizarse usando uno de los tantos paneles que
existen, pero GroupBox agrega un tipo especial de encabezado y borde que
históricamente se ha usado mucho en el sistema operativo Windows.
El GroupBox solo puede contener un elemento hijo, un descendiente, pero esto
no es un problema.
<Grid>
<GroupBox Header="Datos Usuario" Margin="10" Padding="10">
<StackPanel>
<TextBlock>Nombres:</TextBlock>
<TextBox />
<TextBlock>Apellidos:</TextBlock>
<TextBox />
<Button Margin="0,20">Añadir usuario</Button>
</StackPanel>
</GroupBox>
</Grid>
229
<Grid>
<GroupBox Margin="10" Padding="10">
<GroupBox.Header>
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE
Programacion II\Iconos\user.png" Margin="3,0" />
<TextBlock FontWeight="Bold"
Margin="0,7,0,0">Usuarios</TextBlock>
</StackPanel>
</GroupBox.Header>
<StackPanel>
<TextBlock>Nombres:</TextBlock>
<TextBox />
<TextBlock>Apellidos:</TextBlock>
<TextBox />
<Button Margin="0,20">Añadir usuario</Button>
</StackPanel>
</GroupBox>
</Grid>
230
230
115
1/9/2023
Control Calendar
<Grid>
<Calendar />
</Grid>
231
<Viewbox>
<Calendar />
</Viewbox>
<Viewbox>
<Calendar DisplayDate="01.01.2009" />
</Viewbox>
<Viewbox>
<Calendar SelectionMode="MultipleRange" />
</Viewbox>
232
232
116
1/9/2023
<StackPanel Margin="10">
<Calendar Name="cldSample" SelectionMode="MultipleRange"
SelectedDate="10.22.2019" />
<Label>Fecha Seleccionada:</Label>
<TextBox Text="{Binding ElementName=cldSample, Path=SelectedDate,
StringFormat=d, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
public MainWindow()
{
InitializeComponent();
cldSample.SelectedDate = DateTime.Now.AddDays(1);
}
233
233
<StackPanel Margin="10">
<Calendar Name="cldSample" SelectionMode="MultipleRange" />
<Label>Fechas seleccionadas:</Label>
<ListBox ItemsSource="{Binding ElementName=cldSample,
Path=SelectedDates}" MinHeight="150" />
</StackPanel>
<Viewbox>
<Calendar Name="cldSample" SelectionMode="MultipleRange">
<Calendar.BlackoutDates>
<CalendarDateRange Start="10.13.2019" End="10.19.2019" />
<CalendarDateRange Start="10.27.2019" End="10.31.2019" />
</Calendar.BlackoutDates>
</Calendar>
</Viewbox>
234
234
117
1/9/2023
Control DatePicker
El control DatePicker se mostrará más o menos como un TextBox normal, pero
con un pequeño botón que mostrará una vista de calendario al hacer clic, lo que le
permitirá al usuario seleccionar la fecha.
<StackPanel Margin="20">
<Label>Nombre:</Label>
<TextBox />
<Label>Cumpleaños:</Label> <DatePicker SelectedDate="2019-10-23"
<DatePicker></DatePicker> SelectedDateFormat="Long"></DatePicker>
<Label>Genero:</Label>
<ComboBox>
<ComboBoxItem>Femenino</ComboBoxItem>
<ComboBoxItem>Masculino</ComboBoxItem>
</ComboBox>
<Button Margin="20">Registrar</Button>
</StackPanel>
235
Control TabControl
El control TabControl de WPF permite distribuir la interfaz en diferentes áreas,
cada una de ellas accesibles haciendo clic en la pestaña de la cabecera,
usualmente situada en la parte superior del control.
<Grid>
<TabControl>
<TabItem Header="General">
<Label Content="El contenido va aqui..." />
</TabItem>
<TabItem Header="Seguridad" />
<TabItem Header="Detalles" />
</TabControl>
</Grid>
236
118
1/9/2023
Control ItemsControl
WPF cuenta con una amplia gama de controles para mostrar una lista de datos.
Tales controles vienen en distintos aspectos y formas, y varían en su complejidad
y cuánto trabajo realizan. La variante más simple es ItemsControl, que es más o
menos un bucle basado en una plantilla.
xmlns:system="clr-namespace:System;assembly=mscorlib"
<Grid Margin="10">
<ItemsControl>
<system:String>ItemsControl Item #1</system:String>
<system:String>ItemsControl Item #2</system:String>
<system:String>ItemsControl Item #3</system:String>
<system:String>ItemsControl Item #4</system:String>
<system:String>ItemsControl Item #5</system:String>
</ItemsControl>
</Grid>
237
<Grid Margin="10">
<ItemsControl Name="icTodoList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100"
Value="{Binding Completion}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
238
238
119
1/9/2023
public MainWindow()
{
InitializeComponent();
icTodoList.ItemsSource = items;
}
public class TodoItem
{
public string Title { get; set; }
public int Completion { get; set; }
}
239
239
<Grid Margin="10">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" Margin="0,0,5,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<system:String>Item #1</system:String>
<system:String>Item #2</system:String>
<system:String>Item #3</system:String>
<system:String>Item #4</system:String>
<system:String>Item #5</system:String>
</ItemsControl>
</Grid>
240
240
120
1/9/2023
<Grid Margin="10">
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding}" Margin="0,0,5,5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<system:String>Item #1</system:String>
<system:String>Item #2</system:String>
<system:String>Item #3</system:String>
<system:String>Item #4</system:String>
<system:String>Item #5</system:String>
</ItemsControl>
</Grid>
241
241
Control ListBox
El control ListBox es el siguiente componente encargado de generar listas, el cual
agrega un poco más de funcionalidad. Una de las principales diferencias es el
hecho de que el control ListBox trabaja con selecciones, permitiendo al usuario
final seleccionar uno o varios elementos de la lista y automáticamente da
retroalimentación visual.
<Grid Margin="10">
<ListBox>
<ListBoxItem>ListBox Item #1</ListBoxItem>
<ListBoxItem>ListBox Item #2</ListBoxItem>
<ListBoxItem>ListBox Item #3</ListBoxItem>
</ListBox>
</Grid>
242
121
1/9/2023
243
244
244
122
1/9/2023
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right" Margin="10,0">
<StackPanel.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="0,0,0,5" />
</Style>
</StackPanel.Resources>
<TextBlock FontWeight="Bold" Margin="0,0,0,10">Selección del ListBox</TextBlock>
<Button Name="btnShowSelectedItem" Click="btnShowSelectedItem_Click">Ver Selección</Button>
<Button Name="btnSelectLast" Click="btnSelectLast_Click">Último</Button>
<Button Name="btnSelectNext" Click="btnSelectNext_Click">Siguiente</Button>
<Button Name="btnSelectCSharp" Click="btnSelectCSharp_Click">C#</Button>
<Button Name="btnSelectAll" Click="btnSelectAll_Click">Todo</Button>
</StackPanel>
<ListBox Name="lbTodoList" HorizontalContentAlignment="Stretch" SelectionMode="Extended"
SelectionChanged="lbTodoList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="0,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Completion}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel> 245
245
246
123
1/9/2023
Control ComboBox
El control ComboBox es parecido al control ListBox en muchos sentidos, pero usa
mucho menos espacio, ya que la lista de ítems se encuentra oculta cuando no se
necesita.
<StackPanel Margin="10">
<ComboBox>
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
<ComboBoxItem IsSelected="True">ComboBox Item #2</ComboBoxItem>
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
</ComboBox>
</StackPanel>
247
<StackPanel Margin="10">
<ComboBox>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Programacion
II\Iconos\circulo.png" />
<TextBlock Foreground="Red">Red</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Programacion
II\Iconos\circulo.png" />
<TextBlock Foreground="Green">Green</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Programacion
II\Iconos\circulo.png" />
<TextBlock Foreground="Blue">Blue</TextBlock>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</StackPanel>
248
248
124
1/9/2023
cmbColors.ItemsSource = typeof(Colors).GetProperties();
249
249
➢ ISEDITABLE
El ComboBox admite la posibilidad de permitir que el usuario seleccione de una
lista de elementos o ingrese su propio valor. Esto es extremadamente útil en
situaciones en las que se desea ayudar al usuario dándoles un conjunto
predefinido de opciones, mientras tiene la opción de ingresar manualmente el
valor deseado.
<StackPanel Margin="10">
<ComboBox IsEditable="True">
<ComboBoxItem>ComboBox Item #1</ComboBoxItem>
<ComboBoxItem>ComboBox Item #2</ComboBoxItem>
<ComboBoxItem>ComboBox Item #3</ComboBoxItem>
</ComboBox>
</StackPanel>
250
250
125
1/9/2023
251
}
252
252
126
1/9/2023
Control ListView
El control ListView (Lista de datos) es muy comúnmente usado en aplicaciones
de Windows para representar una lista de datos. Un excelente ejemplo de esto es
el archivo "list" (lista) en el Explorador de Windows, donde cada archivo puede
verse por su nombre y si es deseado, con columnas que contienen información
acerca del tamaño, última fecha de modificación y otras más.
El control ListView de WPF es muy minimalista en su forma más simple. De
hecho, se parecerá bastante al control ListBox, a menos que se le empiecen a
añadir vistas especializadas.
253
<Grid>
<ListView Margin="10">
<ListViewItem>Un ListView</ListViewItem>
<ListViewItem IsSelected="True">con muchos</ListViewItem>
<ListViewItem>items</ListViewItem>
</ListView>
</Grid>
254
254
127
1/9/2023
<Grid>
<ListView Margin="10">
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion
II\Iconos\circulo.png" Margin="0,0,5,0" />
<TextBlock>Green</TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem>
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion
II\Iconos\circulo.png" Margin="0,0,5,0" />
<TextBlock>Blue</TextBlock>
</StackPanel>
</ListViewItem>
<ListViewItem IsSelected="True">
<StackPanel Orientation="Horizontal">
<Image Source="D:\UNIVALLE catedras II-2020\Equipo2\UNIVALLE Programacion
II\Iconos\circulo.png" Margin="0,0,5,0" />
<TextBlock>Red</TextBlock>
</StackPanel>
</ListViewItem>
</ListView>
</Grid>
255
255
public MainWindow()
{
InitializeComponent();
256
128
1/9/2023
257
257
258
129
1/9/2023
public MainWindow()
{
InitializeComponent();
259
260
260
130
1/9/2023
public MainWindow()
{
InitializeComponent();
261
262
131
1/9/2023
263
263
<Grid Margin="10">
<ListView Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn Header="Nombre" Width="120"
DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Edad" Width="50"
DisplayMemberBinding="{Binding Age}" />
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock FontWeight="Bold" FontSize="14"
Text="{Binding Name}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid> 264
264
132
1/9/2023
public MainWindow()
{
InitializeComponent();
CollectionView view =
(CollectionView)CollectionViewSource.GetDefaultView(lvUsers.ItemsSource);
PropertyGroupDescription groupDescription = new PropertyGroupDescription("Sex");
view.GroupDescriptions.Add(groupDescription);
}
265
Control ThreeView
La función del control TreeView (vista de árbol), permite mostrar en pantalla datos
de jerarquías, en donde cada pieza de datos es representada por un nodo en el
árbol. Cada nodo puede tener hijos y cada hijo puede tener otro hijo y así
sucesivamente.
266
133
1/9/2023
<Grid Margin="10">
<TreeView>
<TreeViewItem Header="Nivel 1" IsExpanded="True">
<TreeViewItem Header="Nivel 2.1" />
<TreeViewItem Header="Nivel 2.2" IsExpanded="True">
<TreeViewItem Header="Nivel 3.1" />
<TreeViewItem Header="Nivel 3.2" />
</TreeViewItem>
<TreeViewItem Header="Nivel 2.3" />
</TreeViewItem>
</TreeView>
</Grid>
267
267
268
134
1/9/2023
Control DataGrid
El control DataGrid es parecido al ListView cuando se usa un GridView (es decir,
una tabla), pero ofrece una funcionalidad adicional. Por Ejemplo, el DataGrid
puede generar columnas automáticamente, dependiendo de los datos que se le
proporciona. El DataGrid también se puede editar de forma predeterminada, lo
que permite al usuario final cambiar los valores sobre el origen de los datos.
<Grid Margin="10">
<DataGrid Name="dgSimple"></DataGrid>
</Grid>
269
dgSimple.ItemsSource = users;
}
public class User
{
public int Id { get; set; }
270
270
135
1/9/2023
</DataGrid.Columns>
</DataGrid>
</Grid>
271
271
dgUsers.ItemsSource = users;
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
}
} 272
272
136
1/9/2023
273
273
dgUsers.ItemsSource = users;
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
public string Details
{
get
{
return String.Format("{0} nació el {1} y esta es una larga descripción de la
persona.", this.Name, this.Birthday.ToLongDateString());
}
}
}
} 274
274
137
1/9/2023
1.8. TEMPORIZADORES
275
La Clase DispatcherTimer
En Windows Forms existe un control llamado Timer que puede ejecutar una acción
repetidas veces dentro de un intervalo de tiempo. WPF tiene esta posibilidad
también, pero en vez de un control invisible, se tiene el control DispatcherTimer.
Este control hace casi lo mismo, pero en lugar de colocar solamente el elemento
en el formulario, debe ser creado y usado exclusivamente desde el código del
mismo.
La clase DispatcherTimer trabaja especificando un intervalo y suscribiéndolo al
evento Tick que ocurrirá cada vez que se cumpla el intervalo. El DispatcherTimer
no comienza hasta que se llama al método Start() o se establece la propiedad
IsEnabled a verdadero.
276
276
138
1/9/2023
<Grid>
<Label Name="lblTime" FontSize="48" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
277
<Grid>
<TextBlock Name="tbTime" />
</Grid>
public partial class MainWindow : Window
{
DispatcherTimer _timer;
TimeSpan _time;
public MainWindow()
{
InitializeComponent();
_time = TimeSpan.FromSeconds(10);
_timer = new DispatcherTimer(new TimeSpan(0, 0, 1),
DispatcherPriority.Normal, delegate
{
tbTime.Text = _time.ToString("c");
if (_time == TimeSpan.Zero) _timer.Stop();
_time = _time.Add(TimeSpan.FromSeconds(-1));
}, Application.Current.Dispatcher);
_timer.Start();
}
} 278
278
139
1/9/2023
1.9. CONTROLES DE
DIÁLOGO
279
MESSAGE BOX
WPF ofrece varios diálogos para que su uso en aplicaciones, pero MessageBox es
definitivamente el más sencillo. Su único propósito es mostrar un mensaje al
usuario y luego darle múltiples formas de responder al mismo.
MessageBox se utiliza llamando al método estático Show(), que puede recibir una
gama de diferentes parámetros para ser capaz de verse y comportarse de la forma
que se requiera.
public MainWindow()
{
InitializeComponent();
MessageBox.Show("Bienvenido a WPF!");
280
280
140
1/9/2023
✓ TÍTULO
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MessageBox.Show("Bienvenido a WPF", "Sistema v1.1");
}
}
281
281
✓ BOTONES ADICIONALES
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MessageBox.Show("Deseas ingresar a la aplicación.\n\nBienvenido a
WPF?", "Sistema v1.1", MessageBoxButton.YesNoCancel);
}
}
OK
OKCancel
YesNoCancel
YesNo
282
282
141
1/9/2023
283
✓ ICONOS
public MainWindow()
{
InitializeComponent();
MessageBox.Show("Deseas ingresar a la aplicación.\n\nBienvenido a
WPF?", "Sistema v1.1", MessageBoxButton.OK, MessageBoxImage.Information);
}
Asterisk (Asterisco)
Error
Exclamation (Exclamación)
Hand (Mano)
Information (información)
None (Ninguno)
Question (Pregunta)
Stop (Alto)
Warning (Advertencia)
284
284
142
1/9/2023
public MainWindow()
{
InitializeComponent();
MessageBox.Show("Deseas ingresar a la aplicación.\n\nBienvenido a
WPF?", "Sistema v1.1", MessageBoxButton.YesNo, MessageBoxImage.Question,
MessageBoxResult.No);
}
285
285
Ejercicio
Realice un programa en WPF, que muestre los botones para ejecutar los
diferentes diálogos establecidos anteriormente.
286
286
143
1/9/2023
OpenFileDialog
Cada vez que se abre o guarda un archivo en casi cualquier aplicación de Windows,
se puede observar aproximadamente los mismos cuadros de diálogo para hacerlo.
La razón es, por supuesto, que estos cuadros de diálogos forman parte de la API de
Windows y, por lo tanto, también son accesibles para los desarrolladores en la
plataforma de Windows.
En WPF, se encontrarán cuadros de diálogo estándares para abrir y guardar
archivos en el espacio de nombres Microsoft.Win32. Uno de ellos es la
clase OpenFileDialog, que hace que sea muy fácil mostrar un cuadro de diálogo
para abrir uno o varios archivos.
287
<DockPanel Margin="10">
<WrapPanel HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="0,0,0,10">
<Button Name="btnOpenFile" Click="btnOpenFile_Click">Open file</Button>
</WrapPanel>
<TextBox Name="txtEditor" />
</DockPanel>
La función ShowDialog() devolverá un valor
using Microsoft.Win32; booleano que se puede ser nulo, lo que
using System.IO; significa que puede ser falso, verdadero o
nulo. Si el usuario selecciona un archivo y
public partial class MainWindow : Window presiona "Abrir", el resultado es True y, en ese
{ caso, intentamos cargar el archivo en el
public MainWindow()
control TextBox. Obtenemos la ruta completa
{ del archivo seleccionado utilizando la
InitializeComponent(); propiedad FileName de OpenFileDialog.
}
288
144
1/9/2023
✓ FILTRAR
Normalmente, cuando se desea que el usuario abra un archivo en su aplicación,
desea limitarlo a uno o dos tipos de archivos. Por ejemplo, Word casi siempre
abre archivos de Word (con la extensión .doc o .docx) y el Bloc de notas casi
siempre abre archivos de texto (con la extensión .txt), por ejemplo:
openFileDialog.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
openFileDialog.Filter = "Image files (*.png;*.jpeg)|*.png;*.jpeg|All files (*.*)|*.*";
}
289
289
✓ DIRECTORIO INICIAL
El directorio inicial utilizado por el diálogo OpenFileDialog es decidido por
Windows, pero utilizando la propiedad InitialDirectory es posible sobreescribirla.
openFileDialog.InitialDirectory = @"c:\temp\";
Si se desea utilizar una de las carpetas especiales de Windows, p.e. Escritorio, Mis
Documentos o Archivos de Programa, se debe tener un especial cuidado, pues
estas pueden cambiar entre versiones de Windows y también pueden depender
del usuario que esté conectado. El framework .NET puede ayudar, simplemente
utilizando la clase Environment y sus miembros para tratar con carpetas
especiales:
openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
290
290
145
1/9/2023
✓ MÚLTIPLES ARCHIVOS
Si una aplicación requiere varios archivos abiertos, o simplemente se desea
utilizar OpenFileDialog para seleccionar mas de un archivo, es necesario activar
la propiedad Multiselect.
<DockPanel Margin="10">
<WrapPanel HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="0,0,0,10">
<Button Name="btnOpenFile" Click="btnOpenFiles_Click">Open files</Button>
</WrapPanel>
<ListBox Name="lbFiles" />
</DockPanel>
291
291
292
292
146
1/9/2023
SaveFileDialog
El SaveFileDialog permitirá seleccionar una ubicación y asignar nombre cuando se
desee guardar un archivo. Funciona y luce como el OpenFileDialog.
<DockPanel Margin="10">
<WrapPanel HorizontalAlignment="Center" DockPanel.Dock="Top" Margin="0,0,0,10">
<Button Name="btnSaveFile" Click="btnSaveFile_Click">Save file</Button>
</WrapPanel>
<TextBox Name="txtEditor" TextWrapping="Wrap" AcceptsReturn="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</DockPanel>
293
✓ FILTRAR
saveFileDialog.Filter = "Text file (*.txt)|*.txt|C# file (*.cs)|*.cs";
294
294
147
1/9/2023
✓ DIRECTORIO INICIAL
La dirección inicial usada por el SaveFileDialog es decidida por Windows, pero
usando la propiedad InitialDirectory, es posible sobrescribirla. Usualmente se
asignará este valor apuntando a una dirección específica del usuario, a la
carpeta de la aplicación o quizá la última dirección usada.
saveFileDialog.InitialDirectory = @"c:\temp\";
saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
295
295
✓ OTRAS OPCIONES
AddExtension- El valor por defecto es verdadero y determina si el SaveFileDialog debería
automáticamente agregar una extensión al nombre del archivo, si el usuario la omite.- La
extensión se basará en la opción seleccionada en el filtro, a menos que ese no sea el caso,
se le asignará la propiedad DefaultExt (si está especificado). Si se desea que la aplicación
sea capaz de guardar archivos sin extensión, se debe deshabilitar esta opción.
ValidateNames - Por defecto es true y salvo que este deshabilitado, garantiza que el
usuario solo introduzca nombres validos de archivos de Windows antes de permitirle
continuar.
296
296
148
1/9/2023
✓ OTROS DIÁLOGOS
Windows Forms viene con una serie adicionales de diálogos pero que no existen
en WPF. El más importante de ellos es definitivamente el FolderBrowserDialog,
el cual permite al usuario seleccionar una carpeta del sistema de archivos, pero
otros diálogos faltantes en WPF incluyen el ColorDialog, el FontDialog, el
PrintPreviewDialogy el PageSetupDialog.
Esto puede ser un verdadero problema para los desarrolladores de WPF, ya que
la reimplementación de estos diálogos sería una tarea enorme.
Afortunadamente, WPF y WinForms pueden ser mezclados, simplemente
haciendo referencia al ensamblado System.Windows.Forms, pero siendo que
WPF utiliza tipos básicos para ambos, colores y diálogos, esto no siempre es una
solución viable. Esto es sin embargo una fácil solución si sólo necesitas el
FolderBrowserDialog, dado que éste solamente trata con rutas de carpeta como
simples strings, aunque algunos profesionales argumentarían que mezclar WPF
y WinForms jamás es la manera de proceder.
297
297
Una mejor forma de proceder, es usar algo del trabajo creado por otros
desarrolladores. Aquí hay un par de links de un artículo que ofrece una solución a
algunos de los diálogos faltantes:
https://www.codeproject.com/Articles/368070/A-WPF-Font-Picker-with-Color
https://www.codeproject.com/Articles/33001/WPF-A-Simple-Color-Picker-With-Preview
298
298
149
1/9/2023
CONSULTAS Y
OBSERVACIONES
299
299
150