March 2010 - Posts

I'm going to deviate from my typical "line of business" blog posts to discuss a topic that comes up quite a bit with Silverlight: animations. I've had a few projects where it's been necessary to use animations to transition between "screens" in the application. While I use the visual state manager as often as I can for this, sometimes the transitions aren't really changing the state of the control itself, but simply animating the change of underlying data.

Download the source code for this project

I've seen examples where people will actually create a second control to populate with the data, then animate it to the foreground and destroy the old control. While this works, there is a technique that is a lot easier, simpler, and uses far less resources. In fact, while I'm going to introduce it here as a more "manual" process, it's only a few extra lines of code to abstract the entire thing into a behavior you can attach.

Before we jump into the details, let's set up a reference project that is completely contrived. I'm going to have a collection of paragraphs and demonstrate a sort of "page flip" technique to swap between paragraphs.

The Setup

First, let me define a "paragraph" which is simply a line of text. Because I'm keeping it in a collection, I want to make sure that Equals and GetHashCode know how to handle it appropriately.

public class Paragraph
{ 
public string Text { get; set; }

public override bool Equals(object obj)
{
return obj is Paragraph && ((Paragraph) obj).Text.Equals(Text);
}

public override int GetHashCode()
{
return Text.GetHashCode();
}
}

Now I'll encapsulate a set of paragraphs in another container, which is my "book" so to speak. The name will give away where the text is coming from:

public class Lorem
{
public Lorem()
{
Ipsum = new ObservableCollection<Paragraph>();
}

public ObservableCollection<Paragraph> Ipsum { get; set; } 
}

Because my data won't be changing much, the easiest way for me to grab it will be simply to have it serialized right in the project. To do this, I simply add a resource dictionary and fill in my objects. I chose to grab 5 paragraphs of Lorem Ipsum for the example:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:AnimationExample="clr-namespace:AnimationExample">
<AnimationExample:Lorem x:Key="MainLorem">
<AnimationExample:Lorem.Ipsum>
<AnimationExample:Paragraph Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. In neque justo, lobortis ut fermentum at, ultricies vitae lectus. Fusce sit amet mauris orci, eget pulvinar erat. Morbi interdum rutrum justo a faucibus. Aliquam malesuada, nunc id convallis ullamcorper, nunc est posuere tellus, et commodo diam magna id nulla. Nam pretium erat eget sem porta rhoncus quis et leo. Vivamus ornare tincidunt bibendum. Cras varius sagittis sapien, vitae pellentesque orci fringilla sed. Donec ultrices justo quis tellus auctor dignissim. Mauris id rhoncus ante. Mauris elementum, diam non blandit blandit, elit libero sodales tellus, vitae aliquam tellus tortor tempus enim. Ut iaculis tincidunt lacus, in lacinia elit laoreet ut. Vivamus ut velit dui. Sed consectetur feugiat tristique. Fusce velit mi, sodales non sagittis laoreet, viverra in urna. Donec nisi mauris, luctus ut mattis vel, adipiscing vel justo. Aliquam molestie fringilla risus, in blandit lorem eleifend eu. Sed imperdiet egestas elit quis varius. Vestibulum fringilla vestibulum posuere. Phasellus massa augue, laoreet tempus scelerisque id, euismod eu orci."/>
<AnimationExample:Paragraph Text="Suspendisse sit amet felis lorem. Phasellus cursus rhoncus leo, nec fringilla augue tempus a. Cras nec lectus nunc. In hac habitasse platea dictumst. Nullam lobortis, lorem non aliquam faucibus, mauris ligula scelerisque dui, sit amet euismod tellus nisl sit amet lacus. Mauris tempus, neque ac posuere congue, eros nisi hendrerit risus, luctus venenatis massa urna id diam. Quisque in neque magna, quis auctor ipsum. Morbi risus nunc, suscipit at fermentum nec, condimentum ac eros. Curabitur molestie risus non risus dignissim vulputate. Aliquam eget arcu neque. Nam id sem in justo tristique semper ac in elit."/>
<AnimationExample:Paragraph Text="Vivamus vel aliquam nisi. Vestibulum adipiscing, nunc mattis dictum dapibus, elit quam dapibus augue, vitae adipiscing tortor est blandit erat. Pellentesque pretium vehicula neque sed malesuada. Cras dapibus iaculis nunc, et congue felis accumsan vel. Cras convallis scelerisque ligula vitae auctor. Sed pharetra posuere augue ac aliquet. Vestibulum imperdiet nisl sit amet ante cursus in pretium justo cursus. Praesent fringilla tempus semper. Pellentesque malesuada convallis massa, nec adipiscing nunc aliquet id. Maecenas sodales elit sed velit accumsan faucibus."/>
<AnimationExample:Paragraph Text="Curabitur rhoncus pulvinar tortor, ultrices elementum nulla ornare sed. Suspendisse sit amet purus quis dui consectetur dapibus. In hac habitasse platea dictumst. Suspendisse quam diam, dapibus eget hendrerit ut, molestie vel tellus. In auctor tellus quis urna pharetra lobortis. Vestibulum a massa eget arcu pretium convallis eu rhoncus nisl. Cras tincidunt felis nec massa vestibulum molestie. Sed nec mauris metus. Nulla nec dictum diam. Maecenas dictum fermentum est, a rhoncus neque suscipit quis. Etiam et leo non metus blandit malesuada id vitae arcu."/>
<AnimationExample:Paragraph Text="Nullam dignissim porttitor pulvinar. Etiam fringilla viverra iaculis. Pellentesque nec augue urna. Nunc eu eros ac lectus scelerisque pharetra eget a nisi. Morbi mollis dolor sit amet nibh pellentesque eu ullamcorper sapien gravida. Donec at risus eu felis scelerisque tristique eget ut nisi. Suspendisse scelerisque leo vel nibh ornare ultrices. Quisque ac ante lacinia erat dignissim dignissim. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Cras sit amet purus nibh. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sagittis rhoncus tellus eu molestie. Praesent scelerisque libero sit amet dui ultricies elementum. Integer at ullamcorper leo. Maecenas vulputate ante vel tortor tincidunt vestibulum. Nullam posuere felis ac odio dignissim in congue tortor imperdiet. Praesent vel diam nisl, sodales condimentum justo. Vivamus ultricies, tellus a tincidunt ullamcorper, neque ipsum varius libero, et luctus lorem sem in enim."/>
</AnimationExample:Lorem.Ipsum>
</AnimationExample:Lorem>
</ResourceDictionary>

That's the beauty of XAML: I can simply define the object graph right there and let the parser serialize it. I'll add a "helper" extension method that makes it easy for me to grab the instance I want:

public static class Extensions
{
private const string RESOURCE = "/AnimationExample;component/LoremIpsum.xaml";
private const string KEY = "MainLorem";

public static Lorem FromResource(this Lorem lorem)
{
var dictionary = new ResourceDictionary
{Source = new Uri(RESOURCE, UriKind.Relative)};
return (Lorem) dictionary[KEY]; 
}
}

As you can see, I'm simply referencing the resource dictionary, then accessing the key. This will let me do this:

...
var lorem = new Lorem().FromResource(); 
...

Now let's build a view model. I'm not going to drag in any frameworks like MEF or PRISM, so the commanding will be manual and code behind for this example. As such, I'll need to expose properties to determine whether or not we can flip the page forward or backward, and a method to perform the actual swap. Here is the view model:

public class ViewModel : INotifyPropertyChanged 
{
public ViewModel()
{
LoremIpsum = new Lorem().FromResource();
CurrentParagraph = LoremIpsum.Ipsum[0]; 
RaisePropertyChange("CanGoForward");
RaisePropertyChange("CanGoBackward");
Transition = forward => { };
}

public Action<bool> Transition { get; set; }

public bool CanGoForward
{
get
{
int idx = LoremIpsum.Ipsum.IndexOf(CurrentParagraph);
return idx < (LoremIpsum.Ipsum.Count - 1);
}
}

public bool CanGoBackward
{
get
{
int idx = LoremIpsum.Ipsum.IndexOf(CurrentParagraph);
return idx > 0;
}
}

public void Move(bool forward)
{
if (forward && CanGoForward)
{
int idx = LoremIpsum.Ipsum.IndexOf(CurrentParagraph);
Transition(true);
CurrentParagraph = LoremIpsum.Ipsum[idx + 1]; 
}
else if (!forward && CanGoBackward)
{
int idx = LoremIpsum.Ipsum.IndexOf(CurrentParagraph);
Transition(false);
CurrentParagraph = LoremIpsum.Ipsum[idx - 1]; 
}

RaisePropertyChange("CurrentParagraph");
RaisePropertyChange("CanGoForward");
RaisePropertyChange("CanGoBackward");
}

public Lorem LoremIpsum { get; set; }

public Paragraph CurrentParagraph { get; set; }

protected void RaisePropertyChange(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

We wire in the typical INotifyPropertyChanged bits, and expose a copy of the main container along with a current paragraph. I have flags to show if/when we can go forward or backward. Finally, two key areas are the method to actually move in either direction, aptly named Move, along with the transition action. Notice we call the transition action, then update the current paragraph. That will factor in later. Also note we wire up a default (empty) action for the transition.

I made a very simple user control to display the text in a given paragraph. It looks like this:

<UserControl x:Class="AnimationExample.ViewParagraph"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
>
<Border Background="White" BorderBrush="Black" BorderThickness="5" CornerRadius="15">
<Grid>
<TextBlock TextWrapping="Wrap" FontSize="12" TextAlignment="Left" Margin="10"
HorizontalAlignment="Center" VerticalAlignment="Center"
Text="{Binding Text}"/>
</Grid> 
</Border>
</UserControl>

Great. Now we can plumb out the main page. In the main page I'm going to host two buttons for navigating paragraphs, the paragraph view control, and the model. Here it is in the beginning:

<UserControl x:Class="AnimationExample.MainPage"
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" 
xmlns:AnimationExample="clr-namespace:AnimationExample" 
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<UserControl.Resources>
<AnimationExample:ViewModel x:Key="VM"/> 
</UserControl.Resources>
<Grid x:Name="LayoutRoot" DataContext="{StaticResource VM}"> 
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="400"/>
<RowDefinition Height="200"/>
</Grid.RowDefinitions>
<Button x:Name="Back" Content="<" Grid.Column="0" Grid.Row="1" Click="Back_Click"/>
<Button x:Name="Forward" Content=">" Grid.Column="1" Grid.Row="1" Click="Forward_Click"/>
<AnimationExample:ViewParagraph x:Name="View" Grid.Column="0" Grid.ColumnSpan="2" DataContext="{Binding CurrentParagraph}"/> 
</Grid>
</UserControl>

Because I'm not taking advantage of commanding, I need to do a little wiring for code behind to get the buttons to work. That code behind looks like this:

public partial class MainPage
{
public ViewModel ViewModel
{
get { return LayoutRoot.DataContext as ViewModel; }
}

public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
_SetButtons();
ViewModel.PropertyChanged += (o, args) => _SetButtons();
}

private void _SetButtons()
{
Back.IsEnabled = ViewModel.CanGoBackward;
Forward.IsEnabled = ViewModel.CanGoForward; 
}

private void Back_Click(object sender, RoutedEventArgs e)
{
ViewModel.Move(false);
}

private void Forward_Click(object sender, RoutedEventArgs e)
{
ViewModel.Move(true);
}
}

All we do is enable/disable them based on our flags, and hook into property changed so if the flags change, we can update the buttons.

At this point, you can run the project. You'll find a disabled back button, a paragraph, and a forward button. You can click the buttons and navigate between paragraphs and the forward button will be disabled when you hit the end. It all works, and that was a lot of setup, but you'll notice the transition between paragraphs is very boring.

We want to add an animation effect, but what is the best way to do it? Should I create a new view control for each paragraph and swap those in and out? Or is there a better way? I think there is ... and that's the point of this post.

The Animation

First, I'm going to pop in an image as a placeholder. It's important I put this after the main control because the image will overlay it on top. In a grid, I position it in the same row/column and use the same alignment as I do the control itself. We are just putting the control in the main row and spanning two rows. I go ahead and add a plane projection as well so we can do a 3D page flip effect:

<AnimationExample:ViewParagraph x:Name="View" Grid.Column="0" Grid.ColumnSpan="2" DataContext="{Binding CurrentParagraph}">
<AnimationExample:ViewParagraph.Projection>
<PlaneProjection CenterOfRotationX="0"/>
</AnimationExample:ViewParagraph.Projection>
</AnimationExample:ViewParagraph>
<Image x:Name="Clone" Grid.Column="0" Grid.ColumnSpan="2" Visibility="Collapsed">
<Image.Projection>
<PlaneProjection CenterOfRotationX="0"/>
</Image.Projection>
</Image> 

I'm going to rotate on the Y axis so it looks like pages moving toward or away from us. If I used the default projection, it would pivot in the middle. To give it a book effect with the spine to the left, I set the center of rotation X to 0 (it is 0.5 by default) so the Y rotation will "swing" to the left rather than pivot on the center of the image.

Next, I want an easy way to clone the control to the image. The idea is that I clone it to the image, then swap the data. Now I have a snapshot in the image of the old paragraph, while the new paragraph is live. Then I can animate these two for the transition.

Here is my extension method to clone the image:

public static void CloneToImage(this UIElement element, Image image)
{
var bitmap = new WriteableBitmap(element, new TranslateTransform());
bitmap.Invalidate();
image.Source = bitmap;
image.Width = bitmap.PixelWidth;
image.Height = bitmap.PixelHeight;
}

Notice it works with any UIElement. We simply initialize a writable bitmap and pass the element and a transformation. Any transformation will do, and because we want an exact duplicate, I simply pass a default translation. The bitmap remains writable and thus is not bindable to an image until we invalidate it, so I do that and then assign to the image and set the width and height. Note this is generic and will work with any control. The action will automatically render that control and all of the children of it to the bitmap.

Now we set up two storyboards, one to flip forward, and one to flip backward. Because these are just mirror images of each other, I'll just show you the first one:

<Storyboard x:Name="PageForward">
<ObjectAnimationUsingKeyFrames 
Duration="0:0:1"
Storyboard.TargetName="Clone"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:1">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation 
Duration="0:0:1"
Storyboard.TargetName="Clone"
Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
From="0" To="90"/>
<DoubleAnimation 
Duration="0:0:1"
Storyboard.TargetName="View"
Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)"
From="-90" To="0"/>
</Storyboard>

Normally, I wouldn't stretch an animation out so long, but I wanted to emphasize the effect for this example. We basically "turn on" the image (set it to visible) so it immediately overlays the control. Now we'll have the old on the top and the new on the bottom. Then, we animate the two so the image rotates until it is perpendicular to the "camera" or the viewer and disappears, and then we truly do make it disappear by collapsing it again. The new panel starts out perpendicular and then rotates into view.

The final step is use our extension method to clone the image and actually perform the animation. On the loaded method in the main page, I simply wire in the transition action:

ViewModel.Transition = forward =>
{
View.CloneToImage(Clone);

if (forward)
{
PageForward.Begin();
}
else
{
PageBackward.Begin();
}
};

Here it is in action:

Download the source code for this project

And that's all there is to it!

Jeremy Likness

I received quite a bit of feedback related to my sequential asynchronous workflows post. Most people asked if I could simplify the example even more and/or show the inner workings of the coroutine engine itself. Because the source for the library I demonstrated in the last post is not available, I've put together a very simple solution to help you better understand and take advantage of coroutines.

First, the fine print. This framework is simply to help understand the concept and provide a starting point for building out coroutines yourself. I know some companies simple don't allow third-party code and it always helps to learn a framework by starting at the ground floor. Some things you won't find here that would belong in production code include thread-awareness (background or UI thread?), timeouts (i.e. if I call out and it never returns, does my workflow die?) and exception management. All very important but reasons why this framework is educational and not a "production-ready" implementation.

Download the source for this post

Remember the original interface we defined for illustration purposes, the ICoroutine interface? Here it is:

public interface ICoroutine
{
    void Yield();
    Action Yielded { get; set; }
}

Now, to drive a workflow, you simply need an engine. Let's build a quick and dirty engine to drive what we want. Last post I showed how to use an existing framework. This time we'll do it a little differently. Instead of queuing asynchronous calls using the asynchronous process model, we'll drive the process with the coroutine interface itself. This comes with some caveats. What I'm going to show you will work, but a production solution will have to take it a step further and deal with things like execution threads (background vs. UI) etc (this is all handled as part of the AsyncEnumerator class I showed you before).

So, here is our "bare bones" coroutine manager, and again, this is closer to Rob Eisenberg's implementation in his MIX session on building your own MVVM framework than the version I showed you last time, but I've taken it and dumbed it down as much as possible to make it easy to use and understand.

public class CoroutineManager
{
    private readonly IEnumerator<ICoroutine> _enumerator;

    public CoroutineManager(IEnumerable<ICoroutine> workflow)
    {
        _enumerator = workflow.GetEnumerator();
    }
    
    private void Yielded()
    {            
        if(!_enumerator.MoveNext())
            return;

        var next = _enumerator.Current;
        next.Yielded = Yielded; 
        next.Yield();
    }
    
    public static void Begin(object workflow)
    {
        if (workflow is ICoroutine)
        {
            workflow = new[] {workflow as ICoroutine};
        }
        
        if (workflow is IEnumerable<ICoroutine>)
        {
            new CoroutineManager(workflow as IEnumerable<ICoroutine>).Yielded();
        }            
    }     
}

