ISupportInitialize and XAML
Tuesday, 13 April 2010
Article Index
ISupportInitialize and XAML
XAML Trees
Using XAML

XAML Trees

The Tree Class was developed in Custom Shape and the details can be found there. All that really matters for this example is that the constructor needs five parameters before the geometry for the shape can be generated.  Given that Shape inherits from UIElement it already inherits the ISupportInitialize interface methods from its parent class. So rather than having to implement the interface we have to override the BeginInit  and EndInit inherited methods - but the general principle is the same.


We need a flag to indicate that we are in the middle of a BeginInit/EndInit block where parameters can be changed - outside of such a block changes are ignored, We also need a parameter-less constructor with the single task of setting the flag to false:

private bool DoingInit;
public Tree()
DoingInit = false;          

We next need to create properties that can only be changed when the flag is set to true:

private double _L=100;
public  double L {
get {return _L;}
set { if (DoingInit)_L = value; }
private double _s=.5;
public double s {
get {return _s;}
set { if (DoingInit)_s = value; }
private double _t=90;
public double t {
get {return _t;}
set { if (DoingInit)_t = value; }
private double _dt=10;
public double dt{
get {return _dt;}
set { if (DoingInit)_dt = value; }
private int _d = 5;
public int d{
get { return _d; }
set { if (DoingInit)_d = value; }

You can see that the basic idea is simple - write a set method that only sets the value if the flag is true for each of the five essential properties. Notice also that each property has been initialized to something reasonable.

The BeginInit method's only task it to set the flag:

public  override void  BeginInit()
DoingInit = true;

However it also calls the base class which sets some flags of its own and checks for property-nested BeginInit and EndInit calls - if another BeginInit occurs within a block then an exception is thrown by the base class method.

The EndInit is where the interesting things happen. At this point we can assume that all properties are set and so we might as well generate the geometry, or in general the resource, that the block of parameters determines:

public override  void  EndInit()
0, 0, L, s, t, dt, d);
DoingInit = false;

Notice that we also set the flag back to false and call the base class method for the reasons discussed earlier.

If we need or want to allow the use of the constructor to set parameters then we need to add a call to BeginInit and EndInit:

public Tree(double L, double s, 
double t, double dt, int d)
this.L = L;
this.s = s;
this.t = t;
this.dt = dt;
this.d = d;

With these changes we can now create an instance of the Tree class using:

Tree t = new Tree()
Stroke = Brushes.Red,
StrokeThickness = 2 };
t.d = 9;

Notice that it is still OK to set the positional and graphics parameters before creating the geometry within the BeginInit/EndInit block. Notice that you also have to check what happens if the Tree object is called on to display itself before things have been initialized. In this case if the geometry is null nothing is drawn.

An alternative strategy would be to throw an exception at an attempt to use the object before it has finished initializing. The whole point is that the fine details of the batch initialization pattern really are open and you can make the whole thing as strict or as loose as you like.






Last Updated ( Monday, 12 April 2010 )