Blend for Visual Studio 2012 by Example: Beginner’s Guide Discount Offer

I recently published a review of Pack Publishing’s new book, Blend for Visual Studio 2012 by Example – Beginner’s Guide. Well, guess what, Pack is offering a 50% off discount if you buy it between 17th and 25th of September! You just need to use this discount code:

Banner

Keep in mind that this code is only valid for this ebook!

So, what are you waiting for? Winking smile

Silverlight Transform Markup Extension

<ComboBox ItemsSource="{Binding ItemsSource, ElementName=MyDataSource}, Converter={StaticResource MyConverter}}" Width="100" Height="30"/>

<ComboBox ItemsSource="{Binding ItemsSource, ElementName=MyDataSource}, Converter={StaticResource MyConverter}}" Width="100" Height="30"/>

Did you ever have one of those situations where you need to apply a data source to a control, but also convert the each of the data source elements?

Normally we set the data source to the DataContext or ItemsSource property and add an item template where we specify the converter, but sometimes this can’t be done this way, for one reason or the other. So, I worked out a simple solution: the TransformedItemSource! What it does is, it allows us to specify a converter for each of the source values in the data source collection, not the data source as a whole.

Here it is:

public class TransformedItemSource : DependencyObject, IEnumerable

{

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(TransformedItemSource), new PropertyMetadata(null));

    public static readonly DependencyProperty ConverterProperty = DependencyProperty.Register("Converter", typeof(IValueConverter), typeof(TransformedItemSource), new PropertyMetadata(null));

    public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register("Parameter", typeof(Object), typeof(TransformedItemSource), new PropertyMetadata(null));

    public static readonly DependencyProperty CultureProperty = DependencyProperty.Register("Culture", typeof(CultureInfo), typeof(TransformedItemSource), new PropertyMetadata(CultureInfo.CurrentCulture));

    public static readonly DependencyProperty TargetTypeProperty = DependencyProperty.Register("TargetType", typeof(Type), typeof(TransformedItemSource), new PropertyMetadata(null));

 

    public Type TargetType

    {

        get

        {

            return this.GetValue(TargetTypeProperty) as Type;

        }

        set

        {

            this.SetValue(TargetTypeProperty, value);

        }

    }

 

    public Object Parameter

    {

        get

        {

            return this.GetValue(ParameterProperty);

        }

        set

        {

            this.SetValue(ParameterProperty, value);

        }

    }

 

    public CultureInfo Culture

    {

        get

        {

            return this.GetValue(CultureProperty) as CultureInfo;

        }

        set

        {

            this.SetValue(CultureProperty, value);

        }

    }

 

    public IEnumerable ItemsSource

    {

        get

        {

            return this.GetValue(ItemsSourceProperty) as IEnumerable;

        }

        set

        {

            this.SetValue(ItemsSourceProperty, value);

        }

    }

 

    public IValueConverter Converter

    {

        get

        {

            return this.GetValue(ConverterProperty) as IValueConverter;

        }

        set

        {

            this.SetValue(ConverterProperty, value);

        }

    }

 

    IEnumerator IEnumerable.GetEnumerator()

    {

        foreach (var current in this.ItemsSource ?? new Object[0])

        {

            var targetType = this.TargetType ?? ((current != null) ? current.GetType() : null);

 

            yield return this.Converter.Convert(current, targetType, this.Parameter, this.Culture);

        }

    }

}

It inherits from DependencyObject, this is so that I can apply bindings to its properties. It will try to iterate through all the items in the ItemsSource property and convert one at a time using the supplied converter, culture and parameter. An example might be:

<UserControl.Resources>

    <my:TransformedItemSource x:Key="MyTransformer" ItemsSource="{Binding ItemsSource, ElementName=MyDatasource}" Converter="{StaticResource MyConverter}"/>

</UserControl.Resources>

<StackPanel x:Name="LayoutRoot">

    <ComboBox ItemsSource="{StaticResource MyTransformer}" Width="100" Height="30"/>

<StackPanel>

A nice way to use it is through a markup extension:

public class TransformExtension : DependencyObject, IMarkupExtension<IEnumerable>

