Monday, October 24, 2011

Silverlight Binary Serializer

It's never a good idea to rag on another developer for releasing open source software, and so this post does not intend to do that.

I was working on a project for Silverlight that required some serialization. I didn't love my options, XmlSerializer, DataContractSerializer, or Mike Talbot's Silverlight Serializer (http://whydoidoit.com/silverlight-serializer/).

Mike's serializer while in many ways quite good, is at times a bit inelegant for my tastes, and the performance is adequate but often not good enough.

These led me to the path of most/least resistance and I began working on my own. I made it a point not to rip off a single line of his code and as such even basic things are implemented radically differently.

Why you would want to use mine when Mike's is out there:

1. The ability to serialize/deserialize any .NET object (you may need to write a custom helper class for the serializer to do so).
2. Uses lambda expressions (emitting code) for high performance in certain scenarios (dictionary/list/property reflection).
3. Very compact payload and WCF helper class (see Payload) for serializing any object over WCF.

Valid reasons to continue to use Mike's:

1. He can serialize to XML and not just binary
2. You don't feel like changing code you've already written around Mikes Silverlight Serializer
3. ......?

Check it out: https://skydrive.live.com/?cid=f5dc6abbdb926c4f&sc=documents&id=F5DC6ABBDB926C4F%21116

The samples included show how to use this serializer in WCF, have the Serializer serialize complex types automagically (via reflection), and serialize another complex type which it serializes via a custom serializer.

Sunday, November 22, 2009

Building a smarter WPF CollectionView: One that actively tracks group changes!

Recently, I needed to group items by category into a ListView.  So of course I set up a CollectionViewSource and described my grouping criteria.  Everything was hunky-dory except this particular application doesn’t make all of its changes to the objects through the gui. Sometimes in the object layer, the value being wrapped in my view models might change.  This raises the INotifyPropertyChanged event.  WPF sees the new value (it’s also bound to a Label), but does not move the item from one category to another.

Looking online for solutions I found two – neither of which met my needs.

One was to call CollectionViewSource.View.Refresh() when I get a property change notification.  This solution did not meet my needs because it was expensive (performance wise) and it was too drastic – rebuilding DataTemplates and consequently resetting unbound values of dependency properties (an expander is used in the ListView’s GroupStyle where its IsExpanded is not bound for example). 

The second was even more unpalatable, it required me to implement IEditableObject and again the fact that not all changes came through the gui (some were from WCF callbacks for example), this solution didn’t work.  Either way it also seemed tedious to me to implement this interface.

The notable Dr. WPF describes the problem and his proposed workarounds here: http://www.drwpf.com/blog/Home/tabid/36/EntryID/42/Default.aspx

There was only one solution for me, someone would need to build a view that attached Bindings for each PropertyGroupDescription to each item and therefore would know when group values changed.  Since I could not find such a thing anywhere on the internet, and believe me I looked, it became apparent that I would have to write one myself.

This involved many steps and a good amount of time inside Reflector to figure out all the points I absolutely needed to override to prevent the CollectionView class from processing changes in a way I don’t want.  That being said, it was probably only about an hour or so of work, so it’s rewarding to say the least.

Choosing a base class:
I wanted to extend ListCollectionView as I knew I wanted to support both SortDescriptionCollection and IComparer sorting, however seeing how much of it was not virtual, it became necessary for me to extend CollectionView (and then add a CustomSort property).

SortDescriptionCollectionComparer:
A class that implements IComparer, and given a set of SortDescriptions sets up a Binding for each item, caching the result per item in an ArrayList, such that two comparisons using the same item will only need to evaluate the Binding for that item once.  Then it returns a comparison of two items by comparing the result of their Binding values.  If sorting by multiple keys but it can create a comparison using only one, the comparer will not even attempt to evaluate the second Binding.

ActiveGroupingCollectionViewItem:
A class that extends DependencyObject and contains the source collection index of the item as well as a reference to the source collection item.  If grouping is being used, it will also have a reference to the group object.  As well as all that, it has a dependency property for group values (a simple object[]).  Using a dependency property allows notification of a change of any of the grouping criteria.

ActiveGroupingCollectionViewItemCollection:
A KeyedCollection keyed by source collection index to ActiveGroupingCollectionViewItem.  This makes handling INotifyCollectionChanged events from the source collection much easier and faster.  The CollectionView class will internally keep one instance of this collection as its sortable copy of the items collection.

Using the attached code:
All you have to do is specify to the CollectionViewSource the CollectionViewType property.

<CollectionViewSource x:Key="ActiveGroupingCollectionView" Source="{x:Static local:PersonViewModel.People}" 
CollectionViewType="{x:Type e:ActiveGroupingCollectionView}">
<
CollectionViewSource.GroupDescriptions>
<
PropertyGroupDescription PropertyName="Category" />
<
PropertyGroupDescription PropertyName="Gender" />
</
CollectionViewSource.GroupDescriptions>
<
CollectionViewSource.SortDescriptions>
<
scm:SortDescription PropertyName="Age" />
</
CollectionViewSource.SortDescriptions>
</
CollectionViewSource>




Sample application:

The sample application shows two views on the same source collection.  One uses the standard ListCollectionView whereas the other uses the ActiveGroupingCollectionView – go ahead and play with the app.  Select a person and then modify its attributes, you’ll see it move from group to group in the view on the right but it will not do so in the view on the left.



Get the bits:

http://activecollectionview.codeplex.com/