Posts Tagged Silverlight

SilverlightSerializer Version 2


SilverlightSerializer version 2

Well, I know it’s been a long wait and I’ve been promising the new version of SilverlightSerializer for months, but it’s finally here, extracted from my core project and working standalone.

This new version of the serializer is a major rewrite – with 2 goals in mind:

1. Performance

Serialization performance is 61% faster (my test harness serializes 100,000 objects in 1.03 seconds compared to 1.72)
Deserialization performance is 27% faster (my test hardness deserializes 100,000 objects in 1.61 seconds compared to 2.04)

These performance gains are on large object graphs containing multiple instances of the same types – it would nominally be slightly slower on small graphs or graphs that contain only one copy of each object – but of course that’s very unlikely in the real world.

2. Extensibility

The new version of SilverlightSerializer abstracts the storage methods behind a new interface, IStorage.  There’s a complete implementation of a BinarySerializer that is compatible with the old version of SilverlightSerializer, but you could add your own.  Alterian has built versions that store data in XML and SQL Server tables.  This means one standard semantic serialization layer can be used with pluggable storage types to put the information where you need it for the application at hand.

That said, writing an IStorage is fairly involved process and I’ll write a post or a page on it if people want me to.

In addition the serializer now handles arrays and enums far better than before and hopefully should avoid the dreaded MissingMethod exception by providing a more developer friendly exception and message while offering the opportunity to construct classes without a parameterless constructor using a new CreateType event that will help some avoid the need to write custom serializers.

You can find the version 2 source code here.  In response to a couple of requests, the project is also accessible on GitHub, see the link at the top of the SilverlightSerializer page.

Why is it faster?

So read on if you’d like to know why it’s faster!

SilverlightSerializer is a reflection based serializer.  It examines an object to identify the available properties and fields. As anyone who is familiar with .NET will know, reflection isn’t exactly the fastest thing in the world.  SS v1 did its level best to cache everything possible, but it still relied on reflection to write and read properties and fields from the underlying objects.  This is why SS didn’t perform as well as the inbuilt serializers in .NET.

Now reflection in this case is a hard thing to get around, I don’t know the types in advance and I have no interest in getting the developer to have to write a custom serialization class for each of their types.

The answer to this performance challenge came from using generic classes and using .NET to construct a new generic class on the fly for each property of each class being serialized.  The generic class accesses the native property access functions directly, rather than have to use reflection.  Fields have to be handled slightly differently, with a reflection function, but at least it’s no slower than the previous method.

First let’s start with the base class that is used for all of the generic classes, it’s called GetSet.


public abstract class GetSet
{
public PropertyInfo Info;
public string Name;
public FieldInfo FieldInfo;
public object Vanilla;
public bool CollectionType;
public abstract object Get(object item);
public abstract void Set(object item, object value);

}

From this base class I create a definition of a generic class, called GetSetGeneric.  This class creates Get and Set delegates using the class parameters, these delegates then map to the functions that will be exposed by the property getters and setters on the target class (neat huh).  This happens only once per type/property combination and the resulting code is the same speed as writing a function to get the value.

public class GetSetGeneric<T, TR> : GetSet
{
public delegate TR GetValue(T obj);
public delegate void SetValue(T obj, TR value);
private readonly GetValue _get;
private readonly SetValue _set;

public GetSetGeneric(PropertyInfo info)
{
MethodInfo getMethod;
MethodInfo setMethod = null;
Name = info.Name;
Info = info;
CollectionType = Info.PropertyType.GetInterface("IEnumerable", true) != null;
getMethod = info.GetGetMethod();
setMethod = info.GetSetMethod();
_get = (GetValue)Delegate.CreateDelegate(typeof(GetValue), getMethod);
if (setMethod != null) _set = (SetValue)Delegate.CreateDelegate(typeof(SetValue), setMethod);
}

public GetSetGeneric(FieldInfo info)
{
MethodInfo getMethod;
MethodInfo setMethod = null;
Name = info.Name;
FieldInfo = info;
_get = new GetValue(GetFieldValue);
_set = new SetValue(SetFieldValue);
CollectionType = FieldInfo.FieldType.GetInterface("IEnumerable", true) != null;
return;
}

public GetSetGeneric(string name)
{
Name = name;
MethodInfo getMethod;
MethodInfo setMethod= null;
var t = typeof(T);
var p = t.GetProperty(name);
if (p == null)
{
FieldInfo = typeof(T).GetField(Name);
_get = new GetValue(GetFieldValue);
_set = new SetValue(SetFieldValue);
CollectionType = FieldInfo.FieldType.GetInterface("IEnumerable", true) != null;
return;
}
Info = p;
CollectionType = Info.PropertyType.GetInterface("IEnumerable", true) != null;
getMethod = p.GetGetMethod();
setMethod = p.GetSetMethod();
_get = (GetValue)Delegate.CreateDelegate(typeof(GetValue), getMethod);
if(setMethod != null) _set = (SetValue)Delegate.CreateDelegate(typeof(SetValue), setMethod);
}

private TR GetFieldValue(T obj)
{
return (TR)FieldInfo.GetValue(obj);
}

private void SetFieldValue(T obj, TR value)
{
FieldInfo.SetValue(obj, value);
}

public override object Get(object item)
{
return _get((T)item);
}

public override void Set(object item, object value)
{
_set((T)item, (TR)value);
}
}

Once that’s done it’s just a matter of creating the generic classes. Deserialization does this one property at a time form the input stream:

entryConfiguration = new EntryConfiguration();

