XAML para Silverlight

Sintaxis

Elementos, subelementos y atributos.

los elementos declaran la instancia de un objeto:

<Rectangle Width="100" Height="100" Fill="Red" x:Name="rectangulo1">
</Rectangle>

Cuando necesitamos que un elemento esté dentro de otro elemento padre, deberemos declarar una apertura de objeto y otra de cierre. El ejemplo más claro es el propio Grid (LayoutRoot) que se genera automáticamente al crear una aplicación Silverlight.

<UserControl x:Class="EjXAML.MainPage"
 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"
 mc:Ignorable="d"
 d:DesignHeight="300" d:DesignWidth="400">
 <Grid x:Name="LayoutRoot" Background="White">
    <Ellipse Fill="Yellow">
    <Rectangle Width="100" Height="100" Fill="Red" x:Name="rectangulo1"></Rectangle>
    <Rectangle Width="50" Height="50" Fill="Black" x:Name="rectangulo2" />
 </Grid>
</UserControl>


Atributos.

Los atributos en XAML son opcionalels. Se expresan a través de una cadena. Width, Height, Fill, x:Name son ejemplos de atributos o propiedades públicas que modifican las características de un objeto. Los atributos también pueden ser declarados como subelementos.

<Rectangle Fill="Red" x:Name="rectangulo1">
  <Rectangle.Width>100</Rectangle.Width>
  <Rectangle.Height>100</Rectangle.Height>
</Rectangle>

Esta sintaxis de elementos es necesaria cuando el valor de un atributo es un objeto complejo que no puede ser expresado con una simple cadena.

<Rectangle Width="100" Height="100" Fill="Red" x:Name="rectangulo1">
  <Rectangle.Fill>
    <ImageBrush ImageSource="http://philippinerevolution.net/images/organizations/logo/1/default/logo.cpp.png" />
  </Rectangle.Fill>
</Rectangle>

Objetos de .NET

Mediante XAML es posible declarar una instancia de cualquier tipo de .NET. El único requisito es tener en nuestro ámbito el espacio de nombres XML donde está el tipo que queremos instanciar. Por ejemplo si sabemos que en el espacio de nombres System del ensamblado mscorlib.dll se encuentran la clase Double, podríamos hacer lo siguiente:

<UserControl x:Class="EjXAML.MainPage"
 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:core="clr-namespace:System;assembly=mscorlib"
 mc:Ignorable="d"
 d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
  <Ellipse Fill="Yellow"/>
   <Rectangle Width="100" Height="100" Fill="Red" x:Name="rectangulo1"></Rectangle>
   <Rectangle x:Name="rectangulo2">
     <Rectangle.Width>
        <core:Double>100</core:Double>
     </Rectangle.Width>
     <Rectangle.Height>
        <core:Double>100</core:Double>
     </Rectangle.Height>
     <Rectangle.Fill>
        <ImageBrush ImageSource="http://philippinerevolution.net/images/organizations/logo/1/default/logo.cpp.png">           
        </ImageBrush>
     </Rectangle.Fill>
  </Rectangle>
 </Grid>
</UserControl>

En este ejemplo utilizamos el alias “core” para el namespace, por lo que el nombre completo de Double será “core:Double”.

Propiedades adjuntas.

Es un mecanismo para permitir a un elemento hijo reportar al padre inmediato el valor deseado de alguna de sus propiedades.

<Canvas>
  <Ellipse Width="50" Height="50" Fill="Blue"
    Canvas.Top="10"
    Canvas.Left="10" />
</Canvas>
<Grid>
  <Rectangle Grid.Row ="1" Grid.Column="2"
   Fill="Red"
   Width="50" Height="50" />
</Grid>

El siguiente ejemplo estaría mal pero no genera ninguna excepción, simplemente omitirá aquellas propiedades adjuntas que están “fuera de lugar”.

<Canvas>
  <Ellipse Width="50" Height="50" Fill="Blue"
    Grid.Row="1"
    Grid.Column="2" />
</Canvas>

Espacios de nombres

