Windows Phone. Control CustomMessageBox.

Nueva versión del Windows Phone Toolkit

El Windows Phone Toolkit es un paquete de controles totalmente gratuito disponible tanto en Codeplex como utilizando Nuget. Tenemos disponible una nueva versión (Windows Phone Toolkit – September 2012 Release) que cuenta con interesantes novedades:

  • Nuevos Controles:

CustomMessageBox. Nuevo control que nos permite mostrar mensajes emergentes similares a los que podemos utilizar directamente con el SDK de Windows Phone pero altamente personalizable:

CustomMessageBox

Rating Control. Nuevo control que nos permite mostrar visualmente un control para realizar puntuaciones de manera visual:

RatingControl

  • Nueva funcionalidad:

Se han añadido nuevos efectos de transición (SlideInEffect  y FeatherTransition).

  • Corrección de bugs:

Se han corregido un alto número de los bugs más votados por los usuarios.

En la entrada actual vamos a centrarnos en analizar las posibilidades de uno de los nuevos controles disponibles, el CustomMessageBox.

Control CustomMessageBox

El control CustomMessageBox es un nuevo control disponible en el Windows Phone Toolkit que nos permite mostrar mensajes emergentes con muchas posibilidades de personalización. Entre las características más destacadas:

  • Aspecto visual similar al MessageBox disponible en el SDK (animaciones, posición, fuentes, etc.).
  • Podemos mostrar el mensaje emergente al tamaño requerido o a pantalla completa.
  • Posibilidad de personalizar los botones de acción.
  • Posibilidad de añadir contenido (controles) complejos. Por ejemplo, podemos incluso añadir un Pivot dentro del mensaje emergente.

Vamos a crear una aplicación de ejemplo donde utilizaremos el control e iremos viendo sus posibilidades.

En este ejemplo para simplificar al máximo el proceso y lograr concentrar toda la atención en el control CustomMessageBox vamos a seleccionar un proyecto de tipo Windows Phone Application.

Antes de continuar lo primero que debemos hacer es obtener la última versión del Windows Phone Toolkit. Tenemos disponible el paquete en NuGet. Abrimos el «Package Manager Console» para ello:

NuGet Package Manager Console

Una abierta la consola:

NuGet Console

Escribimos:

Install-Package SilverlightToolkitWP

Tras instalar el paquete tendremos la referencia Microsoft.Phone.Controls.Toolkit.dll añadida a nuestro proyecto.

Nos centramos en crear la interfaz de nuestro ejemplo (MainPage.xaml). Para trabajar en nuestro XAML con las opciones del Toolkit debemos añadir el siguiente XML namespace:

xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

Vamos a añadir dos botones y un CheckBox:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel Margin="0,0,12,0" toolkit:TiltEffect.IsTiltEnabled="True">
          <Button Content="Primeros pasos con  CustomMessageBox"/>
          <Button Content="CustomMessageBox complejo"/>
          <CheckBox x:Name="FullScreenCheckBox" Content="Pantalla Completa" Margin="0,12,0,0"/>
     </StackPanel>
</Grid>

Fácil. El primero de los botones lo utilizaremos para utilizar de la forma más básica posible el control CustomMessageBox. Con el segundo utilizaremos opciones más avanzadas del control. El ChechBox sencillamente lo utilizaremos para elegir si mostrar a pantalla completa el CustomMessageBox.

Añadimos los eventos Click de los botones:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel Margin="0,0,12,0" toolkit:TiltEffect.IsTiltEnabled="True">
          <Button Content="Primeros pasos con  CustomMessageBox" Click="BasicMessageBox_Click"/>
          <Button Content="CustomMessageBox complejo" Click="AdvancedMessageBox_Click"/>
          <CheckBox x:Name="FullScreenCheckBox" Content="Pantalla Completa" Margin="0,12,0,0"/>
     </StackPanel>
</Grid>

 

private void BasicMessageBox_Click(object sender, RoutedEventArgs e)
{

}

private void AdvancedMessageBox_Click(object sender, RoutedEventArgs e)
{

}

Nos centramos en el primer botón:

private void BasicMessageBox_Click(object sender, RoutedEventArgs e)
{
     CustomMessageBox messageBox = new CustomMessageBox()
     {
          Caption = "Pregunta?",
          Message = "Mensaje del CustomMessageBox.",
          LeftButtonContent = "Si",
          RightButtonContent = "No",
          IsFullScreen = (bool)FullScreenCheckBox.IsChecked
     };

     messageBox.Dismissed += (s1, e1) =>
     {
          switch (e1.Result)
          {
               case CustomMessageBoxResult.LeftButton:
               // Acción.
               break;
               case CustomMessageBoxResult.RightButton:
               // Acción.
               break;
               case CustomMessageBoxResult.None:
               // Acción.
               break;
               default:
               break;
          }
     };

     messageBox.Show();
}

Como podemos ver en lo realizado en el primer botón, el uso del control es muy similar al del MessageBox. Para definir el control, las propiedades principales utilizadas son:

  • Caption – Título del mensaje.
  • Message – Mensaje.
  • LeftButtonContent, RightButtonContent – Botones utilizados en el mensaje emergente.
  • IsFullScreen. Indica si el mensaje emergente se muestra a pantalla completa o no.

Para mostrar el mensaje emergente utilizamos el método Show() (al igual que hacemos con el MessageBox estándar).

Previamente, nos subscribimos al evento Dismissed que se lanzará cuando se quite el mensaje. Utilizaremos el valor e.Result de tipo CustomMessageBoxResult para determinar que acción (botón) ha realizado el usuario.

Por defecto, el mensaje solo ocupa el tamaño necesario. Podemos utilizar la propiedad IsFullScreen que le asignamos el valor del CheckBox para determinar si el mensaje se muestra a Pantalla completa o no.

Continuamos con el segundo botón:

private void AdvancedMessageBox_Click(object sender, RoutedEventArgs e)
{
     HyperlinkButton hyperlinkButton = new HyperlinkButton()
     {
          Content = "Más información.",
          HorizontalAlignment = HorizontalAlignment.Left,
          NavigateUri = new Uri("https://javiersuarezruiz.wordpress.com/", UriKind.Absolute)
     };

     TiltEffect.SetIsTiltEnabled(hyperlinkButton, true);

     ListPicker listPicker = new ListPicker()
     {
          Header = "Recordar en:",
          ItemsSource = new string[] { "5 minutos", "10 minutos", "15 minutos" }
     };

     StackPanel stackPanel = new StackPanel();
     stackPanel.Children.Add(hyperlinkButton);
     stackPanel.Children.Add(listPicker);

     CustomMessageBox messageBox = new CustomMessageBox()
     {
          Title = "Recordatorio",
          Caption = "Programar Windows Phone",
          Message = "Realizar ejemplo del control CustomMessageBox",
          Content = stackPanel,
          LeftButtonContent = "Aceptar",
          RightButtonContent = "Cancelar",
          IsFullScreen = (bool)FullScreenCheckBox.IsChecked
     };

     messageBox.Dismissing += (s1, e1) =>
     {
          if (listPicker.ListPickerMode == ListPickerMode.Expanded)
          {
               e1.Cancel = true;
          }
     };

     messageBox.Dismissed += (s2, e2) =>
     {
          switch (e2.Result)
          {
               case CustomMessageBoxResult.LeftButton:
               // Acción.
               break;
               case CustomMessageBoxResult.RightButton:
               case CustomMessageBoxResult.None:
               // Acción.
               break;
               default:
               break;
          }
     };

     messageBox.Show();
}

A continuación hablamos de la propiedad más interesante del control. La propiedad Content la podemos utilizar la insertar nuestro propio contenido. Podemos insertar contenido (controles) por código como hemos realizado en el ejemplo y también utilizando recursos en XAML. En nuestro ejemplo, hemos insertado un Grid que contiene un control HyperLinkButton y un ListPicker (control también incluido dentro del Windows Phone Toolkit).

NOTA: Si deseamos definir el contenido del CustomMessageBox vía XAML debemos crear un DataTemplate en los recursos de la aplicación o de una página y utilizar la propiedad ContentTemplate del control para asignar el DataTemplate correspondiente.

Ejemplo CustomMessageBox

Primeros pasos con CustomMessageBox

Primeros pasos con CustomMessageBox a Pantalla Completa

CustomMessageBox complejo

CustomMessageBox complejo Pantalla Completa

Puedes ver de un vistazo todo el ejemplo realizado en video a continuación:

También puedes descargar el ejemplo realizado:

Espero que lo visto en esta entrada os sea de utilidad. Cualquier duda o sugerencia podéis plantearlas en los comentarios.

Más información

[Tips and Tricks] Windows Phone. Acceder a recursos desde código.

Introducción

En Windows Phone un recurso no es más que un trozo de XAML al que le asignamos una clave única con el objetivo de poder acceder a él posteriormente y reaprovechar el código.

Todo elemento tiene una colección de recursos (desde un simple botón a una página). Además, todos los proyectos que realicemos cuentan también con un archivo (app.xaml) que cuenta también con una colección de recursos accesible desde toda la aplicación.

Para entrar en situación y comprender mejor que nos ofrece los recursos. Imagínate que todos los textos de tu aplicación deben de estar en color verde por ejemplo. Podemos en cada texto utilizar su propiedad Foreground y asignarla al color verde. Sin embargo, tenemos mejores opciones. Por un lado en cada página podríamos definir un recurso (el color) y que todos los textos apunten a dicho color. La ventaja es clara, solo definimos el color una única vez y lo reutilizamos. Ademas, si el día de mañana debemos cambiar el verde por azul, de esta forma sólo debemos cambiar el color una vez por página no una por cada texto.