var pi = entry.OwningType.GetProperty(entry.Name);
if (pi != null)
{
entryConfiguration.Type = pi.PropertyType;
var gs = typeof(GetSetGeneric<,>);
var tp = gs.MakeGenericType(new Type[] { entry.OwningType, pi.PropertyType });
entryConfiguration.Setter = (GetSet)Activator.CreateInstance(tp, new object[] { pi });
}
else
{
var fi = entry.OwningType.GetField(entry.Name);
if (fi != null)
{
entryConfiguration.Type = fi.FieldType;
var gs = typeof(GetSetGeneric<,>);
var tp = gs.MakeGenericType(new Type[] { entry.OwningType, fi.FieldType });
entryConfiguration.Setter = (GetSet)Activator.CreateInstance(tp, new object[] { fi });
}
}

Here you can see I get either the property or the field information, use the type of the containing class and the property in a call to MakeGenericType to construct the correct class, then create an instance of that class that can be used to get and set properties on the object.
Serialization works by creating a list of getters and setters for every sensible property on the object, in SilverlightSerializer that creates a few different flavours depending on whether you are using Checksums etc. If you want to see how I do that, have a look at the GetWriteableAttributes class and the GetAccessors() function.

, , , , , , , , , ,

10 Comments

Wordle Style Word Cloud or Tag Cloud Component For Silverlight


Word Cloud

Example Word Cloud

DownloadLATEST VERSION AND DOCUMENTATION AVAILABLE HERE

I’ve been looking for a component that could show Wordle style word clouds.  The only Silverlight component I could find was Infragistics xamTagCloud, but it really didn’t produce the output I was looking for.  What I wanted was to be able to put lower importance words within the spaces left around larger entries.

Words with coloring

Example Subtle Word Coloring

Having looked around the web I couldn’t find a component to buy or borrow so I decided to write my own.

I came across this post on Stack Overflow that had a response from the author of Wordle (Jonathan Feinberg), giving some tips on how Wordle works.  I used that and the extra reference Jonathan provided to build my component.

The key to word layout is to use a spiral (or another progressive positioning equation) to try to position words, every new word needs to be checked against the previously placed items to ensure that there is no overlap.

As collision is the expensvie part of the algorithm Jonathan suggests using a variety of techniques around collision rectangles and space partitioning to do the item testing; I felt this wasn’t necessary for my needs so I actually test the overlapping pixels to see if there is a hit.  This seems to give good enough performance, and if I wanted to improve it I would advocate making a second collision map at a lower resolution (1/8 scale) that would significantly cut down on the processing – but again, wasn’t necessary for me.

If you want to use something to layout instead of my spiral, you need to replace the GetSpiralPoint function with something that will return a progressive space based on an increaseing angle measured in radians.

The component also supports word hit testing and selection as well as coloring words based on a value as well as sizing them.

You can download the full source code for the component and the test project which will allow you to play with the parameters from the link at the top of this post.

, , , , , ,

9 Comments

Automatic Grid Layout for Silverlight


Download

I always find myself cursing Grids in Silverlight when I have to go back and insert something else into the layout after the fact: I always forget to move somethings Row and end up with a lot of obscured components. To compensate for this I’ve written a Grid subclass that can automatically layout its children and fill out the ColumnDefinition and RowDefinition for missing values when the children refer to rows and columns beyond the specified dimensions. In addition it will auto layout for multiple columns using sequential children, this is good if all you want is a 2 by n grid of label/editor cells.

My AutoGrid will allow you to define Rows and Columns like an ordinary grid, but if you don’t catch all of the cases then it fills out the rest for you. For instance you could just define the columns and it will fill out the rows based on the Grid.Row settings of the children. If you want to go a step further, then don’t specify any Grid.Row or Grid.Column attributes and instead add a Columns=”x” to the AutoGrid and it will sequentially lay out the children in column then row order. 

Normally the rows and columns added are “Auto” sized, you can however set the last row and column to be “*” sized using the properties AutoSizeLastColumn and AutoSizeLastRow.  If you need more complex arrangements than this then you should define the items you need sizing explicity using the ColumnDefinitions and/or RowDefinitions attributes.

It really saves me a lot of time when I’m editing this stuff!

Here is an example in full automatic layout mode:


		<AutoGrid:AutoGrid x:Name="LayoutRoot" Columns="2">
			<TextBlock Text="Name"
					   Margin="2"/>
			<TextBox Components:SelectOnFocus.SelectAll="True" Text="{Binding Name, Mode=TwoWay}"
					 Margin="2"
					 Width="150"
					 />
			<TextBlock Text="Type"
					   Margin="2"
					   />
			<ComboBox
					ItemsSource="{Binding Type, Converter={StaticResource EnumSource}}"
					SelectedItem="{Binding Type, Converter={StaticResource EnumValue}}"
					Margin="2"
					Width="150"
					/>
			<TextBlock Text="Width" Margin="2" />
			<TextBox Text="{Binding Width, Mode=TwoWay}"
				 Components:SelectOnFocus.SelectAll="True"
					 Margin="2"
				 Width="150"/>
			<TextBlock Text="Choice List " VerticalAlignment="Top" Margin="2"/>
			<TextBox Width="150"
					 Height="100"
					 Margin="2"
					 AcceptsReturn="True"
					 Text="{Binding ChoiceList, Converter={StaticResource ListToString}, Mode=TwoWay}"/>
		</AutoGrid:AutoGrid>

Which produces this output:

 

You can download the project from here.

, , , ,

5 Comments

Silverlight VisualState changes using DataBinding not code behind


Download
I hate the fact that I have to keep using code behind to trigger VisualState changes in my view.  Frequently I just want to change a visual state of a control based on the properties of the object to which the control is bound – such as making additional options visible or invisible, changing the mode of the display based on information stored in the model etc.

So I’ve come up with a control that helps!  The VisualStateController can be placed in the XAML for a control and be bound to a property of the databound object using its StateMode dependency property. 

  • If the property is a bool then two further properties OnState and OffState are used to determine the visual state of the control based on the value of the property.
  • If the property is an enum then the visual state will be set the the text string name of the enum value.
  • If the property is a string it will be used to directly set the visual state