Para traer a nuestro ámbito un espacio de nombres lo hacemos por medio del atributo xmlns (XML Namespace), esta declaración se suele hacer en la raíz del documento XAML (generalemente el UserControl) o al nivel del contenedor. La elección es una cuestión de visibilidad, si la declaración xmlns está en el contenedor sólo los elementos hijos de ese contenedor tendrán acceso, por lo que es una práctica muy común colocarlos a nivel del UserControl.

  • xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”: éste es el espacio de nombres donde se encuentran los elementos básicos: Rectangle, ellipse, TextBlock, Grid, StackPanel, etc. Además éste espacio de nombres es el mismo que se utiliza para las aplicaciones WPF y aplicaciones Metro en  Windows 8.
  • xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”: éste espacio contiene los atributos globales para todos los elementos XAML, por ejemplo: Name. Este espacio de nombres por defecto está incluido Mainpage.xaml y tienen el alias “x:“.
  • xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″. Incluye atributos para tiempo de diseño como pueden ser DesignWidth y DesignHeight, los cuales indican que tamaño queremos para el UserControl únicamente en tiempo de diseño.
  • xmlns:sdk=”http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk”. Este espacio de nombres es compartido por todos los ensamblados (dll’s) incluidos en el SDK de Silverlight. DataGrid y PivotViewer están en el mismo espacio de nombres pero requieren ensamblados (.dll’s) diferentes.
  • xmlns:toolkit=”http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit”. Serían otros ejemplos de espacios de nombres que podemos incluir en nuestros proyectos Silverlight.



Mapeo de los espacios de nombres.

¿Por qué algunos elementos los puedo declarar de manera directa, tales como <Rectangle>, <TextBox>, <Button>, etc. y otros requieren un espacio de nombres?

La respuesta está en el atributo XmlnsDefinition de los ensamblados, el cual especifica un mapeo entre un espacio de nombres XML y un espacio de nombres del CLR.

Por ejemplo http://schemas.microsoft.com/winfx/2006/xaml/presentation se mapea a diversos espacios de nombres CLR del ensamblado System.Windows.dll, como por ejemplo System.Windows.Shapes, System.Windows.Controls, System.Windows.Data, etc.

Ensamblado System.Windows
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v5.0\System.Windows.dll

Elemento “UserControl”.

Tiene como objetivo el poder declarar todos los espacios de nombres XML necesarios para la interfaz de usuario.

namespace EjemploSilverLight{
  public partial class MainPage : UserControl {
    public MainPage() {
        InitializeComponent();
    }
  }
}

El UserControl soporta sólo un elemento hijo (propiedad Content), por lo que generalmente iniciaríamos con un contenedor raíz (Grid por ejemplo).

Contenedores.

Heredan de la clase base Panel, y permiten dibujar elementos visuales dentro de ellos. Todo lo que se dibuje dentro del contenedor será parte de la colección Children del contenedor en cuestión. esto es importante si programáticamente necesitamos iterar sobre todos los elementos de un contenedor para hacer algo con ellos, por ejemplo repintar, o reordenar.

  • Canvas
  • Grid
  • StackPanel

Canvas.

Lienzo de posicionamiento absoluto basado en coordenadas, y con las propiedades Left, Top, Zindex podemos ubicar un elemento dentro de él. Su naturaleza lo hace bastante inflexible.

<Canvas>
  <Ellipse Width="100" Height="100" Fill="Blue"
    Canvas.Top="100" Canvas.Left="50" 
    Canvas.ZIndex="1" /> 
  <Ellipse Width="100" Height="100" Fill="Red"
    Canvas.Top="110" Canvas.Left="60" 
    Canvas.ZIndex="0" />
</Canvas>

El problema de Canvas.

¿Qué pasa cuando ejecutamos en un navegador y cambiamos el tamaño de éste? LA posición de las Elipses NO cambia ni al maximizar ni al cambiar el tamaño. Las aplicaciones de negocio normalmente necesitaremos que se adapten las interfaces a los diferentes tamaños de los dispositivos.

StacklPanel

Es un panel cuyo objetivo es apilar elementos visuales ya sea de manera vertical u horizontal (propiedad Orientation).