Pero además, podemos definir el color una única vez a nivel de aplicación (app.xaml) con lo que aún reutilizamos más y lo tenemos más fácil en caso de decidir cambiar.

Comenzamos!

Vamos a realizar como de costumbre un ejemplo.

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Definimos un color (SolidColorBrush) en los recursos de la aplicación (app.xaml):

<!--Recursos de la aplicación-->
<Application.Resources>

     <SolidColorBrush x:Key="appColor" Color="Red"/>

</Application.Resources>

Y otro, en los recursos de la página principal (MainPage.xaml):

<phone:PhoneApplicationPage.Resources>

     <SolidColorBrush x:Key="pageColor" Color="Green"/>

</phone:PhoneApplicationPage.Resources>

Hemos definido un recurso a nivel de aplicación, concretamente un color (rojo) y otro recurso, de nuevo un color (verde) a nivel de página.

A continuación, en nuestra página principal vamos a definir dos textos asignandoles los colores previamente definidos:

<StackPanel>
     <TextBlock x:Name="tb1" Text="Color tomado de los recursos de la aplicación" Foreground="{StaticResource appColor}" />
     <TextBlock x:Name="tb2" Text="Color tomado de los recursos de la página" Foreground="{StaticResource pageColor}"/>
</StackPanel>

Vamos a analizar la forma de asignar los colores definidos.

En lugar de indicar un valor literal, añadimos una sentencia entre llaves. Esto indica que estamos ante una expresión que se debe evaluar y resolver. StaticResource indica que buscamos por el nombre que venga a continuación, un recurso en nuestra aplicación cuya clave coincida.

¿Fácil, verdad?.

NOTA: Indicar antes de continuar que profundizaremos mucho más en todo lo relacionado con recursos en próximas entradas.

Vamos a acceder a los recursos desde el code-behind. Para ello, vamos a añadir a la interfaz de usuario dos botones que permitan acceder a los recursos y modificar la asignación de nuestros textos:

<StackPanel Grid.Row="1" HorizontalAlignment="Center">
     <Button x:Name="btn1" Content="Cambiar Recurso 1º Texto"/>
     <Button x:Name="btn2" Content="Cambiar Recurso 2º Texto"/>
</StackPanel>

Añadimos el evento Click de cada botón:

<StackPanel Grid.Row="1" HorizontalAlignment="Center">
     <Button x:Name="btn1" Content="Cambiar Recurso 1º Texto" Click="btn1_Click"/>
     <Button x:Name="btn2" Content="Cambiar Recurso 2º Texto" Click="btn2_Click"/>
</StackPanel>

Y en el code-behind (MainPage.xaml.cs):

private void btn1_Click(object sender, RoutedEventArgs e)
{

}

private void btn2_Click(object sender, RoutedEventArgs e)
{

}

De modo que la interfaz completa de nuestro ejemplo quedaría:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <Grid.RowDefinitions>
          <RowDefinition Height="0.7*"/>
          <RowDefinition Height="0.3*"/>
     </Grid.RowDefinitions>
     <StackPanel>
          <TextBlock x:Name="tb1" Text="Color tomado de los recursos de la aplicación" Foreground="{StaticResource appColor}" />
          <TextBlock x:Name="tb2" Text="Color tomado de los recursos de la página" Foreground="{StaticResource pageColor}"/>
     </StackPanel>
     <StackPanel Grid.Row="1" HorizontalAlignment="Center">
          <Button x:Name="btn1" Content="Cambiar Recurso 1º Texto" Click="btn1_Click"/>
          <Button x:Name="btn2" Content="Cambiar Recurso 2º Texto" Click="btn2_Click"/>
     </StackPanel>
</Grid>

Nos centramos ahora en los eventos de cada botón. El primero de ellos debe acceder al recurso de la página para modificar el color del primer texto.

Para ello, utilizaremos la colección Resources de la página (this) indicándole entre corchetes la clave del recurso:

private void btn1_Click(object sender, RoutedEventArgs e)
{
     SolidColorBrush pageColor = this.Resources["pageColor"] as SolidColorBrush;

     if (pageColor != null)
          tb1.Foreground = pageColor;
}

En el segundo botón accederemos al recurso de la página para modificar el color del segundo texto.

Accederemos desce código a la colección de recursos a nivel de aplicación utilizando App.Current.Resources:

private void btn2_Click(object sender, RoutedEventArgs e)
{
     SolidColorBrush appColor = App.Current.Resources["appColor"] as SolidColorBrush;

     if (appColor != null)
          tb2.Foreground = appColor;
}

NOTA:  Sólo puedes acceder a un recurso de App.Current.Resources utilizando una clave.

Fácil, ¿verdad?

Puedes descargar el ejemplo realizado:

Espero que lo visto en esta entrada os sea de utilidad. Cualquier duda o sugerencia podéis plantearlas en los comentarios.

Más información

Windows Phone. El ApplicationBar.

Introducción

El ApplicationBar nos permite crear de manera rápida y sencilla un menú de botones. Es una barra situada en la parte inferior de la pantalla.

Está compuesto de dos partes diferenciadas:

  • Listado de botones. Cada botón compuesto por un icono junto a un texto descriptivo. Es lo único visible por defecto en el ApplicationBar. Junto al listado de botones podemos ver también tres puntos suspensivos en la parte inferior derecha.
  • Menu de opciones. Oculto por defecto. Lo podemos desplegar al pulsar sobre los tres puntos suspensivos.

Como de costumbre, vamos a realizar un ejemplo práctico. Creamos un nuevo proyecto:

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Al crear el proyecto podemos ver en el archivo MainPage.xaml el código necesario para añadir un ApplicationBar a nuestra aplicación, solo que por defecto está comentado. Para utilizar el ApplicationBar necesitamos la referencia a la siguiente librería:

xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"

La clase PhoneApplicationPage contiene una propiedad ApplicationBar. Para definir el ApplicationBar:

<phone:PhoneApplicationPage.ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

Añadimos imágenes a utilizar en los botones del ApplicationBar (ApplicationBarIconButton). Debemos definir en las propiedades de la imágen a tipo Content la propiedad Build Action:

NOTA: El círculo que rodea a cada icono se coloca de manera automática por el sistema, no es necesario definirlo en la imágen.

Añadimos cuatro botones (indicamos una imágen inexistente al último, fijáos en el resultado):

<phone:PhoneApplicationPage.ApplicationBar>
     <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.heart2.rest.png" Text="IconButton1" Click="ApplicationBarIconButton_Click"/>
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.lamp.rest.png" Text="IconButton2"/>
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.mic.rest.png" Text="IconButton3"/>
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.mic.rest2.png" Text="IconButton4"/>
     </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

Hemos definido el evento Click del primero botón:

private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{

}

Añadimos también un menu de opciones. La definición completa del ApplicationBar quedaría:

<phone:PhoneApplicationPage.ApplicationBar>
     <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.heart2.rest.png" Text="IconButton1" Click="ApplicationBarIconButton_Click"/>
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.lamp.rest.png" Text="IconButton2"/>
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.mic.rest.png" Text="IconButton3"/>
          <shell:ApplicationBarIconButton IconUri="/IMGS/appbar.mic.rest2.png" Text="IconButton4"/>
          <shell:ApplicationBar.MenuItems>
               <shell:ApplicationBarMenuItem Text="MenuItem1"/>
               <shell:ApplicationBarMenuItem Text="MenuItem2"/>
               <shell:ApplicationBarMenuItem Text="MenuItem3"/>
               <shell:ApplicationBarMenuItem Text="MenuItem4" Click="ApplicationBarMenuItem4_Click"/>
               <shell:ApplicationBarMenuItem Text="MenuItem5"/>
               <shell:ApplicationBarMenuItem Text="MenuItem6"/>
          </shell:ApplicationBar.MenuItems>
     </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

El evento Click definido en el cuarto ApplicationBarMenuItem:

private void ApplicationBarMenuItem4_Click(object sender, EventArgs e)
{

}

Puedes ver de un vistazo todo el ejemplo realizado en video a continuación:

También puedes descargar el ejemplo realizado:

Espero que lo visto en esta entrada os sea de utilidad. Cualquier duda o sugerencia podéis plantearlas en los comentarios. En próximas entradas profundizaremos en el uso del ApplicationBar.

Propiedades del ApplicationBar

  • Mode. indica el tamaño del ApplicationBar la primera vez que aparece en la página. Puede ser: Mini o Default. El valor por defecto es Default.
  • Opacity. Se espera un valor entre 0.0 y 1.0 aunque es recomendable utilizar 0.0, 0.5 o 1.0 ya que el valor de esta propiedad afecta al aspecto de la página. Si el valor de la opacidad es 1, el contenido de la página se redimensiona para no ocupar el tamaño del ApplicationBar. Si el valor de la opacidad es inferior a 1, la barra del ApplicationBar se superpone a los elementos de la página.
  • BackgroundColor. Color de fondo del ApplicationBar.
  • ForegroundColor. Define el color del texto de los botones y de los elementos definidos en el menu.
  • IsVisible. Indica si el ApplicationBar está visible o no.