Not much to it, is there? The class has an entry point that can take a single coroutine or group, instantiate the class, then kick off the workflow. The workflow simply takes the next coroutine from the stack, wires in the yielded event to call back into the coroutine manager, and then executes it. That's it!

So how does it look? Let's make two helper classes: one that is generic and can handle any type of action, and another that is specific to our random number service.

Here's what the generic action coroutine looks like:

public class ActionCoroutine : ICoroutine 
{
    private readonly bool _immediate;

    public Action Execute { get; set; }

    public ActionCoroutine()
    {
        
    }

    public ActionCoroutine(bool immediate)
    {
        _immediate = immediate;
    }

    public ActionCoroutine(Action action)
    {
        _immediate = false;
        Execute = action;
    }

    public ActionCoroutine(Action action, bool immediate)
    {
        _immediate = immediate;
        Execute = action;
    }

    public void Yield()
    {
        Execute();
        if (_immediate)
        {
            Yielded();
        }
    }

    public Action Yielded { get; set; }  
}

Again, not much to it. I can either pass an action to trigger immediately, or pass an action and set immediate to false. If I set immediate to false, then I need to wire in something to call the Yielded method (remember, our coroutine manager wires this up for us to re-enter the iterator state machine). I'll show you usage in a second. Finally, here is my random number service helper:

public class RandomResultCoroutine : ICoroutine
{
    private readonly RandomNumberService _service;

    public RandomResultCoroutine(RandomNumberService service)
    {
        _service = service;
    }

    public int Max { get; set; }

    public int Result { get; set; }

    public void Yield()
    {
        _service.GetRandomNumber(Max,
                                 result =>
                                     {
                                         Result = result;
                                         Yielded();
                                     });
    }

    public Action Yielded { get; set; }
}

Notice how this service "wires itself." It has a max setting, calls the random number service, and tells the random number service to call back into a lambda expression. The expression sets the return result, then fires the Yielded message to re-enter the state machine flow.

This is an example where we can make it work, but a more robust solution will have to handle the exceptions. For example, what if the service never calls my action? Then I'm in a bad state because the Yielded will never get executed. That's why having timeouts and other checks and balances are important for a production-ready solution.

OK, we've set up our simple helpers and coroutine manager, let's see it in action. I'm just going to do everything in the code-behind for the main page to keep it simple. I'll set up three workflows. Two will generate shapes (circles and squares) and then feed the shapes to the third workflow which animates colors. This means we'll actually have dozens of workflows running simultaneously, but they will still fire sequentially within the workflow.

Take a look at our color workflow (it has as many iterations as seconds are in a day, just to keep it going for you to watch):

private IEnumerable<ICoroutine> ColorWorkflow(Shape element)
{
    for (int x = 0; x 
                                    {
                                        element.Fill = new SolidColorBrush(color);
                                        ((Storyboard) o).Stop();
                                        storyboardAction.Yielded();
                                    };

        yield return storyboardAction; 
    }

    yield break; 
}

Notice how straightforward it is. With our direct random number service helper, we can keep yield returning results. We will only go past the yield statement when the service call actually returns, and we can inspect the result because of the field we added to the helper, which is only set when the result is received and before the state machine is re-entered by calling yielded.

What's nice about implementing the ICoroutine interface is that all you have to do to repeat the call and get a new result is simply yield the same helper class. The implementation ensures that the manager will call into it, block until a result is received, then continue execution with the new value available.

For the storyboard, we use the generic action coroutine. The begin action is set to kick off the storyboard and when it ends we set the new color and stop the storyboard. In this case I also wire in a call to yielded and set the "immediate" flag to false because we're depending on the story board completion to continue the workflow.

The square and circle workflows are exactly the same, so I'll just show the square one here (probably means they could be refactored to something simpler, too, but it works for this demonstration).

private IEnumerable SquareWorkflow()
{            
    var randomAction = new RandomResultCoroutine(_service) {Max = 20};

    randomAction.Yield();
    yield return randomAction;

    int iterations = randomAction.Result + 5;

    for (int x = 0; x  LayoutRoot.Children.Add(rectangle), false);                                   
        rectangle.Loaded += (o, e) => loadedSquare.Yielded();

        yield return loadedSquare;

        CoroutineManager.Begin(ColorWorkflow(rectangle));
    }

    yield break;
}

This time we get a random number of squares and begin setting them up. We have a random size for the squares. Note we use the generic action coroutine to fire adding the square and loading it, and only when it is loaded do we kick off the color workflow to begin animating the colors on the square. This same workflow is repeated for circles.

You see how easy it is to kick off the routine? In fact, to kick off the main workflows, we simply do this:

public MainPage()
{
    InitializeComponent();
    Loaded += MainPage_Loaded;
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    CoroutineManager.Begin(SquareWorkflow());
    CoroutineManager.Begin(CircleWorkflow());
}

With those kicked off, even though we have two coroutines, you'll see they run asynchronously. While the circles and squares are sequentially added and animated (as opposed to popping in immediately as would happen if they were asynchronous within the workflow), they do so in parallel with each other (and once loaded, all of the color workflows continue to animate the individual elements but don't kick off a new color until the old storyboard is complete).

Here it is to play with. Due to a bug (can you find it?) the storyboard animation runs and completes but we only see the color change when it's done. That's OK because you can pick any shape on the surface and count 2 seconds and you'll notice the color changes every 2 seconds ... for every shape, proof that we have simultaneous sequential workflows all running asynchronously with each other. We also may see some CPU and memory issues over time because I'm not unhooking events.

Hopefully this helped simplify it a bit for those of you who were having trouble with the last post or wanted to see the innards of a framework so you can begin to build your own infrastructure.

Download the source for this post

Jeremy Likness

It all began with a post I read in the Silverlight.Net forums. A user, new to Silverlight, was frustrated with the asynchronous programming model required by Silverlight and wondered how to make all of the calls synchronous. I admit I heavily resisted the notion because I think the asynchronous programming model is one that developers should learn and be comfortable with. Forcing an asynchronous call to "look synchronous" seems to involve a lot of framework overhead just to keep the developer from having to learn something new, and would limit their ability to take advantage of the functionality available.

Then I watched Rob Eisenberg's Build your own MVVM Framework presentation and learned what he was doing with a concept known as coroutines. That was the "ah-hah" moment: some beginning programmers truly are looking for a crutch and should take some time to embrace the asynchronous model and learn it. Other developers have embraced the model but are faced with an interesting challenge: how to keep code maintainable and readable when it is littered with asynchronous calls?

Download the source for this post Note: this requires Wintellect's PowerThreading library. Download that here, then follow the instructions on the download link to add the reference.

Consider for a moment a typical workflow in a service-driven Silverlight application. The application must fetch information from a service, then perhaps take that data and push it to another service, then take even more data and bring it back. You might be Simplifying Asynchronous Calls using Action, but the code can start to look a little interesting.

You really end up with two solutions. One is to wire in the calls with methods, like this (consider a scenario where we get a number from a service, and the previous call result feeds into the next call):

private int n1, n2; 

private void FirstCall()
{
    Service.GetRandomNumber(10, SecondCall);
}

private void SecondCall(int number)
{
    n1 = number; 
    Service.GetRandomNumber(n1, ThirdCall);
}

private void ThirdCall(int number)
{
    n2 = number; 
    // etc
}

Or you can go lambda expression/delegate crazy like this:

private void FetchNumbers()
{
    int n1, n2; 

    Service.GetRandomNumber(10, result =>
                                    {
                                        n1 = result;
                                        Service.GetRandomNumber(n1, secondResult =>
                                                                        {
                                                                            n2 = secondResult;
                                                                        });
                                    });
}

That may be somewhat manageable, but what if your workflow chains, say, a dozen calls together?

You don't want your asynchronous calls to be synchronous. You just want to make them sequential.

Does that point make sense? If and when you become comfortable with asynchronous programming, you understand the issues with blocking threads and waiting for calls and everything else. That's not the issue. You just want clean code that does the job. Something like this:

private void FetchNumbers()
{
   int n1 = Service.GetRandomNumber(10); 
   int n2 = Service.GetRandomNumber(n1);
}

Let that run. We understand it's asynchronous and don't want to block everything else, but please, please, let's just do it sequentially and make it easy to read, mmm kay?

This is where the power of coroutines comes in.

C# does not have direct support for coroutines.

Let's make that clear up front. We have ways to build frameworks that make them happen, but it's not an "out-of-the-box" implementation. But let's start with the basics: what is a coroutine, anyway?