Now changes causing normal binding updates will automatically trigger the visual state changes.

<VisualStateCtrls:VisualStateController StateMode="{Binding IsSelected}"
             OnState="Selected"
             OffState="Unselected"/>

<VisualStateCtrls:VisualStateController StateMode="{Binding IsResizable}"
             OnState="Sizers"
             OffState="NoSizers"/>

The VisualStateController binds automatically to the UserControl (or Control) that it is a child of.  You can put it inside any panel within the body of your UserControl’s XAML.

You can find the project and source code here.

If you want to achieve the same thing using triggers and a slightly more wordy approach, you can use blend and triggers – see here for details.

, , , , , , ,

5 Comments

Serializing classes between Silverlight and .NET 4


I’ve realized that I didn’t detail how to ensure you can serialize your own classes between Silverlight and .NET 4 using my SilverlightSerializer class. 

The vital thing to do in these circumstances is to define the classes you want to share in a Silverlight assembly that only references System, System.Core and mscorlib.  These are the requirements for assemblies that can be used in both types of project.  If you define your classes in this way then they can be deserialized on the back end without a problem, reference anything else and it won’t work.  Fortunately most of what you will need is included in those system assemblies!

, ,

1 Comment

Silverlight AllChildren: find all of the visual children of a FrameworkElement


Our application has some occasions where we need to iterate the entire child tree of a visual component. Not a common thing in many applications, I use it to pass visual states to the sub elements of a tree, but if you need a routine for this purpose then I thought I would post mine here:  


        public static List<T> AllChildren<T>(this FrameworkElement ele, Func<DependencyObject, bool> whereFunc = null) where T : class
        {
            if (ele == null)
                return null;
            var output = new List<T>();
            var c = VisualTreeHelper.GetChildrenCount(ele);
            for (var i = 0; i < c; i++)
            {
                var ch = VisualTreeHelper.GetChild(ele, i);
                if (whereFunc != null)
                {
                    if (!whereFunc(ch))
                    {
                        continue;
                    }
                }
                if ((ch is T))
                    output.Add(ch as T);
                if (!(ch is FrameworkElement))
                    continue;

                output.AddRange((ch as FrameworkElement).AllChildren<T>(whereFunc));
            }
            return output;
        }

The function is an extension method that uses the generic Type to decide on the types of children to return.  It takes an optional “Where function” that can be used to stop iterating down branches of the visual tree – please note that the Where function doesn’t only get passed the Type components, it gets everything so you can stop the recursive operation when you want to.  If you don’t pass the Where parameter then all visual children are returned.  

 

                foreach (var c in panel.AllChildren<Control>((child) => !(child is FdTreeViewItem)))
                {
                    VisualStateManager.GoToState(c, "FlowSelected", true);
                } 

   

, , ,

5 Comments

Debugging Silverlight “element is already the child of another element”!


DownloadThe problem

 I know how many people are having a problem with the catch-all XAML error “Element is already the child of another element” – it’s been a popular post on this blog and I come across it all of the time.  The real problem is that the exception gives no indication of the area causing the failure, you are forced into playing with the source file and banging your head against the wall.  Well, help is at hand!  

I have written a program that helps identify which part of the XAML is going wrong and tells you about it!  Now one caveat – it can only tightly identify a single error that is causing this problem – if more than one thing throws the exception then the best you can hope for is for it to point out the XAML container that contains the code that is failing – such as VisualStateManager.   In most cases it will be more specific, because only one element will have changed and cause the exception to be thrown. This ability is helping me a lot, hopefully it can help you too…  

The solution

 So here’s what I have done.  I have written a XAML validator that reads in the file and then attempts to process it.  When the file has a problem it starts to prune out nodes in the XAML one XML node at a time (I mean it puts back nodes that didn’t solve the problem and tries the next in sequence).  It does this starting with the nodes that have no children, then the ones with 1, 2 and so on, until it has to remove the entire body – hopefully the error is found long before this.  Using this technique the algorithm tries to give you the most tightly isolated area of the XAML to focus on.  

When it identifies a node, it checks whether removing any attribute helps and returns this in addition to the offending XAML if it resolves the issue.  

The result is a string describing the XAML and any offending attribute.  

This is a debugging tool only – it really slows down the application using it, so don’t call it when you don’t have a problem – but it massively improves your debugging time.  I normally instantiate in the constructor of the failing class and Debug.WriteLine() its result.  It is VITAL that you call it from the assembly that contains the failing XAML – it won’t work if you don’t. (See the discussion below if you want to know why!)  

You can download the project from here.  Feel free to use it as you see fit.  

Here’s an example of using it: 

  

public HtmlTextBox()
        {
            var s = ValidateXaml.GetXamlErrors(new System.Uri("/Alchemy.extension;component/Components/HtmlTextBox.xaml", System.UriKind.Relative));
            Debug.WriteLine(s);
            InitializeComponent();
       }   

Caveats

This isn’t going to work too well if removing a node that fails just causes the problem to propagate to a part of the XAML that was previously valid – the only way I can think about solving that requires far more recursion and taking out multiple nodes at each level.  I’d be interested in anyone elses view on this and any other strategies…

You may have a problem with project references, if you do then see the discussion below, hopefully I’ve accounted for most circumstances.

Discussion

Having had the initial idea about this approach I ran into a couple of stumbling blocks which are worth exploring for those who are interested.  

Firstly, when you call InitializeComponent in a UserControl etc – it uses Application.LoadComponent to parse the XAML.  I can’t use that approach because it takes a URI and I need to pass in a string which is the XAML with an element removed.  For this reason my code uses XamlReader to parse the file – the problem there is that it always throws an exception for XAML that contains an x:Class attribute.  My first job then is to strip that out.  