A tener en cuenta

  • Los iconos utilizados en los botones del ApplicationBar deben de ser de un tamaño de 48x48px.
  • Los iconos utilizados en los botones del ApplicationBar deben añadirse como recurso de tipo Content.
  • Los iconos utilizados en los botones del ApplicationBar deben ser blancos con el fondo transparente. Si se cambia es tema del sistema, automáticamente se modificará el color a negro.
  • El círculo que rodea a cada icono se coloca de manera automática por el sistema.
  • Los textos de cada botón independientemente de como lo escribamos se convierte a minúscula. Cuida el texto evitando usar textos de una longitud elevada.
  • Tienes disponible ya directamente una interesante colección de iconos en Program Files \ Microsoft SDK\Windows Phone\Icons.
  • Estamos limitados a un maximo de 4 ApplicationBarIconButtons.
  • No tenemos límite de ApplicationBarMenuItems. Sin embargo, recuerda que solo se verán directamente los cinco primeros elementos por que piensa correctamente el orden.
  • Por defecto, en la mayoría de ocasiones se recomienda el uso del ApplicationBar en lugar de crear nuestros propios menús. Los usuarios están acostumbrados a usarlo además logramos una experiencia de usuario consistente y más cercana a lo reproducido en el sistema y el resto de aplicaciones.
  • El ApplicationBar no soporta el uso de comandos solo eventos. Por lo tanto nos limita el correcto uso del patrón MVVM. Este punto es importante y analizaremos en profundidad en próximas entradas como solucionar este punto (un pequeño adelanto).

Más información

Extra

  • Más de 700 iconos gratuitos: Windows Phone Icons (Templarian).
  • MetroStudio. Syncfusion nos proporciona esta herramienta destinada desarrolladores que quieran incorporar iconos Metro en sus aplicaciones. Es gratis y los iconos son libres.

[Tips and Tricks] Windows Phone. Could not load the assembly.

Introducción

En ocasiones buscando nueva funcionalidad nos descargamos librerías de Internet. Por poner un ejemplo, podemos mencionar el Toolkit Coding4Fun para Windows Phone.

Para utilizar algún control del Toolkit en nuestra aplicación primero debemos añadir una referencia a la librería correspondiente:

Tras añadir la librería podemos probar a compilar nuestra aplicación para verificar que todo esta en orden. Sin embargo, obtenemos el siguiente error:

«No se ha podido cargar el ensamblado .\Coding4Fun.Phone.Controls.dll. Puede que se haya descargado del Web. Si un ensamblado se ha descargado del Web, Windows lo marca como un archivo Web, aunque resida en el equipo local. Esto puede impedir que el archivo pueda utilizarse en un proyecto. Esta designación se puede cambiar modificando las propiedades del archivo.»

El problema es simple. Por motivos de seguridad se ha bloqueado la librería.

¿Cómo lo solucionamos?

Fácil. Nos dirigimos a la carpeta donde tengamos la librería y realizamos clic derecho sobre ella. Hacemos clic sobre la última opción «Propiedades». Veremos algo como lo siguiente:

Debemos hacer clic sobre la opción «Desbloquear» y aplicar los cambios.

Listo. Vuelve a compilar tu proyecto y verás que el problema anterior ha desaparecido.

Más información

Windows phone. Introducción al control Listpicker.

Control Listpicker

El control Listpicker lo tenemos disponible dentro del Windows Phone Silverlight Toolkit, paquete de controles totalmente gratuito disponible tanto en Codeplex como utilizando Nuget. Ya hablamos de que como instalar y que contenía el Toolkit en la siguiente entrada:

Introducción al Windows Phone Silverlight Toolkit

El control ListPicker nos permite mostrar una serie de opciones a elegir por parte del usuario (de manera muy similar a como lo haríamos utilizando un ComboBox). Deriva de la clase ItemsControl, permite una gran personalización, el uso de data bindings y nos facilita un gran control sobre la interacción que el usuario realiza con él mediante el uso de eventos. Tiene dos tipos de selecciones:

  • Expandida en el mismo lugar donde se define (como lo haría un ComboBox).
  • En un popup a pantalla completa (muy útil si se va a mostrar un número elevado de elementos).

En la actual entrada vamos a realizar una introducción al uso de este control.

Para analizar las posibilidades que nos brida el control Listpicker vamos a realizar como de costumbre un ejemplo.

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Tras crear el proyecto lo primero que debemos hacer es agregar la referencia a la librería del Toolkit para tener acceso al control. Para ello agregamos la referencia a la librería Microsoft.Phone.Controls.Toolkit.dll.

Nos centramos en el archivo MainPage.xaml para definir la interfaz básica de nuestro ejemplo:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <Button x:Name="btnBasic" Content="Uso básico"/>
          <Button x:Name="btnStyles" Content="Estilos"/>
          <Button x:Name="btnEvents" Content="Eventos"/>
     </StackPanel>
</Grid>

El resultado lo podéis ver en la captura superior. Muy simple, deseamos dividir el ejemplo en tres apartados diferenciados:

  • Uso básico. Aprenderemos que es el control utilizando sus propiedades principales.
  • Estilos. Dado la potente personalización que nos permite el control vamos a centrarnos un poco en ello.
  • Eventos. Vamos a analizar los eventos principales del control.

Por lo tanto hemos añadido tres botones. Cada uno de ellos nos llevará a una página donde trabajaremos sobre el área indicada. Añadimos los eventos de cada botón:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <Button x:Name="btnBasic" Content="Uso básico" Click="btnBasic_Click"/>
          <Button x:Name="btnStyles" Content="Estilos" Click="btnStyles_Click"/>
          <Button x:Name="btnEvents" Content="Eventos" Click="btnEvents_Click"/>
     </StackPanel>
</Grid>

Al pulsar sobre cada uno de los botones llevaremos al usuario a una nueva página por lo que necesitamos antes que nada añadir al proyecto las 3 páginas necesarias que utilizaremos. En el ejemplo que podéis descargar al final de la entrada se añadieron 3 páginas llamadas:

  • Basic
  • Styles
  • Events

A continuación, vamos a ver que se hace en cada uno de los botones (en la clase MainPage.xaml.cs).

private void btnBasic_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/Basic.xaml", UriKind.Relative));
}

private void btnStyles_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/Styles.xaml", UriKind.Relative));
}

private void btnEvents_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/Events.xaml", UriKind.Relative));
}

Nada fuera de lo común. Utilizamos el servicio de navegación NavigationService para enviar al usuario a la página correspondiente. Puedes ver todo lo relacionado con el servicio de navegación NavigationService en esta entrada.

Nos centramos en la página “Basic.xaml”. Para poder utilizar el control ListPicker en nuestra interfaz lo primero que debemos hacer es añadir la referencia a la siguiente librería:

xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

Añadimos lo siguiente a la interfaz:

<StackPanel>
     <TextBlock Text="Uso Básico" FontSize="36"/>
     <toolkit:ListPicker x:Name="listPicker1"/>
</StackPanel>

Hemos añadido un control ListPicker. De momento no hemos abastecido de información al control ni tampoco hemos utilizado ninguna de sus propiedades fundamentales. Vamos a comenzar abasteciendo al control de información (utilizaremos la propiedad ItemSource para ello). Lo primero que vamos a hacer es crear una clase donde definiremos los objetos que mostrará el control:

public class Drivers
{
     public string Name { get; set; }

     public string Nationality { get; set; }

     public string Scuderia { get; set; }
}

Hemos creado una clase Driver (Piloto) con tres propiedades:

  • Name – Nombre del Piloto.
  • Nationality – Nacionalidad del Piloto.
  • Scuderia – Escudería actual del piloto.

Vamos a crear una colección de pilotos (en nuestro ejemplo, pilotos de Formula 1) que abastecerán al ListPicker:

List<Drivers> source = new List<Drivers>();
source.Add(new Drivers() { Name = "Fernando Alonso", Nationality = "ES", Scuderia = "Ferrari" });
source.Add(new Drivers() { Name = "Lewis Hamilton", Nationality = "UK", Scuderia = "McLaren" });

listPicker1.ItemsSource = source;

Añadimos las propiedades fundamentales del control (analizamos que es cada una un poco más adelante):

<toolkit:ListPicker x:Name="listPicker1" ItemTemplate="{StaticResource ListPickerItemTemplate}" FullModeItemTemplate="{StaticResource ListPickerFullModeItemTemplate}"
Header="Pilotos" FullModeHeader="Pilotos" CacheMode="BitmapCache" SelectionMode="Single" ExpansionMode="ExpansionAllowed"/>

Debemos definir el DataTemplate de las propiedades ItemTemplate y FullModeItemTemplate (elementos del modo a pantalla completa). Lo haremos en los propios recursos de la página:

<phone:PhoneApplicationPage.Resources>
</phone:PhoneApplicationPage.Resources>

Definimos los DataTemplate. Serán lo más sencillos posibles, un simple TextBlock que mostrará el nombre de cada piloto:

<DataTemplate x:Name="ListPickerItemTemplate">
     <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding Name}" Margin="10 0 0 0"/>
     </StackPanel>
</DataTemplate>

<DataTemplate x:Name="ListPickerFullModeItemTemplate">
     <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding Name}" Margin="10 0 0 0"/>
     </StackPanel>
</DataTemplate>

NOTA: En caso de no querer utilizar DataTemplates bastará con abastecer al control con una colección de cadenas (List<String> por ejemplo). Veamos un sencillo ejemplo:

<toolkit:ListPicker Header="Pilotos">
    <sys:String>Fernando Alonso</sys:String>
    <sys:String>Lewis Hamilton</sys:String>
    <sys:String>Sebastian Vettel</sys:String>
</toolkit:ListPicker>