When I learned about coroutines, I understood the concept immediately. What frustrated me was understanding the mechanism to apply them in C#. Most of the posts and topics I uncovered assumed a fairly advanced base of knowledge and often jumped into a solution with a framework and didn't describe the framework itself. I consider myself a fast learner and the fact that I was hitting my head against a brick wall and failing to find some decent "101" tutorials put me on a mission: first, build my own framework from scratch to prove to me that I truly understand coroutines in C#, and second, blog about it so that you, too, can benefit from the learning process to receive better understanding and have an easy set of references to learn about them.

Please use the comments below to let me know if I succeeded!

Note: while I did build my own framework to gain understanding, the example here uses an existing, free library that has been maintained for years. It has been thoroughly tested for stability and performance and is chock full of additional features and benefits ... I'll share more on that in a bit.

In summary, a coroutine is a subroutine or method with multiple entry and exit points that maintains state between calls. That is me paraphrasing the various definitions there. The two keys to a coroutine are that you may enter it from places other than the beginning, and that it retains state when you enter it again after exiting.

When I mentioned that C# doesn't directly support coroutines, I wasn't 100% correct. C# has native support for a very specialized form of a coroutine, known as an iterator. You use these all of the time in your code. Traditional thought is that a foreach loop really just takes a list, like a piece of tape, and then spins through the tape, right? We really just take an index, then increment the index to look at item[0] and item[1] and we're on our merry way, right?

Not quite. The most common uses of iterators work that way, but behind the scenes something far more complex is happening. Whenever you use an iterator (which is really any time you use the keyword foreach), you are invoking a state machine under the covers.

If this is news to you, stop right now and head over to my article, What's in Your Collection Part 3 of 3. Don't worry, parts 1 and 2 just cover basic collections. This part focuses on iterators and shows how an iterator is really a state machine.

Those of you already familiar with the yield command know this. For an example of exploiting this knowledge, take a look at Pipeline and Yield in C#. Once you understand the iterator is a state machine, you begin to realize the possibilities. You don't always have to have the full list, for example. You can generate it on the fly! This way you only create objects in the list when and as you need them.

So this is great, we understand a little bit about coroutines and iterators in C#, but what does that have to do with "sequential asynchronous workflows in Silverlight using coroutines?" A lot, actually.

You see, we can take advantage of the iterator state machine to build our own coroutines. The way we do that is by taking over the IEnumerator implementation required to perform iterations.

Take a moment to look at the IEnumerator documentation. Now, stop thinking of foreach as a simple loop, and instead, consider it a state machine. You climb into the state machine, and the rules are simple:

  1. We're currently at Current. In fact, we're stuck here until MoveNext is called.
  2. Only a call to MoveNext will let us advance. If the call is true, we are now at a new Current state, so back to step 1. If the call is false, we're done. We can either go home, or Reset and start all over again.

The only caveat is that MoveNext can really do a number of things, until it hits a yield statement. Once the yield statement is reached, the process stops until the next MoveNext is called.

Those are some pretty simple rules, aren't they? Armed with that knowledge, you should now be able to predict what will happen in this simple little routine:

public void PrintAll()
{
   foreach(int x in IntegerList())
   {
      Console.WriteLine(x); 
   }
}

public IEnumerable<int> IntegerList()
{
   yield return 1;
   Thread.Sleep(1000);
   yield return 2; 
   yield return 3; 
}

In this program, you'll see 1, then wait a second, then see 2 and 3, then hang. Yes, hang: the program will not end. Remember our rule that we keep doing "something" until we hit a yield statement. In the state machine above, we return 1 and save our state. When the loop returns, we call move next. This results in jumping into our spot right after the yield, where we sleep, then return 2. After we return 3, the foreach loop still asks for something more. The state machine hits the end of the yield statement, and returns ... never finding anything. Because yield isn't hit, the machine just sits there, waiting.

To rectify the situation, we add a "yield break" to the end. This will result in the MoveNext call returning false and let our state machine know we're out of states. Then, unless we reset the enumerator, we're done.

Solving the Problem with Coroutines

Let me restate the problem: we have asynchronous calls that we want to process sequentially without having to chain dozens of methods or resort to complex lambda expressions. How do we do it?

The trick lies within our state machine. Because the state machine is linked to two key events: MoveNext and the yield keyword, we can hook into the enumerator and force the state machine to wait for our asynchronous actions to complete. We do this without blocking other threads: everything else still happens asynchronously, we just have a "sequential view" of our workflow.

The first step is to consider a generic contract we'll use to navigate the workflow. This is similar to Rob's but I chose to use a delegate instead of an event, as I don't need multiple subscribers to the workflow. This is a very simple interface, but it's important to note something: the Yield method is what is called for the class to start it's "life" in the state machine. The Yielded delegate should be called when it's done. If I have an instant action, then yield might be:

() => { action(); Yielded(); }

So you enter through one function, but call the other. Who sets the Yielded action? Our enumerator, or the "state machine manager" that is taking care of everything. Here's the interface:

public interface ICoroutine
{
    void Yield();
    Action Yielded { get; set; } 
}

Note: I'm using this interface to help conceptualize the model. We won't actually use this interface in the final solution. It helps here with understanding the general flow.

Before we worry about an implementation, let's conceptualize the engine that drives this, I'll call the engine CoroutineManager. This is the "master of the universe" that controls the state engine. Let me show the idea to you first, then we'll talk about what it does:

CoroutineManager

Begin: Yield()    

Yield: Move Iterator
       At End? 
          Yes: Done 
       No: Grab next item
       Set next item "Yielded" action to point to local "Yield" action
       Call "Yield" on item 

OK, let's break it down. This is driving a state machine. The method will encapsulate our workflow. Each item in the workflow gets passed into the coroutine engine, does it's thing, then exits and moves to the next workflow item.

To help us enter our workflow, we have a Begin method to start the process. This simply calls into the Yield, which is the main routine.

Now we play a game of back-and-forth using yield and yielded. The manager's yield method moves the iterator along. If there is nothing left, it stops. Our workflow is finished. Otherwise, it does two interesting things. First, it hooks up the next instance to call back to the engine by setting the Yielded action. While this is done sequentially, it also happens asynchronously. I prove that in the sample code by having several workflow happen simultaneously. We'll get to that in a second.

Once the callback is wired in, it calls into the item to execute. Note that our enumerator is now "hanging" and cannot go anywhere until we come back into the Yielded action, and then it will go to look for another yield in the code.

Conceptually, it looks something like this ... here our workflow has some miscellaneous code, then yield returns an ICoroutine instance, then has some more code, etc. Keep in mind the "hook" into yielded happens based on an asynchronous event completing, or a direct call:

So how do we use this engine, now that we have it defined?

The Wintellect PowerThreading Library

Wintellect's Jeffrey Richter has built a PowerThreading Library that does exactly what we needed. The Silverlight version is lightweight (under 30KB) but contains some powerful functionality. I'll let you drive through the full capabilities of the library; we're going to focus on two key aspects.

First, the AsyncEnumerator class is what helps us implement the ICoroutine concept. This class allows for asynchronous sequential enumeration of any process that implements the IAsyncResult interface. Next, we'll use the EventAPMFactory to cast event-driven processes into an asynchronous result. Because some of our code uses action callbacks instead of events, we'll also take advantage of a simple event wrapper that allows any process to fire a completed event.

You can find the download link for the PowerThreading library, complete with documentation and examples, here.

First, the class that allows any action to become an event:

public class EventWrapper
{        
    public EventWrapper()
    {
        
    }

    public EventWrapper(Action action)
    {
        Begin = action;
    }

    public Action Begin { get; set; }

    public void End()
    {
        if (Completed != null)
        {
            Completed(this, EventArgs.Empty);
        }
    }

    public event EventHandler Completed; 
}

Fairly straightforward: set the start action, and make sure you call End and it will raise the Completed event.

For the sample program, I included several layers so you can see both the sequential workflow, but understand it is still truly asynchronous because other workflows are also executing at the same time. Here's the premise:

First, I simulate a "random number" routine that gets passed a maximum value and returns a random number. We pretend this is a service call and even build in a random delay so it doesn't return immediately. In my main page, I'm going to do a few workflow tasks like animating a text box, etc. Then, I make a square 400 x 400. I get a random number from the "service" with a max of 400, and draw that square. If the square has a size of 320 x 320, I then get another random number between 0 and 320. The result is subsequently smaller squares until we hit zero.

The signature of the random number routine is:

...
void GenerateRandomNumber(int max, Action<int> result); 
...

To make it even more interesting, the squares themselves use a workflow to get random numbers to set their fill color. This is interesting because they use the same random number generator with the delay built in, so each square may take several seconds before it gets a color. The reason I did this is so you can see the squares being drawn and colored at the same time: proof we are asynchronously stepping through each workflow, however the individual workflows themselves are firing sequentially.

Here is the XAML for a square:

<UserControl x:Class="Coroutines.SquareView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    x:Name="SquareHost"
    >
    <Grid x:Name="LayoutRoot" Background="Black"
          HorizontalAlignment="Center"
          VerticalAlignment="Center">
        <Rectangle x:Name="Square" 
                   Width="{Binding Size}" 
                   Margin="3" 
                   Height="{Binding Size}" 
                   Fill="{Binding RectangleFill}"/>
    </Grid> 
</UserControl>

As you can see, it's a black grid with a rectangle that is bound to a size and a fill property. Here's the code behind:

[Export]
public partial class SquareView : IPartImportsSatisfiedNotification 
{
    [Import]
    public RandomNumberService Service { get; set; }

    public SquareView()
    {
        InitializeComponent();
        SetValue(NameProperty,Guid.NewGuid().ToString());
        LayoutRoot.DataContext = this;            
    }

    public static readonly DependencyProperty SizeProperty =
        DependencyProperty.Register(
            "Size",
            typeof (int),
            typeof (SquareView),
            null);

    public int Size
    {
        get { return (int) GetValue(SizeProperty); }
        set { SetValue(SizeProperty, value);}
    }

    public static readonly DependencyProperty RectangleFillProperty =
        DependencyProperty.Register(
            "RectangleFill",
            typeof(SolidColorBrush),
            typeof(SquareView),
            new PropertyMetadata(new SolidColorBrush(Colors.Gray)));

    public SolidColorBrush RectangleFill
    {
        get { return (SolidColorBrush)GetValue(RectangleFillProperty); }
        set { SetValue(RectangleFillProperty, value); }
    }

    private IEnumerator<Int32> ColorWorkFlow(AsyncEnumerator ae)
    {
        int alpha = 0, red = 0, green = 0, blue = 0;

        ae.SetOperationTag("Starting random number request.");

        var randomNumberWrapper = new EventWrapper();
        randomNumberWrapper.Begin =
            () => Service.GetRandomNumber(128,
                                          result =>
                                              {
                                                  alpha = result + 128;
                                                  randomNumberWrapper.End();
                                              });
        
        var eventArgsFactory = new EventApmFactory<EventArgs>();
        EventHandler serviceEnded = eventArgsFactory.PrepareOperation(ae.End()).EventHandler;
        randomNumberWrapper.Completed += serviceEnded;
        randomNumberWrapper.Begin();

        yield return 1;
        eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());

        ae.SetOperationTag("Starting request for color red.");

        randomNumberWrapper.Begin =
            () => Service.GetRandomNumber(255,
                                          result =>
                                          {
                                              red = result;
                                              randomNumberWrapper.End();
                                          });

        randomNumberWrapper.Begin();
        yield return 1;

        eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());

        ae.SetOperationTag("Starting request for color green.");

        randomNumberWrapper.Begin =
            () => Service.GetRandomNumber(255,
                                          result =>
                                          {
                                              green = result;
                                              randomNumberWrapper.End();
                                          });

        randomNumberWrapper.Begin();
        yield return 1;

        eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());

        ae.SetOperationTag("Starting request for color blue.");

        randomNumberWrapper.Begin =
            () => Service.GetRandomNumber(255,
                                          result =>
                                          {
                                              blue = result;
                                              randomNumberWrapper.End();
                                          });

        randomNumberWrapper.Begin();
        yield return 1;

        randomNumberWrapper.Completed -= serviceEnded;
        eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());

        RectangleFill = new SolidColorBrush(new Color { A = (byte)alpha, B = (byte)blue, G = (byte)green, R = (byte)red });

        ae.SetOperationTag("End of Color Workflow.");

        yield break; 
    }
   
    public void OnImportsSatisfied()
    {
        var ae = new AsyncEnumerator("Color Workflow");
        ae.BeginExecute(ColorWorkFlow(ae), ae.EndExecute);           
    }
}

The user control itself is exported. We have to import the service for the random number, so we wait until that is available using IPartImportsSatisfiedNotification. Once it is imported, we begin our workflow. You'll notice I'm using a helper class to call to the random number service and get the alpha, red, green, and blue values for my color. When I'm done, I set it and break out of the loop. In a nutshell, here are the steps we're taking:

  1. Create an AsyncEnumerator and kick off the process
  2. Implement IEnumerator<Int32> for the workflow. The documentation for the PowerThreading library explains this. Basically, the enumerator uses the yield return statements to keep track of how many pending asynchronous calls exist. We return 1 each time we start a process because were queuing up a single call. The yield statements cause the state machine to block until the asynchronous calls are complete.

With our ICoroutine concept, we "yield" or begin the process by kicking off the actual asynchronous call. The call's end is hooked into the Async Enumerator's End method (the "yielded" concept we discussed). The yield returns are what lock the state engine to wait for the operation to complete.

If you recall the diagram above, here is what the overall process looks like:

  1. Kick it off by calling BeginExecute on the coroutine manager (our AsyncEnumerator)
  2. Wire in a process so it completes by calling the coroutine manager's End method
  3. Kick off the process
  4. Yield
  5. The engine now blocks until the asynchronous call completes and hooks back into the end method
  6. Now we dequeue the result, and decide if we wish to continue the workflow or end it

By wrapping the random service call in the event wrapper, I can use the library's EventAPMFactory to convert the event to an asynchronous result that implements IAsyncResult. You'll notice we hook into the completed event by pointing to our enumerator, which will handle grabbing the result and implementing the interface for us. When it comes back, we dequeue the result and continue on, and unhook the event handler at the end.

The code behind does some other interesting things. You'll notice it exposes the dependency properties for the size and color so it sets the data context for the grid to itself. Not always the best practice, but it made this example a little more simple. You'll also notice we aren't doing anything with the size. Where does that come from?

The size is populated by the main workflow in the main page. The main page has a text box and some story boards. It dynamically inserts the squares onto the grid surface via the workflow. Take a look at the page XAML:

<UserControl x:Class="Coroutines.MainPage"
    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:DesignWidth="640" d:DesignHeight="480">
    <Grid>
        <Grid.Resources>
            <Storyboard x:Name="ScaleText">
                <DoubleAnimation Storyboard.TargetName="TextScale" Storyboard.TargetProperty="ScaleX"
                                 From="0.3" To="1.0" Duration="0:0:2"/>
                <DoubleAnimation Storyboard.TargetName="TextScale" Storyboard.TargetProperty="ScaleY"
                                 From="0.3" To="1.0" Duration="0:0:2"/>
            </Storyboard>
            <Storyboard x:Name="SlideText">
                <DoubleAnimation Storyboard.TargetName="TextSlide" Storyboard.TargetProperty="X"
                                 From="400" To="0" Duration="0:0:2"/>                
            </Storyboard>
            <Storyboard x:Name="HideText">
                <ObjectAnimationUsingKeyFrames 
                    Duration="0:0:2"
                    Storyboard.TargetName="Loading" Storyboard.TargetProperty="(UIElement.Visibility)">
                    <DiscreteObjectKeyFrame KeyTime="0:0:0">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                    <DiscreteObjectKeyFrame KeyTime="0:0:2">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
                <DoubleAnimation Storyboard.TargetName="Loading" Storyboard.TargetProperty="(UIElement.Opacity)"
                                 Duration="0:0:2" From="1.0" To="0"/>
            </Storyboard>
        </Grid.Resources>
        <Grid x:Name="LayoutRoot">
        
        </Grid>
        <Button x:Name="BeginButton" Content="Click to Begin" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <TextBlock FontSize="30" Foreground="White" FontWeight="Bold" x:Name="Loading" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock.Effect>
                <DropShadowEffect/>
            </TextBlock.Effect>
            <TextBlock.RenderTransform>
                <TransformGroup>
                    <ScaleTransform x:Name="TextScale"/>
                    <TranslateTransform x:Name="TextSlide"/>
                </TransformGroup>                
            </TextBlock.RenderTransform>
        </TextBlock>
    </Grid>
</UserControl>

Notice the layout root is empty, and nested inside another grid. This allows us to layer the button to kick the workflow off and the text box we'll use to show some animations on top of everything.

The fun, of course, is in the code behind:

[Export]
public partial class MainPage : IPartImportsSatisfiedNotification
{
    [Import]
    public ExportFactory<SquareView> ViewFactory { get; set; }

    [Import]
    public RandomNumberService Service { get; set; }

    public MainPage()
    {
        InitializeComponent();            
    }
    
    public void OnImportsSatisfied()
    {
        BeginButton.Click += (o, e) =>
                                 {
                                     var asyncEnum = new AsyncEnumerator("Main Workflow");
                                     asyncEnum.BeginExecute(Workflow(asyncEnum), asyncEnum.EndExecute);
                                 };      
    }