The next attribute problem was much harder to solve.  UserControl xmlns attributes are used to provide reference to components stored in other assemblies. The attribute provides the namespace and the assembly.  The assembly is omitted for other controls that are contained in the same assembly as the problem control.  LoadComponent has no problems with resolving this reference, but XamlReader throws our favorite exception if it isn’t there – this took me a LONG time to figure out.  

So I have to add an “assembly=” extension to the xmlns references that don’t contain one (except the xlmns:x) to ensure that XamlReader will parse a correct file.  I do this by enquiring about the calling assembly and adding its name to the attribute.  

Sounds sensible right?  Well it was a bit more complicated than that – if I just modify the attribute while it is connected to the document, some behind the scenes magic changes all of the things that are referred to by that namespace! Guess what the error is? Yep, “element is already the child of another element” 🙂  

So now I remove the attribute from the document, modify it and put it back – presto!  No unwanted changes and the algorithm finally gets to have a go at parsing the file.

If this attribute modification causes you a problem, you could remove the code and explicitly qualify your project references, this does work, I’ve tried it and would account for a situation in which I accidentally update an xmlns that doesn’t need touching – but this does mean that you won’t be using the VS2010 automatically generated references.  I hope that this won’t normally be a problem.

UPDATE: I’ve modified the source to allow you to pass a parameter that turns off the xmlns modifications – see above comment about explicit assembly references if you set this.  It defaults to “true” which enables the automatic update of references.

, , , , , , ,

7 Comments

ProportionalPanel for Silverlight


I wanted a panel that distributes its children according to the proportion of their width or by a proportion supplied by the object attached to the DataContext.  This lead to me writing PropotionalPanel – the first custom panel I have written.  It’s useful in building dashboards and other layouts that require collections of children, because Grids aren’t easy to use inside ItemsControls.  I wrote this control to be used as the ItemsPanel of a list box and it works well in that context.When writing a panel the two important routines are MeasureOverride and ArrangeOverride.  There’s lots of documentation on these in the help, but it’s interesting to see the parameters with which these methods are called at different times.  

For instance, even if you have a fixed size container, MeasureOverride is called with infinite dimensions on the first occasion, thereafter the call specifies the fixed size.  

Here’s my version of the MeasureOverride routine. I maintain a variable called totalProportion which is either the sum of the proportions of the attached objects, or the sum of the proportions of the stretched dimension based on orientation.  

  

        protected override Size MeasureOverride(Size availableSize)
        {
            Size finalSize = new Size(availableSize.Width, availableSize.Height);
            double totalProportion = 0;
            foreach (var c in Children.OfType<FrameworkElement>())
            {  

                if (c.DataContext is IProportional)
                {
                    totalProportion += (c.DataContext as IProportional).GetProportion();
                }
                else
                {
                    totalProportion += Orientation == Orientation.Vertical
                                           ? c.DesiredSize.Height
                                           : c.DesiredSize.Width;
                }
            }  

            double sizeAvailable, maxAlternate = 0;
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    sizeAvailable = availableSize.Width;
                    if (double.IsNaN(sizeAvailable) || double.IsPositiveInfinity(sizeAvailable))
                    {
                        sizeAvailable = 0;
                        foreach (var c in Children)
                        {
                            c.Measure(availableSize);
                            sizeAvailable += c.DesiredSize.Width;
                            maxAlternate = Math.Max(maxAlternate, c.DesiredSize.Height);
                        }
                        finalSize.Width = sizeAvailable;
                        finalSize.Height = maxAlternate;  

                    }
                    else
                    {
                        foreach (var c in Children.OfType<FrameworkElement>())
                        {
                            double p;
                            if (c.DataContext is IProportional)
                            {
                                p = (c.DataContext as IProportional).GetProportion();
                            }
                            else
                            {
                                p = Orientation == Orientation.Vertical
                                                       ? c.DesiredSize.Height
                                                       : c.DesiredSize.Width;
                            }
                            c.Measure(new Size(Math.Max(0,Math.Floor((sizeAvailable * p)/totalProportion)), finalSize.Height));
                        }
                    }
                    break;
                case Orientation.Vertical:
                    sizeAvailable = availableSize.Height;
                    if (double.IsNaN(sizeAvailable) || double.IsPositiveInfinity(sizeAvailable))
                    {
                        sizeAvailable = 0;
                        foreach (var c in Children)
                        {
                            c.Measure(availableSize);
                            sizeAvailable += c.DesiredSize.Height;
                            maxAlternate = Math.Max(maxAlternate, c.DesiredSize.Width);
                        }
                        finalSize.Height = sizeAvailable;
                        finalSize.Width = maxAlternate;
                    }
                    else
                    {
                        foreach (var c in Children.OfType<FrameworkElement>())
                        {
                            double p;
                            if (c.DataContext is IProportional)
                            {
                                p = (c.DataContext as IProportional).GetProportion();
                            }
                            else
                            {
                                p = Orientation == Orientation.Vertical
                                                       ? c.DesiredSize.Height
                                                       : c.DesiredSize.Width;
                            }
                            c.Measure(new Size(finalSize.Width, Math.Max(0, Math.Floor((sizeAvailable * p) / totalProportion))));
                        }
                    }  

                    break;
            }  
            return finalSize;
        }
    }  

 

First the total proportion is calculated by walking through the children and summing either the proportions from the attached object, or the required size.  

  

            double totalProportion = 0;
            foreach (var c in Children.OfType<FrameworkElement>())
            {  

                if (c.DataContext is IProportional)
                {
                    totalProportion += (c.DataContext as IProportional).GetProportion();
                }
                else
                {
                    totalProportion += Orientation == Orientation.Vertical
                                           ? c.DesiredSize.Height
                                           : c.DesiredSize.Width;
                }
            }  

 

