More About the Layout System

I recently posted about the Silverlight Layout System (and now have posted videos on the subject here and here). But this can get quite confusing and a reader posted this question:

You mention PreArrange() and it is called but you are not clear on which of the functions should be used in it.  I am also not clear on where “item” and “center” are defined.

This gives me an opportunity to do a better job explaining how the location of each object as it moves around the carousel, is determined.

Please be sure to read the two blog postings before reading this response. The best bet would be to download the complete source (which is available with the video), but let’s tackle your specific questions.

Also, please note, in the code associated with the video, PreArrange is called DoArrange – these are the same method.

Answering your three questions, first.

PreArrange() is not part of the Silverlight Layout System, it is a method that I wrote (or, more accurately, “borrowed” from the original author of the code I based my approach on).

I’m not quite sure what you mean when you write “you are not clear on which of the functions should be used in it,” but the goal of this method is explained in the second article under the heading PreArrange.

Center and Item

Both center and item are defined within the DoArrange method as local variables.

Item is defined in the for loop (about four lines into the method) to hold each member of the Children collection of the panel, and is defined to be of type UIElement,

UIElement item = Children;

Essentially, what this method does is to distribute the objects at the appropriate distance from the center of your panel.

To do that, it needs a working definition of “center” and by center we mean half the width and half the height, but we want to center the item and so must allow for the width and height of the item as well.

Picture, for example, that we are working in a panel that is 500 x 300,

CarouselRect

The center of this rect could be found as follows