Vamos a pararnos antes de seguir a determinar que son y para que sirven  las propiedades fundamentales del control:

  • ListPickerMode. Propiedad de dependencia de tipo ListPickerMode. Se utiliza para indicar el modo utilizado por el control. Su valor puede ser: Normal (valor por defecto, solo el elemento seleccionado es visible sin que el control esté expandido), Expanded (todos los elementos están visibles, no hace falta expandir) o Full (todos los elementos están visibles en un popup a pantalla completa).
  • Header. Propiedad de dependencia de tipo Object. Es la cabecera (normalmente un String) que aparecerá en la parte superior derecha del control.
  • FullModeHeader. Propiedad de dependencia de tipo DataTemplate. Como mencionamos al inicio del artículo, el control ListPicker tiene dos modos de expansión (selección y pantalla completa). Esta propiedad define la cabecera utilizada cuando el modo de selección es a pantalla completa.
  • ItemTemplate. Propiedad de dependencia de tipo DataTemplate.Sirve para definir la apariencia de cada elemento mostrado.
  • FullmodeItemTemplate. Propiedad de dependencia de tipo DataTemplate. Sirve para definir la apariencia de cada elemento mostrado cuando la forma de desplegar el control es a pantalla completa. Si se deja a cero, automáticamente pasamos a modo pantalla completa.
  • ExpansionMode. Propiedad de dependencia de tipo ExpansionMode. Nos sirve para obtener o indicar como se expande el ListPicker. Hay dos opciones, ExpansionAllowed o FullScreenOnly. Importante, esta propiedad solo tiene efecto cuando el modo del control (propiedad SelectionMode) es Single. Si el valor de la propiedad SelectionMode es Multiple, la propiedad SelectionMode será FullScreenOnly.
  • ItemCountThreshold. Propiedad de dependencia de tipo int. Indica el numero máximo de elementos visibles en el modo de expansión normal. Por defecto, el valor es cinco.
  • SelectionMode. Propiedad de dependencia de tipo SelectionMode. Determina el modo de selección del control. Los valores posibles son: Single, Multiple o Extended.
  • SelectedIndex. Indica o establece el índice del elemento seleccionado.
  • SelectedItem. Indica o establece el elemento seleccionado.
  • SelectionItems. Propiedad de dependencia de tipo IList. Devuelve el listado de elementos seleccionados.

A continuación, vamos a añadir un segundo ListPicker con una única diferencia, el modo de expansión será a pantalla completa (fijaos en el valor de la propiedad ExpansionMode):

<toolkit:ListPicker x:Name="listPicker2" ItemTemplate="{StaticResource ListPickerItemTemplate}" FullModeItemTemplate="{StaticResource ListPickerFullModeItemTemplate}"
Header="Pilotos" FullModeHeader="Pilotos" CacheMode="BitmapCache" SelectionMode="Single" ExpansionMode="FullScreenOnly"/>

¿Interesante, verdad?. Continuamos, nos centramos en la página “Styles.xaml”. Añadimos los dos listpicker utilizados en los pasos básicos:

<StackPanel>
     <TextBlock Text="Estilos" FontSize="36"/>
     <toolkit:ListPicker x:Name="listPicker1" ItemTemplate="{StaticResource ListPickerItemTemplate}" FullModeItemTemplate="{StaticResource ListPickerFullModeItemTemplate}"
     Header="Pilotos" FullModeHeader="Pilotos" CacheMode="BitmapCache" SelectionMode="Single" ExpansionMode="ExpansionAllowed"/>

     <toolkit:ListPicker x:Name="listPicker2" ItemTemplate="{StaticResource ListPickerItemTemplate}" FullModeItemTemplate="{StaticResource ListPickerFullModeItemTemplate}"
     Header="Pilotos" FullModeHeader="Pilotos" CacheMode="BitmapCache" SelectionMode="Single" ExpansionMode="FullScreenOnly"/>
</StackPanel>

La diferencia esta vez radicará en las posibilidades de personalización de los elementos del control. Vamos a mostrar en el modo de expansión normal (Expanded) el nombre de la escudería a la que pertenece el piloto junto a su nombre. Para darle peso al nombre de la escudería, añadiremos un color de fondo (el más representativo de cada escuería):

<DataTemplate x:Name="ListPickerItemTemplate">
     <StackPanel Orientation="Horizontal">
          <Border Background="{Binding Scuderia, Converter={StaticResource scuderiaColorConverter}}" Width="60" Height="60">
               <TextBlock Text="{Binding Scuderia}" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center"/>
          </Border>
         <TextBlock Text="{Binding Name}" Margin="10 0 0 0"/>
     </StackPanel>
</DataTemplate>

Para que el fondo del borde reciba un color dependiendo del nombre de la escudería utilizaremos un Converter:

<Converters:ScuderiaColorConverter x:Name="scuderiaColorConverter"/>

La definición del Converter:

public class ScuderiaColorConverter : System.Windows.Data.IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
          if (value is string)
          {
               switch ((string)value)
               {
                    case "Ferrari":
                         return new SolidColorBrush(Colors.Red);
                    case "McLaren":
                         return new SolidColorBrush(Colors.Gray);
                    case "RedBull":
                         return new SolidColorBrush(Colors.Blue);
               }
          }

          throw new NotSupportedException();
     }

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
          throw new NotSupportedException();
     }
}

En la captura superior podéis ver el resultado conseguido. ¿Empezáis a ver las infinitas posibilidades?. Continuamos personalizando cada elemento del modo de expansión a pantalla completa (Full). En esta ocasión y gracias al mayor espacio disponible, vamos a mostrar la foto de cada piloto junto a su nombre. Para ello, antes que nada creamos una nueva carpeta (en el ejemplo llamada IMGS) donde añadiremos una foto por cada piloto. Veamos el DataTemplate correspondiente:

<DataTemplate x:Name="ListPickerFullModeItemTemplate">
     <StackPanel Orientation="Horizontal" Margin="16 21 0 20">
          <Image Source="{Binding Name, Converter={StaticResource nameImageConverter}}" Height="100" Width="100" Stretch="UniformToFill"/>
          <StackPanel>
               <TextBlock Text="{Binding Name}" FontSize="43" FontFamily="{StaticResource PhoneFontFamilyLight}"/>
               <StackPanel Orientation="Horizontal" Margin="10 0 0 0">
                    <TextBlock Text="Escudería: "/>
                    <TextBlock Text="{Binding Scuderia}" Foreground="DarkGray"/>
               </StackPanel>
          </StackPanel>
     </StackPanel>
</DataTemplate>

De nuevo hemos utilizado un Converter que recibirá el nombre del piloto y devolverá la ruta a la imágen correspondiente:

<Converters:NameImageConverter x:Name="nameImageConverter"/>

La definición del Converter:

public class NameImageConverter : System.Windows.Data.IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {
          if (value is string)
               return string.Format("/IMGS/{0}.jpg", (string)value);

          throw new NotSupportedException();
     }

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {
          throw new NotSupportedException();
     }
}

El resultado conseguido lo puedes ver en la captura superior.

Por último, nos centramos en la página “Events.xaml”. El evento principal del control es SelectionChanged:

<StackPanel>
     <TextBlock Text="Eventos" FontSize="36"/>
     <toolkit:ListPicker x:Name="listPicker" ItemTemplate="{StaticResource ListPickerItemTemplate}" FullModeItemTemplate="{StaticResource ListPickerFullModeItemTemplate}"
Header="Pilotos" FullModeHeader="Pilotos" CacheMode="BitmapCache" SelectionMode="Single" ExpansionMode="ExpansionAllowed" SelectionChanged="listPicker_SelectionChanged"/>
</StackPanel>

Se lanza cada vez que el elemento seleccionado cambia.

private void listPicker_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
     MessageBox.Show(((Drivers)listPicker.SelectedItem).Name);
}

Puedes ver de un vistazo todo el ejemplo realizado en video a continuación:

Tambien puedes descargar el ejemplo completo realizado:

Espero que lo visto en esta entrada os sea de utilidad. Sin duda en próximas entradas seguiremos viendo particularidades del control. Cualquier duda o sugerencia podéis plantearlas en los comentarios.

Más información

[Tips and Tricks] Windows Phone. Tipos de Teclado.

Introducción

Cuando deseamos obtener información introducida por el usuario es muy común el uso del control Textbox. Cuando utilizamos este control por defecto, el usuario introduce la información utilizando un teclado completo que le aparece en pantalla.

Sin embargo, no siempre se espera el mismo tipo de información. Dependiendo del tipo de información podríamos mejorar mucho la usabilidad de nuestra aplicación si el usuario utiliza el teclado adecuado. Por ejemplo, si esperamos un nombre, el teclado completo sería idóneo pero si lo que esperamos es un número de teléfono lo ideal sería mostrar el teclado numérico.

Input Scope. Cambiando el tipo de teclado.

Vamos a realizar como de costumbre un ejemplo.

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Añadimos un TextBox a nuestra aplicación (en MainPage.xaml):

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <TextBlock Text="Teclado"/>
          <TextBox/>
     </StackPanel>
</Grid>

Si ejecutamos la aplicación y ponemos el foco en el TextBox añadido aparecerá de manera automática el teclado completo en pantalla.

Continuamos. ¿Y si queremos que el usuario introduzca un valor numérico? Lo ideal sería que le apareciese directamente el teclado numérico para facilitarle al máximo la labor.

Para ello, añadimos un segundo TextBox. Utilizaremos la propiedad InputScope que nos permite indicar el tipo de teclado. Dicha propiedad espera una opción de la enumeración InputScopeNameValue (recomiendo echarle un vistazo a las opciones disponibles y los distintos tipos de teclados que podemos utilizar).

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <TextBlock Text="Teclado"/>
          <TextBox/>
          <TextBlock Text="Teclado Numérico"/>
          <TextBox Name="txtPhone" InputScope="Number"/>
     </StackPanel>