If the parameters of the MeasureOverride call have infinite dimensions I need to measure all of the children for their desired size, if there is a specific size then I need to measure each child providing guidance on how much space they will be allocated.  

  

           case Orientation.Horizontal:
                    sizeAvailable = availableSize.Width;
                    if (double.IsNaN(sizeAvailable) || double.IsPositiveInfinity(sizeAvailable))
                    {
                        sizeAvailable = 0;
                        foreach (var c in Children)
                        {
                            c.Measure(availableSize);
                            sizeAvailable += c.DesiredSize.Width;
                            maxAlternate = Math.Max(maxAlternate, c.DesiredSize.Height);
                        }
                        finalSize.Width = sizeAvailable;
                        finalSize.Height = maxAlternate;  

                    }
                    else
                    {
                        foreach (var c in Children.OfType<FrameworkElement>())
                        {
                            double p;
                            if (c.DataContext is IProportional)
                            {
                                p = (c.DataContext as IProportional).GetProportion();
                            }
                            else
                            {
                                p = Orientation == Orientation.Vertical
                                                       ? c.DesiredSize.Height
                                                       : c.DesiredSize.Width;
                            }
                            c.Measure(new Size(Math.Max(0,Math.Floor((sizeAvailable * p)/totalProportion)), finalSize.Height));
                        }
                    }
                    break;  

 

In the fixed size measurement I use the proportion to calculate the amount of stretched space available to the control.  It is vital that you both measure and arrange children in the correct size – if you don’t measure then it initially appears to work, but strange sizing artefacts occur.  

The arrangement pass is very similar to the fixed size measurement, except you pass a rectangle to the child giving it the layout slot into which it will fit:  

  

            if (Orientation == Orientation.Vertical)
            {
                foreach (var c in Children.OfType<FrameworkElement>())
                {
                    double p = 0;
                    if (c.DataContext is IProportional)
                    {
                        p = (c.DataContext as IProportional).GetProportion();
                    }
                    else
                    {
                        p = c.DesiredSize.Height;
                    }
                    double d = Math.Max(0,Math.Floor((finalSize.Height * p) / totalProportion));
                    c.Arrange(new Rect(0, offset, finalSize.Width, d));
                    offset += d;
                }
            }  

 

The IProportional interface is implemented on objects that are used as DataContexts for the items in my panel:  

  

    public interface IProportional
    {
        double GetProportion();
    } 

 

When you have a proportional panel like this it’s a good idea to provide some way for the user to resize things!  I use a thing called FrameControl in my ListBox’s DataTemplate – this provides sizing thumbs that can change the horizontal and vertical proportions of the underlying DataContext objects. 

 

        private void WidthThumb_OnDragDelta(object sender, DragDeltaEventArgs e)
        {
            var pp = this.FirstVisualAncestorOfType<ProportionalPanel>();
            var thisIndex = pp.Children.IndexOf(this.FirstVisualAncestorOfType<ListBoxItem>());
            var thisItem = DataContext as DashboardItem;
            var nextItem = pp.Children[thisIndex + 1].Cast<FrameworkElement>().DataContext as DashboardItem; 

            Debug.Assert(thisItem != null);
            Debug.Assert(nextItem != null); 

            var move = (e.HorizontalChange * GetProportions()) / pp.ActualWidth;
            if (thisItem.Proportion + move < 0)
                move = - thisItem.Proportion;
            if (nextItem.Proportion - move < 0)
                move = nextItem.Proportion;
            thisItem.Proportion += move;
            nextItem.Proportion -= move;
            pp.InvalidateMeasure();
        } 

 

This example uses my FirstVisualAncestorOfType extension method found elsewhere on this blog.  For the FrameControl it finds the ProportionalPanel that owns it then works out what the pixel change in the Thumb means in terms of the change to the arbitrary proportions returning by the IProportional implementation.  If you just used heights then this would be a lot simpler, but harder to store.  Obviously you need a thumb for the sizable dimension, but not both, so I show just the relevant thumb based on the panel’s orientation. 

To build a dashboard I layer panel within panel as you can see in this video – which also shows the thumb action and the ability to react to drag and drop (not allowing containers of the same type to be embedded within containers). 

Here’s the complete code for the panel.  I have the IProportional interface defined in a library that is used by the items I attach to the DataContext, so that they don’t have to reference the Panel – but you might just want to insert it in this namespace. 

 

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls; 