    public IEnumerator Workflow(AsyncEnumerator ae)
    {
        BeginButton.Visibility = Visibility.Collapsed; // get rid of the button 
        
        Loading.Text = "Animating"; 

        SlideText.Completed += (o, e) => ((Storyboard)o).Stop();
        SlideText.Begin();
                    
        var eventArgsFactory = new EventApmFactory<EventArgs>();
        EventHandler storyboardEnded = eventArgsFactory.PrepareOperation(ae.End()).EventHandler;
        ScaleText.Completed += storyboardEnded;
        
        ae.SetOperationTag("Begin ScaleText Storyboard");
        ScaleText.Begin();

        yield return 1;
        ScaleText.Completed -= storyboardEnded; 
        ScaleText.Stop();
        
        eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());
        
        Loading.Text = "Loading Squares";

        int max = 400; 
        
        while (max > 5)
        {
            var routedEventWrapper = new EventWrapper();

            EventHandler eventEnded = eventArgsFactory.PrepareOperation(ae.End()).EventHandler;
            
            ae.SetOperationTag("Adding a square.");

            var square = ViewFactory.CreateExport().Value;
            square.Size = max;

            routedEventWrapper.Begin = () => LayoutRoot.Children.Add(square);
            square.Loaded += (o, e) => routedEventWrapper.End();

            routedEventWrapper.Completed += eventEnded;
            routedEventWrapper.Begin();

            yield return 1;

            routedEventWrapper.Completed -= eventEnded;                
            eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());

            ae.SetOperationTag("Getting a new random number.");

            var eventWrapper = new EventWrapper();
            
            int i = max;                

            eventWrapper.Begin =
                () =>
                    {
                        Service.GetRandomNumber(i,
                                                result =>
                                                    {
                                                        max = result;
                                                        eventWrapper.End();
                                                    });
                    };

            EventHandler randomCompleted = eventArgsFactory.PrepareOperation(ae.End()).EventHandler;
            eventWrapper.Completed += randomCompleted;

            eventWrapper.Begin();

            yield return 1;

            eventWrapper.Completed -= randomCompleted;
            eventArgsFactory.EndInvoke(ae.DequeueAsyncResult());
        }

        Loading.Text = "Goodbye";

        HideText.Begin();

        ae.SetOperationTag("End of main workflow.");
        
        yield break;
    }        
}

So the first thing you'll notice is my use of MEF's ExportFactory. This let's me get the "means to create" an export, rather than a single export value. This allows me to generate as many squares as I like, all using MEF's composition engine to inject the service so the workflow can create the random colors.

We wire the button click when the imports are ready, and that kicks off the workflow.

Notice how easy it is to read the sequential workflow. We hide the button and set the text up. I kick off one animation asynchronously (the expansion) but plug the other into the workflow. This is to show how you can mix the asynchronous and sequential calls: these are two different storyboards, but they run at the same time and only when the coroutine one ends does the text update. Our state engine allows us to have our own loops, so we continue to loop until the random value gets too small to draw a visible square. Notice I actually wait for the square to get loaded into the visual tree before I draw the next square. This means you'll get several squares with the default (gray) color visible while the color workflow fires and then eventually colors the squares when complete.

When the last square is drawn, it changes the text and fades it out and then the workflow ends.

Here is the actual application for you to play with:

There you have it! Feel free to pull down the source and kick the tires. I hope this article has done a decent job of explaining what coroutines are, how you can implement them in C# and what they are practical for. Please share your feedback and comments below as I believe this area is very interesting for discussion.

Download the source for this post Note: this requires Wintellect's PowerThreading library. Download that here, then follow the instructions on the download link to add the reference.

Jeremy Likness

This is just a short post to share an "ah-hah" moment I experienced building out a large Managed Extensibility Framework (MEF) Silverlight application. Traditionally, I've wired in the view models using the code behind. I'm not one of those who believes code behind is evil no matter what, so I haven't taken issue with something like this:

[Import] 
public MainViewModel ViewModel 
{
   get { return LayoutRoot.DataContext as MainViewModel; }
   set { LayoutRoot.DataContext = value; }
}

This simply imports the view model that I need and then passes it along to the data context. The issue with XAML is that it doesn't allow me to pass in constructor information and always creates a "new" instance, so if the view model is part of a larger dependency chain, I'd get a new instance in every page that needed a copy.

This is an example of when having design patterns as a part of your vocabulary can improve your ability to solve problems. Obviously, it wasn't part of my vocabulary or I wouldn't have missed it! There is a nice pattern that neatly addresses the concern of having a view model wired in by MEF that allows for attaching it in XAML without having to use code behind. Again, I'm not opposed to code behind, but any time I can abstract the behavior further and do it in a natural way without jumping through hoops just to make it work is something I'll consider.

Enter the Service Locator design pattern. The challenge is that you have components that are based on service contracts and the concrete implementation not known at design time. In our case, the "service" is the view model, and it's not concrete yet because we haven't composed the parts.

Let's create our service locator for view models. In this example, I only have one, but in the application I am working on there are several, and they all get exposed via the service locator:

public class ViewModelLocator 
{
   public ViewModelLocator()
   {
      CompositionInitializer.SatisfyImports(this);
   }
  
   [Import]
   public MainViewModel MainViewModelInstance { get; set; }
}

It's that simple. The class itself composes the view model for us, then provides a property we can use to access the view model. Because we are importing via MEF, we can control the lifetime for the view model and any other attributes we need to compose it properly. Now, we can wire in the view model with no code behind. The XAML looks like this:

<UserControl ... xmlns:vm="clr-namespace:ViewModel">
<UserControl.Resources>
   <vm:ViewModelLocator x:Key="VMLocator"/>
</UserControl.Resources>
<Grid
   x:Name="LayoutRoot"
   DataContext={Binding Source={StaticResource VMLocator},Path=MainViewModelInstance}">
   ...
</Grid>

There you have it ... a simple, clean way to bind the view model to the view without code behind and still allow MEF to compose all of the parts for you.

Jeremy Likness

Over the past few weeks I've been exploring the concept of region management using the Managed Extensibility Framework, and for a good reason. I'm working on a project that has several different regions and controls that must be managed effectively and across the boundaries of dynamic XAP files in Silverlight 3.

Sound like a mouthful? In previous posts I demonstrated some methods for handling region management using MEF. This post is an advanced post and I'm assuming you have the fundamentals of MEF down. If not, I would come back to this post at a later time. You'll also want to be familiar with my previous experiments detailed in this article and another version in this video tutorial.

So the ultimate goal for me is to tag a view with a type, tag a region with a type, then route views to regions and vice versa. This way I can easily add controls (just tag 'em) and regions (again, tag 'em) and have a routing table that handles swapping them in and out for me.

One of the issues in the past has been having to explicitly export the region. In other words, I might have a ContentControl tagged for a particular region. I have to give it an x:Name in the XAML, like this:

...
<ContentControl x:Name="MyName"/>
...

And then export it with my custom attributes like this:

...
[TargetRegion(Region=ViewRegion.MainRegion)]
public FrameworkElement MainRegionExport 
{
   get { return MyName; }
}
...

This assumes I created a custom export attribute with a Region parameter and a base type of FrameworkElement. Where I want to go is here: eliminate the code behind, and tag my regions like this:

...
<ContentControl mef:TargetRegion.Region="MainRegion"/>
...

In the XAML, with no code behind. Can we get there? Of course, this is MEF!

The first step for me is to create to a custom export provider. I spoke briefly about this in an old post: Custom Export Provider for Attached Exports, but that was for static controls. Here, I want to export regions with meta data. The export provider looks like this:

public class RegionExportProvider : ExportProvider
{
    private static readonly Dictionary<ExportDefinition, List<Export>> _exports = new Dictionary<ExportDefinition, List<Export>>();

    private static readonly RegionExportProvider _provider = new RegionExportProvider();

    public static DependencyProperty RegionProperty = 
        DependencyProperty.RegisterAttached(
        "Region", 
        typeof(ViewRegion), 
        typeof(RegionExportProvider),
        null);       

    public static ViewRegion GetRegion(DependencyObject obj)
    {
        return (ViewRegion) obj.GetValue(RegionProperty);
    }

    public static void SetRegion(DependencyObject obj, ViewRegion value)
    {
        obj.SetValue(RegionProperty, value);
        GetRegionExportProvider().AddExport(value, obj);
    }

    private static readonly object _sync = new object();

    public static RegionExportProvider GetRegionExportProvider()
    {
        return _provider;
    }