</Grid>

También se podría hacer lo mismo desde el code-behind de la página:

InputScope scope = new InputScope();
InputScopeName name = new InputScopeName();
name.NameValue = InputScopeNameValue.Number;
scope.Names.Add(name);

txtPhone.InputScope = scope;

Puedes descargar el pequeño ejemplo realizado:

Espero que lo visto en esta entrada os sea de utilidad. Cualquier duda o sugerencia podéis plantearlas en los comentarios.

Más información

Windows Phone. Leer un RSS.

Introducción

Una fuente de datos muy común en una aplicación móvil suele ser meduante una fuente RSS. RSS (Really Simple Syndication), es un formato XML utilizado normalmente para  compartir contenidos en la web.

HttpWebRequest vs WebClient. Fight!

Tenemos dos opciones para poder obtener los datos de la fuente RSS:

  • WebClient.
  • HttpWebRequest.

Vale, ¿cual usar?

WebClient es un wrapper de la clase HttpWebRequest utilizado para realizar peticiones web. La gran ventaja de la clase WebClient es que es fácil de usar (muy pocas líneas). Sin embargo, como contra el proceso lo realiza en el hilo de la interfaz congelando la misma mientras está procesando.

HttpWebRequest realiza la petición en un hilo separado sin bloquear la interfaz. Debemos ser nosotros quien pasemos los datos obtenidos a la interface de usuario. Por contra, necesita más líneas para obtener el mismo resultado pero la ventaja de trabajar en un hilo aparte es suficiente como para que sea el método más utilizado para obtener datos de una fuente RSS.

Para que quede todo más claro veamos un ejemplo rápido:

  • Utilizando WebClient:
var cliente = new WebClient();
cliente.DownloadStringCompleted += (s, ev) => { responseTextBlock.Text = ev.Result; };
cliente.DownloadStringAsync(new Uri("https://javiersuarezruiz.wordpress.com/feed/"));
  • Utilizando HttpWebRequest:
var request = (HttpWebRequest)WebRequest.Create(
                new Uri("https://javiersuarezruiz.wordpress.com/feed/"));
request.BeginGetResponse(r =>
{
    var httpRequest = (HttpWebRequest)r.AsyncState;
    var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);

    using (var reader = new StreamReader(httpResponse.GetResponseStream()))
    {
        var response = reader.ReadToEnd();

        //Interfaz de Usuario
        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                TextBlock.Text = response;
            }));
    }
}, request);

Como de costumbre, vamos a realizar un ejemplo práctico. Creamos un nuevo proyecto:

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo. El objetivo del ejemplo será poder leer el RSS del blog que es el siguiente:

https://javiersuarezruiz.wordpress.com/feed/

Vamos a utilizar la clase HttpWebRequest para obtener el RSS. Recordar que la petición se realizará en segundo plano:

private void ObtenerDatos()
{
     var request = (HttpWebRequest)WebRequest.Create(
     new Uri("https://javiersuarezruiz.wordpress.com/feed/"));
     request.BeginGetResponse(r =>
     {
          var httpRequest = (HttpWebRequest)r.AsyncState;
          var httpResponse = (HttpWebResponse)httpRequest.EndGetResponse(r);

          using (var reader = new StreamReader(httpResponse.GetResponseStream()))
          {
               var response = reader.ReadToEnd();

               //Interfaz de Usuario
               Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
               {
                    LeerDatos(response);
               }));
          }
     }, request);
}

Utilizamos el método Create de la clase HttpWebRequest para inicializar el objeto. A continuación, utilizamos el método BeginGetResponse (fijaos que es un método asíncrono) donde realizamos la llamada para obtener los datos.

Importante. Fijaos como debemos utilizar un Dispatcher para poder pasar los datos al hilo principal de ejecución de la aplicación, donde pasamos la información almacenada en la variable response a un método llamado LeerDatos (no os preocupéis por el método, lo analizaremos a continuación).

Antes de continuar, debemos crear una pequeña clase en nuestro proyecto que define todas las propiedades que deseamos obtener del RSS:

public class RSSItem
{
     public string Titulo { get; set; }
     public string Contenido { get; set; }
     public string Fecha { get; set; }
}

Nuestro método ObtenerDatos ha obtenido toda la información de la fuente RSS y ha pasado la información a otro método en el hilo principal de ejecución llamado LeerDatos. Vamos a analizar ese método:

private void LeerDatos(string rss)
{
     XDocument documento = XDocument.Parse(rss);

     List<RSSItem> items = (from item in documento.Descendants("item")
     select new RSSItem
     {
          Titulo = item.Element("title").Value,
          Contenido = item.Element("description").Value,
          Fecha = item.Element("pubDate").Value
     }).ToList();
}

Tras descargar los datos con la clase HttpWebRequest (un archivo XML) debemos lograr extraer la información que deseamos y almacenarla en objetos del tipo RSSItem (recordar la clase que hemos creado anteriormente).

¿Cómo lo conseguimos?

Una de las opciones posibles es utilizar LINQ to XML. Es la forma más común hoy día y será el método utilizado. LINQ to XML proporciona una interfaz de programación XML en memoria que aprovecha las características de LINQ. Nos basaremos en el uso de una clase llamada XDocument. Para poder utilizarla debemos añadir la siguiente referencia al proyecto:

System.Xml.Linq.dll

Utilizamos el método Parse de la clase XDocument pasandole la información obtenida. De esta forma logramos un documento XML con el que podemos trabajar utilizando LINQ to XML. Buscamos todos los nodos de tipo «item» existentes y vamos creando un nuevo objeto RSSItem al que le asignamos sus propiedades principales.

Continuamos. Hemos obtenido la información que necesitamos y hemos creado una colección de objetos RSSItem con ella. Aún no hemos realizado ningún cambio en la interfaz. Dado que tenemos una colección de objetos, vamos a utilizar un control Listbox para representarla visualmente:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <ListBox x:Name="lstRss">
     </ListBox>
</Grid>

Tras agregar el control debemos definir la estructura visual de cada elemento de la lista. Lo conseguiremos modificando el ItemTemplate del ListBox:

<ListBox x:Name="lstRss">
     <ListBox.ItemTemplate>
          <DataTemplate>
               <StackPanel VerticalAlignment="Top">
                    <TextBlock FontSize="28" TextWrapping="Wrap" Margin="12,0,0,0" HorizontalAlignment="Left" Foreground="White" Text="{Binding Titulo}" />
                    <TextBlock Foreground="{StaticResource PhoneSubtleBrush}" Margin="12,0,0,10" Text="{Binding Fecha}" />
               </StackPanel>
          </DataTemplate>
     </ListBox.ItemTemplate>
</ListBox>

Por último, debemos enlazar nuestra colección de datos en memoria con nuestro control Listbox de la interfaz de usuario (utilizamos la propiedad ItemsSource del control):

lstRss.ItemsSource = items;

En este punto si compilamos y ejecutamos la aplicación veremos lo siguiente:

Puedes ver en video el resultado de nuestro ejemplo a continuación:

También puedes descargar el ejemplo realizado a continuación:

Conclusiones

Los pasos que hemos debido realizar han sido:

  • Obtener la información deseada. Hemos utilizado la clase HttpWebRequest para ello.
  • Procesar la información obtenida para lograr una lista de objetos que podamos enlazar con la interfaz de usuario. Linq to XML.
  • Enlazar los datos ya procesados con la interfaz.

Si os surgen dudas o sugerencias podéis dejarlas en los comentarios.

Más información

Windows Phone. Coding4Fun MemoryCounter.

Una vez finalizado el desarrollo de nuestra aplicación para Windows Phone desearemos publicarla en el MarketPlace. Para ello, debe pasar un proceso de certificación donde se le realizarán múltiples pruebas que debe superar con éxito. Uno de los puntos vitales a tener en cuenta durante la fase de desarrollo es el rendimiento. Hoy nos centraremos en la gestión de memoria.

NOTA: En Windows Phone Mango el límite de consumo de memoria por parte de la aplicación eran 90MB, en Windows Phone Tango, el límite  baja a los 60MB.

Para ello, utilizaremos el control Memory Counter disponible en el Conding4Fun Toolkit (totalmente gratuito, hablamos  del toolkit en esta entrada). El control Memory Counter permite monitorear el uso total de memoria de nuestra aplicación de manera muy fácil (algo vital a hacer para llegar a buen puerto en la certificación de la misma).

Vamos a realizar un ejemplo práctico para entender mejor que nos aporta el control y como aprovechar todas sus posibilidades. Creamos un nuevo proyecto:

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Para poder utilizar el control MemoryCounter lo primero que debemos hacer es añadir la referencia a la siguiente librería:

Coding4Fun.Phone.Controls.dll

Nos centramos en la página principal (MainPage.xaml). Añadimos el siguiente namespace:

xmlns:Coding4Fun="clr-namespace:Coding4Fun.Phone.Controls;assembly=Coding4Fun.Phone.Controls"

Ya podemos utilizar el control. Es tán sencillo como añadir:

<Coding4Fun:MemoryCounter/>

Si compilas en este momento podrás ver al control en acción:

NOTA: El control MemoryCounter sólo funciona en modo DEBUG.