namespace DashboardRenderers
{
    public class ProportionalPanel : Panel
    {
        public Orientation Orientation
        {
            get
            {
                return (Orientation)GetValue(OrientationProperty);
            }
            set
            {
                SetValue(OrientationProperty, value);
            }
        } 

        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ProportionalPanel), new PropertyMetadata(System.Windows.Controls.Orientation.Vertical)); 

        protected override Size ArrangeOverride(Size finalSize)
        {
            double offset = 0;
            double totalProportion = 0;
            foreach (var c in Children.OfType<FrameworkElement>())
            { 

                if (c.DataContext is IProportional)
                {
                    totalProportion += (c.DataContext as IProportional).GetProportion();
                }
                else
                {
                    totalProportion += Orientation == Orientation.Vertical
                                           ? c.DesiredSize.Height
                                           : c.DesiredSize.Width;
                }
            }
            if (Orientation == Orientation.Vertical)
            {
                foreach (var c in Children.OfType<FrameworkElement>())
                {
                    double p = 0;
                    if (c.DataContext is IProportional)
                    {
                        p = (c.DataContext as IProportional).GetProportion();
                    }
                    else
                    {
                        p = c.DesiredSize.Height;
                    }
                    double d = Math.Max(0,Math.Floor((finalSize.Height * p) / totalProportion));
                    c.Arrange(new Rect(0, offset, finalSize.Width, d));
                    offset += d;
                }
            }
            else
            {
                foreach (var c in Children.OfType<FrameworkElement>())
                {
                    double p = 0;
                    if (c.DataContext is IProportional)
                    {
                        p = (c.DataContext as IProportional).GetProportion();
                    }
                    else
                    {
                        p = c.DesiredSize.Width;
                    }
                    double d = Math.Max(0, Math.Floor((finalSize.Width * p) / totalProportion));
                    c.Arrange(new Rect(offset, 0, d, finalSize.Height));
                    offset += d;
                } 

            }
            return finalSize;
        } 
        protected override Size MeasureOverride(Size availableSize)
        {
            Size finalSize = new Size(availableSize.Width, availableSize.Height);
            double totalProportion = 0;
            foreach (var c in Children.OfType<FrameworkElement>())
            { 

                if (c.DataContext is IProportional)
                {
                    totalProportion += (c.DataContext as IProportional).GetProportion();
                }
                else
                {
                    totalProportion += Orientation == Orientation.Vertical
                                           ? c.DesiredSize.Height
                                           : c.DesiredSize.Width;
                }
            } 

            double sizeAvailable, maxAlternate = 0;
            switch (Orientation)
            {
                case Orientation.Horizontal:
                    sizeAvailable = availableSize.Width;
                    if (double.IsNaN(sizeAvailable) || double.IsPositiveInfinity(sizeAvailable))
                    {
                        sizeAvailable = 0;
                        foreach (var c in Children)
                        {
                            c.Measure(availableSize);
                            sizeAvailable += c.DesiredSize.Width;
                            maxAlternate = Math.Max(maxAlternate, c.DesiredSize.Height);
                        }
                        finalSize.Width = sizeAvailable;
                        finalSize.Height = maxAlternate; 

                    }
                    else
                    {
                        foreach (var c in Children.OfType<FrameworkElement>())
                        {
                            double p;
                            if (c.DataContext is IProportional)
                            {
                                p = (c.DataContext as IProportional).GetProportion();
                            }
                            else
                            {
                                p = Orientation == Orientation.Vertical
                                                       ? c.DesiredSize.Height
                                                       : c.DesiredSize.Width;
                            }
                            c.Measure(new Size(Math.Max(0,Math.Floor((sizeAvailable * p)/totalProportion)), finalSize.Height));
                        }
                    }
                    break;
                case Orientation.Vertical:
                    sizeAvailable = availableSize.Height;
                    if (double.IsNaN(sizeAvailable) || double.IsPositiveInfinity(sizeAvailable))
                    {
                        sizeAvailable = 0;
                        foreach (var c in Children)
                        {
                            c.Measure(availableSize);
                            sizeAvailable += c.DesiredSize.Height;
                            maxAlternate = Math.Max(maxAlternate, c.DesiredSize.Width);
                        }
                        finalSize.Height = sizeAvailable;
                        finalSize.Width = maxAlternate;
                    }
                    else
                    {
                        foreach (var c in Children.OfType<FrameworkElement>())
                        {
                            double p;
                            if (c.DataContext is IProportional)
                            {
                                p = (c.DataContext as IProportional).GetProportion();
                            }
                            else
                            {
                                p = Orientation == Orientation.Vertical
                                                       ? c.DesiredSize.Height
                                                       : c.DesiredSize.Width;
                            }
                            c.Measure(new Size(finalSize.Width, Math.Max(0, Math.Floor((sizeAvailable * p) / totalProportion))));
                        }
                    } 

                    break;
            } 
            return finalSize;
        }
    }
} 

, , , , , , , ,

Leave a comment

Finding a typed visual parent in Silverlight


My application frequently needs to find a parent of a Silverlight element, and due to the nature of popup panels I also sometimes want to know if the element is “logically” connected to another element.  To achieve this I wrote a couple of helper functions that walk the visual tree and return a typed parent.  You can implement a special interface to indicate that there is a logical connection between items that aren’t physically connected to each other in the Visual Tree too if you need to (very helpful with focus issues).


        public static T FirstVisualAncestorOfType<T>(this DependencyObject element) where T : DependencyObject
        {
            if (element == null) return null;
           
            var parent = VisualTreeHelper.GetParent(element) as DependencyObject;
            while (parent != null)
            {
                if (parent is T)
                    return (T)parent;
                if (parent is IBreakVisualParenting)
                {
                    parent = ((IBreakVisualParenting)parent).Parent;
                }
                else
                    parent = VisualTreeHelper.GetParent(parent) as DependencyObject;
            }
            return null;
        }

        public interface IBreakVisualParenting
        {
            DependencyObject Parent { get; }
        }

        public static T LastVisualAncestorOfType<T>(this DependencyObject element) where T : DependencyObject
        {
            T item = null;
            var parent = VisualTreeHelper.GetParent(element) as DependencyObject;
            while (parent != null)
            {
                if (parent is T)
                    item = (T) parent;
                if(parent is IBreakVisualParenting)
                {
                    parent = ((IBreakVisualParenting) parent).Parent;
                }
                else
                    parent = VisualTreeHelper.GetParent(parent) as DependencyObject;
            }
            return item;
        }

, ,

Leave a comment

IsInVisualTree – helper function for determining if a Silverlight item is visible or in the visual tree


Some Silverlight functions, especially those to do with coordinate transforms, tend to throw exceptions if the item you are testing isn’t in the visual tree and it is often interesting to know if an item is presently going to be displayed or not.  The following code uses the standard way of determining this, by walking the visual tree to see if the item is connected to the root visual of the application.  Being in the visual tree doesn’t mean the item is actually visible, this depends on the collapsed state of the element and its parents.


        /// <summary>
        /// Determines if an element is in the visual tree
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>
        ///  <c>true</c> if element parameter is in
        ///  visual tree otherwise, <c>false</c>.
        /// </returns>
        public static bool IsInVisualTree(this DependencyObject element)
        {
            return IsInVisualTree(element, Application.Current.RootVisual as DependencyObject);
        }

        public static bool IsInVisualTree(this DependencyObject element, DependencyObject ancestor)
        {
            DependencyObject fe = element;
            while (fe != null)
            {
                if (fe == ancestor)
                {
                    return true;
                }

                fe = VisualTreeHelper.GetParent(fe) as DependencyObject;
            }

            return false;
        }

