Mixing Style Setters and Bindings in WinRT

To say the truth, this caught me by surprise. When I stumbled upon the fact that in WinRT you cannot just assign a Binding to a Property Setter. Surprisingly enough, this is not supported.

So no <Setter Property=”Blah” Value=”{Binding Path=Bleh}” />

But some smart dudes have coined a method to make it work. At least, the did in Silverlight 4 (the version 5 already supports Bindings in those Setters). Later, the trick came to WinRT… they say WinRT was forked from Silverlight 4. Now a lot of things make sense :S

What’s the trick? Using Attached Properties.

It uses a helper class to wire up everything. It may seem ugly at first sight, but while WinRT is so restrictive (and much more for a WPF developer like me), it’s the only way I can think of that is more of less XAML oriented.

This is the helper class (WinRT, of course):

// Copyright (C) Microsoft Corporation. All Rights Reserved.
// This code released under the terms of the Microsoft Public License
// (Ms-PL, http://opensource.org/licenses/ms-pl.html).

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Markup;

namespace Delay
{
    /// <summary>
    /// Class that implements a workaround for a Silverlight XAML parser
    /// limitation that prevents the following syntax from working:
    ///    &lt;Setter Property="IsSelected" Value="{Binding IsSelected}"/&gt;.
    /// </summary>
    [ContentProperty(Name = "Values")]
    public class SetterValueBindingHelper
    {
        /// <summary>
        /// Gets or sets an optional type parameter used to specify the type
        /// of an attached DependencyProperty as an assembly-qualified name,
        /// full name, or short name.
        /// </summary>
        [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
            Justification = "Unambiguous in XAML.")]
        public string Type { get; set; }

        /// <summary>
        /// Gets or sets a property name for the normal/attached
        /// DependencyProperty on which to set the Binding.
        /// </summary>
        public string Property { get; set; }

        /// <summary>
        /// Gets or sets a Binding to set on the specified property.
        /// </summary>
        public Binding Binding { get; set; }

        /// <summary>
        /// Gets a Collection of SetterValueBindingHelper instances to apply
        /// to the target element.
        /// </summary>
        /// <remarks>
        /// Used when multiple Bindings need to be applied to the same element.
        /// </remarks>
        public Collection<SetterValueBindingHelper> Values
        {
            get
            {
                // Defer creating collection until needed
                if (null == _values)
                {
                    _values = new Collection<SetterValueBindingHelper>();
                }
                return _values;
            }
        }

        /// <summary>
        /// Backing store for the Values property.
        /// </summary>
        private Collection<SetterValueBindingHelper> _values;