Centremonos a continuación en las propiedades principales del control:

  • UpdateInterval. Propiedad de dependencia de tipo Int. Indica cada cuanto se refresca la información proporcionada por el control. Por defecto el valor es 1000.
  • CurrentMemory. Propiedad de dependencia de tipo String. Representa el consumo de memoria actual por la aplicación.
  • PeakMemory. Propiedad de dependencia de tipo String. Representa el pico máximo de memoria alcanzado por la aplicación en algún momento.
<Coding4Fun:MemoryCounter x:Name="memoryCounter" UpdateInterval="250" Foreground="Red"/>

Vamos a añadir una serie de botones que nos permita «jugar» con la memoria utilizada para poder probar el control MemoryCounter:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <Coding4Fun:MemoryCounter x:Name="memoryCounter" UpdateInterval="250" Foreground="Red"/>
     <StackPanel VerticalAlignment="Center">
          <Button x:Name="btnLoad" Content="Cargar 10MB en Memoria"/>
          <Button x:Name="btnClear" Content="Limpiar Memoria"/>
          <Button x:Name="btnInfo" Content="Ver uso de Memoria" Margin="0,150"/>
     </StackPanel>
</Grid>

Hemos añadido tres botones. El primero de ellos sumará cada vez que se pulse 10MB más a la memoria usada, el segundo limpiará la memoria añadida por el primero botón y por último el tercer botón nos permite consultar el uso de memoria.

Añadimos los eventos Click de cada botón:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <Coding4Fun:MemoryCounter x:Name="memoryCounter" UpdateInterval="250" Foreground="Red"/>
     <StackPanel VerticalAlignment="Center">
          <Button x:Name="btnLoad" Content="Cargar 10MB en Memoria" Click="btnLoadClick"/>
          <Button x:Name="btnClear" Content="Limpiar Memoria" Click="btnClearClick"/>
          <Button x:Name="btnInfo" Content="Ver uso de Memoria" Click="btnInfoClick" Margin="0,150"/>
     </StackPanel>
</Grid>

Creamos una colección de Bytes para cargar en memoria:

List<Byte[]> _memoria;

// Constructor
public MainPage()
{
     InitializeComponent();

     _memoria = new List<byte[]>();
}

En el primer botón añadimos 10MB al uso de memoria. En el segundo, limpiamos la colección y llamamos el recolector de basura:

private void btnLoadClick(object sender, RoutedEventArgs e)
{
     _memoria.Add(new Byte[1024 * 1024 * 10]);
}

private void btnClearClick(object sender, RoutedEventArgs e)
{
     _memoria.Clear();
     GC.Collect();
}

Por último, utilizaremos las propiedades CurrentMemory y PeakMemory del control MemoryCounter para mostrarselas al usuario en un mensaje al pulsar el botón:

private void btnInfoClick(object sender, RoutedEventArgs e)
{
     string mensaje = string.Format("Memoria usada actualmente: {0}Mb" + Environment.NewLine + "Memoria máxima que se ha llegado a utilizar: {1}Mb", memoryCounter.CurrentMemory, memoryCounter.PeakMemory);
     MessageBox.Show(mensaje);
}

Puedes ver en video el ejemplo realizado a continuación:

También puedes descargar el ejemplo realizado:

Nada más en esta entrada. Hemos visto un control bastante interesante y sobretodo muy útil. Os recomiendo que lo probéis. Si os surgen dudas o sugerencias podéis dejarlas en los comentarios.

Más información:

Windows Phone. Control ToggleSwitch.

El control ToggleSwitch permite al usuario  activar o desactivar una opción de manera fácil e intuitiva. Es un control equivalente al control Checkbox. Lo tenemos disponible dentro del Windows Phone Silverlight Toolkit, paquete de controles totalmente gratuito disponible tanto en Codeplex como utilizando Nuget. Ya hablamos de que como instalar y que contenía el Toolkit en la siguiente entrada:

Introducción al Windows Phone Silverlight Toolkit

Para analizar las posibilidades que nos brida el control ToggleSwitch vamos a realizar como de costumbre un ejemplo.

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Tras crear el proyecto lo primero que debemos hacer es agregar la referencia a la librería del Toolkit para tener acceso al control. Para ello agregamos la referencia a la librería Microsoft.Phone.Controls.Toolkit.dll.

Vamos a dividir al ejemplo en tres partes claramente diferenciadas:

  1. Analizaremos las propiedades básicas del control.
  2. Modificaremos su aspecto visual.
  3. Utilizaremos los múltiples eventos que nos facilita.

Para ello, en el XAML de la página principal (MainPage.xaml) añadiremos:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <Button x:Name="btnBasic" Content="Uso básico"/>
          <Button x:Name="btnStyles" Content="Estilos"/>
          <Button x:Name="btnEvents"  Content="Eventos"/>
     </StackPanel>
</Grid>

Simple, hemos añadido tres botones que nos redirigirán a páginas donde analizaremos los puntos anteriores. Vamos a añadir los eventos Click de cada botón:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <Button x:Name="btnBasic" Content="Uso básico" Click="btnBasicClick"/>
          <Button x:Name="btnStyles" Content="Estilos" Click="btnStylesClick"/>
          <Button x:Name="btnEvents"  Content="Eventos" Click="btnEventsClick"/>
     </StackPanel>
</Grid>

Al pulsar sobre cada uno de los botones llevaremos al usuario a una nueva página por lo que necesitamos antes que nada añadir al proyecto las 3 páginas necesarias que utilizaremos. En el ejemplo que podéis descargar al final de la entrada se añadieron 3 páginas llamadas:

  • Basic
  • Styles
  • Events

A continuación, vamos a ver que se hace en cada uno de los botones.

private void btnBasicClick(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/Basic.xaml", UriKind.Relative));
}

private void btnStylesClick(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/Styles.xaml", UriKind.Relative));
}

private void btnEventsClick(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/Events.xaml", UriKind.Relative));
}

Nada fuera de lo común. Utilizamos el servicio de navegación NavigationService para enviar al usuario a la página correspondiente. Puedes ver todo lo relacionado con el servicio de navegación NavigationService en esta entrada.

Para poder utilizar el control ToggleSwitch en nuestra interfaz lo primero que debemos hacer es añadir la referencia a la siguiente librería:

xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"

Nos centramos en la página «Basic.xaml». Añadimos lo siguiente a la interfaz:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel Margin="25">
          <TextBlock Text="Uso básico"/>
          <toolkit:ToggleSwitch x:Name="toggleActivado" Content="Activado" IsChecked="True"/>
          <toolkit:ToggleSwitch x:Name="toggleDesactivado" Content="Desactivado" IsChecked="False" Header="Cabecera"/>
     </StackPanel>
</Grid>

Analizamos que hemos añadido. Hemos añadido dos ToggleSwitch. El control tiene dos estados:

  • Activado
  • Desactivado

Para determinar si el control esta activado o desactivado utilizamos la propiedad IsChecked.

  • IsChecked. Propiedad de dependencia de tipo bool?.

Otras propiedades utilizadas o de interés:

  • Content. Propiedad de dependencia de tipo object. Cabecera del control.
  • Header. Propiedad de dependencia de tipo object. Contenido del control.

Continuamos con la página «Styles.xaml» donde nos centraremos en las posibilidades de personalización del control:

<toolkit:ToggleSwitch Content="Contenido" Header="Cabecera" IsChecked="True" SwitchForeground="Yellow"/>
<toolkit:ToggleSwitch Content="Contenido" Header="Cabecera" IsChecked="True" SwitchForeground="HotPink"/>

Hemos utilizado la propiedad:

  • SwitchForeground. Propiedad de dependencia de tipo Brush. Nos permite elegir el color del ToggleSwitch en su estado activado.
  • Background. Propiedad de dependencia de tipo Brush. Nos permite elegir el color del ToggleSwitch en su estado desactivado.

Continuamos profundizando en las opciones disponibles para modificar la apariencia del control:

<toolkit:ToggleSwitch Content="Contenido" Header="Cabecera" IsChecked="True" Background="DarkGreen" SwitchForeground="LawnGreen">
     <!-- Personalizamos la cabecera -->
     <toolkit:ToggleSwitch.HeaderTemplate>
          <DataTemplate>
               <ContentControl Foreground="Green" Content="{Binding}"/>
          </DataTemplate>
     </toolkit:ToggleSwitch.HeaderTemplate>
     <toolkit:ToggleSwitch.ContentTemplate>
          <DataTemplate>
               <ContentControl FontSize="{StaticResource PhoneFontSizeLarge}" Foreground="OrangeRed" Content="{Binding}"/>
          </DataTemplate>
     </toolkit:ToggleSwitch.ContentTemplate>
</toolkit:ToggleSwitch>

¿Qué hemos hecho?

Fácil, hemos utilizado las propiedades HeaderTemplate y ContentTemplate para modificar el DataTemplate utilizado en la cabecera y el contenido del control:

  • HeaderTemplate. Propiedad de dependencia de tipo DataTemplate. Es el Template utilizado para la cabecera.
  • ContentTemplate. Propiedad de dependencia de tipo DataTemplate. Es el Template utilizado para el contenido.

Por último, aparte de conocer el uso básico del control y como personalizarlo, debemos interaccionar con él. Debemos saber cuando el usuario pulsa sobre él, cuando cambia de estado, etc. Para ello, vamos a utilizar los múltiples eventos que nos facilita el control. Nos centramos en la página «Events.xaml»:

<toolkit:ToggleSwitch x:Name="tEvents" Content="Contenido" Header="Cabecera" IsChecked="True" Checked="tEventsChecked" Unchecked="tEventsUnchecked"/>

Hemos utilizado los eventos:

  • Checked. Se lanza cuando el ToggleSwitch pasa al estado activado.
  • Unchecked. Se lanza cuando el ToggleSwitch para al estado desactivado.
private void tEventsChecked(object sender, RoutedEventArgs e)
{
     tEvents.Content = "Activado";
     MessageBox.Show("Activado");
}

private void tEventsUnchecked(object sender, RoutedEventArgs e)
{
     tEvents.Content = "Desactivado";
     MessageBox.Show("Desactivado");
}

Aparte de los eventos ya vistos, tenemos otros también de interés:

  • Click. Se lanza cada vez que se pulsa el ToggleSwitch.

Puedes ver de un vistazo todo el ejemplo realizado en video a continuación:

También puedes descargar el ejemplo realizado:

Más información:

Windows Phone. Uso de gráficas.

En ocasiones en nuestras aplicaciones tendremos la necesidad de mostrar al usuario cierta información de la manera más directa y sencilla posible de modo que de un solo vistazo el usuario sea capaz de obtener la mayor información posible. A nivel de interfaz tenemos muchísimas opciones muy interesantes sin embargo, un excelente recurso muy utilizado para este tipo de situaciones es el uso de gráficas. Por ejemplo, estamos realizando una aplicación de compra de viviendas. Sería fantástico mostrarle al usuario la información de como ha oscilado el precio de la viviendo en el último trimestre por ejemplo. ¿Como lo hacemos?, ¿Que piensas que sería lo más acertado?. Posiblemente una gráfica de barras u otra similar te haya pasado por la mente.

En esta entrada vamos a aprender como utilizar gráficas en nuestras aplicaciones Windows Phone además de analizar las opciones más interesantes que tenemos a nuestro alcance para ello.

Podemos encontrar el Silverlight Toolkit en Codeplex. La dirección sería:

http://silverlight.codeplex.com

El primero de los enlaces es un archivo de instalación (.msi) que nos instalará los binarios del Toolkit.

EL segundo de los enlaces en un archivo comprimido (.zip) que contiene el código fuente. Aunque no pienses modificar los controles del Toolkit y tal como están disponibles en los binarios te son totalmente válidos, te recomiendo si tienes tiempo echarle un vistazo.

Vamos a crear un proyecto nuevo.

La plantilla seleccionada será “Windows Phone Application” para simplificar al máximo el ejemplo.

Agregamos dentro del Grid principal de la página MainPage.xaml:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <Button x:Name="btnBarChart" Content="Gráfica de Barras"/>
          <Button x:Name="btnPieChart" Content="Gráfica Circular"/>
          <Button x:Name="btnLineChart" Content="Gráfica de Líneas"/>
          <Button x:Name="btnStyleBarChart" Content="Gráfica de Barras - Estilos"/>
     </StackPanel>
</Grid>

Tenemos cuatro botones. Vamos a añadir los eventos Click de cada botón:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <StackPanel>
          <Button x:Name="btnBarChart" Content="Gráfica de Barras" Click="btnBarChart_Click"/>
          <Button x:Name="btnPieChart" Content="Gráfica Circular" Click="btnPieChart_Click"/>
          <Button x:Name="btnLineChart" Content="Gráfica de Líneas" Click="btnLineChart_Click"/>
          <Button x:Name="btnStyleBarChart" Content="Gráfica de Barras - Estilos" Click="btnStyleBarChart_Click"/>
     </StackPanel>
</Grid>

Al pulsar sobre cada uno de los botones llevaremos al usuario a una nueva página por lo que necesitamos antes que nada añadir al proyecto las 4 páginas necesarias que utilizaremos. En el ejemplo que podéis descargar al final de la entrada se añadieron 4 páginas llamadas:

  • BarChart
  • PieChart
  • LineChart
  • StyleBarChart

A continuación, vamos a ver que se hace en cada uno de los botones.

private void btnBarChart_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/BarChart.xaml", UriKind.Relative));
}

private void btnPieChart_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/PieChart.xaml", UriKind.Relative));
}

private void btnLineChart_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/LineChart.xaml", UriKind.Relative));
}

private void btnStyleBarChart_Click(object sender, RoutedEventArgs e)
{
     NavigationService.Navigate(new Uri("/StyleBarChart.xaml", UriKind.Relative));
}

Nada fuera de lo común. Utilizamos el servicio de navegación NavigationService para enviar al usuario a la página correspondiente. Puedes ver todo lo relacionado con el servicio de navegación NavigationService en esta entrada.

Entramos en materia. Lo primero que vamos a necesitar es un objeto donde almacenar la información necesaria. Cada elemento dentro de la gráfica tendrá un valor en el eje X y otro en el eje Y:

public class ChartItem
{
     public string EjeX { get; set; }
     public decimal EjeY { get; set; }
}

Para poder añadir gráficas en nuestra interfaz lo primero que debemos hacer es añadir las referencias a las siguientes librerías:

  • System.Windows.Controls 
  • System.Windows.Controls.DataVisualization.Toolkit

Además, debemos añadir el siguiente espacio de nombres en cada página donde utilicemos gráficas (en la parte superior de nuestro XAML):

xmlns:chart="clr-namespace:System.Windows.Controls.DataVisualization.Charting; assembly=System.Windows.Controls.DataVisualization.Toolkit"

Podremos utilizar los siguientes tipos de gráficas:

  • Area
  • Bar
  • Bubble
  • Column
  • Line
  • Pie Scatter
  • Stacked

Nos centramos en la página «BarChart.xaml». La definición más simple posible (aún sin enlazar con fuente de datos alguna) de una gráfica de barras (BarSeries) es la siguiente:

<chart:Chart>
  <chart:BarSeries />
</chart:Chart>

Ya tenemos el objeto que almacenará la información y la interfaz básica preparada. Vamos a crearnos en el constructor de la clase una colección de objetos ChartItem para poder abastecer de la información necesaria a la interfaz:

public BarChart()
{
InitializeComponent();

     List<ChartItem> data = new List<ChartItem>
     {
          new ChartItem { EjeX = "Prueba 1", EjeY = 50 },
          new ChartItem { EjeX = "Prueba 2", EjeY = 100 },
          new ChartItem { EjeX = "Prueba 3", EjeY = 163.2M }
     };

     ContentPanel.DataContext = data;
}

Veamos como quedaría la interfaz:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <chart:Chart x:Name="barChart" Foreground="LightGray" Title="Ejemplo Título">
     <chart:BarSeries
     ItemsSource="{Binding}"
     Title="Ejemplo Título"
     IndependentValueBinding="{Binding EjeX}"
     DependentValueBinding="{Binding EjeY}"/>
          <chart:Chart.Axes>
               <chart:CategoryAxis Title="Eje Y" Orientation="Y"/>
               <chart:LinearAxis Title="Eje X" Orientation="X" Minimum="0" Maximum="250" Interval="50" ShowGridLines="True"/>
          </chart:Chart.Axes>
     </chart:Chart>
</Grid>

El resultado lo podéis ver en la pantalla superior. Analicemos con más calma lo que acabamos de hacer. Hemos asignado por código el DataContext del Grid que contiene la gráfica a nuestra colección. En la gráfica de barras hacemos binding a la colección de memoria usando su propiedad ItemsSource. Asignamos la propiedad  IndependentValue a EjeX que significa que cada barra correspondiente a la gráfica tendra una entrada de texto con el valor asignado al EjeX junto con la propiedad DependentValuePath a EjeY que mostrará la cantidad almacenada en la propiedad EjeY asigando un ancho determinado a cada barra.

¿Fácil, verdad?

Continuamos con más gráficas diferentes, a continuación, las gráficas circulares (denominados también gráficos de pastel o gráficas de 360 grados). Nos centramos ahora en la página «PieChart.xaml». Al igual que hicimos con el gráfico de barras comenzaremos añadiendo a la interfaz el código mínimo para crear la gráfica circular:

<chart:Chart>
     <chart:PieSeries />
</chart:Chart>

Definimos la interfaz completa de la gráfica circular (PieSeries):

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <chart:Chart x:Name="pieChart" Foreground="LightGray" Title="Ejemplo Título">
          <chart:PieSeries
          ItemsSource="{Binding}"
          Title="Ejemplo Título"
          IndependentValueBinding="{Binding EjeX}"
          DependentValueBinding="{Binding EjeY}"/>
     </chart:Chart>
</Grid>

Al igual que hicimos con el gráfico de barras, en el contructor crearemos una colección en memoria:

public PieChart()
{
     InitializeComponent();

     List<ChartItem> data = new List<ChartItem>
     {
          new ChartItem { EjeX = "Prueba 1", EjeY = 25 },
          new ChartItem { EjeX = "Prueba 2", EjeY = 70 },
          new ChartItem { EjeX = "Prueba 3", EjeY = 203.7M }
     };

     ContentPanel.DataContext = data;
}

Para seguir viendo posibilidades repetiremos la misma acción con una tercera gráfica (página «LineChart.xaml»). En esta ocasión utilizaremos una gráfica de líneas (LineSeries):

<chart:Chart>
     <chart:LineSeries />
</chart:Chart>

Definimos la interfaz:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <chart:Chart x:Name="barChart" Foreground="LightGray" Title="Ejemplo Título">
          <chart:LineSeries
          ItemsSource="{Binding}"
          Title="Ejemplo Título"
          IndependentValueBinding="{Binding EjeX}"
          DependentValueBinding="{Binding EjeY}"/>
          <chart:Chart.Axes>
               <chart:CategoryAxis Title="Eje Y" Orientation="Y"/>
               <chart:LinearAxis Title="Eje X" Orientation="X" Minimum="0" Maximum="250" Interval="50" ShowGridLines="True"/>
          </chart:Chart.Axes>
     </chart:Chart>