    public void AddExport(ViewRegion region, object export)
    {
        lock (_sync)
        {
            string contractName = typeof (FrameworkElement).FullName;

            var metadata = new Dictionary<string, object>
                               {
                                   {"ExportTypeIdentity", typeof (FrameworkElement).FullName},
                               }; 

            var found =
                from e in _exports
                where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0
                select e;
            
            if (found.Count() == 0)
            {                    
                var definition =
                    new ExportDefinition(contractName, metadata);

                Debug.WriteLine("Region Export Provider: Add custom export: " + region);

                _exports.Add(definition, new List<Export>());
            }

            metadata.Add("Region", region); 

            var wrapper =
                new Export(contractName, 
                    metadata, 
                    () => export);

            found.First().Value.Add(wrapper);
        }
    }

    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
    {
        var contractDefinition = definition as ContractBasedImportDefinition;
        IEnumerable<Export> retVal = Enumerable.Empty<Export>();
        
        if (contractDefinition != null)
        {
            string contractName =
                contractDefinition.ContractName;
            
            Debug.WriteLine("GetExportsCore: Request for contract: " + contractName);

            if (!string.IsNullOrEmpty(contractName))
            {
                var exports =
                    from e in _exports
                    where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0
                    && definition.IsConstraintSatisfiedBy(e.Key)
                    select e.Value;

                if (exports.Count() > 0)
                {
                    Debug.WriteLine("Export satisfied.");
                    retVal = exports.First();
                }
                else
                {
                    Debug.WriteLine("Export was not satisfied.");
                }
            }
        }

        return retVal;
    }
}

Let's step through it. First, I need to keep a catalog of my exports. These are unique type definitions and contract names that we are going to satisfied with our custom export provider. I use the singleton pattern because I'm going to double this class as an attached behavior. Probably violating the single responsibility principle here, and could break it out, but let's run with it for now. Sometimes it makes sense to keep the code together for readability and maintainability.

The attached property just takes the type of the region. Because we type it to the enumeration, intellisense will work in the XAML when adding the behavior, which is nice, because it makes it less of a "magic string" for us to use.

The key to note is the setter. When we set the value, we add the export. The export itself is going to be the contract name and the type identity. This is why we add the first bit of meta data, the ExportTypeIdentity, and then see if we've already made an entry or not. If not, we add a new entry with an empty list of the actual exports.

Adding the exports is easy. Metadata on an export is really just a dictionary of labels and values. We know this particular export has one label ("Region") and that it is the enum of the region type. Therefore, once we find or create our export definition, we go ahead and add the export with the region itself (a content control, items control, or other container) and meta data for that region (in this case, the "Region" tag and the enumeration value).

Now we just need to be prepared to supply the exports when our custom provider is queried. This is the GetExportsCore. Fortunately, we get it easy. Instead of having to keep track of all of the rules, the import definition comes with a IsConstraintSatisfiedBy method that calls the Constraint provided to filter the export values. We simply find the definition that matches the contract and the constraint, then provide all of the exports we have. These will then have their meta data parsed and if a capabilities interface is provided, it will be populated with the values so that the Lazy<Type,ITypeCapabilities> target can be populated. Notice I added some debug lines to help troubleshoot.

Now I can tag my export the way I wanted to:

...
<ContentControl mef:RegionExportProvider.Region="MainRegion" .../>
...

There is only one more step I need to take in order for this all to work. Remember back when I showed you how to override the container so we could continue to compose new DeploymentCatalogs into an AggregateCatalog as they became available? When we create that special container, we need to add our secret sauce. We do it like this:

...
var container = new CompositionContainer(catalogService.GetCatalog(), RegionExportProvider.GetRegionExportProvider());
...

Now we've told the container to query our own custom export provider when trying to satisfy parts.

If you recall from my prior posts, I used a routing class to map view types to regions, and loaded the regions like this:

[ImportMany(AllowRecomposition = true)]
public Lazy<FrameworkElement, ITargetRegionCapabilities>[] RegionImports { get; set; }

Our new provider kindly exports the tagged regions, which are then imported with the routing class and used to swap views in and out of the display.

Jeremy Likness

In the first part of this series, I demonstrated a very simple project that used MVVM (Model-View-ViewModel) along with the Managed Extensibility Framework to produce a simple screen that toggled between a square and a circle.

In this next video, I am re-designing the original project. This video starts with the original solution, but then I rework the code, using metadata, to turn the shapes into plugins. I duplicate the original effort with the new design (using a combobox instead of a checkbox because now we can support 1 ... n plugins) and then show how easy it is to add a new plugin with the architecture.

Download the source code for this project.

Here is the final application:

Download the source code for this project.

Jeremy Likness

This is a video tutorial to introduce beginners to how to use both MVVM (Model-View-ViewModel) and MEF (Managed Extensibility Framework) with Silverlight (should work for versions 3 and 4). Of course, some "veterans" may want to watch as well in case you've missed some of the fundamentals, or have a clever way to do something that you can share in the comments for future visitors to the page.

In this edition, I build a simple application that allows the user to check a preference on the screen (whether they prefer squares over circles) and then displays a square or a circle. We use MVVM and wire everything together with MEF.

Download the source code: MEFMVVMDemoSln.zip

Click here to watch the video directly if it doesn't appear in the frame below (recommended to watch in full screen): Watch the video in a separate window

Here is the final application:

Download the source code: MEFMVVMDemoSln.zip

Jeremy Likness

A few weeks ago, I had the privilege of presenting a talk entitled, "Silverlight Line of Business Applications" at the Atlanta Silverlight Meetup Group. This talk focused on several aspects of building line of business applications, ranging from the principles that belong in the foundation or architecture, to specific frameworks and methodologies.

You can view the video below, or link directly by clicking here. I did take some time to encode chapters, so if you click the chapter icon in the player, you can jump to sections. I was hesitant to post this because there was not a microphone at the event. I spoke loud and recorded the talk via the built-in laptop microphone but the sound quality suffered as a result and there is plenty of background noise.

I hope the value of the content makes up for the poor audio quality. Here is the table of contents:

  • What is "Line of Business"?
  • Frameworks and Tools
  • Demo: Unit Testing Framework
  • Data Access Strategies
  • WCF RIA Services
  • Demo: RIA with POCO
  • UI Modularity and Scalability
  • Silverlight 4 and Beyond

I hope you enjoy the video and appreciate any comments or feedback you may have!

Jeremy Likness

We often trip over ourselves trying to minimize code behind and abstract behaviors in the UI from the models, etc. This is important for clean separation, but sometimes behaviors may add too much abstraction. The real fact is many applications require some sort of transition or animation based on events, and while we can try to put as many of those as possible into the VisualStateManager, there may be instances such as dynamically created animations or special triggers that end up involving the view model somehow.

What I'm proposing here is a very simple solution to allowing your view model to fire and respond to animations without having to know about those animations. The view model knows it has to fire some event, and may want notification when the event is done, but how that event is implemented is up to you. This way, the live version can contain Storyboard objects while the unit tests can contain mocks.

First, let's create a simple interface that our view model can talk to. It simply begins the animation and provides a callback when the animation is complete. (If you like, you can make it even more generic and call it a transition or an event).

public interface IAnimationDelegate
{
    void BeginAnimation(Action animationComplete);
}

That's pretty simple. Now, in my view model, I can fire the event and react. In this totally contrived example, whenever our first value changes, we fire a transition and only when the transition is complete, we move it with some changes to a second value.

public class MyViewModel : BaseNotify 
{
   public IAnimationDelegate Value1Transition { get; set; }

   private string _value1; 

   public string Value1 
   { 
      get { return _value1; } 
      set {
              _value1 = value;
              Value1Transition.BeginAnimation(_Value1Transitioned);
              RaisePropertyChanged("Value1"); 
          }
    }

    private string _value2; 

    public string Value2 
    {
       get { return _value2; }
       set {
             _value2 = value; 
             RaisePropertyChanged("Value2");
           }       
    }

    private void _Value1Transitioned()
    {
       Value2 = "This was the first value: " + Value1; 
    }
}    

The implementation of the animation delegate class might look like this:

public class AnimationDelegate : IAnimationDelegate
{
    private readonly Storyboard _storyboard;

    private Action _animationComplete;

    public AnimationDelegate(Storyboard storyboard)
    {
        _storyboard = storyboard;
        _storyboard.Completed += StoryboardCompleted;
    }

    void StoryboardCompleted(object sender, EventArgs e)
    {
        if (_animationComplete != null)
        {
            _animationComplete();
        }
    }

    public void BeginAnimation(Action animationComplete)
    {
        _animationComplete = animationComplete;
        _storyboard.Begin();
    }
}

We could unregister the event when completed, add other parameters to stop it when completed, etc, but this is a good staring point.

Now I simply need to wire the delegate. If my animation is called AnimateValue1 then with the Managed Extensibility Framework (MEF), I'd do something like this in the code behind for my control:

[Import]
public MyViewModel ViewModel
{
   get {  return LayoutRoot.DataContext as MyViewModel; }
   set {
          value.Value1Transition = new AnimationDelegate(AnimateValue1); 
          LayoutRoot.DataContext = value;          
       }
}

... and there you have it.

Jeremy Likness

In my last post, I showed you how to dynamically load modules on demand using the latest MEF release in Silverlight 3. This post, I will take you through managing regions with MEF. This will enable us to have a 100% MEF-based solution in Silverlight 3 if the only pieces of PRISM we were using were the dynamic module loading and region management.