        /// <summary>
        /// Gets the value of the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="element">Element for which to get the property.</param>
        /// <returns>Value of PropertyBinding attached DependencyProperty.</returns>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "SetBinding is only available on FrameworkElement.")]
        public static SetterValueBindingHelper GetPropertyBinding(FrameworkElement element)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            return (SetterValueBindingHelper)element.GetValue(PropertyBindingProperty);
        }

        /// <summary>
        /// Sets the value of the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="element">Element on which to set the property.</param>
        /// <param name="value">Value forPropertyBinding attached DependencyProperty.</param>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "SetBinding is only available on FrameworkElement.")]
        public static void SetPropertyBinding(FrameworkElement element, SetterValueBindingHelper value)
        {
            if (null == element)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(PropertyBindingProperty, value);
        }

        /// <summary>
        /// PropertyBinding attached DependencyProperty.
        /// </summary>
        public static readonly DependencyProperty PropertyBindingProperty =
            DependencyProperty.RegisterAttached(
                "PropertyBinding",
                typeof(SetterValueBindingHelper),
                typeof(SetterValueBindingHelper),
                new PropertyMetadata(null, OnPropertyBindingPropertyChanged));

        /// <summary>
        /// Change handler for the PropertyBinding attached DependencyProperty.
        /// </summary>
        /// <param name="d">Object on which the property was changed.</param>
        /// <param name="e">Property change arguments.</param>
        private static void OnPropertyBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // Get/validate parameters
            var element = (FrameworkElement)d;
            var item = (SetterValueBindingHelper)e.NewValue;

            if (null != item)
            {
                // Item value present
                if ((null == item.Values) || (0 == item.Values.Count))
                {
                    // No children; apply the relevant binding
                    ApplyBinding(element, item);
                }
                else
                {
                    // Apply the bindings of each child
                    foreach (var child in item.Values)
                    {
                        if ((null != item.Property) || (null != item.Binding))
                        {
                            throw new ArgumentException(
                                "A SetterValueBindingHelper with Values may not have its Property or Binding set.");
                        }
                        if (0 != child.Values.Count)
                        {
                            throw new ArgumentException(
                                "Values of a SetterValueBindingHelper may not have Values themselves.");
                        }
                        ApplyBinding(element, child);
                    }
                }
            }
        }

        /// <summary>
        /// Applies the Binding represented by the SetterValueBindingHelper.
        /// </summary>
        /// <param name="element">Element to apply the Binding to.</param>
        /// <param name="item">SetterValueBindingHelper representing the Binding.</param>
        private static void ApplyBinding(FrameworkElement element, SetterValueBindingHelper item)
        {
            if ((null == item.Property) || (null == item.Binding))
            {
                throw new ArgumentException(
                    "SetterValueBindingHelper's Property and Binding must both be set to non-null values.");
            }

            // Get the type on which to set the Binding
            TypeInfo type = null;
            if (null == item.Type)
            {
                // No type specified; setting for the specified element
                type = element.GetType().GetTypeInfo();
            }
            else
            {
                // Try to get the type from the type system
                type = System.Type.GetType(item.Type).GetTypeInfo();
                if (null == type)
                {
                    // Search for the type in the list of assemblies
                    foreach (var assembly in AssembliesToSearch)
                    {
                        // Match on short or full name
                        type = assembly.DefinedTypes
                            .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
                            .FirstOrDefault();
                        if (null != type)
                        {
                            // Found; done searching
                            break;
                        }
                    }
                    if (null == type)
                    {
                        // Unable to find the requested type anywhere
                        throw new ArgumentException(
                            string.Format(
                                CultureInfo.CurrentCulture,
                                "Unable to access type \"{0}\". Try using an assembly qualified type name.",
                                item.Type));
                    }
                }
            }

            // Get the DependencyProperty for which to set the Binding
            DependencyProperty property = null;

            var allProperties = type.GetAllProperties();
            var field = allProperties.FirstOrDefault(info => info.Name.Equals(item.Property + "Property"));

            if (null != field)
            {
                property = field.GetValue(null) as DependencyProperty;
            }
            if (null == property)
            {
                // Unable to find the requsted property
                throw new ArgumentException(
                    string.Format(
                        CultureInfo.CurrentCulture,
                        "Unable to access DependencyProperty \"{0}\" on type \"{1}\".",
                        item.Property,
                        type.Name));
            }

            // Set the specified Binding on the specified property
            element.SetBinding(property, item.Binding);
        }

        /// <summary>
        /// Gets a sequence of assemblies to search for the provided type name.
        /// </summary>
        private static IEnumerable<Assembly> AssembliesToSearch
        {
            get
            {
                // Start with the System.Windows assembly (home of all core controls)
                yield return typeof(Control).GetTypeInfo().Assembly;

#if SILVERLIGHT && !WINDOWS_PHONE
                // Fall back by trying each of the assemblies in the Deployment's Parts list
                foreach (var part in Deployment.Current.Parts)
                {
                    var streamResourceInfo = Application.GetResourceStream(
                        new Uri(part.Source, UriKind.Relative));
                    using (var stream = streamResourceInfo.Stream)
                    {
                        yield return part.Load(stream);
                    }
                }
#endif
            }
        }

    }

    public static class ReflectionExtensions
    {
        public static IEnumerable<PropertyInfo> GetAllProperties(this TypeInfo type)
        {
            var list = type.DeclaredProperties.ToList();

            var subtype = type.BaseType;
            if (subtype != null)
                list.AddRange(subtype.GetTypeInfo().GetAllProperties());

            return list.ToArray();
        }
    }
}

And the other important thing is to know how to use it inside XAML:

 <Button
            Grid.Column="1"
            Grid.ColumnSpan="2"
            DataContext="Coco">
            <Button.Style>
                <Style TargetType="Button">
                    <!-- Equivalent WPF syntax:
                    <Setter Property="Content" Value="{Binding}"/> -->
                    <Setter Property="delay:SetterValueBindingHelper.PropertyBinding">
                        <Setter.Value>
                            <delay:SetterValueBindingHelper
                                Property="Content"
                                Binding="{Binding}"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Button.Style>
        </Button>