</Grid>

De nuevo, en el constructor creamos una colección en memoria que abastecerá a nuestra gráfica:

public LineChart()
{
     InitializeComponent();

     List<ChartItem> data = new List<ChartItem>
     {
          new ChartItem { EjeX = "Prueba 1", EjeY = 35 },
          new ChartItem { EjeX = "Prueba 2", EjeY = 80 },
          new ChartItem { EjeX = "Prueba 3", EjeY = 223.7M }
     };

     ContentPanel.DataContext = data;
}

Lo visto hasta ahora nos demuestra como podemos conseguir de manera rápida y sencilla múltiples gráficas gracias al Toolkit de Silverligth. Sin embargo, la apariencia por defecto de gráficas creadas hasta ahora aunque perfectamente válida podría mejorar. Ese va a ser nuestro objetivo en este último ejemplo. Para ello vamos a crear un estilo para la gráfica que añadiremos en los recursos de la página:

<phone:PhoneApplicationPage.Resources>
</phone:PhoneApplicationPage.Resources>

Creamos un color sólido que utilizaremos para rellenar las barras de nuestra gráfica. Si descargáis el ejemplo, podéis probar distintos colores con suma facilidad modificando el valor de este recurso:

<SolidColorBrush Color="GreenYellow" x:Key="appColor"/>

Comenzamos:

<ControlTemplate x:Key="PhoneChartPortraitTemplate" TargetType="chart:Chart">
     <Grid>
          <Grid.RowDefinitions>
               <RowDefinition Height="Auto"/>
               <RowDefinition Height="*"/>
               <RowDefinition Height="Auto"/>
          </Grid.RowDefinitions>
          <datavis:Title
          Content="{TemplateBinding Title}"
          Style="{TemplateBinding TitleStyle}"/>
          <datavis:Legend x:Name="Legend"
          Grid.Row="2"
          Header="{TemplateBinding LegendTitle}"
          Style="{TemplateBinding LegendStyle}">
               <datavis:Legend.ItemsPanel>
                    <ItemsPanelTemplate>
                         <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
               </datavis:Legend.ItemsPanel>
               <datavis:Legend.Template>
                    <ControlTemplate TargetType="datavis:Legend">
                         <Border
                         Background="{TemplateBinding Background}"
                         BorderBrush="{TemplateBinding BorderBrush}"
                         BorderThickness="{TemplateBinding BorderThickness}"
                         Padding="2">
                         <Grid>
                              <Grid.RowDefinitions>
                                   <RowDefinition Height="Auto" />
                                   <RowDefinition />
                              </Grid.RowDefinitions>
                              <datavis:Title
                              Grid.Row="0"
                              x:Name="HeaderContent"
                              Content="{TemplateBinding Header}"
                              ContentTemplate="{TemplateBinding HeaderTemplate}"
                              Style="{TemplateBinding TitleStyle}"/>
                              <ScrollViewer
                              Grid.Row="1"
                              HorizontalScrollBarVisibility="Auto"
                              VerticalScrollBarVisibility="Disabled"
                              BorderThickness="0"
                              Padding="0"
                              IsTabStop="False">
                                   <ItemsPresenter
                                   x:Name="Items"
                                   Margin="10,0,10,10"/>
                              </ScrollViewer>
                         </Grid>
                         </Border>
                     </ControlTemplate>
                </datavis:Legend.Template>
           </datavis:Legend>
           <chartingprimitives:EdgePanel
           Grid.Column="0"
           Grid.Row="1"
           x:Name="ChartArea"
           Style="{TemplateBinding ChartAreaStyle}">
                <Grid
                Canvas.ZIndex="-1"
                Style="{TemplateBinding PlotAreaStyle}" />
           </chartingprimitives:EdgePanel>
     </Grid>
</ControlTemplate>

Ahora nos centramos en el estilo (en nuestro ejemplo lo hemos llamado PhoneChartStyle):

<Style x:Key="PhoneChartStyle" TargetType="chart:Chart">
     <Setter Property="IsTabStop" Value="False" />
     <Setter Property="BorderThickness" Value="0" />
     <Setter Property="Padding" Value="10" />
     <Setter Property="Palette">
          <Setter.Value>
               <datavis:ResourceDictionaryCollection>
                    <ResourceDictionary>
                         <SolidColorBrush x:Key="Background" Color="Transparent"/>
                         <Style x:Key="DataPointStyle" TargetType="Control">
                              <Setter Property="Background" Value="{StaticResource appColor}" />
                         </Style>
                         <Style x:Key="DataShapeStyle" TargetType="Shape">
                              <Setter Property="Stroke" Value="{StaticResource appColor}" />
                              <Setter Property="StrokeThickness" Value="1" />
                              <Setter Property="StrokeMiterLimit" Value="1" />
                              <Setter Property="Fill" Value="{StaticResource appColor}" />
                         </Style>
                    </ResourceDictionary>
               </datavis:ResourceDictionaryCollection>
          </Setter.Value>
     </Setter>
     <Setter Property="TitleStyle">
          <Setter.Value>
               <Style TargetType="datavis:Title">
                    <Setter Property="HorizontalAlignment" Value="Center"/>
                    <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeExtraExtraLarge}"/>
                    <Setter Property="Margin" Value="5"/>
               </Style>
         </Setter.Value>
     </Setter>
     <Setter Property="LegendStyle">
          <Setter.Value>
               <Style TargetType="datavis:Legend">
                    <Setter Property="HorizontalAlignment" Value="Center"/>
                    <Setter Property="VerticalAlignment" Value="Center"/>
                    <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/>
                    <Setter Property="Margin" Value="5"/>
               </Style>
          </Setter.Value>
     </Setter>
     <Setter Property="ChartAreaStyle">
          <Setter.Value>
               <Style TargetType="Panel">
                    <Setter Property="MinWidth" Value="100" />
                    <Setter Property="MinHeight" Value="75" />
               </Style>
          </Setter.Value>
     </Setter>
     <Setter Property="PlotAreaStyle">
          <Setter.Value>
               <Style TargetType="Grid">
                    <Setter Property="Background" Value="Transparent"/>
               </Style>
          </Setter.Value>
     </Setter>
     <Setter Property="Template" Value="{StaticResource PhoneChartPortraitTemplate}"/>
</Style>

Asignamos el estilo creado a la gráfica de barras:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
     <chart:Chart Style="{StaticResource PhoneChartStyle}" Height="225">
          <chart:Chart.LegendStyle>
               <Style TargetType="datavis:Legend">
                    <Setter Property="Width" Value="0"/>
                    <Setter Property="Height" Value="0"/>
               </Style>
          </chart:Chart.LegendStyle>
          <chart:ColumnSeries x:Name="barSeries"
          ItemsSource="{Binding}"
          DependentValuePath="Eje Y"
          IndependentValuePath="Eje X"
          IndependentValueBinding="{Binding EjeX}"
          DependentValueBinding="{Binding EjeY}"
          Title="Ejemplo Estilos"
          IsSelectionEnabled="True"
          TransitionDuration="0"
          AnimationSequence="Simultaneous">
          </chart:ColumnSeries>
     </chart:Chart>
</Grid>

Para no complicar el ejemplo y centrarnos exclusivamente en el estilo visual, hemos repetido la misma forma de abastecer la gráfica, con datos en memoria:

public StyleBarChart()
{
     InitializeComponent();

     List<ChartItem> data = new List<ChartItem>
     {
          new ChartItem { EjeX = "Prueba 1", EjeY = 35 },
          new ChartItem { EjeX = "Prueba 2", EjeY = 80 },
          new ChartItem { EjeX = "Prueba 3", EjeY = 223.7M }
     };

     ContentPanel.DataContext = data;
}

El resultado conseguido tras trabajar sobre los estilos lo podéis ver en la captura superior. ¿Mejor?

Nota: Todo lo relacionado con plantillas, estilos y la utilización de recursos lo veremos con mucha más calma y detalle en una próxima entrada.

Puedes ver en video el resultado de nuestro ejemplo a continuación:

También, puedes descargar el ejemplo realizado:

Nada más en esta entrada. Recordar simplemente que cualquier tipo de duda o sugerencia la podéis dejar en los comentarios. Espero que lo visto os haya sido útil.

Alternativas

Tenemos múltiples alternativas tanto de pago como gratuitas de gran calidad:

  • Telerik. Atesoran una enorme experiencia a la hora de realizar controles para entornos .NET por lo tanto han logrado un conjunto cada vez más completo de controles para Windows Phone de una enorme calidad y a un precio muy competitivo (99$). Centrandonos en la parte relacionada con gráficas, ofrecen variedad de tipos de gráficas, donde lo más destacable sin duda es el gran rendimiento ofrecido junto a la sencillez para trabajar con datos.
  • Amcharts. Controles para crear gráficas gratuitos (como limitación colocan un enlace a su web en la versión gratuita).
  • Visifire. Muy completo conjunto de gráficas de diferente tipo. A destacar la interactividad que permiten por parte del usuario de manera muy sencilla de implementar junto a animaciones de bella factura. Tienen un coste de 99$.
  • Touch Enabled Graph Control WP7. Interesante proyecto disponible en Codeplex que nos ofrece la posibilidad de crear gráficas (de líneas) donde el usuario puede manipular con los dedos el nivel de zoom, zona visible, etc. Muy interesante.

Más información:

Maromas Digitales: 31 días de Windows Phone | Día #31: Graficando datos