<StackPanel>
   <Ellipse Width="100" Height="100" Fill="Blue" />
   <Ellipse Width="100" Height="100" Fill="Red" />
</StackPanel>
<StackPanel Orientation="Horizontal">
   <Ellipse Width="100" Height="100" Fill="Blue" />
   <Ellipse Width="100" Height="100" Fill="Red" />
</StackPanel>

Grid

El contenedor más flexible es el Grid, de hecho es el contenedor por defecto en MainPage.xaml. Es similar a la etiqueta <table> del HTML.

  • Column: La primera columna es 0.
  • Row: La primera fila es 0.
  • ColumnSpan: Indica cuantas columnas abarcará el elemento dentro del Grid
  • RowSpan: Indica cuántas filas abarcará el elemento dentro del Grid
<Grid x:Name="LayoutRoot" Background="White"> 
  <Grid.ColumnDefinitions>
    <ColumnDefinition></ColumnDefinition>
    <ColumnDefinition></ColumnDefinition>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition></RowDefinition>
    <RowDefinition></RowDefinition>
  </Grid.RowDefinitions>
  <Button Grid.Row="1" Grid.Column="0" Width="100" Height="30" Content="Botón"></Button>
  <TextBlock Text="aaaa" Grid.Column="1" ></TextBlock>
</Grid>

Tamaños de columnas y filas

  • Fijo: Unidad en pixels.
  • Automático: “Auto”. Ajusta el tamaño al contenido del mismo.
  • Proporcional (predeterminado): Es el más flexible de todos, indica un factor de proporción que por defecto es 1* o bien *. Si quisieramos hacer algo el doble de grande que la zona anterior tendríamos que poner 2*.
<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100"></ColumnDefinition>
    <ColumnDefinition Width="Auto"></ColumnDefinition>
    <ColumnDefinition></ColumnDefinition>
  <ColumnDefinition></ColumnDefinition>
  </Grid.ColumnDefinitions>

  <Ellipse Width="150" Height="150" Fill="Red" />
  <Ellipse Width="60" Height="150" Fill="Blue" Grid.Column="1" />
  <Ellipse Width="100" Height="100" Fill="LightGray" Grid.Column="2" />
  <Ellipse Width="100" Height="100" Fill="Orange" Grid.Column="3" />
</Grid>

Controles

Todos los controles de manera directa o indirecta heredan de la clase abstracta Control. Es en esta clase base donde se definen las propiedades de apariencia, la funcionalidad necesaria para poder navegar a través de los controles usando el tabulador, así como la funcionalidad necesaria para detectar o establecer el enfoque sobre ellos.

  • Controles de usuario. Son aquellos del tipo UserControl o clases derivadas, que nos permiten definir código XAML y comportamiento relacionado.
  • Controles de contenido. Aquellos del tipo ContentControl o derivadas. Permiten establecer un elemento o jerarquía de elementos de XAML arbitrarios como su contenido. Es en esta clase donde podemos encontrar la propiedad Content, cuyo objetivo es permitirnos establecer cualquier elemento visual como su valor. Un ejemplo es la clase ButtonBase, que sirve de clase base para toda la familia de botones (Button, RadioButton, CheckBox, HyperlinkButton, etc.)

Ejemplo con la clase Button:

<Button Width="200" Height="80" Content="Prueba" />
<Button Width="200" Height="80">
  <Button.Content>
    <Ellipse Width="40" Height="40" Fill="Black"></Ellipse>
  </Button.Content>
</Button>

Incluso ya que la propiedad Content está identificada como la propiedad de contenido en la clase ContentControl (a través del atributo ContentProperty), la siguiente declaración también sería válida:

<Button Width="200" Height="80">
    <Ellipse Width="40" Height="40" Fill="Black"></Ellipse>
</Button>

La flexibilidad de los controles de contenido es notable, ya que podemos establecer cualquier elemento visual o incluso una jerarquía de elementos, si estuviésemos utilizando un contenedor con elementos hijos tal y como se demuestra con el siguiente código:

<Button Width="200" Height="80">
 <Button.Content>
  <StackPanel Orientation="Horizontal">
    <Image Source="http://2-ps.googleusercontent.com/x/www.oldapps.com/cache.oahermes.com/softimg/xsilverlight-logo.png.pagespeed.ic.MYfr_pDehB.png"></Image>
    <StackPanel>
      <TextBlock Text="Silverlight" />
      <TextBlock Text="permite una" />
      <TextBlock Text="flexibilidad" />
      <TextBlock Text="enorme" /> 
    </StackPanel>
  </StackPanel>
 </Button.Content>
</Button>

Otro ejemplo con elementos RadioButton dentro de un StackPanel:

 <StackPanel Width="200" Height="200">
   <RadioButton>
     <StackPanel Orientation="Horizontal">
       <Image Width="50" Source="http://iconos.gratis.es/iconos/banderas/128/Espana.png" />
       <TextBlock Text="España"></TextBlock>
     </StackPanel>
   </RadioButton>
   <RadioButton>
     <StackPanel Orientation="Horizontal">
       <Image Width="50" Source="http://iconos.gratis.es/iconos/banderas/128/Estados-Unidos.png" />
       <TextBlock Text="Estados Unidos"></TextBlock>
     </StackPanel>
   </RadioButton>
   <RadioButton>
     <StackPanel Orientation="Horizontal">
       <Image Width="50" Source="http://iconos.gratis.es/iconos/banderas/128/Portugal.png" />
       <TextBlock Text="Portugal"></TextBlock>
     </StackPanel>
   </RadioButton>
 </StackPanel>

    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel Width="200" Height="200">
            <CheckBox IsChecked="True">
                <CheckBox.Content>
                    <StackPanel Orientation="Horizontal">
                        <Image Width="50" Source="http://iconos.gratis.es/iconos/banderas/128/Espana.png" />
                        <TextBlock Text="España"></TextBlock>
                    </StackPanel>
                </CheckBox.Content>
            </CheckBox>
            <CheckBox IsChecked="False">
                <CheckBox.Content>
                    <StackPanel Orientation="Horizontal">
                        <Image Width="50" Source="http://iconos.gratis.es/iconos/banderas/128/Estados-Unidos.png" />
                        <TextBlock Text="España"></TextBlock>
                    </StackPanel>
                </CheckBox.Content>
            </CheckBox>
            <CheckBox IsChecked="True">
                <CheckBox.Content>
                    <StackPanel Orientation="Horizontal">
                        <Image Width="50" Source="http://iconos.gratis.es/iconos/banderas/128/Portugal.png" />
                        <TextBlock Text="España"></TextBlock>
                    </StackPanel>
                </CheckBox.Content>
            </CheckBox>            
        </StackPanel>
    </Grid>

Controles de lista

Son controles que despliegan una lista de datos que normalmente serán enlazados a una colección de datos, o incluso algunos pueden agregar o borrar elementos de manera manual.

ItemsControl
Algunos controles de lista heredan directa o indirectamente de la clase base ItemsControl, como por ejemplo el ListBox o el ComboBox. No obstante también es posible utilizar la clase ItemsControl de forma explícita.

    <ItemsControl>
        <TextBlock Text="Juan"></TextBlock>
        <TextBlock Text="Carla"></TextBlock>
        <TextBlock Text="Juanjo"></TextBlock>
        <TextBlock Text="Laura"></TextBlock>
    </ItemsControl>

La clase ItemsControl incluye la propiedad Items,  propiedad que representa el contenido del ItemsControl, es donde guardamos los elementos que representan el contenido. Items es de tipo ItemCollection el cual es una colección genérica de tipo object.

for (int i = 1; i <= 20; i++) {
  lista.Items.Add(i);
}

El código anterior agregará una lista de 20 números enteros de manera dinámica en un ItemsControl llamado “lista“.