Download the Source Code for this Post

Quick note: technically, the Composite Application Guidance (PRISM) is more of a guidance than an actual library. The library that is often used is the reference library for the guidance. I only mention this because in using the concept of the region manager and views, technically we are implementing the PRISM concept here and using CAG, we're just using MEF as the engine instead of the included reference library.

OK, let's get going ...

The first thing I did this time around was to rip out all of the IModuleInitialization pieces. They aren't needed because MEF will initialize what we need, as it's loaded. I destroyed the classes in the modules (it was good to see them load, anyway) and updated the navigation class to look like this:

[Export(typeof(INavigation))]
public class ViewNavigator : INavigation 
{        
    [Import]
    public ICatalogService CatalogService { get; set; }
    
    private readonly Dictionary<ViewType, string> _viewMap =
        new Dictionary<ViewType, string>
            {
                { ViewType.MainView, "DynamicModule.xap" },
                { ViewType.SecondView, "SecondDynamicModule.cs.xap" }
            };   

    private readonly List<string> _downloadedModules = new List<string>();
                                                                   
    public void NavigateToView(ViewType view)
    {
        if (!_downloadedModules.Contains(_viewMap[view]))
        {
            var catalog = new DeploymentCatalog(_viewMap[view]);
            CatalogService.Add(catalog);
            catalog.DownloadAsync();
            _downloadedModules.Add(_viewMap[view]);
        }
    }           
}

Thanks to Glenn Block for pointing out the excellent sample that comes included with the MEF bits (the deployment sample) ... this shows a different way of abstracting even the XAP file from the action of loading the catalog. In this case, I'm assuming I have prior knowledge of the controls and want to make my application more official by loading them dynamically as the user selects them.

So, now we've re-factored. That's a lot cleaner! Next, I want strongly-typed regions. I created a new project just for the regions, and added this class to define the enumeration:

public enum ViewRegion
{
    MainRegion,
    SubRegion 
}

public static class ViewRegionExtensions
{
    private static readonly List<ViewRegion> _regions = new List<ViewRegion> { ViewRegion.MainRegion, ViewRegion.SubRegion };       

    public static ViewRegion AsViewRegion(this string regionName)
    {
        foreach(var region in _regions)
        {
            if (regionName.Equals(region.ToString(), StringComparison.InvariantCultureIgnoreCase))
            {
                return region;
            }
        }
        return ViewRegion.MainRegion; 
    }
}

Unfortunately, I don't believe the Silverlight version of the Enum class allows you to enumerate the values of an enumeration. Therefore, I'm simply providing a static class to hold those and putting it next to the enum so it's easy to remember for maintenance. I also added an extension method that allows me to take a string and do AsViewRegion() to convert it to the enum.

In order to make the enum appear in XAML, we need to give Silverlight a hint that tells it how to convert from the string we'll key in the XAML to an actual enum we use in code. Here is the type converter, it basically says it only knows how to convert from strings, and uses the extension method to cast the string when called:

public class ViewRegionConverter : TypeConverter 
{        
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType.Equals(typeof (string));
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        return ((string) value).AsViewRegion();
    }
}

Now we can create our behavior. The behavior is an attached property we'll use to tag a container as a region. Eventually this can become complex as we support lists and content controls, but for the sake of this blog series I'm keeping it simple and limiting our containers to panels. Panels all have children, so it is easy to add an item to the children. The behavior will simply keep a static dictionary that maps the view region to the panel it was tagged to, and exposes a method that lets us request the panel for a view region. Here it is:

public static class RegionBehavior
{
    private static readonly Dictionary<ViewRegion, Panel> _regions = new Dictionary<ViewRegion, Panel>();
    
    public static readonly DependencyProperty RegionNameProperty = DependencyProperty.RegisterAttached(
        "RegionName",
        typeof (ViewRegion),
        typeof (RegionBehavior),
        new PropertyMetadata(ViewRegion.MainRegion, null));

    public static ViewRegion GetRegionName(DependencyObject obj)
    {
        return (ViewRegion) obj.GetValue(RegionNameProperty);
    }

    [TypeConverter(typeof(ViewRegionConverter))]
    public static void SetRegionName(DependencyObject obj, ViewRegion value)
    {
        obj.SetValue(RegionNameProperty, value);
        var panel = obj as Panel;
        if (panel != null)
        {
            _regions.Add(value, panel);
        }
    }
   
    public static Panel GetPanelForRegion(ViewRegion region)
    {
        return _regions[region];
    }

}

Notice the type converter hint I give the setter. That lets the XAML know how to convert. In fact, this will even give us intellisense in the XAML, so it knows what the valid enumerations are! Now I can go into my main shell and create my first region (the intellisense quickly gave me a list to choose from ... right now there are only two choices!)

<StackPanel Orientation="Vertical" Grid.Row="2" Regions:RegionBehavior.RegionName="MainRegion"/>

We can debug at this point and see that indeed the panel is registered with the dictionary with the behavior, so we're set on that front. Now we need to get our views into the region. We're still in the special "Regions" project and namespace. For now, I'm simply going to export type UserControl for my view, and specify the region with an attribute. In MEF, we can create a strongly typed attribute for metadata:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class TargetRegionAttribute : ExportAttribute 
{        
    public TargetRegionAttribute() : base(typeof(UserControl))
    {
        
    }

    public ViewRegion Region { get; set; }
}

So the type is UserControl but we can specify a region in the meta data. Now I can add a view to my dynamic module. I'm also specifying a region here for a nested view.

<UserControl x:Class="DynamicModule.View"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:Regions="clr-namespace:RegionsWithMEF.Regions;assembly=RegionsWithMEF.Regions" 
    >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" Text="Left Column of Outer View"/>
        <StackPanel Grid.Column="1" Orientation="Vertical" Regions:RegionBehavior.RegionName="SubRegion">
            <TextBlock Text="Right Column of Outer View"/>
        </StackPanel>
    </Grid>
</UserControl>

We then tag the view for export with our custom attribute, like this:

[TargetRegion(Region=ViewRegion.MainRegion)]
public partial class View
{
    public View()
    {
        InitializeComponent();
    }
}

Very easy and readable. I went ahead and added another control for the second view, and tagged it to the "sub region" view.

Now we've got our custom attributes and exports, but we still need to glue it together. When the catalog is loaded, the views will be tagged as exports. We just need something to import them and we can then inspect the meta data and put them in their proper places. For this, I created the RegionManager.

First, let me back up. We want to read our meta data, so I need an interface with read only properties to pull it in:

public interface ITargetRegionCapabilities
{
    ViewRegion Region { get;  }
}

Great! Now I can define region manager. We'll use the Lazy object so we can define the capabilities with the import and inspect the meta data. I put it into an observable collection and listen to the collection. When it fires, I inspect the data for new controls, and then route them to their region based on the meta data:

[Export]
public class RegionManager
{
    private readonly List<UserControl> _controls = new List<UserControl>();

    [ImportMany(AllowRecomposition = true)]
    public ObservableCollection<Lazy<UserControl, ITargetRegionCapabilities>> Controls { get; set; }

    public RegionManager()
    {
        Controls = new ObservableCollection<Lazy<UserControl, ITargetRegionCapabilities>>();
        Controls.CollectionChanged += Controls_CollectionChanged;
    }

    void Controls_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach(var item in e.NewItems)
            {
                var controlInfo = item as Lazy<UserControl, ITargetRegionCapabilities>;

                if (controlInfo != null)
                {
                    if (!_controls.Contains(controlInfo.Value))
                    {
                        ViewRegion region = controlInfo.Metadata.Region;
                        Panel panel = RegionBehavior.GetPanelForRegion(region);
                        panel.Children.Add(controlInfo.Value);
                        _controls.Add(controlInfo.Value);
                    }
                }
            }
        }
    }
}

Note: if you are wondering why I use a list and an observable collection, it's because with recomposition, MEF is free to rebuild the entire list. I need to know specifically what changed and the "new items" might include older items that were recomposed. So the internal list allows me to keep track of what I've processed while I can parse out the newer items. With custom items you'll want to make sure you have a good implementation of Equals and GetHashCode, and if you have items that will go out of focus and disappear, you'll want to switch the internal list to a list of WeakReference instead.

That's it! The last step is to make sure that the region manager participates in the entire chain of imports and exports. I could wire it up in the container, but I know the shell view model is the top of the hierarchy, so to speak, so I'll just import the region manager directly. I haven't interfaced it because it doesn't expose any methods or properties: all of the work is internal and interfaces with the static dictionary we put into our behavior.

[Import]
public RegionManager Manager { get; set; }

OK, let's fire it up. I made a short video to show you the results.

Download the Source Code for this Post

Jeremy Likness