Follow Me on Instagram Subscribe via RSS Feed

Binding to Multiple Properties in Universal Apps

September 1, 2014

The binding engine in the various XAML stacks has to be one of my favorite features of XAML. Its clean, fast, and provides a great deal of flexibility to the developer. While examining a problem I came up against on a recent project, I realized I needed a controlling class to manage the appearance and features of a control. Now of course I could just manage this using a resource file and using styles, but for this particular application I needed a bit more logic behind the control.

The end result was I built a class to manage the properties of the control for me. The result worked like I needed it too, but one issue I came across is that I would add new functionality to my controlling class and forget to map the binding to the control itself. In addition, I got tired of writing all of the binding code.

So I decided to create a utility that would bind all the properties of a class to any matching properties of a DependencyObject. This way as I added more functionality to my controlling class, I didn’t have to worry about adding any additional mapping code.

The utility needed to work in Universal apps, so I decided to create it in a portal library and used reflection to handle the mapping.

So let’s take a look at the code first and then we can walk thru an example. Here is my class that resides in a portal library:

namespace PCLUtilities
{
    public sealed class ObjectToXamlBinding
    {
        public static void BindObjectToXaml(DependencyObject depObj, object source)
        {
            BindObjectToXaml(depObj, source, false);
        }

        public static void BindObjectToXaml(DependencyObject depObj, object source, bool forceMapping) {

            var sourceType = source.GetType();
            var sourceProps = GetPropertyList(sourceType);
           
            var depObjType = depObj.GetType();
            var depObjProps = GetPropertyList(depObjType);
            var depObjDepProps = depObjProps.Where(p => p.PropertyType == typeof(DependencyProperty)).ToList();

           // depObjType.
            foreach (var sourceProp in sourceProps)
            {
                var depProp = depObjDepProps.Where(p => p.Name == sourceProp.Name + "Property").FirstOrDefault();
                var prop = depObjProps.Where(p => p.Name == sourceProp.Name).FirstOrDefault();

                if (depProp != null && prop != null)
                {

                    bool doMap = true;

                    if (forceMapping)
                    {
                        doMap = prop.PropertyType == sourceProp.PropertyType;
                    }

                    if (doMap)
                    {
                        var binding = new Binding();
                        binding.Path = new PropertyPath(sourceProp.Name);
                        binding.Source = source;
                        binding.Mode = BindingMode.TwoWay;

                        BindingOperations.SetBinding(depObj, depProp.GetValue(depObj) as DependencyProperty, binding);


                    }
                }
                        
            }
        }

        private static List<PropertyInfo> GetPropertyList(Type type)
        {
            var ret = type.GetRuntimeProperties().ToList();

            var typeInfo = type.GetTypeInfo();

            if (typeInfo.BaseType != null)
            {
                var child = GetPropertyList(typeInfo.BaseType);

                ret.AddRange(child);
            }
            
            return ret;
        }
    }
}

The utility is rather straight forward. There are two constructors. Both constructors have a destination object that must be a DependencyObject and a source object that will be the controlling class. The 2nd constructor also has a matchType parameter which tells the utility to verify that the property types match up, which as we will see is not always needed.

The BindObjectToXaml method then uses reflection to get a list of properties for the source class and a list of DependencyProperty’s of the destination DependencyObject. It then loops thru the list of properties in the source object and looks for a matching DependencyProperty in the destination. It is important to note that this utility assumes standard dependency property naming which is {propertyName}Property. So a Width property of a DependencyObject would have a corresponding WidthProperty DependencyProperty.

If the matchType parameter is being used, then it will also check to verify that the type’s of the two properties match. This is not always desired. For example, if the underlying property behind a DependencyProperty has a type of double, you could still bind a source property with the type of int to it.

If the properties match up and the type check is done, then the utility creates a binding between the two properties. In this example a two way binding is created so the source class can react to changes (like a change in value is IsChecked).

So let’s take a look at this in practice. As the nature of all demo’s, this is a very simple example of this is code in action. Suppose we have a Button that we want to create a controlling class for. Our class doesn’t have any special logic in it and is pretty simple.

public class ButtonSettings
{
    public string Content { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }
    public Brush Background { get; set; }
}

We can set up the button in XAML.

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Button x:Name="btnTest"/>
</Grid>

Now all we have to do is to create an instance of our ButtonSettings class and use the utility to bind the settings class to the button.

var set = new ButtonSettings() { Content = "Test", 
                                 Width = 400, 
                                 Height = 200,
                                 Background = new SolidColorBrush(Colors.Blue)};

ObjectToXamlBinding.BindObjectToXaml(btnTest, set);

The result is the Button is now sized and formatted based on the settings class. Below is an example of the output in both a Windows Store app and a Windows Phone app.

image SNAGHTML7ace195

This type of setup provides you a couple of benefits. First, you can create intelligent controls that react to the control using a nice level of separation. For instance, that same settings class could be use for other types of controls. Second, it creates the bindings without using the DataContext of the control which frees up the data for the control to be used for defining and shaping the data displayed and not the appearance of the control itself. Lastly, it saves you from writing a lot of mapping code if you find yourself in a situation where you need to create these mappings.

This example is just the first iteration of this utility. I’ve gone on and added event handling and some other features that started to get a little domain specific for my needs. So I left the initial version here for you to take a look at. I’ll follow up this post with a more complex implementation of this utility later this week. You can download the example project here: http://tonyc.me/1nPFeMU.

Leave a Reply