En Items podemos agregar cualquier tipo de objeto incluso no relacionados entre sí.

    <ItemsControl x:Name="lista">
        <TextBlock Width="100" Text="Juan"></TextBlock>
        <Button Width="90" Height="30" Content="Botón prueba"></Button>
        <Rectangle Fill="Orange" Width="80" Height="20" />
        <StackPanel Orientation="Horizontal" Width="140">
            <RadioButton>R1</RadioButton>
            <RadioButton>R2</RadioButton>
            <RadioButton>R3</RadioButton>
            <RadioButton>R4</RadioButton>
        </StackPanel>
    </ItemsControl>

Podemos incluso agregar objetos que están basados en nuestras propias clases.

namespace Controles
{
    public class Disco
    {
        public string Titulo {get; set;}
        public string Banda {get; set;}
    }
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            lista.Items.Add(new Disco(){ Banda="Sex Pistols", Titulo="God save the Queen"});
            lista.Items.Add(new Disco() { Banda = "Fisher-Z", Titulo = "Marlise" });
            lista.Items.Add(new Disco() { Banda = "Los Manolos", Titulo = "Lailo Lailo La" });
        }
    }
}

El control ItemsControl no tiene la menor idea de como presentar adecuadamente un objeto tipo Disco. dado este caso lo único que hace por defecto es invocar al método ToString. Para solucionar esto tendríamos varias posibilidades.

  1. Reemplazar el método ToString a traves del método override y devolver alguna de las propiedades, o bien  …
  2. Utilizar la propiedad DisplayMemberPath. esta segunda es la solución más limpia y aconsejable.

Propiedad DisplayMemberPath.

Establece la ruta para llegar a la propiedad que deseamos mostrar en cada momento, en vez de mostrar el resultado de la ejecución del método ToString.

<ItemsControl x:Name="lista" DisplayMemberPath="Titulo">

Al ser una ruta también sería válido:

<itemsControl x:Name="lista" DisplayMemberPath="Titulo.Length" />

Propiedad ItemsPanel

El control ItemsControl usa internamente un panel de tipo StackPanel vertical, éste panel puede ser redefinido a través de la propiedad ItemsPanel, que es de tipo ItemsPanelTemplate, veamos el concepto con un ejemplo:

 <Grid x:Name="LayoutRoot" Background="White">
   <ItemsControl x:Name="lista" DisplayMemberPath="Titulo">
     <ItemsControl.ItemsPanel>
       <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal"></StackPanel>
       </ItemsPanelTemplate>
     </ItemsControl.ItemsPanel>
     <TextBlock Width="100" Text="Juan"></TextBlock>
     <Button Width="90" Height="30" Content="Botón prueba"></Button>
     <Rectangle Fill="Orange" Width="80" Height="20" />
     <StackPanel Orientation="Horizontal" Width="140">
        <RadioButton>R1</RadioButton>
        <RadioButton>R2</RadioButton>
        <RadioButton>R3</RadioButton>
        <RadioButton>R4</RadioButton>
     </StackPanel>
   </ItemsControl>
 </Grid>

ItemsPanelTemplate soporta cualquier contenedor incluso Canvas o Grid; pero no tiene sentido utilizarlos porque todos los elementos se verían unos encima de otros.

Hay un contenedor especial dentro del Silverlight Toolkit llamado WrapPanel, NO es una clase base de Silverlight sino del Tooolkit. La idea es colocar los elementos hasta que desborde el ancho del contenedor con lo que automáticamente saltará a la línea siguiente.

Acuérdate de añadir el espacio de nombres: xmlns:toolkit=”http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit” x:Class=”Controles.MainPage”
y referenciar al ensamblado: System.Windows.Controls.Toolkit.dll

 <Grid x:Name="LayoutRoot" Background="White">
   <ItemsControl x:Name="lista" DisplayMemberPath="Titulo">
     <ItemsControl.ItemsPanel>
       <ItemsPanelTemplate>
         <toolkit:WrapPanel />
       </ItemsPanelTemplate>
     </ItemsControl.ItemsPanel>
     <TextBlock Width="100" Text="Juan"/>
     <Button Width="90" Height="30" Content="Botón prueba"/>
     <Rectangle Fill="Orange" Width="80" Height="20" />
     <StackPanel Orientation="Horizontal" Width="140">
       <RadioButton Content="R1"/>
       <RadioButton Content="R2"/>
       <RadioButton Content="R3"/>
       <RadioButton Content="R4"/>
     </StackPanel>
   </ItemsControl>
 </Grid>

