Archive

Archive for September, 2011

INotifyPropertyChanged woes? Too much ceremony?

September 27, 2011 14 comments

One of the things that Sivlerlight, Windows Phone 7, Windows Presentation Foundation, and WinRT developers face is the issue of data binding. This is a powerful feature that XAML technologies give us out of the box but there is a painful pattern that you have to implement in any property in order to get two-way binding to work.

First, you must implement the INotifyPropertyChanged event. Next you need to go through all of your properties and make sure you call the OnPropertyChanged method that you have in your implementation. This is a pain and adds no value to the underlying structure of your object. The only reason we need this extra fluff is to support data binding.

Well, there is a better way. There are actually several solutions or products out on the market right now but I prefer one that is the least intrusive and expensive. Let me introduce you to the NotifyPropertyWeaver project.

Here is a sample of what your code has to look like in order to have your properties raise the PropertyChanged event properly:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

This is really nice in that you don’t have to worry about any scaffolding or ceremony to get your properties to behave the way you would expect them. It also keeps your domain very clean and tight in that the only real fluff that you are exposing is the PropertyChanged event.

Here is what your code looks like when you compile it:

public class Person : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

As you can see, this pattern is typically what you would have had to have done in the first place but this now happens during compilation. The cool thing about this is that you have less code to maintain.

You can also have your objects derive from a base class that has the PropertyChanged event defined and anything else that you may want to have exposed in your base. Your base class would look like the following:

public class ModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    // Common logic here ....
}

Your derived class would look like the following:

public class Person : ModelBase
{
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

Finally, your source code would look like the following after it has been compiled:

public class Person : ModelBase
{
    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                base.OnPropertyChanged("GivenNames");
                base.OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set
        {
            if (value != familyName)
            {
                familyName = value;
                base.OnPropertyChanged("FamilyName");
                base.OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

This is really nice in that we did not have to do any extra work to get this functionality. It also finds any dependencies and makes sure that the OnPropertyChange method is called for them as well. We can see an example of this with the FullName property. It is readonly but it should still be updated whenever the GivenNames or FamilyName properties are changed.

One of the reasons why I like this solution so much is that it uses a convention to provide the IL weaving. You are not required to have any attributes over your class or properties to get this to work. I find the solution simple and elegant in its assumptions and it typically represents the ways we would end up coding the INotifyPropertyChanged interface any ways.

Another nice aspect to this project is that it already supports the following toolkits:

  • Caliburn.Micro
  • Caliburn
  • MvvmLight
  • Prism
  • Cinch
  • Windows Phone Essentials

You also have the flexibility to use custom Attirbutes to let the compiler know what to weave as well.  I personally, don’t like this since I want to keep my domain as clean as possible but it does give you a lot of flexibility.

In order to get this working for your project, you have several options.  You can either download and install a VSIX Package and have this capability ready for any of your Visual Studio projects.  Or, you can use NuGet and bring in the package on demand in the project that you need.

There are other solutions out there on the market.  The biggest one that comes to mind is PostSharp.  With PostSharp, you can do even more than weaving for the property changed event.  There is a free version with it as well but I didn’t see a single implementation that didn’t require an attribute.

I will be going over the power of PostSharp in a later post so that we can compare the goodness of both implementations.

Hope this helps…

Using ICustomTypeProvider in Silverlight 5 with XML

September 16, 2011 1 comment

Back in June I did a post on ICustomTypeProvider with JSON and ASP.NET MVC 3. Today, I want to present to you the ability to use XML as your source data for the ICustomTypeProvider and being able to bind to the data. If you download the code from my previous post and start looking around, you will see a class with the following structure:

    public class JsonHelper<T> where T : ICustomTypeProvider
    {
        private readonly IEnumerable<string> _keys = Enumerable.Empty<string>();
        private readonly Dictionary<string, Func<object, object>> _converters = 
            new Dictionary<string, Func<object, object>>();

        public JsonHelper(IDictionary<string, JsonValue> template)
        {
            CustomTypeHelper<T>.ClearCustomProperties();

            _keys = (from k in template.Keys select k).ToArray();

            foreach (var key in template.Keys)
            {
                int integerTest;
                double doubleTest;
                DateTime datetimeTest;
                var value = template[key].ToString();
                if (DateTime.TryParse(value.Replace(@"\", "").Replace("\"", ""), out datetimeTest))
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(DateTime));
                    _converters.Add(key, obj => DateTime.Parse(obj.ToString().Replace(@"\", "").Replace("\"", "")));
                }
                else if (int.TryParse(value, out integerTest))
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(int));
                    _converters.Add(key, obj => int.Parse(obj.ToString()));
                }
                else if (double.TryParse(value, out doubleTest))
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(double));
                    _converters.Add(key, obj => double.Parse(obj.ToString()));
                }
                else
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(string));
                    _converters.Add(key, obj =>
                    {
                        // strip quotes
                        var str = obj.ToString().Substring(1);
                        return str.Substring(0, str.Length - 1);
                    });
                }
            }
        }

        public void MapJsonObject(Action<string, object> setValue, JsonValue item)
        {
            foreach (var key in _keys)
            {
                setValue(key, _converters[key](item[key]));
            }
        }
    };

Again, thanks goes out to all the other posts that I read and used in my solution.

