Tuesday, March 30, 2010

Using WriteableBitmap to Simplify Animations with Clones

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

Thursday, March 25, 2010

Sequential Asynchronous Workflows Part 2: Simplified

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 < 60 * 60 * 24; x++)
    {
        var randomAction = new RandomResultCoroutine(_service) { Max = 128 };

        yield return randomAction;

        int a = randomAction.Result + 128;

        randomAction.Max = 255;
        yield return randomAction;

        int r = randomAction.Result;

        yield return randomAction;

        int g = randomAction.Result;

        yield return randomAction;

        int b = randomAction.Result;

        var color = new Color {A = (byte) a, R = (byte) r, G = (byte) g, B = (byte) b};

        var fromColor = color; 

        var storyboard = new Storyboard();
        if (element.Fill != null && element.Fill is SolidColorBrush)
        {
            fromColor = ((SolidColorBrush) element.Fill).Color; 
        }
        var colorAnimation = new ColorAnimation {Duration = TimeSpan.FromSeconds(2), From = fromColor, To = color};
        Storyboard.SetTarget(colorAnimation, element);
        Storyboard.SetTargetProperty(colorAnimation, new PropertyPath("(Shape.Fill).(SolidColorBrush.Color)"));

        var storyboardAction = new ActionCoroutine(storyboard.Begin, false);
        
        storyboard.Completed += (o, e) =>
                                    {
                                        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 < iterations; x++)
    {
        var rectangle = new Rectangle();
        rectangle.SetValue(NameProperty, Guid.NewGuid().ToString());

        randomAction.Max = 100; 
        yield return randomAction;
        
        var size = randomAction.Result + 10;

        rectangle.Width = size;
        rectangle.Height = size;

        yield return randomAction;

        int left = randomAction.Result;

        yield return randomAction;

        int top = randomAction.Result; 

        rectangle.Margin = new Thickness(left, top, 0, 0);

        var loadedSquare = new ActionCoroutine(() => 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

Tuesday, March 23, 2010

Sequential Asynchronous Workflows in Silverlight using Coroutines

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.

When you are ready, read Part 2: Simplified where I break down the concept further and show how to create a custom framework from scratch to simplify the use of coroutines.

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

Thursday, March 18, 2010

Introducing the Visual State Aggregator

The visual state aggregator. What is it?

How many times have you found yourself adding freak methods and commands to your Silverlight projects just to manage some animations? It's a common issue, and I've even built solutions like the IAnimationDelegate to help solve the problem. While it works, one thing always bothered me.

I know it's a ViewModel, so it does do things with the view, but should I really be that concerned with what's going on with the UI? In other words, while it's nice that I can abstract the firing of an animation behind an Action call and use a command to set it off and then unit test without a real Storyboard object, it has always felt just a little bit dirty to do it that way.

Download the source code for this post

I also am a big fan of the VisualStateManager and got to thinking about whether I ever really need a named story board outside of VSM other than programmatic or complex ones that have to be built at runtime. Looking at the current application I'm working with, which uses some very heavy animated transitions, I realized that all of these could be boiled down to the VSM.

Consider this scenario: we have two panels. Panel A is active, Panel B is collapsed and off the screen. These are independent controls that probably don't even share the same view model.

In this case, I'm going to give Panel A a visual state of "Foreground" and Panel B a visual state of "Offscreen". If you're scratching your head about the visual state manager, take a look at Justin Angel's excellent post on the topic. You can create your own groups and states and have both "final" states and transition states.

Quick Tip: Visibility

Probably more people abuse visibility by wiring in delegates or commands that set visibility to visible or collapsed (I'm guilty as well) when it's not needed. Stop thinking in terms of visible, collapsed, etc, and start thinking in terms of states. With the visual state manager, this is what your states might look like:

<VisualStateGroup x:Name="TransitionStates">
    <VisualStateGroup.States>
        <VisualState x:Name="Show">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.00000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Visibility)">
                    <DiscreteObjectKeyFrame KeyTime="00:00:00">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Visible</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </VisualState>
        <VisualState x:Name="Hide">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Visibility)">                                
                    <DiscreteObjectKeyFrame KeyTime="00:00:00">
                        <DiscreteObjectKeyFrame.Value>
                            <Visibility>Collapsed</Visibility>
                        </DiscreteObjectKeyFrame.Value>
                    </DiscreteObjectKeyFrame>
                </ObjectAnimationUsingKeyFrames>
             </Storyboard>
        </VisualState>
    </VisualStateGroup.States>
</VisualStateGroup>

Now you can simply go to a hide or show state, and if you want transitions, you add them to the VSM and voilà! It works ... no need to hard code the transition from collapsed to visible. Now back to our regularly scheduled program ...

When an event happens on Panel A, it goes to the "Background" state and the Panel B goes to the "Onscreen" state. It looks like this:

Then, when we close Panel B, it goes back to "Offscreen" and the Panel A comes back to foreground. By using visual states, we can manipulate the plane projection and scale transform properties as well as the visibility to achieve our results, and use animations.

But here's the rub: how can I fire the event in "A" and then let "B" know it's time to change states?

The most common way I've seen goes something like this:

Put an Action or delegate of some sort in a view model. In the code behind or using a behavior (more clever than code behind), attach the desired visual state to the action. Make a command object, and while the command does it's thing, go ahead and call the delegate which in turn flips the visual state. For example, my view model might have:

...
public Action SwapPanelA { get; set; }
...

And in the code-behind, I can wire it up like this:

...
ViewModel.SwapPanelA = () => VisualStateManager.GoToState(this, "Foreground", true);
...

And so on and so on. While this certainly decouples it a bit, it also forces us to change the design of our view model to accommodate the transitions. What if we have four controls participating in the same event? Do we wire up a bunch of references for the view model? Does a control bring in a view model only for the sake of wiring in it's animations?

No, no, no. All wrong (but again, let me elaborate these are things I've tried and worked with in the past, so don't feel bad if you've been doing the same things).

It hit me that I really needed to decouple view actions from business actions. When I click Panel A, the business action might be to call out to a web service to get data to populate in Panel B. I shouldn't care about any transitions.

The view action would be the movement of the panels.

So how do we decouple this? Enter the Visual State Aggregator. What I decided to do was build an aggregator that could respond to published events by flipping view states. This includes a behavior to participate in an event, and a trigger to push the event out. The first piece is a subscription. A subscription contains a weak reference to a control, an event the control is listening for, and the state the control should go to when the event fires (including whether or not to use transitions). Here is VisualStateSubscription:

public class VisualStateSubscription
{
    private readonly WeakReference _targetControl;
    private readonly string _state;
    private readonly bool _useTransitions;
    private readonly string _event;
    private Guid _id = Guid.NewGuid();

    public VisualStateSubscription(Control control, string vsmEvent, string state, bool useTransitions)
    {
        _targetControl = new WeakReference(control);
        _event = vsmEvent;
        _state = state;
        _useTransitions = useTransitions; 
    }

    public bool IsExpired
    {
        get
        {
            return _targetControl == null || !_targetControl.IsAlive || _targetControl.Target == null; 
        }
    }

    public void RaiseEvent(string eventName)
    {
        if (!IsExpired && _event.Equals(eventName))
        {
            var control = _targetControl.Target as Control;
            VisualStateManager.GoToState(control, _state, _useTransitions); 
        }
    }

    public override bool Equals(object obj)
    {
        return obj is VisualStateSubscription && ((VisualStateSubscription) obj)._id.Equals(_id);
    }

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

Next comes the aggregator. It contains the list of subscriptions. It will provide a means to subscribe, as well as a means to publish the event. I decided to use the Managed Extensibility Framework (MEF) to wire it in, so it also gets exported:

[Export]
public class VisualStateAggregator
{
    private readonly List<VisualStateSubscription> _subscribers = new List<VisualStateSubscription>();

    public void AddSubscription(Control control, string eventName, string stateName, bool useTransitions)
    {
        _subscribers.Add(new VisualStateSubscription(control, eventName, stateName, useTransitions));
    }

    public void PublishEvent(string eventName)
    {
        var expired = new List<VisualStateSubscription>();
        
        foreach(var subscriber in _subscribers)
        {
            if (subscriber.IsExpired)
            {
                expired.Add(subscriber);
            }
            else
            {
                subscriber.RaiseEvent(eventName);
            }
        }

        expired.ForEach(s=>_subscribers.Remove(s));
    }
}

Notice that I take advantage of the event to iterate the subscriptions and remove any that have expired (this means the control went out of scope, and we don't want to force it to hang on with a reference).

Now there is a behavior to subscribe. First, I want to indicate when a control should participate. This behavior can be attached to any FrameworkElement. Because the visual state manager only operates on controls, I'll walk the visual tree to find the highest containing control for that element. This way, if you have a grid (which is not a control) inside a user control, it will find the user control and use that as the target. If you don't want to use MEF, just give the aggregator a singleton pattern and reference it here instead of using the import.

public class VisualStateSubscriptionBehavior : Behavior<FrameworkElement> 
{        
    public VisualStateSubscriptionBehavior()
    {
        CompositionInitializer.SatisfyImports(this);
    }

    [Import]
    public VisualStateAggregator Aggregator { get; set; }

    public string EventName { get; set; }

    public string StateName { get; set; }

    public bool UseTransitions { get; set; }

    protected override void OnAttached()
    {
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }

    void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        Control control = null;

        if (AssociatedObject is Control)
        {
            control = AssociatedObject as Control;
        }
        else
        {
            DependencyObject parent = VisualTreeHelper.GetParent(AssociatedObject);
            while (!(parent is Control) && parent != null)
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            if (parent is Control)
            {
                control = parent as Control; 
            }
        }

        if (control != null)
        {
            Aggregator.AddSubscription(control, EventName, StateName, UseTransitions);
        }
    }
}

Notice we hook into the loaded event so the visual tree is built prior to walking the tree for our hooks.

Of course, this implementation gives us a weak or "magic string" event, you could wire that to an enumeration to make that strongly typed. Let's call the event of swapping out Panel A "ActivatePanelB" and the event of bring it back "DeactivatePanelB". Panel A subscribes like this:

<UserControl>
   <Grid x:Name="LayoutRoot">
   <i:Interaction.Behaviors>
      <vsm:VisualStateSubscriptionBehavior EventName="ActivatePanelB" StateName="Background" UseTransitions="True"/>
      <vsm:VisualStateSubscriptionBehavior EventName="DeactivatePanelB" StateName="Foreground" UseTransitions="True"/>
   </i:Interaction.Behaviors>
   </Grid>
</UserControl>

Then Panel B may subscribe like this:

<UserControl>
   <Grid x:Name="LayoutRoot">
   <i:Interaction.Behaviors>
      <vsm:VisualStateSubscriptionBehavior EventName="ActivatePanelB" StateName="Onscreen" UseTransitions="True"/>
      <vsm:VisualStateSubscriptionBehavior EventName="DeactivatePanelB" StateName="Offscreen" UseTransitions="True"/>
   </i:Interaction.Behaviors>
   </Grid>
</UserControl>

I'm assuming the visual states are wired up with those names.

Now we need something to trigger an event. We use a trigger action for that. The trigger class is very simple, as it simply needs to publish the event. Because we are using a trigger action, we can bind to any routed event in order for the transition to fire, so this would work for a mouseover that had to animate a separate control for example.

public class VisualStateTrigger : TriggerAction<FrameworkElement> 
{
    public VisualStateTrigger()
    {
        CompositionInitializer.SatisfyImports(this);
    }

    [Import]
    public VisualStateAggregator Aggregator { get; set; }

    public string EventName { get; set; }

    protected override void Invoke(object parameter)
    {
        Aggregator.PublishEvent(EventName);
    }
}

To trigger this, let's say we have a fancy grid with information and clicking on the grid itself fires the event. In Panel A, we'd wire the event like this:

<Grid>
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="MouseLeftButtonUp">
         <vsm:VisualStateTrigger EventName="ActivatePanelB"/>
      </i:EventTrigger>
   </i:Interaction.Triggers>
</Grid>

In Panel B, we might have a close button:

<Button Content="Close">
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
         <vsm:VisualStateTrigger EventName="DeactivatePanelB"/>
      </i:EventTrigger>
   </i:Interaction.Triggers>
</Button>

And that's it! Without any view models involved, entirely in the UI with the help of our behaviors, we've aggregated the visual state transitions. When you click on the grid, panel A will flip to the "Background" state and animate away, while panel B will flip to the "Onscreen" state and slide in.

Here is an example for you to have fun with:

When you grab the source, you'll find there are absolutely no code-behinds whatsoever other than what is automatically generated. While Panel A and Panel B are completely separate controls that know nothing about each other, the common subscription to a aggregate event coordinates their actions when Panel A is clicked or the close button on Panel B is clicked.

The standalone project for this is included in the download. Enjoy!

P.S. implementing this in my project has been a boon. Was able to eliminate tons of methods and delegates that were there simply to facilitate the VM/View glue. Here's what's nice as well: you can type the events with an enum. If you need to fire an event within your view model, you don't have to find a delegate or grab anything special. Instead, you just import the aggregator and fire your event, like this:

[Import]
IAggregator Aggregator { get; set; }

private void SomeCode()
{
   Aggregator.RaiseEvent(Events.ActivatePanelB); 
}

That's it!

Download the source code for this post

Jeremy Likness

Wednesday, March 17, 2010

ViewModel binding with the Managed Extensibility Framework

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

Friday, March 12, 2010

Custom Export Providers with Custom Metadata for Region Management

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

Advanced Silverlight Applications using the Managed Extensibility Framework

Voting for this year's CodeStock sessions has begun. The conference will be held in Knoxville, Tennessee on June 25th and June 26th. The conference is only $55.00 USD to attend if you register before May 3rd. Most sessions are determined based on vote by attendees.

If you are interested in attending, you may register to attend here. The details of my session and place you can vote for it is here: Building Advanced Silverlight Applications using the Managed Extensibility Framework. Thanks, and I hope to see you there!

Jeremy Likness

Tuesday, March 9, 2010

MVVM with MEF in Silverlight Video Tutorial Part 2: Plugins and Metadata

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

Saturday, March 6, 2010

MVVM with MEF in Silverlight: Video Tutorial

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. Want to learn more about MEF? Watch my video series, Fundamentals of the Managed Extensibility Framework.

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