To test if an item is visible you just walk the parents and check the Visibility state:


        public static bool IsVisible(this FrameworkElement ele, FrameworkElement topParent=null)
        {
            if (!ele.IsInVisualTree()) return false;

            while(ele != topParent && ele != null)
            {
                if (ele.Visibility == Visibility.Collapsed) return false;
               ele = VisualTreeHelper.GetParent(ele) as FrameworkElement;
            }
            return true;
        }

, , , , ,

Leave a comment

Silverlight Flip Control – page flipping without the performance problems



Download

A while ago I was blogging about the flip control that I had written for Silverlight. My first attempt at this used basic transitions only to show two sides of a page, but I found this slowed down dramatically when the contents of each side were complex.  The answer was to take an image of the contents of each side at the moment of the flip occuring and animate that instead, in this way it’s always smooth no matter how many controls are being used.

I’m posting the code for the control here.  As usual feel free to use or modify it in any way you like, I’d appreciate any really interesting upgrades be sent back to me so I can include them here.  There’s a sample project and web site in the ZIP file too.

The flip control is pretty straight forward.  It has two sides called Page1 and Page2.  The property used to flip over the control is Page2Visible, which is a bool.  There’s a PageChanged event that fires if you need the notificaton.  There are also advanced properties for horizontal and vertical alignment separate for each side (Side1VerticalAlignment etc).

If you are looking through the code then it’s CreateImages that does most of the hard work.  This routine takes an image of each of the pages and swops those for the real content during the flip.  The images are reset when the Visual State Manager says the transition is complete.

 

, , , , , ,

9 Comments

Element is already the child of another element – Arghhhhhh


Sometimes I just hate Silverlight. Spent 5 hours debugging a problem that resulted in the “Element is already the child of another element” InvalidOperation exception. I looked at everything; looked to see if I was accidentally reparenting something: no. Looked for unexpected recursion: no. Played with every debugger setting to get more information and finally disected the application – all to no avail.

Then I noticed I’d commented out an Image in one of my templates (derived from a Telerik template for tree nodes) and happened to notice that it was the target of a Storyboard. Yep that was it – not an error that reads “You’ve targeted an element that doesn’t exist” oh no. “Element is already the child of another element” – like hell it was 🙂

So word to the wise, if you don’t think you are actually making an element the child of another element, look for any inconsistencies in your storyboards and animations.

Help is at hand:

Since writing this post I’ve come up with an algorithm to help identify XAML markup that causes this exception. The post here has a link to the project and a description of the approach.

, , ,

5 Comments

Checking in at 30,000ft


Well I can confirm that GoGoInflight, VPN and TFS are working fine together – just did my first code check in while flying!  Unfortunately I am flying to Chicago rather than England thanks to the Icelandic Volcano… Oh well, while my plans have changed I think I’ve got it lucky compared to many.

Just been looking through the performance of my Silverlight app – drop shadows are still a real killer, they appear to spend an inordinate amount of time rendering the drop shadows of text that will be obscured completely by the rectangle on which it sits.  I’ve ended up doing a lot of fake shadows and written a component that does this using embedded borders with semi transparent fill.  It looks good and the performance is much better.

I’ve also spent a while looking at my flip control – the performance was getting very poor when the sides were full of complex objects – guess there’s no surprise there – so I’ve modified it to take an image of both sides during the flip and it’s back to smooth as silk no matter what I’m turning over.

I’ll extract the code for those two components into a separate project and post up here shortly, in case anyone needs that kind of functionality.

, , , , ,

2 Comments

Silverlight Binary Serialization


Download

For the latest information, version and more complete documentation, please click here.

Overview

SilverlightSerializer is a binary serializer that works in .NET and Silverlight, allowing you to move your objects between the two instances or store and retrieve them locally in either.  It is highly performant and produces small files which are suitable for further compression if you need to.

It can serialize just about anything, including complex multi-dimensional arrays of complex objects. It can only serialize public fields and properties, unless you write a custom serializer for a particular type.

The serializer can also produce Checksums that can be used to compare different objects to see if they have the same meaning, or to use as file names to see if you have a cached version already available.

There is now a Silverlight Serializer page on this blog where I will keep a version history and add revisions. This page has additional instructions on how to use the serializer and configure your classes, I suggest you take a look at that as I’m going to stop updating this post and start putting information on there.  Feel free to comment in either location however.

Commentary

I finally got fed up with the terrible performance of the DataContract serializer, especially for shared class libraries and was forced to write my own.

The serializer I have created doesn’t need to know about KnownTypes, is capable of suppressing a property or field with a [DoNotSerialize] attribute and writes to a byte array which is much smaller than the bloated XML format favoured by DataContractSerializer. It also handles object references, which you can’t make DCS do in a shared library.

The serialization won’t waste space and therefore doesn’t serialize properties/fields that have their initial values from the constructor. It won’t bother serializing empty collections etc and it uses tokens for type names and property names to save space; though I’m also using SharpZip to compress the output further in a wrapper I’ve put around the serializer in my own code (not shown here, or in the example project). This is sometimes necessary as it does store the AssemblyQualifiedName of the types in the graph (which is the trade off for not marking everything with KnownType in advance). I might look at a way of adding that functionality myself later, but my version doesn’t have problems with conflicting names that DCS frequently pops up.

So you can find the project here if you are interested, feel free to use or modify it in any way you like.

Here’s an example of using it:

        public class outer
        {
            public enum MyModes
            {
                One,
                Two,
                Three
            };
            public string Name { get; set; }
            public Dictionary Dict { get; set; }
            public BaseItem[] Array { get; set; }
            public MyModes Mode { get; set; }
            public outer()
            {
                Name = string.Empty;
                Dict = new Dictionary();
                Array = new BaseItem[10];
            }
        }

