Etiquetado: Silverlight

Tema personalizado en Windows Phone Mango

Vintage Phone Embroidery Hoop ArtEn la versión anterior de Windows Phone 7 crear un tema personalizado para nuestra aplicación era bastante sencillo. Bastaba con copiar el fichero ThemeResource.xaml que se encontraba en la carpeta en %programfiles%\Microsoft SDKs\Windows Phone\v7.0\Design y luego hacíamos un Merge de los diccionarios de recursos.

Según Peter Torr esto se podía hacer debido a un “bug” de Silverlight 3 que en el 4 está solucionado. Fuera o no un bug era bastante útil; en Mango usamos Silveright 4 así que tendremos que trabajar un poco más, pero aún podremos hacerlo. La recomendación de Peter Torr es usar estilos implícitos o bien actualizar los estilos del tema. En Windows Phone Geek han encontrado una manera de utilizar el ThemeResource.xaml, pero se han dejado algún paso, o no han probado a poner el tema del dispositivo/emulador en modo claro (light), así que os voy a contar cómo lo hago yo.

Vamos a combinar las dos técnicas y lo explicado en Windows Phone Geek para ahorrarnos el tedioso trabajo de crear todos los estilos de todos los controles de nuevo.

Creación y aplicación de tema personalizado

1. Copiaremos el fichero ThemeResource.xaml, que ahora lo encontramos en %programfiles%\Microsoft SDKs\Windows Phone\v7.1\Design, a una carpeta de nuestra solución, por ejemplo Themes:

2. Una vez copiado, cambiaremos su BuildAction a Resource para que la carga sea más rápida:

3. Editamos los colores del ThemeResource.xaml que hemos copiado a nuestra solución; podemos, por ejemplo, cambiar el color del Accent a un rojo claro:

<Color x:Key="PhoneAccentColor">#FFFF2828</Color>

4. Ahora, en el App.Xaml.cs creamos un método que nos permita copiar los valores del diccionario de recursos sobre los valores por defecto, tal como proponen en Windows Phone Geek:

private void MergeCustomColors()
{
    var dictionaries = new ResourceDictionary();
    string source = string.Format("/{0};component/Themes/ThemeResources.xaml",
        new System.Reflection.AssemblyName(
        this.GetType().Assembly.FullName).Name);
    var themeStyles = new ResourceDictionary { Source = new Uri(source, UriKind.Relative) };
    dictionaries.MergedDictionaries.Add(themeStyles);

    ResourceDictionary appResources = App.Current.Resources;
    foreach (DictionaryEntry entry in dictionaries.MergedDictionaries[0])
    {
        SolidColorBrush colorBrush = entry.Value as SolidColorBrush;
        SolidColorBrush existingBrush = appResources[entry.Key] as SolidColorBrush;
        if (existingBrush != null && colorBrush != null)
        {
            existingBrush.Color = colorBrush.Color;
        }
    }
}

5. Desde el constructor de App llamamos al método para que se efectúe la copia lo antes posible:

public App()
{
    // Global handler for uncaught exceptions.
    UnhandledException += Application_UnhandledException;

    // Standard Silverlight initialization
    InitializeComponent();

    // Phone-specific initialization
    InitializePhoneApplication();

    //Carga del esquema de colores:
    MergeCustomColors();
...

Si os habéis fijado en el método MergeCustomColors habréis visto que lo único que hacemos es ir actualizando los colores de todos los elementos Brush. El diccionario de recursos es read-only, así que no podemos reasignar los valores, sólo podemos cambiar propiedades de esos valores y en el caso de Color no es posible.
Esto tiene un problema y es que el LayoutRoot tiene el color predefinido a Transparent y toma el color de fondo del ApplicationFrame, que en lugar de utilizar un Brush utiliza directamente un Color.

Si ejecutamos nuestra aplicación en modo claro no veremos casi nada:

6. Para resolver el problema del fondo no nos quedará más remedio que cambiar el color de fondo para toda la aplicación. Podríamos ir pantalla por pantalla y cambiar el color de fondo de cada LayoutRoot a negro, pero no nos hará falta. Gracias a los estilos implícitos nos bastará con cambiar el color en el App.Xaml para el PhoneApplicationFrame:

<!--Application Resources-->
<Application.Resources>
    <Style TargetType="phone:PhoneApplicationFrame">
        <Setter Property="Background" Value="Black"/>
    </Style>
</Application.Resources>

Así conseguiremos ver todo el contenido correctamente.

Últimos retoques

Ahora que ya vemos correctamente nuestra aplicación en los colores que nosotros deseamos podemos dar un poco más de coherencia al tema si cambiamos también el color del ApplicationBar. Como no es un control no podremos controlar su aspecto con los estilos implícitos (o por lo menos yo no he sabido), así que o bien usamos una barra para toda la aplicación en el Application.Resources o tendremos que cambiar los colores en cada página donde tengamos una barra:

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True" 
               BackgroundColor="Black" ForegroundColor="White">
        ...

También se puede esconder la barra de sistema, pues en modo claro aparecerá también de color blanco, aunque no es recomendable pues a muchos usuarios les gusta saber qué hora es mientras usan la aplicación.
Para esconderla hay que editar también cada página y cambiar el valor shell:SystemTray.IsVisible a False.

Para probar con las nuevas maneras de cambiar los estilos es necesario utilizar el SDK7.1 de Windows Phone

Espero que os sirva de utilidad y si encontráis una forma mejor de hacerlo ¡compartid! 😀

Anuncios

Usar el micrófono de Windows Phone 7 desde Silverlight

Descarga el código de ejemplo aquí: WindowsPhoneMicrophoneSL.zip.
(Nueva versión corregida)

microphone
Hace unos meses escribí un artículo sobre cómo grabar un WAV con el micrófono del Windows Phone 7. En él explicaba cómo utilizar las clases de XNA desde Silverlight para poder leer la señal del micrófono y algún truco necesario para crear el archivo WAV.

Como sabréis ya ha salido la nueva versión Windows Phone 7.5 (AKA Mango) junto con el nuevo SDK 7.1.
Ahora ya podemos grabar la señal del micrófono desde Silverlight sin necesidad de usar XNA. Ya tenemos acceso a las clases de Silverlight 4, así podremos utilizar un AudioSink para poder grabar audio.

Para que funcione el micrófono en Silverlight necesitaremos habilitar el tag <Capability Name=“ID_CAP_CAMERA” />. He añadido una solicitud en UserVoice para que en próximas versiones no sea necesario y baste con el tag ID_CAP_MICROPHONE.

El código

La diferencia con el artículo anterior está en la clase MicrophoneWavRecorder, que ahora hereda de la clase AudioSink:

public sealed class MicrophoneWavRecorder : AudioSink
{
    private AudioFormat _format;
...

En el constructor solicitaremos acceso al dispositivo de captura y seleccionaremos el formato que más nos convenga utilizar, en nuestro caso 16 bits y algo mejor que 11Khz

Edit: por ahora no podemos seleccionar el formato, pidamos lo que pidamos el micrófono seguirá capturando a 16 bits Mono 16Khz, así que mejor no indicamos nada en ese punto.

public MicrophoneWavRecorder()
{
    if (!CaptureDeviceConfiguration.AllowedDeviceAccess)
        CaptureDeviceConfiguration.RequestDeviceAccess();

    AudioCaptureDevice device =
        CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice();
    if (device == null)
    {
        throw new Exception("Can't get capture device!");
    }

    //Por ahora no podemos seleccionar el formato, esperemos que más adelante si...
//    _format = (from af in device.SupportedFormats
//              where af.BitsPerSample == 16 && af.SamplesPerSecond > 11025
//              select af).First();

//    device.DesiredFormat = _format;
//    device.AudioFrameSize = 100;

    this.CaptureSource = new CaptureSource();
    this.CaptureSource.AudioCaptureDevice = device;
}

Como no hemos podido asignar el formato de audio preferido tendremos que esperar que el dispositivo nos indique qué formato ha elegido él, para esto tenemos el método OnFormatChange con el que podremos capturar la información:

protected override void OnFormatChange(AudioFormat audioFormat)
{
    //capturamos el formato
    //en windows phone 7.1 es: mono 16 bit 16000 Hz
    _format = audioFormat;
}

Ahora ya sólo nos queda capturar el audio cada vez que se llena el buffer:

protected override void OnSamples(long sampleTime,
    long sampleDuration, byte[] sampleData)
{
    _bwOutput.Write(sampleData, 0, sampleData.Length);
    _rawDataLength += sampleData.Length;
}

Una de las ventajas que tenemos usando la clase AudioSink es que tenemos acceso al formato real y ya no tenemos que escribir los datos de la cabecera con valores fijos como hacíamos en el ejemplo anterior en el método WriteHeader, tendremos que ir con cuidado pues el formato de audio no lo sabemos en la primera escritura, pero lo tendremos cuando cerremos el audio:

if (_format != null)
{
    // Channel Numbers (Always 0x01=Mono, 0x02=Stereo)
    _bwOutput.Write((ushort)_format.Channels);

    // Sample Rate (Binary, in Hz)
    _bwOutput.Write((uint)this._format.SamplesPerSecond);

    // Bytes Per Second
    _bwOutput.Write((uint)(_format.BitsPerSample *
        _format.SamplesPerSecond * _format.Channels / 8));

    // Bytes Per Sample: 1=8 bit Mono,
    // 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo
    _bwOutput.Write((ushort)(_format.BitsPerSample
        * _format.Channels / 8));

    // Bits Per Sample
    _bwOutput.Write((ushort)_format.BitsPerSample);
}

¿Qué voy a necesitar?

  1. Un dispositivo: aquí no os puedo ayudar mucho, en el emulador no funciona el micrófono, aunque podéis poner otra solicitud en UserVoice.
  2. El SDK 7.1 que puedes encontrar en 9 idiomas, incluido el castellano: Windows Phone SDK 7.1
  3. Descarga el código completo de ejemplo aquí: WindowsPhoneMicrophoneSL.zip

Las redes sociales y nuestras aplicaciones de Windows Phone 7.1

social media
Hasta ahora, añadir recursos de redes sociales en nuestras aplicaciones era algo tedioso, no sólo para nosotros, sino también para los usuarios.

Por nuestra parte teníamos que o bien programar un conector para cada red social, con la consecuencia de que además debíamos crear un sistema para guardar las credenciales usadas, solicitar una clave para la api de cada red social (facebook, twitter, etc), o bien hacer una “chapucilla” usando una URL que nos redirigiera a la red social usando una WebBrowserTask. Las soluciones de terceros no nos solucionan demasiado la vida.

Del lado del usuario también se complicaba bastante, pues la primera solución implicaba la introducción los datos de su cuenta en cada aplicación, complicando en exceso el mantenimiento en múltiples aplicaciones. La segunda solución es aún peor pues cada vez que se quiere compartir algo se salta a un navegador donde hay que introducir las credenciales.

Afortunadamente, la filosofía de hubs de Windows Phone 7 va a simplificar muchísimo esta tarea tan natural en el ser humano de compartir lo que sea que estemos haciendo. Como dicen en los anuncios de WP7: la gente tiene amigos, no aplicaciones.

¿Cómo se soluciona esto? Pues integrando las redes sociales en el sistema operativo del móvil. Gracias a esto y a una nueva Task que incluye el teléfono, compartir cualquier cosa desde nuestra aplicación de WP7 va a ser tan complicado como llamar a la ShareLinkask:

new Microsoft.Phone.Tasks.ShareLinkTask()
{
Title="Comparto link!",
Message="Aquí tenéis mi link compartido...",
LinkUri=new Uri("https://jmservera.wordpress.com")
}.Show();

Y si sólo es un mensaje es aún más fácil, basta con la ShareStatusTask:

new Microsoft.Phone.Tasks.ShareStatusTask(){
Status="Estoy compartiendo!"}.Show();

Pasadlo bien… y compartid! 😀

Más recursos útiles para Windows Phone 7

Microsoft Patterns & PracticesHace unos días hicimos unos laboratorios de Windows Azure para Windows Phone. Para los que os picó el gusanillo del cloud, los chicos de Patterns & Practices han creado una guía llena de documentos y ejemplos que nos ayudarán a hacer aplicaciones de WP7 con tecnología cloud. Se puede descargar del codeplex o podemos leerla online en el msdn.
Es una guía muy interesante aunque no vayamos a usar Azure, pues ya sabéis que los servicios WCF que hacemos en Azure son casi los mismos que los que podemos hacer en casa.

Y para compensar tanto post de programación hoy os pongo un enlace para para diseñadores y “devigners”, la escuela de diseño de Microsoft incluye un montón de tutoriales nuevos para Windows Phone 7:

Tutoriales de Windows Phone 7 para diseñadores

http://www.microsoft.com/design/toolbox/school/tutorials.aspx

¡Que los disfrutéis!

¿Cómo usar las propiedades de un UserControl desde su propio XAML?

En ocasiones veo Bindings… y no puedo dejar de usarlos. El caso es que estaba leyendo algunos ejemplos de databindings y me he topado con uno que no funcionaba correctamente. El ejemplo intentaba explicar cómo usar las dependency properties definidas en un UserControl directamente desde el XAML del mismo, ocupa cuatro páginas y usa un truco para poder acceder: dar un nombre al UserControl en la definición del mismo, algo así como:

<UserControl x:Class="MyLibrary.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Name="this">

Entonces en el código podríamos usar la palabra “this” para hacer referencia al control y acceder a sus propiedades, así si tuvieramos una propiedad Label definida como DependencyProperty:

public static readonly DependencyProperty LabelProperty =
   DependencyProperty.Register("Label", typeof(string), typeof(MyUserControl),
   new PropertyMetadata("myLabel"));

public string Label
{
    get{ return (string) this.GetValue(LabelProperty);}
    set { this.SetValue(LabelProperty, value); }
}

Teóricamente podríamos usarla así:

        <TextBlock Height="Auto"
                   Text="{Binding ElementName=this, Path=Label}"
                   HorizontalAlignment="Center" VerticalAlignment="Center" />

Y al principio nos parecerá que funciona, hasta que se nos ocurra dar un nombre a nuestro control cuando lo usamos dentro de un contenedor:

        <my:MyUserControl x:Name="userControl1" .. />

Entonces se habrá acabado la magia, nuestro control ya no leerá la propiedad porque a alguien le dió por cambiarle el nombre.

Buscando por ahí he visto alguna solución alternativa, como por ejemplo crear el binding por código porque no encuentran la manera de definirlo bien en el XAML, pero hay una manera, lo sorprendente de todo esto es que la pista me la ha dado el mismo libro que contenía el ejemplo anterior, es tan sencillo como usar el Parent del elemento LayoutRoot, (o del contenedor principal del control que hayamos puesto):

<UserControl x:Class="MyLibrary.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <TextBlock Name="label" Height="Auto" Margin="0"
                   Text="{Binding Path=Parent.Label, ElementName=LayoutRoot}"
                   HorizontalAlignment="Center" VerticalAlignment="Center" />
...

Así hemos conseguido usar la propiedad Label desde el TextBlock de nuestro UserControl sin tener que escribir código que se encargue de manejar los cambios, que para eso tenemos los Bindings.

Predeterminar el teclado numérico en WP7

Ayer nos preguntasteis si era posible predeterminar el teclado numérico sobre un control de texto. No sólo es posible sino que es muy fácil. Antiguamente se hacía con el método SetInputMode, que debíamos llamar por código para cada control. En Silverlight podemos declarar cómo queremos que sea el InputScope directamente desde el diseñador:

<TextBox Height="68" Name="textBox1" Text="" VerticalAlignment="Top" Margin="67,186,0,0"
         InputScope="Number">
</TextBox>

Esto hará aparecer automáticamente el teclado numérico cuando nuestro cuadro de texto reciba el foco.

 

Si sacamos la propiedad InputScope podremos ver los valores con intellisense:

InputScopeName toma los valores de la enumeración InputScopeNameValue.

El InputScope nos ayudará a mostrar el teclado más adecuado en cada momento. Por ejemplo, el valor EmailSmtpAddress nos mostrará un teclado con el símbolo @ y un atajo al sufijo .com para poder escribir más rápidamente una dirección de correo electrónico.

En ningún caso InputScope validará que los datos introducidos sean del tipo correcto.

Para tener un control en el que sólo se puedan introducir valores numéricos hay que crear métodos de validación o bien usar un control de terceros. Por ahora no hay demasiados disponibles, Telerik está desarrollando un set de controles aún en beta que contienen un control numérico.

WP7: Canal de noticias (episodio 3)

Este artículo fue publicado en www.cristalab.com, para ver el contenido completo sigue el siguiente enlace.

Este es un artículo de una serie dedicada al desarrollo de aplicaciones para Windows Phone 7 en Silverlight. Como primer ejemplo estamos creando una aplicación sencilla de representación de datos y la iremos refinando en sucesivos episodios:

  1. Aplicación base: representación de datos y visionado de vídeos.
  2. Mejoras visuales y navegación
  3. Guardar el estado (tombstoning)
  4. Mejoras de rendimiento
  5. Interacción con otros servicios
  6. Preparación para el Marketplace

Hoy toca el episodio 3Guardar el estado, donde aprenderemos cómo hacer que nuestra aplicación no pierda los datos cuando es desactivada.

Sigue leyendo en Cristalab.

WP7: Canal de noticias (episodio 1)

Este artículo fue publicado en www.cristalab.com, para ver el contenido completo sigue el siguiente enlace.

Descarga el código de ejemplo

Este es el primer artículo de una serie dedicada al desarrollo de aplicaciones para Windows Phone 7 en Silverlight. Como primer ejemplo vamos a crear una aplicación sencilla de representación de datos y la iremos refinando en sucesivos episodios:

  1. Aplicación base: representación de datos y visionado de vídeos.
  2. Mejoras visuales y navegación
  3. Guardar el estado (tombstoning)
  4. Mejoras de rendimiento
  5. Interacción con otros servicios
  6. Preparación para el Marketplace

Veremos lo fácil que nos va a resultar realizar la primera versión mientras que el aspecto de la aplicación va a resultar profesional desde el primer momento. Una característica común de las aplicaciones WP7.

Sigue leyendo en Cristalab.

Hago mis propios programas… y juegos!

Parece que ese infame anuncio de un curso de programación dejó huella en alguien del equipo de Popfly, y ahí tenéis el resultado:

Un creador de juegos online basado en Silverlight. Podéis ver más en el blog de Jason Zander.

Silverlight 2.0

Scott Guthrie acaba de anunciar en su blog (entre otras muchas cosas) el lanzamiento de la primera beta de Silverlight 2.0 a principios del año que viene.
El “truco” reside en que estaban añadiendo tantas características nuevas a 1.1 que han decidido cambiarle el número de versión.
Las mejoras son: uso de un subconjunto de las características del WPF UI compatibles con éste, más de 20 controles ricos que incluyen textbox, checkbox, radiobutton, grid, tabcontrol, progressbar y un largo etcétera, manejo en red de REST, POX, RSS, and WS* y conexiones cross-domain (por fin!), además de las funcionalidades de las librerías base de .Net (colecciones, generics,…) e incluso LINQ to XML.
¡Ya no tendremos excusa para no usarlo!