Point center = new Point( 
   this.Width / 2, 
   this.Height / 2;

As you can see, center is defined to be of type Point. A Point’s constructor takes two doubles, as shown in the Silverlight documentation

PointConstructor

In this case, we find the X coordinate by taking the width of the panel (this) and dividing it in half. We do the same for the y coordinate.

MidPointApproach1

Centering an Object

If we had an object that was 60 x 40 and wanted to place it dead center, you might think that we would set its coordinates to 250,150, but the coordinate for an object is upper left hand corner of the bounding rectangle of the object, and we’d end up with something like this:

OffCenterObject

You will remember that we decided earlier to set all our objects to the same size, so we have two ways of fixing this problem. We can offset each object’s center by 1/2 its width and 1/2 its height, or we can offset the center by 1/2 the width and height of the ItemSize, which is what we do:

Point center = 
   new Point( ( this.Width - ItemSize ) / 2, 
      ( this.Height - ItemSize ) / 2 );

In the original computation, the X coordinate of the center was 1/2 of the width (or 500 /2 or 250). In this formula it is (500 – 60) /2 or 440 /2 = 220. Similarly the Y coordinate is now (300-40)/2 = 130. Thus the center moves from 250,150 to 220,130. When we place the object at 220,130 we center the object perfectly!

ObjectCentered

Finding The Distance from the Center

To place each object, we need to know the coordinates for that object, and we need to know it in terms of distance from the center and then we need to translate that into distance from the (0,0) coordinates of the upper left hand corner.

To accomplish this, we start with the mathematics of a triangle to find the distance along the x axis  and the distance along the y axis,  given the two facts we know: the radius and the angle.

The distance from the center on the X axis is equal to the radius times the cosine of the angle.

The distance from the center on the Y axis is equal to the radius times the sine of the angle

How Do We Find the Radius?

Let’s assume that we redraw our rectangle to be a square, 150 pixels on a side as shown in the figure. If we draw our carousel as a circle within the square, and drawing lines through the center, make our circle tangential to the square at the X and Y axis, we can then take advantage of the fact that the width of the square will be equal to the diameter of the circle (or 1/2 the width will be equal to the radius).

AngleToPositionComplete

If we then stretch our square to a rectangle, the circle will stretch to an ellipse, but the principle will hold, so long as we differentiate between the X and Y “radius”

This is why we you see this in the code:

double radiusX = center.X;
double radiusY = center.Y;

You can read this as “the variable radiusX  is set equal to the distance on the X axis from the edge to the center, which serves as the radius of a circle circumscribed within the rectangle, if that radius is drawn on the x axis. and the variable radiusY….”

How Do We Find the Angle?

The angle was stored in the angle property of the CarouselPanel, in the ArrangeOverride method. It was set by iterating through the children, and for each child multiplying that child’s fractional part of the total number of children by 2 pi  (the number of radians equal to 360 degrees, or the number of radians in a full circle).

for ( int i = 0; i < Children.Count; i++ )
{
   Children[ i ].SetValue( CarouselPanel.AngleProperty,  
        Math.PI * 2  * i / Children.Count );
}

Computing the X, Y Coordinate

We are now ready to compute the x,y coordinate of the object. We know that the radius is the same as the distance to the center. We know that the AngleProperty is a representation of the angle in radians. We know the formula.

 for ( int i = 0; i < Children.Count; i++ )
 {
    UIElement item = Children[ i ];
    double radians = (double) item.GetValue( 
             CarouselPanel.AngleProperty );

    Point p = new Point(
        ( Math.Cos( radians ) * radiusX ) + center.X,
        ( Math.Sin( radians ) * radiusY ) + center.Y
    );

Why Do we add center.X and Center.Y?

While the formula tells us the distance the object should be located from the center, our coordinate system doesn’t have (0,0) at the center. Instead (0,0) is at the upper left corner, counting up on the X axis as you move to the right, and up on the y axis as you move down. To compensate, we must move to the center by adding back the distance from (0,0) to the center, which is to say we must move center.X on the X axis and center.Y on the Y axis. 

This might be slightly clearer if we were to reverse the order of the operations:

Point p = new Point(
     center.X + ( Math.Cos( radians ) * radiusX ),
     center.Y + ( Math.Sin( radians ) * radiusY )
                   );

Thus, you would read this: “move to the center, and then move the computed distance.”

Previous: Putting the Silverlight Layout System To Work


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on More About the Layout System

Tech Ed Connect

Interesting social / community approach at tech ed. You fill out your community quick card (here’s mine):

TechEdConnect

and you then fill in a quick survey of your interests and the types of folks (designer, developer, etc.) you are interested in meeting at Tech Ed.  Click on PeopleMap and hey! presto! a map with you at the center and others positioned so that proximity = closeness of match in interest. Mouse over tells you more, click on the individual to see their profile.

PeopleMap

Neat way to make contact with folks.


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on Tech Ed Connect

Carousel Video Posted – Parts 1 and 2

I’m very pleased to be able to announce that the videos Creating a Carousel Part 1 and Creating a Carousel Part 2 are now available.  These videos cover the material that is also discussed in my two part blog entry (beginning here) including such advanced topics as

  • The Silverlight Layout System
  • Overriding MeasureOverride and ArrangeOverride
  • Matrix Transforms
  • Adding Attached Dependency Properties
  • Programmatic Animation

This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on Carousel Video Posted – Parts 1 and 2

Putting the Silverlight Layout System to Work

In my previous blog entry I described the fundamentals of the Silverlight Layout System (SLS). Today, I’d like to build a simplified version of the custom Carousel control that I create in greater detail in a forthcoming video, and examine the role of the SLS in laying out and animating the objects in the Carousel.

We’ll start by creating a new Silverlight solution, and immediately adding a Silverlight library (Add New Project –>Silverlight Class Library) named SimpleCarouselControl. Within that library we’ll add a single class: CarouselPanel.cs, and we’ll delete Class1.cs that Visual Studio created.

We’re going to animate the carousel programmatically using a DispatchTimer, so be sure to add

using System.Windows.Threading;

at the top of the page. Within the class, let’s add a pair of private member variables,

protected DispatcherTimer timer;
public double ItemSize { get; set; }

The latter will be used to hold the size of the items we’ll be adding to the carousel (and to keep things absurdly simple, we’ll set a single size for all the items).

Attached Dependency Property

We want to enable each child to set its Angle Property, but of course each child won’t have such a property; the angle property only makes sense in the context of a carousel.  This is exactly analogous to allowing each item in a grid to set the grid.row and grid.column and the solution is the same: we create an attached dependency property:

 public static readonly DependencyProperty AngleProperty =
       DependencyProperty.RegisterAttached(
       "Angle",
       typeof( double ),
       typeof( CarouselPanel ),
       null );

If you are familiar with the syntax for registering regular dependency properties, you’ll notice this is identical except that the keyword Property is changed to DependencyProperty.  The first parameter is the name of the Dependency property, the second is its type, the third is the type of its parent, and the fourth is a reference to its metadata (almost always a delegate used as a callback for when the property changes).

We’ll also declare a static get and set method for the DP:

 public static double GetAngle( DependencyObject obj )
 {
    return (double) obj.GetValue( AngleProperty );
 }

 public static void SetAngle( DependencyObject obj, double value )
 {
    obj.SetValue( AngleProperty, value );
 }

 

With the properties in place, we’re ready to implement the methods needed to handle layout (MeasureOverride and ArrangeOverride).  We’ll use a helper method for the latter, which will come in handy in animating the carousel, which, after all, is just repeatedly laying out the controls, changing their angle and then laying them out again.

MeasureOverride

We’ll make our override of MeasureOverride simple. Rather than asking each object for its size, and then deciding on a total size needed, we’ll get the size of the largest item, and then multiply that by the number of items. Quick, sleazy and effective.

protected override Size MeasureOverride( Size availableSize )
{
   double maxSize = ItemSize;
   int numChildren = 0;
   if ( ItemSize == 0.0 )
   {
      foreach ( UIElement element in Children )
      {
         element.Measure( availableSize );
         maxSize = Math.Max( element.DesiredSize.Width, maxSize );
         maxSize = Math.Max( element.DesiredSize.Height, maxSize );
         ++numChildren;
      }
      ItemSize = maxSize;
   }
   return new Size( numChildren * maxSize, numChildren * maxSize );
}

ArrangeOverride checks that the panel has chidlren, and iterating through the children sets each one’s angle property for even spacing around the circle that represents the carousel. (Note that the member variables Width and Height are inherited from FrameworkElement).

protected override System.Windows.Size ArrangeOverride( 
System.Windows.Size finalSize ) { if ( Children.Count == 0 ) return new Size( Width, Height ); for ( int i = 0; i < Children.Count; i++ ) { Children[ i ].SetValue( CarouselPanel.AngleProperty, ( Math.PI * 2 ) * i / Children.Count ); } PreArrange(); return new Size( Width, Height ); }

Setting the Angles

The key to this math is that a circle is 360 degrees or 2pi radians. Thus, you are setting the angle to each child’s fraction of the total number of children times the circumference  number of radians in a circle [corrected 2/21/2009] (e.g., if there are 6 children and this is child 5 you are setting the angle to 5/6 of the circumference. Each of the 6 children will be its fraction of the way around (1/6th, 2/6th etc.).  If there are 8 children, they will be 1/8, 2/8, etc. Sweet.

As an aside, when I first saw this, it was written:

Children[ i ].SetValue( 
         CarouselPanel.AngleProperty, 
          i * ( Math.PI * 2 ) / Children.Count );

The result is identical, but the reasoning is harder to discern.

PreArrange

The helper method PreArrange finds the center of the panel, and from that, the X and Y coordinates of the center.

It then iterates through the children of the panel and uses the Angle of each element to find the distance from the center at which to place the object. It does so by setting a Point (P) as the run (multiplying the sine and cosine by the radius) from the center.

double radians = (double) item.GetValue( CarouselPanel.AngleProperty );

Point p = new Point(
                    ( Math.Cos( radians ) * radiusX ) + center.X,
                    ( Math.Sin( radians ) * radiusY ) + center.Y
                   );

Matrix Transform

In other columns and videos we discuss various transforms that can be made directly on shapes and objects such as scale transforms, skew transforms and so forth.  All of these and more can be made directly using a Matrix transform.

While matrices are powerful and have many applications the Matrix we care about here is called an affine matrix which is used to manipulate a coordinate system on a two dimensional plane.

You’re not going crazy

I’ve chased down pages and pages of documentation, and this is what I’ve found. You are told repeatedly that the Matrix we use is a 3×3 structure in which you can safely ignore the third column. The matrix looks like this

    Ignore this column
M11 M12 0
M21 M22 0
OffsetX OffsetY 1

You are told that the OffsetX and OffsetY represent translation values which their name more or less tells you and you are told that the other four can be used for any kind of transform. Great, which does what?  Aha!  That you are not told.  Most of the documentation teases wonderfully, with sentences like this: “M11, the numeric value in the first row and first column of the matrix. for more information see the M11 property.   You follow that link with eager anticipation where you find an entire page of documentation that tells you that this attribute or property sets or retrieves the first row and first column of the matrix (!). Yikes!

So, because I honestly don’t think it is a corporate secret, here is what they actually do: (The default values are in parentheses)

Secrets Revealed!  
M11  X Scale (1.0) M12  Y Skew (0.0)
M21  X Skew (0.0) M22  Y Scale (1.0)
OffsetX  (0.0) OffsetY  (0.0)

For our carousel we want to scale the object based on where it is on the Y scale as in a two dimensional plane, as it moves towards higher values on the Y scale it should appear to move closer to you and thus appear larger.

To compute that value, we return to the point P we computed earlier (the placement for our object as a distance from the center).  Since we know the distance from the center we need only set the apparent perspective by dividing that distance by the sum of the center and radius values plus a small constant found by the incredibly scientific method of trial and error.

 double scaleMinusRounding = p.Y / ( center.Y + radiusY ) +0.2;

We then ensure that we use the value we just computed or the value 1, whichever is less,

double scaleY = Math.Min( scaleMinusRounding, 1.0 );
double scaleX = Math.Min( scaleMinusRounding, 1.0 );

Note carefully that we set the scaleX adn scaleY to the scaling factor we derived based on the Y axis. Objects appear larger as they approach, but not as they move from side to side, and they appear larger both in height and in breadth.

Using the Matrix to implement the scaling up

With the scale values in hand, we retrieve the MatrixTransform object from each item in the carousel and we create a new Matrix to provide to it. The Matrix constructor takes six values (as you would expect) as shown,

MatrixConstructor

Here’s the complete block of code,

MatrixTransform mt = item.RenderTransform as MatrixTransform;
double scaleMinusRounding = p.Y / ( center.Y + radiusY ) +0.2;
double scaleY = Math.Min( scaleMinusRounding, 1.0 );
double scaleX = Math.Min( scaleMinusRounding, 1.0 );
Matrix mx = new Matrix( scaleX, 0.0, 0.0, scaleY, 0.0, 0.0 );
mt.Matrix = mx;
item.RenderTransform = mt;

All that is left to do is to ensure that the items in front are not only larger, but are on top of the items that are behind, which we do by hacking the zIndex,

int zIndex = (int) ( ( p.Y / base.Height ) * 50 );
item.SetValue( Canvas.ZIndexProperty, zIndex );

We can now compute the bounding rectangle for each item, and call Arrange on the item, passing in that rectangle,

Rect r = new Rect( p.X, p.Y, ItemSize, ItemSize );
item.Arrange( r );

Starting  The Animation

All that is left is to start the animation, which we can do by creating and starting the DispatcherTimer:

public CarouselPanel()
    : base()
{
    Loaded += new RoutedEventHandler( CarouselPanel_Loaded );
}

void CarouselPanel_Loaded( object sender, RoutedEventArgs e )
{
    if ( timer == null )
    {
       timer = new DispatcherTimer();
       timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
       timer.Tick += new EventHandler( timer_Tick );
       timer.Start();
    }
}

The DispatcherTimer’s interval property is set with a TimeSpan, the constructor for the TimeSpan used here takes days, hours, minutes, seconds and milliseconds. We have instructed the timer to fire its Tick event every 10 milliseconds or 100 times per second.

The timer Tick is registered with an event handler and then the Timer is started with the cleverly named Start method (no extra points for guessing how it is stopped).

Each time the event fires, our event handler iterates through the children, and moves each child’s angle by a small increment,

void timer_Tick( object sender, EventArgs e )
{
   foreach ( UIElement uie in Children )
   {
      double current = (double) ( uie.GetValue( CarouselPanel.AngleProperty ) );
      uie.SetValue( CarouselPanel.AngleProperty,
         current + ( .0016 * (2 * Math.PI ) ) );  
   }
   PreArrange();
}

That’s it for the custom control. There is no need to create a default appearance (e.g., generic.xaml) as this control derives from Panel. The next step is to use your new SimpleCarousel in your xaml file to hold and display the items in the Carousel.

 

Page.xaml

The very first thing you’ll need is to make your main project (SimpleCarousel) aware of the control you just created, by adding a reference to the Control Library project,

AddReferenceToCarousel

Once you’ve done this you can add a namespace identifier so that you can add an instance of the control to the page.

xmlns:custom="clr-namespace:SimpleCarouselControl;assembly=SimpleCarouselControl"

 

 

 

From there, you just add the panel as you would any other container,

<custom:CarouselPanel x:Name="cPanel"
                          Width="500"
                          Height="400"
                          Background="Bisque">

</custom:CarouselPanel>

Between the open and close tags you may place as many UI elements as you like,

<custom:CarouselPanel x:Name="cPanel"
                      Width="500"
                      Height="400"
                      Background="Bisque">
  <Ellipse Width="15"
           Height="15"
           Fill="Orange" />
  <Ellipse Width="75"
           Height="40"
           Fill="Blue" />
  <Rectangle Height="60"
             Width="30"
             Stroke="Black"
             StrokeThickness="3" />
  <Ellipse Width="50"
           Height="50"
           Fill="Red" />
  <Rectangle Height="40"
             Width="40"
             Fill="Green" />
  <TextBlock Text="Hello!"
             FontFamily="Georgia"
             FontSize="24" />
  <ListBox Height="70"
           Width="75">
    <ListBoxItem Content="George" />
    <ListBoxItem Content="Paul" />
    <ListBoxItem Content="John" />
    <ListBoxItem Content="Ringo" />
  </ListBox>
</custom:CarouselPanel>

The Sequence Of Events

Page.xaml will load, and your panel will be initialized. Your class will be constructed, and then when Page.xaml loads the Carousel will load firing the CarouselPanel_Loaded event.

As part of loading the page, MeasureOverride and ArrangeOverride are called and initial sizing and placement of each object is accomplished. The Carousel_Loaded event handler also creates the timer, sets its interval and starts it. 

10 milliseconds later the event will fire and be caught by timer_Tick which will iterate through all the Panel’s children, getting their angleProperty and incrementing them slightly. Timer_Tick then calls PreArrange which re-scales each object depending on its position on the y axis and calls arrange on the object, which in turn triggers a call to ArrangeOverride on each object (but not on the panel.

Note that the overrides of MeasureOverride and ArrangeOverride in panel are each called only once; after that the values are scaled and incremented as part of the animation but not as part of the layout system.

Streaming Example

— Begin streaming application

— End streaming application

 

    Previous: The Layout Model       Next: More about Layout


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | 3 Comments

The Layout Model

 

 

I have finished a video, to be posted soon, on how to build a Carousel control. Along the way, I had the opportunity to explore the Silverlight Layout System (SLS) and will describe this fascinating corner of Silverlight 2 in this and future blog entries.

The first thing to know about the SLS is that most of the time you can ignore it! It is possible to become quite proficient in Silverlight programming without even knowing explicitly that the system exists, much less having to override any of its methods. For most developers, most of the time, the layout system is implicit and mediated for you by layout controls such as the GridPanel and StackPanel, and more recently by the Silverlight Toolkit layout controls such as the DockPanel and the WrapPanel.

That said, there are times when you want to do something the existing controls just don’t provide, and familiarity with how Silverlight lays out controls can be both fascinating and essential.

Page Fundamentals

When you ask Visual Studio to create an application, it creates Page.xaml. Pages consist of a UserControl that contains a single element, typically a panel which in turn has any number of child elements.  If you create additional pages  the same pattern is repeated (Perhaps confusingly, you create pages by selecting “Add User Control” )

Because you can put a UserControl inside another user control (see my video on multiple-page applications and also my video on reusable user controls) we distinguish between a page (a .xaml file with a user control and its contents) on the one hand and a Custom UserControl on the other, but this is a matter of convention.

In any case, the key point is that the outermost user control can only have one child, and that child is almost always a type derived from Panel.

About Panels

Panel itself is abstract, meaning that it was created to provide shared functionality for types derived from it, but it is not possible to instantiate a Panel per se.

The Panel Class derives from FrameworkElement, which in turn derives from UIElement.

PanelControl

UIElement

The UIElement class provides the common features for most of the objects that have a visual appearance in Silverlight, and lays the ground work for layout. It is uncommon to derive directly from Framework element, and almost unheard of to derive directly from UIElement (both should be though of as infrastructure) but it is not illegal. Probably the key UIElement method for layout is InvalidateArrange (described below) and the key property is RenderTransform.

FrameworkElement

Framework element (which derives from UIElement) provides the API for any object that participates in the Silverlight Layout System (as well as APIs for data binding and object lifetime). It is here that you find the two essential methods for taking programmatic control of layout

  • MeasureOverride
  • ArrangeOverride

Along with various important properties and events.

A Two Step Process (Measure twice, cut once)

Laying out a Silverlight application is a two-step process. This allows the Silverlight Layout System to first measure all the objects you wish to display and then to lay them out given the available space balanced against each objects’ desired size. Compromises are made, and to some degree the size allocated one object is determined both by the total of the sizes requested and the total size available (and (in some cases) who asks first!)

As you can imagine, this can get quite complicated, but we can keep it relatively simple, at least at first. 

Let’s start by making the assumption that what we will have is a user control with a class derived from Panel.

MeasureOverride

iStock_TapeMeasureXSmall

Your main job in MeasureOverride is to loop through the Panel’s children and call Measure() on each child. The parameter you pass in to each child’s Measure() method is of type Size and tells the child object the maximum size it can have.

Note that you can say to the child “take all the size you want,” by passing in a Size object with Double.PositiveInfinity for both dimensions.

Measure() does not return a value. Instead it sets its own internal property DesiredSize to the size it wants or the size it can have, whichever is smaller.

Note that it is essential to call Measure on every child even if you don’t need its size. A critical side-effect of calling measure is to set the “yes I want you to display” bit.

MeasureOverride() returns the desired size of the layout container (often the sum of the desired sizes of the children).

ArrangeOverride

iStock_Parts_XSmall

The Silverlight Layout System calls ArrangeOverride() on the panel, and again, the panel iterates over every child, this time calling Arrange() on each one, telling it how much space it has been allocated.

Interestingly, each time you call Arrange on a child element, it calls ArrangeOverride as the first step. For that matter, each time MeasureOverride calls Measure on a child, the child calls MeasureOverride on itself!  We’ll examine this bit of recursion in a future blog entry.

You remember that the parameter to MeasureOverride was a Size object. The parameter to ArrangeOverride is a System.Windows.Rect object which describes not only the size but the location of the object.

In my next blog entry, I’ll work through a simplified Carousel example that puts all this theory into practice.

Next: Putting the layout system to work


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | 1 Comment

Help! The Silverlight Toolkit Ate My PC!

Dear Jesse,

"I loaded the Silverlight Toolkit from December 1988 on my CPM machine and it broke my Apple IIe in my vacation home in Maine. What should I do?" – Toolkit Lover.

Dear Toolkit Lover,

We have a dedicated forum for posting questions about the Silverlight Toolkit where you will be able to get very fast answers. The forum is watched by the Toolkit team as well as many community experts.

To get there, please click here or enter http://silverlight.net/forums/35.aspx in your browser.  You can also reach the forum through the Toolkit page on Codeplex).

To get the best results, please be sure your message includes:

Note that screen captures can be very helpful:

SilverlightVer
To get to this image, navigate to any Silverlight application and right click. You will see a small box that says "Silverlight Configuration." Left click on that box and a tabbed dialog box will open with this information on the About tab.

SystemInfo

To get this information from Vista, Click on Start –> Control Panel –> Welcome Center and then in the upper right hand corner: Show More Details.

ToolKitControlVer

To get to this information about the Toolkit dll’s, open a Silverlight application, click on references and navigate to wherever you installed the Toolkit. Hover over the appropriate Silvelight Toolkit DLL (in the illustration above I hovered over the Controls.DLL file) to see the File version adn Date Created.

 

The Subject Line Is Critical

One great tip on getting help is to make sure the subject of your message summarizes the problem. You’ll get a faster response with Crashes on binding to XML File  than with Help! Urgent!

Small Programs Get Tested, Big Programs Get Ignored

Boil your problem down to the smallest possible program that reproduces the error/bug/issue. I find that when I do so, 50% of the time I solve the problem my self, and in any case I greatly increase the likelihood that someone will bother to load my problem and find out what is wrong.

Comments Can Help or Kill

Also be sure to comment your program wisely: don’t fill the program with self-evident comments

x = 5   // assign 5 to x

they are just clutter.

On the other hand, do explain anything you are doing that is less than self-evident

// get the collection from the
// isolated storage reference variable
foo.itemSource = bar; 

Short Paragraphs

Finally, you want folks to read your message; so make it short, and make each paragraph short. Make it easy and inviting and more folks will read and help.

 

Best of luck!

 

-jesse

 

 

 


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Tagged | Comments Off on Help! The Silverlight Toolkit Ate My PC!

Creating Extension Methods in VB

 

I received a question about how to create extension methods in VB. It turns out that the key difference is that the extension must be defined in a Module and not in a class.

Thus, building on the code from the previous example, we end up with the same Page.xaml and a very similar Page.xaml.vb and a quite different Extension.vb

Here is Extension.vb

Imports Microsoft.VisualBasic
Imports System
Namespace GetLastNFromString
   Module ExtensionModule
      <System.Runtime.CompilerServices.Extension()> _
      Public Function Right(ByVal s As String, _
ByVal howMany As Integer) As String If howMany <= s.Length Then Return s.Substring(s.Length - howMany, howMany) Else Return s End If End Function End Module End Namespace



And here is Page.xaml.vb

Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Net
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Shapes

Namespace GetLastNFromString
   Partial Public Class Page
       Inherits UserControl
      Public Sub New()
         InitializeComponent()
         AddHandler GoButton.Click, AddressOf GoButton_Click
      End Sub

      Private Sub GoButton_Click( _
            ByVal sender As Object, _
            ByVal e As RoutedEventArgs)
         ResultBox.Text = _
StringToParse.Text.Right(Convert.ToInt32 (NumberToGet.Text)) End Sub End Class End Namespace

For completeness, here is Page.xaml

<UserControl x:Class="GetLastNFromString.Page"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   Width="650"
   Height="200">
  <Grid x:Name="LayoutRoot"
        Background="Bisque">
    <Grid.RowDefinitions>
      <RowDefinition Height="1.5*" />
      <RowDefinition Height="1*" />
      <RowDefinition Height="1*" />
      <RowDefinition Height="1*" />
      <RowDefinition Height="1*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="1*" />
      <ColumnDefinition Width="2*" />
    </Grid.ColumnDefinitions>
    <TextBlock HorizontalAlignment="Center"
               Margin="0,0,0,0"
               x:Name="Title"
               Grid.ColumnSpan="2"
               FontFamily="Georgia"
               FontSize="36"
               Foreground="#FF0C42EE"
               Text="Last n Traditional (VB)"
               TextWrapping="Wrap" />
    <TextBlock x:Name="String_Prompt"
               Text="String"
               Width="Auto"
               Grid.Row="1"
               Margin="0,0,10,0"
               Foreground="Blue"
               FontFamily="Georgia"
               FontSize="24"
               VerticalAlignment="Bottom"
               HorizontalAlignment="Right" />
    <TextBlock x:Name="NumChars_Prompt"
               Text="Number To  Get"
               Grid.Row="2"
               Margin="0,0,10,0"
               Foreground="Blue"
               FontFamily="Georgia"
               FontSize="24"
               VerticalAlignment="Bottom"
               HorizontalAlignment="Right" />
    <TextBlock x:Name="Result"
               Text="Result"
               Grid.Row="3"
               Margin="0,0,10,0"
               Foreground="Blue"
               FontFamily="Georgia"
               FontSize="24"
               VerticalAlignment="Bottom"
               HorizontalAlignment="Right" />
    <TextBox FontFamily="Georgia"
             FontSize="24"
             HorizontalAlignment="Left"
             Margin="5,0,0,2"
             x:Name="StringToParse"
             VerticalAlignment="Bottom"
             Width="400"
             Grid.Column="1"
             Grid.Row="1"
             Text="" />
    <TextBox  x:Name="NumberToGet"
              FontFamily="Georgia"
              FontSize="24"
              HorizontalAlignment="Left"
              Margin="5,0,0,0"
              VerticalAlignment="Bottom"
              Width="Auto"
              Grid.Column="1"
              Grid.Row="2"
              Text="?" />
    <TextBlock x:Name="ResultBox"
               HorizontalAlignment="Left"
               Margin="5,0,0,0"
               VerticalAlignment="Bottom"
               Grid.Column="1"
               Grid.Row="3"
               FontFamily="Georgia"
               FontSize="24"
               Text="" />
    <Button x:Name="GoButton"
            Content=" Go! "
            Grid.Row="4"
            Grid.Column="0"
            FontFamily="Georgia"
            FontSize="18"
            Foreground="Blue"
            HorizontalAlignment="Right"
            Margin="5"
            Width="Auto" />
  </Grid>
</UserControl>

Next: Extension Methods 
 

This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on Creating Extension Methods in VB

Extension Methods Part 2 – Lambda Expressions in Linq

 

 

In my previous entry on this topic I demonstrated how you can use Extension methods to add what appear to be new methods to existing classes. In this entry I will demonstrate how Extension methods enhance Linq by adding “method queries” using lambda expressions.

To see how this works, let’s set up a simple query,  with a display that will show the two ways we might execute that query using Linq.

We’ll start by creating a new Silverlight application and within the application a simple data class, Person. Here is the code for Person.cs

using System.Collections.Generic;

namespace ExtensionPart2
{
   public class Person
   {
      public string FirstName { get; set; }
      public string LastName { get; set; }
      public string EmailAddress { get; set; }

      public override string ToString()
      {
         return string.Format( "{0} {1}\n{2}",
                     FirstName, LastName, EmailAddress );
      }

      public static List<Person> GetPeople()
      {
         List<Person> people = new List<Person>();
         people.Add( new Person() 
         { 
            FirstName = "Jesse", 
            LastName = "Liberty", 
            EmailAddress = "jliberty@microsoft.com" 
         } );

         people.Add( new Person() 
         { 
            FirstName = "George", 
            LastName = "Washington", 
            EmailAddress = "gWashington@whitehouse.gov" 
         } );



// also added John Adams, Thomas Jefferson
// James Madison, James Monroe, John Q. Adams return people; } } }

(I’ve elided the initialization of 5 of the presidents to save room)

 

We will issue two queries against this data. The first is a traditional Linq query,

from person in people
where person.LastName.StartsWith( "M" )
select person;

While this works fine, taking advantage of extension methods allows us (or more accurately the authors of the library) to extend the List<t> class to add the Where method, which in turn allows us to collapse these three statements to a single line of code using a lambda expression,

people.Where( person => person.LastName.StartsWith( "M" ) );

Examining the Extension Method

The tooltip for people.Where give great insight into what is actually going on here

whereExtension

Taking this apart, we see that Where is defined to be an extension method that returns an IEnumerable<Person> and takes one argument: a function (named predicate) that takes two arguments: a Person object and a boolean.

Rather than passing in a method, or a delegate to a method, or even an anonymous method, we go one step further and pass in a lambda expression. As you know from previous articles, the lambda expression “are a way to write short in-line substitutions for the methods that delegates refer to.”

You can read the lambda expression above as

“There is a method that takes one parameter, a list of person objects named people and that returns  each person whose last name starts with the letter m in an IEnumberable collection.”

or, more conventionally you can read it as

“person goes to each person whose last name starts with m”

For a lengthy review of how to read this aloud see this article.

The result for both queries is identical, but I would argue the second query is far more readable, as shown in the running program,

Extension2Running

The code for Page.xaml is shown here, and below it the code for Page.xaml.cs

Page.xaml

<UserControl x:Class="ExtensionPart2.Page"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  mc:Ignorable="d"
  HorizontalAlignment="Left"
  VerticalAlignment="Center"
  FontFamily="Georgia"
  FontSize="14"
  Width="650"
  Height="553"
  Margin="5">
  <Grid x:Name="LayoutRoot"
        Background="Bisque"
        Margin="20">
    <Grid.RowDefinitions>
      <RowDefinition Height="1*" />
      <RowDefinition Height="5*" />
      <RowDefinition Height="3*" />
      <RowDefinition Height="3*" />
      <RowDefinition Height="1.5*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="6*" />
      <ColumnDefinition Width="4.5*" />
    </Grid.ColumnDefinitions>
    <TextBlock Height="Auto"
               Width="Auto"
               Grid.Row="0"
               Text="Where last name begins with M"
               TextWrapping="Wrap"
               FontFamily="Georgia"
               FontSize="24"
               Margin="0"
               Grid.RowSpan="1"
               Grid.ColumnSpan="2"
               HorizontalAlignment="Center" />
    <TextBlock Text="Presidents"
               TextWrapping="NoWrap"
               FontFamily="Georgia"
               FontSize="18"
               HorizontalAlignment="Left"
               VerticalAlignment="Top"
               Margin="5,5,5,5"
               d:LayoutOverrides="Height"
               Grid.Row="1" />
    <ListBox x:Name="PresidentsListBox"
             Margin="5"
             Grid.Row="1"
             Grid.Column="1" />
    <TextBlock HorizontalAlignment="Left"
               VerticalAlignment="Bottom"
               Margin="5,4,5,5"
               Grid.Row="2"
               FontFamily="Georgia"
               FontSize="14"
               Text=""
               TextWrapping="Wrap" />
    <ListBox x:Name="LinqResults"
             Margin="5"
             Grid.Row="2"
             Grid.RowSpan="1"
             Grid.Column="1" />
    <ListBox x:Name="QOEM_Results"
             Margin="5"
             Grid.Column="1"
             Grid.Row="3"
             Grid.RowSpan="1" />
    <StackPanel Margin="0"
                Grid.Row="2">
      <TextBlock Height="Auto"
                 Width="Auto"
                 RenderTransformOrigin="0.5,0.5"
                 FontFamily="Georgia"
                 FontSize="18"
                 Text="from person in people"
                 TextWrapping="NoWrap"
                 HorizontalAlignment="Left" />
      <TextBlock Height="Auto"
                 RenderTransformOrigin="0.5,0.5"
                 FontFamily="Georgia"
                 FontSize="18"
                 Text="where person.LastName.StartsWith
                     (&quot;M&quot;)"
                 TextWrapping="NoWrap"
                 Width="Auto"
                 HorizontalAlignment="Left" />
      <TextBlock RenderTransformOrigin="0.5,0.5"
                 FontFamily="Georgia"
                 FontSize="18"
                 Text="select person"
                 TextWrapping="NoWrap"
                 Width="334"
                 Height="20"
                 HorizontalAlignment="Left" />
    </StackPanel>
    <StackPanel Margin="0,0,0,0"
                Grid.Row="3">
      <TextBlock x:Name="QOEM"
                 FontFamily="Georgia"
                 FontSize="18"
                 Text="people.Where ( 
    person =&gt; person.LastName.StartsWith ( &quot;M&quot; );"
                 TextWrapping="Wrap"/>
    </StackPanel>
    <Button x:Name="Go"
            Background="#FF00FF00"
            FontFamily="Georgia"
            FontSize="24"
            Foreground="#FF0000FF"
            Margin="5"
            Grid.Column="1"
            Grid.Row="5"
            Content="Go!" />
  </Grid>
</UserControl>

Page.xaml.cs

using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace ExtensionPart2
{
   public partial class Page : UserControl
   {
      public Page()
      {
         InitializeComponent();
         Go.Click += new RoutedEventHandler( Go_Click );
      }

      void Go_Click( object sender, RoutedEventArgs e )
      {
         List<Person> people = Person.GetPeople();

         // bind entire collection
         PresidentsListBox.ItemsSource = people;

         // traditional linq statement
         LinqResults.ItemsSource = from person in people
                            where person.LastName.StartsWith( "M" )
                            select person;

         // extended method
         QOEM_Results.ItemsSource = people.Where(
person => person.LastName.StartsWith( "M" ) ); } // end go button event handler } // end class } // end namespace
Previous: Extension Methods Part 1 
 

This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on Extension Methods Part 2 – Lambda Expressions in Linq

Background: Extension Methods, Silverlight & Linq

 

 

A number of articles I’ve read recently have mentioned “Extension methods” in passing, yet it is difficult to find out what this is, if you don’t already know.

A few searches, however, did turn up three good sources: MSDN provides this reference page, then I found a classic “Gu” blog post from March of ’07, and finally, the incredible Pete Brown tackles Extension methods as well.

This mini-tutorial will attempt to fill in the details and focus on two key uses of Extension Methods:

  • To add functionality to a class you don’t own
  • To enable method-based queries (using lambda expressions) in Linq

Adding Functionality to a Class You Don’t Own

Programmers are often faced with wishing that a given class had a method that the designer of the class did not supply. If the class is not sealed, you can derive a specialized version that has your method, but many framework classes are sealed. You can write around this problem, but it would be nice to create a method that looks like it is part of the original class, and Extension methods let you do just that.

Adding LastN to String

It is certainly possible to get the last n characters from a string, but it is a little tedious.  The traditional way to do so (broken out into fragments so that the steps are obvious) is shown in this very small Silverlight application,

lastnTraditional

Here is the click handler for GoButton (you’ll be able to deduce the names of the other controls),

void GoButton_Click( object sender, RoutedEventArgs e )
{
   string target = StringToParse.Text;
   int howMany = Convert.ToInt32( NumberToGet.Text ); 
   string retString = string.Empty;
   if ( howMany <= target.Length )
   retString = target.Substring( target.Length - howMany, howMany);
   ResultBox.Text = retString;
}

Extending String

It would be nice, especially if we are going to be doing this a lot, if the String  class had a Right() method so that we could shorten this listing to

void GoButton_Click( object sender, RoutedEventArgs e )
{
   string target = StringToParse.Text;
   int howMany = Convert.ToInt32( NumberToGet.Text );
   ResultBox.Text = target.Right( howMany );
}

While the actual savings may not be that great, the code is far easier to understand (and thus maintain). 

Some Like It Terse

I must confess the old C programmer in me wants to rewrite this as

void GoButton_Click( object sender, RoutedEventArgs e )
{
  ResultBox.Text = StringToParse.Text.Right( 
Convert.ToInt32 (NumberToGet.Text )); }

While I would have eschewed such a compressed style in the past as forfeiting any chance to see the interim variables, the debugger is now quite sophisticated, and has no trouble providing the information needed,

InterimVariables

Creating the Extended Method

The example above works because I created an extended method for the String class. This is done by creating a static method, typically in a static class. That method must have as its first variable a parameter declared in three parts:

  1. the key word this
  2. the type you are extending
  3. an instance identifier

It can then have any other “normal” parameters you care to give it.  The extended method Right was thus created (in a file named Extensions.cs as follows:

namespace GetLastNFromString
{
   public static class Extensions
   {
      public static string Right( this string s, int howMany )
      {
         if ( howMany <=  s.Length )
            return s.Substring( s.Length - howMany, howMany );
         else
            return s;
      }
   }
}

The “else” statement is arbitrary; here I choose to return the original string if I can’t return the requested portion (e.g., the user asks for the right most 10 characters of an 8 character string. Alternative solutions are to return string.empty, null or, if you insist, to throw an exception.

(I normally would put the if and the else in braces as well (you never know when you’ll add more code) but I’ve left them out here to save space.

Extension Methods and LINQ

In the next column I’ll tackle the second primary use of Extension methods, enabling method-based LINQ queries using Lambda expressions.

 

Next  Extension Methods and Lambda Expressions


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on Background: Extension Methods, Silverlight & Linq

Silverlight Test Driven Development – Part II

MiniTutorialLogo

 

 

 

 

At the end of Test Driven Body Snatchers I promised to follow up with a walkthrough of real-world Test Driven Development. What gets into me? 

Well, a promise is a promise. 

Walking Through Test Driven Development

Waybackmachine3[1] The set up is this: We’ve designed the  Silverlight HyperVideo Platform using the MVVM pattern. 

We’re going to take a trip in the way-back machine, and design  the ItemsViewModel class (the VM in MVVM)  using Test-Driven Development. 

 

Begin At The Beginning…

We start out by examining the existing ItemsView class (the V in MVVM ) which is implemented in ItemsView.xaml (and its code-behind):

<UserControl x:Class="SilverlightHVP.View.ItemsView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
           d:DesignHeight="300"
             d:DesignWidth="400">
   <Grid x:Name="LayoutRoot" Background="White">
      <ListBox Name="ItemsList"
               Background="Beige"
               Width="200"
               Height="250"
               HorizontalAlignment="Center"
               VerticalAlignment="Top"
               ItemsSource="{Binding Items}"
               SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
               DisplayMemberPath="TextToDisplay">
      </ListBox>

   </Grid>
</UserControl>

Designing the View Model

We are now ready to create the ItemsViewModel, which will serve as the data-context for the binding shown in the ListBox.

iStock_BoyWithBrainXSmall And here the world turns upside down. 

In the absence of test-driven development, I’d think about this a lot and make all sorts of decisions before writing a line of code. I’d decide, no doubt that the ItemsViewModel needs to provide a collection of Item objects to serve as the ItemsSource, and thus the Items property of the class would be a collection of Item objects. 

Since CurrentItem is bound to the SelectedItem, I’d try to figure out if that is a property with its backing value held in the ItemsViewModel or in, for example, the state object that is shared by all the ViewModel classes.

You can do all that, and you can make unit tests for it, but test-driven development works differently.  In TDD you make much smaller design decisions, write much smaller bits of code, and create a rapid cycle of three steps:

  1. Determine one key thing  you believe the ItemsViewModel class must provide and write a test asserting that it does provide that. Run that test. It will fail.
  2. Write just enough code in ItemsViewModel to make the test pass. No stop, just enough, no more. Good. Run the test again, it should pass.
  3. Repeat*
* Old joke: a programmer  was stuck in the shower because the shampoo bottle said “apply, lather, rinse, repeat.”

 

The Discipline of TDD

Yes, it is infuriating to write the simplest thing when you believe you already know more. But a funny thing happens… you find that you are never lost, confused, befuddled or even in need of a debugger. You only did a little bit and the test either passes or it fails. If it fails, it is trivial to figure out what is wrong; after all you probably only wrote a couple lines of code.

Creating The Test in Visual Studio

HVPTests To get started, I’ll add a project to the SilverlightHVP solution of type Test Project and I’ll name it SilverlightHVP.Tests.

Visual Studio will add the project, add a file UnitTest1.cs and add two new files to the solution: Local.testsettings and TraceAndTestImpact.testsettings. It also adds a reference to Microsoft.VisualStudio.Quality.

Tools.UnitTestFramework. Once the project is added to the solution, I can right click on the new project and choose Add->NewTest, bringing up the Add New Test dialog box.  I recommend experimenting with each of the tests offered, but for now, I’ll just  AddNewTest choose Basic Unit Test and name it ItemsViewModelUnitTests. 

Visual Studio will create the class and a first test method, and adorn each with the appropriate attributes.  Delete TestMethod1 and it is time to write (and name!) our first test method.

The First Test

So; what is the very least we think the ItemsViewModel must do? Let’s return to the ViewModel and note that the ListBox.ItemsSource property is binding to a ItemsViewModel property named Items. 

A quick look at the Silverlight documentation reveals that the ListBox.ItemsSource property is of type IEnumerable. That is, a collection. We don’t yet know what is in the collection, but we do know that the ItemsViewModel must have a property Items that returns an IEnumerable of something. Let’s create a test for that.

So what is the test actually testing for? The minimum is that the Items property, an IEnumerable<object> (that is, an enumerable list of something) is not null.

Our naming convention is to identify the thing we are testing and what should be true. The name, therefore, is ItemsProperty_ShouldNotBeNull.

C#

 [TestMethod]
 public void ItemsProperty_ShouldNotBeNull()
 {
 }

VB.Net

<TESTMETHOD>
Public Sub ItemsProperty_ShouldNotBeNull()
End Sub</TESTMETHOD>

 

Creating the body of the test requires testing the property of an ItemsViewModel instance; so the first line of the test will create the beast. 

CreateInstanceOfIVM

When we attempt to make an instance, we immediately get the feedback that something is amiss; no surprise; the class doesn’t exist yet. Visual Studio is ever-helpful, however, and it offers to generate the classs for you. Let’s have it do  that.  Hey! Presto! a new file ItemsViewModel.cs /ItemsViewModel.vb is generated in the test project. That’s not where we’ll want it, but for now it is just fine.

Our first test line no longer shows an error, and oh, by the way, creating this line was a forcing function on the design: we needed a class of type ItemsViewModel.   ItemsProperty Similarly, we now will attempt to retrieve the Items property as an enumerable, which of courses will generate both an error (no such property) and an offer to create the property for you.  Once again we’ll let Visual Studio generate the needed stub.  With that, we can test that Items is not null:

TestFailed

Place your cursor on the name of the test method and press Control-R, T; this will run this one test and display the results in a window, as shown.

Our dreams and ambitions are fulfilled; the test failed as we expected it to!  Great.

(click on images for full size)

Making The Code Pass The Test

Now we write just enough code for the test to pass. Watch it! Just enough and no more.

C#

 class ItemsViewModel
 {
    public IEnumerable<object> Items 
    {
       get { return new List<Object>(); }
       set { }
    }
 }

VB.Net

Friend Class ItemsViewModel
    Public Property Items() As IEnumerable(Of Object)
       Get
           Return New List(Of Object)() From {New Object()}
       End Get
       Set(ByVal value As IEnumerable(Of Object))
       End Set
    End Property
End Class

Since I can’t instantiate an interface, I chose a very simple class that implements IEnumerable. Notice that I’ve not populated the list; all I’ve done is write enough code to satisfy the test. This is pedantic, rigid, annoying and incredibly useful. The design emerges based on the needs, the needs are expressed by the tests, and the code never goes beyond the (thought through and tested) requirements. 

A real though not driving benefit is that the tests become both insurance and documentation; and unlike other documentation, as long as you “rigidly” make sure you run all the tests every time you make any change, the documentation never goes out of date.

The Second Test

At this point we know that we want more than for the property to be non-null; we want it to have items. Let’s test for that:

C#

      [TestMethod]
      public void ItemsProperty_ShouldNotBeNull()
      {
         var itemsViewModel = new ItemsViewModel();
         IEnumerable<object> items = itemsViewModel.Items;
         Assert.IsNotNull( items );
      }

      [TestMethod]
      public void ItemsProperty_ShouldReturnListOfObjects()
      {
         var itemsViewModel = new ItemsViewModel();
         IEnumerable<object> items = itemsViewModel.Items;
         Assert.AreNotEqual<int>( 0, items.Count<object>() );
      }

VB.NET

<TESTMETHOD>
Public Sub ItemsProperty_ShouldNotBeNull()
   Dim itemsViewModel = New ItemsViewModel()
   Dim items As IEnumerable(Of Object) = itemsViewModel.Items
   Assert.IsNotNull(items)
End Sub

</TESTMETHOD><TESTMETHOD>
Public Sub ItemsProperty_ShouldReturnListOfObjects()
   Dim itemsViewModel = New ItemsViewModel()
   Dim items As IEnumerable(Of Object) = itemsViewModel.Items
   Assert.AreNotEqual(Of Integer)(0, items.Count(Of Object)())
End Sub</TESTMETHOD>

 

Running Two Tests

You can run the second test just as you ran the first, but we really want to make sure that it is wicked easy to run all the tests every time. Click in the class, but not on either test, and press Ctrl-R, T.  This causes both tests to be run, and sure enough the first test (ShouldNotBeNull) passes, but the new test fails.

Once again, we write just enough code to make this pass.

C#

 class ItemsViewModel
 {
    public IEnumerable<object> Items 
    {
       get { return new List<Object>() { new Object() }; }
       set { }
    }
 }

VB.Net

 

Friend Class ItemsViewModel
   Public Property Items() As IEnumerable(Of Object)
      Get
          Return New List(Of Object)() From {New Object()}
      End Get
      Set(ByVal value As IEnumerable(Of Object))
      End Set
   End Property
End Class

And running the tests again, both pass. And so it goes. Step by tiny step. 

Factor Out Common Code In Tests?

Most of you are probably starting to itch terribly, as you look at the two tests and note that the first two (of three!) lines are identical.  Yikes! Somebody factor that out, quick!

And we will, but before we do, let me note that this is not a given; in fact doing so is somewhat controversial.  First, how to do it, then the controversy.

C#

[TestClass]
public class ItemsViewModelTests
{
   private IEnumerable<object> items;
   [TestInitialize]
   public void ItemsProperty_SetUp()
   {
      var itemsViewModel = new ItemsViewModel();
      items = itemsViewModel.Items;
   }

   [TestMethod]
   public void ItemsProperty_ShouldNotBeNull()
   {
      Assert.IsNotNull( items );
   }

   [TestMethod]
   public void ItemsProperty_ShouldReturnListOfObjects()
   {
      Assert.AreNotEqual<int>( 0, items.Count<object>() );
   }

   [TestCleanup]
   public void ItemsProperty_CleanUp()
   {
      items = null;
   }
}

VB.Net

<TESTCLASS>
Public Class ItemsViewModelTests
   Private items As IEnumerable(Of Object)
   <TESTINITIALIZE>
   Public Sub ItemsProperty_SetUp()
      Dim itemsViewModel = New ItemsViewModel()
      items = itemsViewModel.Items
   End Sub

   <TESTMETHOD>
   Public Sub ItemsProperty_ShouldNotBeNull()
      Assert.IsNotNull(items)
   End Sub

   </TESTMETHOD><TESTMETHOD>
   Public Sub ItemsProperty_ShouldReturnListOfObjects()
      Assert.AreNotEqual(Of Integer)(0, items.Count(Of Object)())
   End Sub

   <TESTCLEANUP>
   Public Sub ItemsProperty_CleanUp()
      items = Nothing
   End Sub
End Class</TESTCLEANUP></TESTMETHOD></TESTINITIALIZE></TESTCLASS>

The trick here is that the testing framework will run each test in the following sequence:

  • If there is a method marked [TestInitialize] run that first
  • Run the test method
  • If there is a method marked [TestCleanup] run that last

The controversy is this: you do not want any dependencies between tests. It can never be allowed that running one test affects another. That is, for example, ShouldReturnListOfObjects should return the same results if it is run before or after ShouldNotBeNull or even if ShouldNotBeNull is not run at all.

One way to protect yourself is to have each test be fully self-contained. A second way is to ensure that CleanUp eliminates any side-effects. 

Or Not…

James Newkirk, one of the brighter lights in the field, author of nUnit and xUnit, explains in some detail why he opposes using Setup and Cleanup (TearDown) methods.

I’ve taken the liberty® of quoting one of the key paragraphs:

The problem that I have with SetUp in this case is twofold. The first and primary complaint is that when I am reading each test I have to glance up to BeforeTest() to see the values that are being used in the test. Worse yet if there was a TearDown method I would need to look in 3 methods. The second issue is that BeforeTest() initializes member variables for all 3 tests which complicates BeforeTest() and makes it violate the single responsibility pattern. 

Brad Wilson, Newkirk’s partner in crime, elucidates four objections to the use of setup and teardown, which I summarize here,

  • You can’t tell what the test is doing without looking at the setup, which can be far away in the file when you have a number of tests
  • If the setup or teardown throws an exception it can be very confusing as to what is wrong
  • There is only one setup and teardown per set of tests, and that presumes every test needs the same setup; a dangerous and misleading assumption that makes the test harder to understand.
  • It is too easy to have the setup code change the environment for tests run later in the series; breaking the rule that tests are independent.

==========

I am incredibly grateful to Abby Fichtner for helping me past the initial hurdles in Test Driven Development (though she may argue I’m not yet past them!). 

She recommended to me, and I recommend to you this excellent tutorial by Jason Olson from Channel 9 (where you can now watch Silverlight TV)

 

jessesig

Posted in Mini-Tutorial, z Silverlight Archives | Tagged | 5 Comments

New Tutorial: DataGrid Binding via Data Entities & WCF

 

DataTutorialIcon

 

I’m very pleased to announce the posting of my latest Silverlight 2 Tutorial: ADO.NET Data Entities and WCF Feeding A Silverlight Datagrid, available in both C# and VB in HTML and pdf.

This is the first (but not the last) in an occasional series on how Silverlight can be combined with other aspects of .NET 3.5 to create complete applications. This tutorial touches on WCF, Data Entities, LINQ and SqlServer.

Complete code is available for download on the html pages as well.


This work is licensed under a Creative Commons Attribution By license.
Posted in z Silverlight Archives | Comments Off on New Tutorial: DataGrid Binding via Data Entities & WCF

Permanent Up-to-date Get Started Link

I have added a link on my sidebar to a permanent page, that I will be keeping up to date, on Getting Started with Silverlight.

EssentialLinks (clicking the image will take you to the page)

Please feel free to direct “newbies” to this link and to let me know what you think should be added to this page.

Thanks!

Posted in z Silverlight Archives | Comments Off on Permanent Up-to-date Get Started Link