Tag Archives: English

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!

Advertisements

Introducing VisualDesigner, my library for developing visual designers in .NET

Hi friends! I’m developing a personal project just for fun. Its goal is to serve as a starting point to make any visual designer with the best user interaction possible. Drag operations, resize, grouping, snapping, copy&paste…

The code is really abstract, decoupled and following the best software engineering principles I know to make it pure Clean Code. In fact, I have made a big effort to include almost all the code in a Portable Class Library (PCL).

For the moment, it supports basic drag (move), resize, multi-selection and SNAPPING!

I hope you go there and try it. I think it’s really interesting. The main application is WPF demo application, but the main functionality is almost totally platform-agnostic.

The project site in GitHub is this: https://github.com/SuperJMN/VisualDesigner

Feel free to collaborate or suggest anything. Maybe we can learn a lot sharing thoughts or even code 🙂

Thanks.

Concern: How to design a distributed service?

I have a major concern nowadays when trying to design distributed services that are consumed by the UI.
Imagine that you want to abstract as much as you can thinking of a View. This View consumes a distributed service that can fail to work under a lots of different situations. The most common failure: The connection cannot be established / is lost.
The view can be aware of those problems and try to recover from a failure, for example, warning the user and attempting to reconnect. But, then we totally break the abstraction! we start to think of it as a connected service.
What can we do? Should we put every method call in a try-catch block and a add reconnection loop?
It seems very ugly to me.
How to proceed?

Successfully applied Uncle Bob’s lessons

sticker,375x360I was absolutely tired of repeating myself when making the same calculations for both X and Y, Width, and Height. So, I contacted Robert C. Martin and got the answer a few months ago. At that moment, I felt almost the same as when I solved a difficult equation. And now I have put it to work, and POCOOOCK! It shouted like a little puppy.

TRIPLE HIT!

I still don’t like to pass 3 arguments to a  method, although it’s private. Fine cinnamon ;D

public class MarginBasedScalingStrategy : ScalingStrategy
    {

        public MarginBasedScalingStrategy(FrameworkElement element) : base(element) { }

        public override void ApplyDeltaHorizontal(double delta)
        {
            Element.Margin = ApplyDeltaToThickness(delta, Element.Margin, Hook);
        }

        public override void ApplyDeltaVertical(double delta)
        {
            Element.Margin = ApplyDeltaToThickness(delta, Element.Margin.Swap(), Hook.Swap()).Swap();
        }

        private Thickness ApplyDeltaToThickness(double delta, Thickness originalMargin, Point hookPoint)
        {
            var left = originalMargin.Left;
            var right = originalMargin.Right;

            var finalLeft = left + (delta * hookPoint.X);
            var finalRight = right + (delta * (1 - hookPoint.X));

            return new Thickness(finalLeft, 0, finalRight, 0);
        }
    }

Go, go, go!

Quercus Rotundifolia Empowered Code®

Handling selected items in a parent. Part 1.

When trying to make a good design you face situations in which you have to take a difficult decision that will easily affect the whole complexity of any  further development.

“Design concerns”. That is how I call them. And some are really nasty!

From now on, I will share the troubles I stumble upon. Because not only will I annotate my current design concerns for future self-reference, but also let people participate with comments.

One of my current design issues I ran into was the relationship that a parent and its children keep in several ways, the most important of them being the selection of children.

Let’s imagine this situation:

image

We’ve got a designer surface with some items. This surface is the parent of every other items inside.  Its children are Mario, a Button that says “Hola tío” (Hello dude), and the pretty obvious TextBox “This is my text”.

Knowing that it’s a designer with some elements into it, the user will expect some specific behavior. The most important are dragging and resizing.

Now the user sees Mario into a blue rectangle, remembers the times when they jumped all the way breaking blocks and decides “I will drag Mario!”. OK, the user expects Mario to be dragged around the surface.

STOP. Before moving anything we have to know what we want to move. How will we know that we have to move Mario?

ANSWER: Oh yes. In order to move him, we will have to select it first. So we will have some items that will be selected. Selected items! Risa A common concept, uh?

OK, that sounds good.

Selected items, but what selected items? We need to select some of the children.

HOW?

Clicking on the desired item should be enough. It’s the standard behavior. Isn’t it? So we decided that we will get the clicks on each item in order to know it has been selected to do something (dragging, for example).

Let’s go!

  1. Create a boolean IsSelected property, for the class that will represent the item.
  2. Add an event handler to each child to capture the mouse click and change its state.
  3. On click, turn the IsSelected to true.
  4. Give the element the proper appearance when it’s selected.

Pretty good.

Now, click every item and observe the goodness we achieved!

image

OK, you may have noticed that not only the items are selected individually, but also they is a concept of group in the capture. Just ignore it Sonrisa it’s part of my Glass library, currently being under development.

The fact is that we have a bunch of selected items that cannot be unselected. “Woahh, simple!” you will say. Just toggle IsSelected when clicking each time.

IsSelected = !ISelected;

Neat. Now you have more options. It’s alright. You win. But this is still far from being usable.

  1. First of all, when you have selected something and you want to drag it, each click will change the selection state.
  2. It’s really annoying to select items because most of times you will only want to select a single item: the one you just clicked. The others are discarded and only the newest should be the selected one.
    I know, I know! there will be many times in which you will want to select multiple items. We definitely will have to handle those situations.

You may ask:

– Couldn’t I just intercept clicks on an item and then iterate through the rest of children in order to unselect them? In other words: each time I click one, I can unselect the others.

WRONG! If you click an item and this item and you make it responsible for changing the state of its neighbors, you’re giving it a really high responsibility. How could it be aware of each other item? That sounds like we’re breaking some very important rule.

If we have to interact with other neighbors but we’re just a little modest item that cannot say the others what to do (we don’t mind about them), who could help us to unselect the rest of the items if I, as a child, receive a click and I want to change my state?

To be continued… Sonrisa