Another example from my Project VisualDesigner:

   <designSurface:DesignSurface Background="PowderBlue"
                                     ItemTemplateSelector="{StaticResource TypedTemplateSelector}"
                                     ItemsSource="{Binding  Items}" Grid.Row="1">
            <!--<designSurface:DesignSurface.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </designSurface:DesignSurface.ItemsPanel>-->
            <designSurface:DesignSurface.ItemContainerStyle>
                <Style TargetType="winRt:CanvasItemControl">
                    <Setter Property="delay:SetterValueBindingHelper.PropertyBinding">
                        <Setter.Value>
                            <delay:SetterValueBindingHelper>
                                <delay:SetterValueBindingHelper
                                    Type="Canvas"
                                    Property="Left"
                                    Binding="{Binding Left, Mode=TwoWay}" />
                                <delay:SetterValueBindingHelper
                                    Type="Canvas"
                                    Property="Top"
                                    Binding="{Binding Top, Mode=TwoWay}" />
                                <delay:SetterValueBindingHelper
                                    Property="Width"
                                    Binding="{Binding Width, Mode=TwoWay}" />
                                <delay:SetterValueBindingHelper
                                    Property="Height"
                                    Binding="{Binding Height, Mode=TwoWay}" />
                            </delay:SetterValueBindingHelper>
                        </Setter.Value>
                    </Setter>
                </Style>
            </designSurface:DesignSurface.ItemContainerStyle>
        </designSurface:DesignSurface>

Finally, I would like to give thanks to Mark Smith (@marksm in Twitter), for pointing me out some interesting posts to the solution. He has supported me from the beginning. These were the links that he gave me 🙂

Thanks to them, too!

Hard things with Expressions (property selector)

It has been hard at least for me.

This method applies the value to the specified property of the target items:

 private static void SetPropertyToAll<T, TValue>(IEnumerable<T> targetItems, Expression<Func<T, TValue>> propertyExpression, TValue value)
        {
            if (propertyExpression.Body is MemberExpression)
            {
                var memberExpression = (MemberExpression)propertyExpression.Body;

                var propInfo = (PropertyInfo)memberExpression.Member;

                foreach (var item in targetItems)
                {
                    propInfo.SetValue(item, value, null);
                }
            }
            else
            {
                throw new InvalidOperationException("See link to the Stack Overflow question below!!");
            }
        }

And this is the original question in which I found all the information I needed in order for this to work like fine cinnamon 😉

http://stackoverflow.com/a/2789606/1025407

Good luck, Expression Boy!

Flashear Nokia Lumia 920

EDICIÓN: Gracias a nuestro amigo Juanito Limaña, aquí están las instrucciones completas.

  1. Descargar el Nokia Suite Care: http://www.mediafire.com/download/yqm3h1jjj6ref7p/Nokia_Care_Suite_PST_5.0_2012.51.4.4.rar
  2. Instalarlo, luego ejecutáis NOKIA SUITE CARE (en el escritorio) y le dais doble click en Product Support Tool for Store 5.0
    En donde pone Sign in to: Seleccionar CareSuite External.
  3. Conectar el Teléfono, y en las pestañas de arriba selección Tool/ Firmware Download
    Se te abre una ventana y en el rectángulo en blanco ponéis este código 059R2R8 click en CHECK ONLINE Y DOWNLOAD
  4. Una vez descargado, Clic en Programming, y clic en RECOVERY
  5. Le das Clic a START, te saldrá un mensaje de error, Desconecta el teléfono (Apágalo) y dale OK
  6. Clic otra vez en START
  7. Verás que te dice que tienes que mantener presionado las teclas el VOLUMEN ABAJO y EL BOTON DE ENCENDIDO
    y sentirás una pequeña Vibración, en ese momento Conecta el USB y le das a START
  8. En la pantalla de tu PC veras un mensaje que dice Rebooting, y luego te saldrá un mensaje le das OK
  9. Y empieza el flasheo y la actualización a AMBER la pantalla de tu tlefono esta de color Rojizo y una barra de progreso de la actualización
    NO TOQUES Y NO HAGAS NADA espera a que termine que como mucho tarde 3 minutos, luego Cuando termine.
  10. Verás en la Pantalla Successful (y ya esta todo listo!) A disfrutar

* Antes de nada Carga al 100% la Batería,
** Esta actualización y flash es limpia osea sin logos de operador.

A disfrutarlo, y gracias por los comentarios, saludos.

Instrucciones antiguas

Flipa, colega. Hoy se me ocurre flashear la actualización Amber (GDR2) y después de un buen rato dándome este error: “Unable to get error message”, me encuentro en un foro alguien al que le pasaba lo mismo. Resulta que:

  1. En el móvil he pulsado los botones [Bajar Volumen] + [POWER] hasta que ha salido el logo de Nokia.
  2. Acto seguido, le he pulsado el botón de Start en el “Product Support Tool For Store”.
  3. Ya no ha salido ningún error y se ha puesto a flashear como un demonio.