{

    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(TransformExtension), new PropertyMetadata(null));

    public static readonly DependencyProperty ConverterProperty = DependencyProperty.Register("Converter", typeof(IValueConverter), typeof(TransformExtension), new PropertyMetadata(null));

    public static readonly DependencyProperty ParameterProperty = DependencyProperty.Register("Parameter", typeof(Object), typeof(TransformExtension), new PropertyMetadata(null));

    public static readonly DependencyProperty CultureProperty = DependencyProperty.Register("Culture", typeof(CultureInfo), typeof(TransformExtension), new PropertyMetadata(CultureInfo.CurrentCulture));

    public static readonly DependencyProperty TargetTypeProperty = DependencyProperty.Register("TargetType", typeof(Type), typeof(TransformExtension), new PropertyMetadata(null));

 

    public Type TargetType

    {

        get

        {

            return this.GetValue(TargetTypeProperty) as Type;

        }

        set

        {

            this.SetValue(TargetTypeProperty, value);

        }

    }

 

    public Object Parameter

    {

        get

        {

            return this.GetValue(ParameterProperty);

        }

        set

        {

            this.SetValue(ParameterProperty, value);

        }

    }

 

    public CultureInfo Culture

    {

        get

        {

            return this.GetValue(CultureProperty) as CultureInfo;

        }

        set

        {

            this.SetValue(CultureProperty, value);

        }

    }

 

    public IEnumerable ItemsSource

    {

        get

        {

            return this.GetValue(ItemsSourceProperty) as IEnumerable;

        }

        set

        {

            this.SetValue(ItemsSourceProperty, value);

        }

    }

 

    public IValueConverter Converter

    {

        get

        {

            return this.GetValue(ConverterProperty) as IValueConverter;

        }

        set

        {

            this.SetValue(ConverterProperty, value);

        }

    }

 

    public IEnumerable ProvideValue(IServiceProvider serviceProvider)

    {

        return new TransformedItemSource { ItemsSource = this.ItemsSource, Parameter = this.Parameter, Culture = this.Culture, Converter = this.Converter };

    }

}

The TransformExtension class just delegates all of the work to the TransformedItemSource, but because it is a markup extension, it can be used as:

<ComboBox ItemsSource="{Binding ItemsSource, ElementName=MyDataSource, Converter={StaticResource MyConverter}}" Width="100" Height="30"/>

Enjoy!

Silverlight DynamicResource Markup Extension

This will be my first post on Silverlight!

WPF offers two markup extensions, StaticResource and DynamicResource, that can be used to set property values from items in resource dictionaries.

The difference between the two can be summarized as:

  • StaticResource is evaluated at the start of the application, and will find resources defined before its actual usage;
  • DynamicResource is evaluated at a later point, and will find resources declared anywhere, before or after its usage.

Unfortunately, Silverlight does not include DynamicResource, but it is relatively easy to achieve something like that; that is the purpose of this post.

Check out the following code:

public class DynamicResource : MarkupExtension

{

    public DynamicResource()

    {

    }


    public String ResourceName { get; set; }


    public override Object ProvideValue(IServiceProvider serviceProvider)

    {

        var provideValueTarget = serviceProvider.GetService<IProvideValueTarget>();

        var target = provideValueTarget.TargetObject as FrameworkElement;

        var property = provideValueTarget.TargetProperty as PropertyInfo;


        if (target != null)

        {

            RoutedEventHandler handler = null;

            handler = (sender, e) =>

            {

                var elm = sender as FrameworkElement;


                if (elm != null)

                {

                    var resource = TryFindResource(elm, this.ResourceName);

                    var typeConverterAttribute = property.GetCustomAttributes(typeof(TypeConverterAttribute), true).OfType<TypeConverterAttribute>().SingleOrDefault() ?? property.PropertyType.GetCustomAttributes(typeof(TypeConverterAttribute), true).OfType<TypeConverterAttribute>().SingleOrDefault();


                    if (typeConverterAttribute != null)

                    {

                        var typeConverterType = Type.GetType(typeConverterAttribute.ConverterTypeName, false);


                        if (typeConverterType != null)

                        {

                            var typeConverter = Activator.CreateInstance(typeConverterType) as TypeConverter;


                            if (typeConverter != null)

                            {

                                resource = typeConverter.ConvertFrom(resource);

                            }

                        }

                    }


                    property.SetValue(sender, resource, null);

                }


                target.Loaded -= handler;

            };


            target.Loaded += handler;

        }


        return (property.PropertyType.IsClass == true) ? null : Activator.CreateInstance(property.PropertyType);

    }


    private static Object TryFindResource(FrameworkElement element, Object resourceKey)

    {

        var currentElement = element;


        while (currentElement != null)

        {

            var resource = currentElement.Resources[resourceKey];

            if (resource != null)

            {

                return resource;

            }


            currentElement = currentElement.Parent as FrameworkElement;

        }


        return Application.Current.Resources[resourceKey];

    }

}

I won’t go into details on markup extensions and all that, but basically, this one hooks to the Loaded event of the FrameworkElement, thus deferring the setting of the property. The property and the target are found through the IProvideValueTarget instance and the resource is looked up recursively from the target element up to the Application instance. If the property to be set, or its class, defines a type converter, it will try to convert the found resource to the proper type.  In the meantime, it just returns the default value of the property type, null or a default instance, in case of a value type.