Al redimensionar la pantalla:

Propiedad ItemTemplate.

Hay una manera aún mejor para poder indicar a un control de tipo ItemsControl cómo queremos que cada elemento se muestre. Esto es a través de la propiedad ItemTemplate, que es de tipo DataTemplate (se verá en profundidad más adelante).

ListBox

Acabamos de ver que la clase ItemsControl es la clase base para todos los controles de la lista; no obstante, ItemsControl no es interactivo, es decir, no podemos seleccionar un elemento de la lista. Para ello existen varias opciones de controles, pero uno de los más utilizados es el ListBox.

El control ListBox hereda indirectamente de la clase ItemsControl por lo que todo lo anterior también es válido para este control. La particularidad es que ahora podemos seleccionar (uno o varios) los elementos de la lista.

Ejemplo:

<Grid x:Name="LayoutRoot" Background="White">
  <ListBox x:Name="lista" DisplayMemberPath="Titulo" SelectionMode="Extended"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <toolkit:WrapPanel />
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel> 
  </ListBox>
</Grid>

Propiedad SelectionMode

  • Single: el usuario solo puede seleccionar un sólo elemento
  • Extended: el usuario podrá seleccionar varios elementos, haciendo uso de alguna tecla modificadora, por ejemplo: Ctrl.
  • Multiple: El usuario podrá seleccionar varios elementos sin necesidad de hacer uso de alguna tecla moficadora.

Propiedad SelectedItem y SelectedItems

Estas propiedades nos devolverán el elemento o elementos seleccionados.

Ejemplo

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Text;

namespace Controles
{

    public class Disco
    {
        public string Titulo {get; set;}
        public string Banda {get; set;}
    }
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            lista.Items.Add(new Disco(){ Banda="Sex Pistols", Titulo="God save the Queen"});
            lista.Items.Add(new Disco() { Banda = "Fisher-Z", Titulo = "Marlise" });
            lista.Items.Add(new Disco() { Banda = "Los Manolos", Titulo = "Lailo Lailo La" });
        }

        private void BtnSeleccionados_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Has seleccionado: ");
            foreach (var item in lista.SelectedItems)
            {
                sb.Append((item as Disco).Titulo);
            }
            MessageBox.Show(sb.ToString());
        }
    }
}

El código XAML de nuestra aplicación sería:

<Grid x:Name="LayoutRoot" Background="White">
<ListBox x:Name="lista" DisplayMemberPath="Titulo" SelectionMode="Extended"
 ScrollViewer.HorizontalScrollBarVisibility="Disabled">
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>
      <toolkit:WrapPanel />
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel> 
</ListBox>
<Button x:Name="BtnSeleccionados" Width="200" Height="30" Click="BtnSeleccionados_Click">Seleccionados</Button>
</Grid>


Propiedades SelectedValuePath y SelectedValue

SelectedValuePath nos permite indicar la ruta que será utilizada por la propiedad SelectedValue.

Ejemplo:

        private void BtnMostrar_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(lista.SelectedValue.ToString());
        }

Interfaz XAML:

<Grid x:Name="LayoutRoot" Background="White">
  <StackPanel>
    <ListBox x:Name="lista" DisplayMemberPath="Titulo" SelectionMode="Extended"
     SelectedValuePath="Banda"
     ScrollViewer.HorizontalScrollBarVisibility="Disabled">
      <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
           <toolkit:WrapPanel />
        </ItemsPanelTemplate>
      </ListBox.ItemsPanel> 
    </ListBox> 
    <Button x:Name="BtnMostrar" Width="100" Height="30" Click="BtnMostrar_Click" >Mostrar</Button>
    <Button x:Name="BtnSeleccionados" Width="100" Height="30" Click="BtnSeleccionados_Click">Seleccionados</Button>
  </StackPanel>
</Grid>


Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.