This class is actually does all the magic for allowing us to map our JSON data to an object that implements ICustomTypeProvider. It gets a lot of help from a CustomTypeHelper class that you can look at in the source code from the previous post. But what is nice about this class is that we have a simple implementation that allows us to map our JSON object to a typed CustomType object. As you can see, we are basically trying to parse the data into the underlying data types we care about.

It happens that I had a requirement to be able to take XML in as an input and create a CustomType that I could bind to a DataGrid in XAML. Well this turned out to be extremely easy. Here is the new class that provides the same functionality as the JsonHelper class called, XamlHelper:

    public class XmlHelper<T> where T : ICustomTypeProvider
    {
        private readonly IEnumerable<string> _keys = Enumerable.Empty<string>();
        private readonly Dictionary<string, Func<object, object>> _converters =
            new Dictionary<string, Func<object, object>>();


        public XmlHelper(XElement input)
        {
            CustomTypeHelper<T>.ClearCustomProperties();

            var template = new Dictionary<string, object>();

            foreach (var xe in input.Descendants())
            {
                template.Add(xe.Name.LocalName, xe.Value);
            }
            _keys = (from k in template.Keys select k).ToArray();

            foreach (var key in template.Keys)
            {
                int integerTest;
                double doubleTest;
                DateTime datetimeTest;
                var value = template[key].ToString();
                if (DateTime.TryParse(value, out datetimeTest))
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(DateTime));
                    _converters.Add(key, obj => DateTime.Parse(obj.ToString()));
                }
                else if (int.TryParse(value, out integerTest))
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(int));
                    _converters.Add(key, obj => int.Parse(obj.ToString()));
                }
                else if (double.TryParse(value, out doubleTest))
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(double));
                    _converters.Add(key, obj => double.Parse(obj.ToString()));
                }
                else
                {
                    CustomTypeHelper<T>.AddProperty(key, typeof(string));
                    _converters.Add(key, obj => obj.ToString());
                }
            }
        }

        public void MapXmlObject(Action<string, object> setValue, XElement item)
        {
            foreach (var key in _keys)
            {
                setValue(key, _converters[key](item.Element(key).Value));
            }
        }
    };

Here is a snippet of code that uses this new helper:

StringReader sr = new StringReader(item);
XDocument xDoc = XDocument.Load(sr);
if (xDoc.Element("data").Descendants("Table").Count() > 0)
{
    // Pull the first record as a template.
    XElement template = xDoc.Element("data").Descendants("Table").ToList()[0];
    // Use the template to get type information.
    var xmlHelper = new XmlHelper<CustomType>(template);
    // Iterate over the results and add to the underlying collection.
    foreach (var xe in xDoc.Element("data").Descendants("Table").ToList())
    {
        var customType = new CustomType();
        xmlHelper.MapXmlObject(customType.SetPropertyValue, xe);
        ResultsPaneItems.Add(customType);
    }
}

In my XAML, I have a DataGrid that has its ItemsSource property bound to the ResultsPaneItems property on my ViewModel.

From the server, I am using a ADO.NET DataSet and DataAdapter to write the DataSet out as XML. Then on the client side, I just receive the XML and use the ICustomTypeProvider implementation to allow me to bind to this shape. The cool thing about this is that the shape of my query can be anything as long as it is tabular. I would have to do some extra work if I want to support hierarchical data.

With the helper classes in place, you can provide mappers for just about any shape you need and still have the ability to bind to it in Silverlight. Pretty cool, right?

If you want to use this class, download the source code from my previous post on this subject and just copy and paste this class.

Hope this helps…

Introducing Visual Studio LightSwitch 2011

September 15, 2011 Leave a comment

I had a great time talking with the Triangle .NET Users Group last night. Here is my slide deck from my presentation.

Had a good time meeting your group and discussing LightSwtich.

Thanks to all who came out!

Categories: English Tags: , ,

Silverlight 5 RC available

September 2, 2011 Leave a comment

Silverlight 5 RC was released yesterday to the developer community giving us the remaining features that we were missing in the earlier Beta release. Here is a list of what we get with this release:

  • In-Browser Trusted Applications
  • PivotViewer control, which adds support for dynamic client-based collections, XAML-based visuals, and customizability.
  • Data binding improvements such as a DataContextChanged event and PropertyChanged added to the UpdateSourceTrigger enumeration
  • 3D: Improvements to the 3D support added in SL5 beta. This includes XNA built-in effects, surface composition settings for depth and stencil buffers and mult-sample anti-aliasing
  • File access: OpenFileDialog offers a DefaultDirectory property and SaveFileDialog offers a DefaultFileName property
  • Printing: SL5 now supports vector printing in addition to the bitmap printing offered in SL4.
  • Power awareness for media applications, e.g. Not sleeping while you are watching a movie, etc.
  • Remote control event support added with the MediaCommand event on UIElement.
  • P/Invode support for calling native functions.
  • Application restricted media: Enables content providers to ensure DRM’d content is only consumed by SL applications they authorize.
  • Support for OpenType and pixel-snapped text.
  • 64 bit support.

This version does not come with a go-live license, you will just have to wait till the final release before you deploy your Silverlight 5 applications. This version is not yet compatible with Blend and it is recommended that you wait for the final release later this year.

You can check out all the details here.

You can download it here.

Categories: English Tags: