Custom Shape
Wednesday, 07 April 2010
Article Index
Custom Shape
Optimising DefiningGeometry
A custom shape example
Repositioning a shape
Choosing a method

Optimising DefiningGeometry

This might all work but it is a very bad idea and not the way you should organise the work of a Shape object.

The problem is that the DefiningGeometry will be retrieved each time the shape is rendered. This creates a LineGeometry object on the heap and then discards it. In no time at all the heap will be full and the garbage collector will have to do a lot of work to free space.

The DefiningGeometry property should be written so as not to create any temporary objects - and this makes positioning and sizing more difficult than you might think because, rather than recreating the geometry each time it needs to be rendered, you have to create it when its position has been set and then effectively keep it ready for use.

In other words for a fast render you need to cache the geometry.

In the case of MyLine modifying DefiningGeometry is relatively easy. All we have to do is to move the creation of the LineGeometry out of the get method:

`private LineGeometry line =                     new LineGeometry()protected override Geometry                       DefiningGeometry{ get {  line.StartPoint = new Point(X1, Y1);  line.EndPoint = new Point(X2, Y2);  return line; }}`

Now the LineGeometry instance is created when the class is instantiated and isn't left floundering on the heap each time DefiningGeometry is called.

If you are thinking that there is still something wrong with the above - you would be correct. The problem is that we are still creating two temporary Point objects and leaving these on the heap!

The rule is that "new" should not occur within the get method.

Once again it is easy to fix the code in this case. We simply move the creation of the Point objects outside of the get method and initialize them when the X and Y properties are set.

`public class MyLine : Shape{ private LineGeometry line =                     new LineGeometry();  private Point start = new Point(0, 0); private Point end = new Point(0, 0);  public double X1         {set{start.X =value;}} public double Y1         {set{start.Y = value;}} public double X2         {set{end.X = value;}} public double Y2         {set{end.Y = value;}} protected override           Geometry DefiningGeometry {  get  {   line.StartPoint = start;   line.EndPoint = end;   return line;  } }}`

At last we have a version of the new class that not only works but works correctly.

The only change that needs to be made to turn it into a fully functioning version of the Line class is that the new properties X1,Y1,X1 and X2 should really be implemented as dependency properties - a step that has been left out of the entire article for simplicity.

Any property that you add to the derived Shape class should be a dependency property if you want to use it for data binding or animation. Even if you don't want to use animation or data binding you need to keep in mind that dependency properties are usually more efficient.

<ASIN:1430219106>

<ASIN:1933988223>

<ASIN:0596510373>

<ASIN:1430210842>

Last Updated ( Wednesday, 07 April 2010 )