Calling the serializer:

             var s = new outer();
            var br = new Branch();  //One of my complex objects
            br.Elements.Add(new FilterBranch());
            s.Dict["Hello"] = br;
            s.Array[2] = new Campaign();
            s.Mode = outer.MyModes.Two;

            var bytes = SilverlightSerializer.Serialize(s);
            var item = SilverlightSerializer.Deserialize(bytes)  as outer;

Update: if you want to share classes between Silverlight and .NET4 make sure you read this post first!

Significant update:

Thanks to Peter and Steve I have modified the serializer so that it handles arrays with more than 2 dimensions and can construct some further types of object.

I’ve also updated it so that you can write your own custom serializers for your types and indeed for system types as well.  The way you do this is by creating a class that implements ISerializeObject and decorate it with a SerializerAttribute which declares the type that the item can serialize (one class is allowed to serialize more than one type, by using the attribute more than once).  The methods of ISerializeObject will then be called for your type – this allows you to have objects without a parameterless constructor be serialized in the normal way.  You must register each assembly that contains these decorated extensions by calling SilverlightSerializer.RegisterSerializationAssembly – if you are calling it from the assembly that contains your extension you don’t need to pass a parameter.

If you want to make your serializer store private properties you can implement the interface on the actual item you want to serialize (still decorating it with the attribute) and therefore have access to them.

Here’s a class without a paramterless constructor and containing a complex array:

public class myClass
{
   public int Parameter;
   public string[,,] Myarray = new string[3,3,3];
   public myClass(int aParameter)
   {
      Parameter = aParameter;
   }
}

Now here’s the definition of a helper class to serialize it:

[Serializer(typeof(myClass))]
public class SerializeMyClass : ISerializeObject
{
   public object[] Serialize(object target)
   {
        return new object[]
           {
               ((myClass) target).Parameter,
               SilverlightSerializer.Serialize(((myClass)target).Myarray)
            };
   }

   public object Deserialize(object[] data)
   {
       var parm = (int) data[0];
       return new myClass(parm)
          {
              Myarray = SilverlightSerializer.Deserialize((byte[]) data[1]) as string[,,]
          };
    }
}

Serializing it might look something like this (though you would probably register your serialization extensions during some init phase):

SilverlightSerializer.RegisterSerializationAssembly();
var cls = new myClass(101);
cls.Myarray[0, 1, 1] = "Hello Mum";
var d = SilverlightSerializer.Serialize(cls);
var x = SilverlightSerializer.Deserialize(d);

 

Further Update

I’ve fixed a number of bugs with serializing Enums when they were stored in an object property and handle Decimals properly.

Silverlight Serializer In Action

Peter Bromberg has come up with a great article on EggheadCafe that combines my serializer with a compression library and some utility classes plus examples. Check it out here.

The serializer has been linked into a persistent storage library for client side isolated storage by Ashiq Alibhai that you can find here.

, , , , , , , , , ,

39 Comments

Silverlight shared class libraries


I’ve been struggling with the fact that my application really needs shared class libaries and it needs to pass instances of these back and forth with a WCF service running on the back end.  After lots of playing around with data contracts I finally have an elegant solution that uses POCO object serialization and transfers the entities using byte arrays.  The real problem now is the huge size of those serialized objects, wow, DataContractSerializer is wordy as hell – so I’ve stuck a ZIP in the code to reduce the data transmission size but now I’m really on the lookout for a Silverlight serializer that knows what it’s doing via reflection and doesn’t feel the need to write massive descriptor strings on every property – just uses a dictionary of knowntypes and tokens to reduce the size.

If I can’t actually find one of those yet it looks like I may be rolling my sleeves up!  You can find an article here that does an implementation where you write a lot of the serialization logic yourself – that’s going to work for a lot of people but in my app there are so many objects being serialized written by different users it’s too risky to introduce all of the additional coding. My biggest hope is for this project that looks like it might be the right way to go.

Back to the original point: the trick to an elegant, scalable and pluggable implementation of POCO serialization between Silverlight and WCF is to use MEF or write your own type scanner and decorate the types you want to send with an attribute that indicates the type needs to be added to the KnownTypes collection of the serializer.  The built in KnownType attribute only works when you know all of the classes you might want to serialize in advance – not good in the case of a dynamic application, because every time someone wrote a new class you would have to change the WCF definition!

//UPDATE:

Oh well, tried out the serialization library that looked good, unfortunately I need to have my properties serialized not fields, and the project clearly has had that disabled for a reason  – quite a lot of hard to trace errors when I did enable it so I guess it’s back to the drawing board.  Damn.

//FURTHER UPDATE: Another post on this blog lists my solution to this.

, , , , ,

Leave a comment

Silverlight ComboBox loses selection on ItemsSource update


Download

I’ve been beating my head against a number of problems with the Silverlight project I am working on – but one of the worst was the amount of spaghetti you need to write if you are going to use Combo boxes or other ItemsControls whose source may change but you want to persist the current selection.  I figured that there had to be a better way, but I couldn’t find anything on Google.  

Eventually I bit the bullet and hijacked Silverlight’s binding system and replaced the bindings for ItemsControls with my own version that replaces the value after updating the source.  It’s nice because you wire the binding like normal and then just call “Hook” on my class and it does the rest for you! Woohoo, data grids with comboboxes that can update…. That’s going to save me a few of the hours I burned writing this thing.  

You start the hook by defining an instance in your UserControl and calling Hook from the _Loaded event, or anywhere after the tree has been formed and the initial bindings made.  That’s pretty much it – you can supply a delegate if you want to fix up your own list and you can hijack the ItemControls method of selecting to force a search of the list using the Equals override.

_hook.Hook(this); //!!!!!!

Source files here

, , , ,

10 Comments