Aquí un ejemplo de captura del final de proceso:

Capture

¡La de truqueles que tiene esto de flashear y el miedo que se pasa a veces! Y todo por no esperar a la actualización OTA.

Más información:

  • Código de producto: 059R2R8 
  • Modelo de teléfono: RM-821
  • Variante: RM-821 VAR EU ES CV BLACK (Unbranded)
  • Firmware: 3047.0000.1326.2004_046
  • Archivos de flash: RM821_059R2R8_3047.0000.1326.2004_046

Leyendo imágenes desde streams

Imagina que te da por leer un array de bytes que sabes que es un PNG. Vale, estupendo. Ahora pones todo lo que sabes sobre la mesa y dices “esto está tirado, tío”. Que sí, que me lo creo, pero hay una cosa que fijo no sabes si cuando decodificas la imagen la estás leyendo desde un flujo:

Si el decoder de la imagen lo creas con la opción de BitmapCacheOption Default, la carga de la imagen será “lazy”, o sea, perezosa. No se cargará inmediatamente y si, como yo, eres un programador que suele cerrar los flujos cuando ya no los necesita (stream.Close o con un bloque “using”), en el momento en que va a cargar la imagen porque la necesita, el flujo está cerrado y la imagen no carga ni a la de 3.

En el ejemplo está bien claro, ¡majuelo!

 public static ImageSource FromArray(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream(bytes))
            {
                var decoder = new PngBitmapDecoder(memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                BitmapSource bitmapFrame = decoder.Frames[0];                            
                return bitmapFrame;
            }
        }

Observa el BitmapCacheOption.OnLoad Winking smile Ahí flipamos en 16,7 millones de colores. NECESARIO SI EL STREAM SE CIERRAAAAAAAAA.

Pon guapo tu XAML con namespaces

En tus ensamblados:

Para definir un espacio de nombres:

[assembly: XmlnsDefinition("http://www.sample.com/schemas/wpf/project/namespace", "UI")]

Para definir el prefijo al que asociar los espacios de nombres del ensamblado:

[assembly: XmlnsPrefix("http://www.sample.com/schemas/wpf/project/namespace", "myprefix")]

Y así es como se mezclan los espacios de nombres en un mismo prefijo ;D

Recurso estático en XAML a partir de un Singleton

No he encontrado manera mejor de hacerlo que esta:

<x:Static Member="common:ResourcesUIService.Instance" x:Key="ResourcesUIService"  />

Con esta sencilla nomenclatura y si has diseñado bien tu singleton, la extensión Static lo dará todísimo y tendrás acceso desde tu XAML favorito a la instancia con cosas tales como Bindings (que es de lo que se trata, ¡jojojo!).

Ponlo a prueba y nota su aroma.

Herencia en Dependency Properties

El temita jodido del otro día, cuando estuve dándole caña a las propiedades de dependencia heredables (FrameworkPropertyMetadata.Inherits)

Yo tenía una magggnífica propiedad llamada Relleno compuesta de:

  • Color (Color)
  • Id de patrón (int)
  • Tint (double)

Esta propiedad se hereda por por lo que los elementos del árbol visual. Hasta ahí, bien.

El asunto se puso marrón oscuro cuando en un hijo me daba por modificar el miembro “Color”. ¿Qué ocurría?

Resultado esperado:

image

Resultado obtenido:

image

La razón es que el Relleno es una instancia compartida entre todos los elementos de la jerarquía. El del padre es la misma instancia que el del hijo, por lo que si modificamos el Color al Relleno, efectivamente, ¡estamos cambiando la misma cosa!

¿Qué hemos de hacer? Pues la cosa quizá no es muy sencilla, pero lo primero de todo es que tenemos que tener claro qué es un Value-Object, es decir, cuándo el valor de una cosa determina qué cosa es.

Esto depende de la semántica que queramos darle. Para mí, si tengo una instancia de Relleno y le cambio el Color, serán dos patrones distintos, por lo que no sería admisible cambiar el Color, sino que debería otra crearme otra instancia de Relleno distinta (Relleno debería ser inmutable). De estas manera, 2 instancias distintas nos darían el resultado deseado.

Espero que la monserga te haya servido, pequeño saltamontes.

Hala, a echarte un Call Of Duty, que ya es escrito bastante, mamoncete.