Posts Tagged Programming

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 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