Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Reactive Extensions #3: Windows Phone 7

Following the theme from my previous two posts, this post will be about using Reactive Extensions on Windows Phone 7. I'll use a similar scenario as before – gradually load a few tiles into an ItemsControl. Let’s get started.

Starting a project

Create a new “Windows Phone Application”. Add references to assemblies Microsoft.Phone.Reactive and System.Observable to add support for Rx, then Microsoft.Phone.Controls.Toolkit (found in Silverlight Toolkit for Windows Phone 7) and System.Windows.Interactivity (Expression Blend for Windows Phone 7 SDK, should be already installed if you installed WP7 tools / Expresion Blend 4 SP1).

Layout

Put a ListBox on the main, name it list and possibly change the control to an ItemsControl (we don’t need to select items).

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <ItemsControl Name="list" />
</Grid>

Create the ItemTemplate:

<DataTemplate x:Key="TileTemplate">
    <Grid Width="142"
          Height="142"
          Background="{StaticResource PhoneAccentBrush}"
          Margin="5">
        <TextBlock Text="{Binding}"
                   FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}"
                   Foreground="{StaticResource PhoneForegroundBrush}"
                   VerticalAlignment="Bottom"
                   HorizontalAlignment="Left"
                   Margin="20,0,0,10" />
    </Grid>
</DataTemplate>

… use WrapPanel for the ItemsPanel:

<ItemsPanelTemplate x:Key="WrapItemsPanelTemplate">
    <toolkit:WrapPanel />
</ItemsPanelTemplate>

… and update the ItemsControl to use them:

<ItemsControl Name="list" 
              ItemTemplate="{StaticResource TileTemplate}"
              ItemsPanel="{StaticResource WrapItemsPanelTemplate}" />

Reactive Extensions

I copied the code from my previous post:

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();

        Loaded += OnLoaded;
    }

    private readonly string text = "reactive wp7";

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        text.ToObservable()
            .OnTimeline(TimeSpan.FromSeconds(.3))
            .ObserveOnDispatcher()
            .Subscribe(AddLetter);
    }

    private void AddLetter(char letter)
    {
        list.Items.Add(letter);
    }

Animating on appearance

Instead of using layout states as in Silverlight version (they are not supported in WP7’s ListBox), I was back on using a behavior to trigger the entrance animation:

public class LoadedBehavior : Behavior<FrameworkElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }

    void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
    {
        CreateStoryboard().Begin();
    }

    private Storyboard CreateStoryboard()
    {
        Storyboard sb = new Storyboard();
        DoubleAnimation animation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(1000),
            From = -90,
            To = 0,
            EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
        };
        Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.Projection).(PlaneProjection.RotationY)"));

        sb.Children.Add(animation);

        animation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(1000),
            From = 0,
            To = 1,
            EasingFunction =
                new CubicEase() { EasingMode = EasingMode.EaseOut }
        };
        Storyboard.SetTargetProperty(animation, new PropertyPath(UIElement.OpacityProperty));

        sb.Children.Add(animation);
        Storyboard.SetTarget(sb, AssociatedObject);
        return sb;
    }
}

Wrapping up

The last thing to do was adding the behavior to the ItemTemplate and prettify the layout a bit.

That’s it, pretty easy – tiled letters are now gradually filling up the space on the main page, each letter appearing on the screen with a subtle animation. For more details on how that works check out my previous posts on Reactive Extensions.

The demo project can be downloaded from here. In the future I’ll look into using more Reactive Extensions on Windows Phone 7 – stay tuned.

image



Lost in time? Zip it!

In my last blog post I wrote about using Reactive Extensions together with layout states in Silverlight to gradually introduce collections of data to a ListBoxes. One small problem with code from that post is that I’m generating the sequence of data myself, whereas in real-world scenario would be pulling it from some data source like database or web service. It’s easy to turn an existing collection to an Observable by using the ToObservable() operator, but the generated sequence wouldn’t be time-based, as it would have been if we had used the GenerateWithTime() constructor.

So how do we turn an existing enumerable collection into a time-based observable sequence?

First, we need to convert the enumerable to a plain observable. Here’s the example of such conversion:

private readonly string text = "REACTIVE";

IObservable<char> letters = text.ToObservable();

[Reminder: a string is a collection/sequence of chars – turning this collection into an observable sequence results in IObservable<char>]

Next, we need to create an observable sequence that will serve as a “beat” – a time-based sequence that would define points in time at which we want to “release” (or trigger) the next item in our data collection. The following code will create a fast “beat”, “thumping” at every 300 ms:

IObservable<long> beat = Observable.Interval(TimeSpan.FromSeconds(.3));

Now we only need to lay the numbers from the enumerable collection over created beat and for that, there is a convenient combinator operator available in Reactive Extensions. It’s called – Zip.

IObservable<string> dancingLetters = numbers.Zip(beat, (letter, time) => letter);

Zip operator will take two observable sequences (letters and beat) and produce a new value pair when a new value is present in both sequences, kind of like a zipper. In our case, the letters sequence starts with 8 values and beat starts with zero. As the beat sequence starts producing new values (one every 0.3 seconds), these new values are paired (zipped) with values from letters, resulting in a new pair of data (letter, time) releasing every 0.3 seconds. As we’re only interested in numbers from the numbers sequence, we return only those values, ignoring values values from the beat sequence (=> letter).

dancingLetters is now a time-based observable sequence which we can subscribe to:

dancingLetters.ObserveOnDispatcher().Subscribe(AddLetter);

… and get the same result as in previous post, only with letters.

One great thing about Reactive Extensions is they are very extensible, meaning you can write your own operators by creating new extension methods. For frequent operations like the one we’ve just performed, it’s a perfect fit. Here’s an example of an OnTimeline() operator that would put an observable sequence on a live timeline:

public static class ObservableEx
{
    public static IObservable<TSource> OnTimeline<TSource>(this IObservable<TSource> source, TimeSpan period)
    {
        return source.Zip(Observable.Interval(period), (d, t) => d);
    }
}

With the new operator handy and in place, we could rewrite the previous snippet as (full code ahead):

private readonly string text = "REACTIVE";

private void OnLoaded(object sender, RoutedEventArgs e)
{
    text.ToObservable()
        .OnTimeline(TimeSpan.FromSeconds(.3))
        .ObserveOnDispatcher()
        .Subscribe(AddLetter);
}

private void AddLetter(char letter)
{
    list.Items.Add(letter);
}

This application in action can be observed through this link

image

In this post, I extended the code sample from previous post by creating a new extension method that puts an existing observable sequence on a timeline, with delayed item notification.

Download source code from here.



Silverlight Layout States with Reactive Extensions

I’ve been working on several applications where I needed to display several items in a ListBox (or an ItemsControl) at startup, but they had to appear on the screen one by one, with a short delay, not all at once. Using ListBoxItem’s layout states took care of handling how an individual item would appear in the list, but I still needed to handle a short pause between each item being added to the list. Usually I resorted to using a Timer, which sorted out that needed delay for me, but that really felt like hacking that had nothing to do with the real problem.

Reactive Extensions, however, offer a much elegant solution. The GenerateFromTime() construction operator is a close relative to the Generate() operator used in my previous blog entry, except GenerateFromTime() adds an important time dimension to generated sequence – the last parameter in this operator lets you specify a delay between each call to OnNext():

private readonly IObservable<string> numbers = Observable.GenerateWithTime(1, i => i <= 8, i => i + 1, i => i.ToString(), i => TimeSpan.FromSeconds(.3));

The above code snippet will produce an observable sequence of 8 strings, progressing through these strings with a 0.3 seconds delay.

The rest of the code:

private void OnLoaded(object sender, RoutedEventArgs e)
{
    numbers.ObserveOnDispatcher().Subscribe(AddImage);
}

private void AddImage(string image)
{
    list.Items.Add(image);
}

Note the ObserveOnDispatcher() operator again – GenerateWithTime uses a timer operating on a background thread so we need to ensure the AddImage() method is called on the UI thread.

Layout states for this sample are kept really basic:

<VisualStateGroup x:Name="LayoutStates">
    <VisualStateGroup.Transitions>
        <VisualTransition GeneratedDuration="0:0:1">
            <VisualTransition.GeneratedEasingFunction>
                <CubicEase EasingMode="EaseOut"/>
            </VisualTransition.GeneratedEasingFunction>
        </VisualTransition>
    </VisualStateGroup.Transitions>
    <VisualState x:Name="AfterLoaded"/>
    <VisualState x:Name="BeforeLoaded">
        <Storyboard>
            <DoubleAnimation Duration="0" To="-94" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
        </Storyboard>
    </VisualState>
    <VisualState x:Name="BeforeUnloaded"/>
</VisualStateGroup>

And the final result can be observed by following this link.image

This post has shown how to use Reactive Extensions in Silverlight to gradually fill a ListBox, with a bonus of a nice item entry animation, provided by the layout states.

Download source code from here.



Reactive Extensions – from pull to push: where’s the block?

I’ve discussed Reactive Extensions with a few people after my Rx talk last week and thought I’d clear up some confusion by clarifying on this blog…

One thing to know about Reactive Extensions is that simply going from pull model (enumerating) to push model (observing) doesn’t give you immediate background thread processing – everything is still happening on the same thread.

For example, let’s look at the following code and put a few debugger breakpoints in it:

image

Right at the top, there’s an array of image names I’m adding to the ListBox (AddImage() method). In this WPF app, the OnLoaded() method handles the Loaded event, where foreach loop iterates through the array and calls the AddImage() method.

Red balls indicate the places where I’d put the breakpoints, and the number in it tells the order in which they would be hit. Following the track, it is obvious that the OnLoaded() method is blocking until all images in the array is added into the ListBox.

To transform this code to use the observer/pull model, the following changes are made:

  1. The array (now an IObservable<string>) is generated with the Generate() Observable constructor.
  2. foreach loop is removed from the OnLoaded() method and replaced with the Observable subscription, providing the methods for OnNext and OnCompleted.

The Subscribe() method looks harmless sitting alone on now shortened OnLoaded() method, but guess what – it’s still blocking it! Take a look at the execution path: the code would enter the method, and upon subscription, starts calling the AddImage() method. After that, it calls OnCompleted() and then, only then, continues the execution in the OnLoaded() method and finally exits.

The thing to be careful about here is the fact that even if the images.Subscribe() method looks innocent and instant, it may be executing a long(er) time, if an observable sequence is very long. Which also means that the current thread will be blocked for that time also. And we don’t want the UI thread blocked.

image

What we can do to achieve the behavior we want and expected (not blocking the UI) is forcing subscription on a new – background – thread and expect the observable to call us back on the UI thread. Note that the AddImage() method has to be called on the UI thread because the code accesses the ListBox and if called from a non-UI thread, the call would fail. The code below exercises these changes and results in a whole different flow: upon subscription, the UI thread exits the OnLoaded() method immediately, while the subscription processing is done in a new thread. ObserveOnDispatcher() operator ensures that for each element in the observable sequence, AddImage() method is safely called on the UI thread.

image



Bleeding Edge 2010: Reactive Extensions Slides and Demo

These are slides and demo from my talk on Reactive Extensions from Thursday’s Bleeding Edge conference:

Slides | Demo code

Thanks to all for attending the talk.



What's Wrong with *my* WCF Service?

While I was watching the Silverlight TV episode on common WCF service issues with Silverlight (Silverlight TV 46: What's Wrong with my WCF Service?) I remembered one more issue that bit my neck a while back and thought it was worth pointing it out again... It was one of those “Service returned ‘Not found’” issues, except nothing I would do seemed to help solving it.

My simple WCF service was returning an IEnumerable<T> and I was using a Linq query for filtering the results before returning them to the client. Can you guess where I’m going to?

Let’s step back and take a look at the symptoms I was facing: the original problem was that service call returned with the infamous “NotFound” exception.

I would try using Client Http Stack to get more info about the exception – nothing. Reverted to Browser Http Stack and implemented service stack to return Faults – still nothing. I wrapped my service method call into a try…catch statement inside service method – no errors would’ve been caught on the server side and the NotFound error would persist… Furthermore, stepping through the service code didn’t throw any exceptions and the error only happened when service call returned one or more records. When there was zero, it returned fine… Hmmm… Something happening on the wire? Fiddler wasn’t much of a help either.

What helped at last was a careful examination of the service method call. Facepalm! I was failing in materializing the Linq query by not forcing its evaluation with the .ToList() extension method (or similar) and data never made it to the other side.

Lesson learned – when your services return IEnumerable and you’re using Linq to query/transform data double check that you’re returning something that client would actually have a chance enumerating.



My NTK10 slide decks

Another NTK has ended, and in my opinion, this year’s conference was one of the greatest and most enjoyable for the past few years. This is a list of sessions I had (alone or with co-speakers), along with the PowerPoint slide decks (all in Slovenian Language):

Silverlight and MEF

[The Photo Gallery application I was showing is available on the CodePlex and will be updated with the latest bits shortly]

ASP.NET, WebForms, Silverlight – What to choose?

Having @dusanzu as a co-host, this was a Birds of Feather (BoF) session. And although not listed as such, it turned out great anyway. There wasn’t much slides since this was a discussion – the slide-deck will be available from the NTK site.

Silverlight and WCF RIA Services

[I built a basic NTK schedule viewer app from the scratch, using Silverlight Business project template and showing off different features of RIA Services in the process. If somebody is interested in seeing the code that was produced on the talk, please contact me]

Tips & Tricks: Expression Blend for Developers

Again, we (@krofdrakula and I) wanted to show as much useful information and show designer-developer workflow, so we concentrated on showing off Visual Studio, Expression Blend (through Team Foundation Server running in a cloud), and the result was only a two-slide PowerPoint slide-deck (which will be available for download from the NTK site as well). As it turned out, even those two slides were way too much for what we wanted to share in a 45-minute time slot.

What’s new in Silverlight 4?

[The source code accompanying this slide-deck is way overdue for publishing – stay tuned for my future blog posts, where I’ll cover all the features I put together in my Silverlight 4 demo app]

A big thanks to all that attended my talks, I hope to hear from you in the near future. Another big thanks goes to local Microsoft office, for organizing another great event.

Oh, and another thing – this year’s NTK conference was covered through twitter as well (significantly better than last year, but still, plenty of room to improve for the next year). I’ll sign off with the snapshot of Twedge, a Silverlight 4 widget, finding its way to the CodePlex later this week. To see it in action, visit http:/www.ntk.si.

image

See you next year!



Named & optional parameters in Silverlight 4

Named & optional parameters are a new C# language feature coming up with .NET FX 4.0 and guess what… it’s in Silverlight 4 as well!

Optional parameters will come very useful when defining complex APIs where you would usually have to provide several overloads for the same method for it to make sense to wide variety of usages. Let’s take a look at this basic example:

public void PositionWindow(bool isTopMost, double left = 0, double top = 0, double width = 800, double height = 600)
{
    Window window = Application.Current.MainWindow;
    window.TopMost = isTopMost;
    window.Left = left;
    window.Top = top;
    window.Width = width;
    window.Height = height;
}

isTopMost is the only parameter that’s required, all other parameter specify their default value, which makes them optional. Needless to say, the default values will be used for those parameters which the calling function doesn’t provide. One thing to know is that optional parameter must always be declared after required parameters.

The following calls are all valid:

PositionWindow(true); // position and size set to defaults
PositionWindow(true, 100); // top position and size set to defaults
PositionWindow(true, 100, 200); // sizes set to defaults
PositionWindow(true, 100, 200, 600, 200); // all parameters provided

But what if you wanted to provide the size only and leave the position to be set to defaults? Enter named parameters. The same method above can be called also with:

PositionWindow(isTopMost:true, width: 600, height: 200); // named parameters
PositionWindow(true, width: 600, height: 200); // naming is optional when positioned right
PositionWindow(true, height: 200, width: 600); // order doesn't matter
PositionWindow(height: 200, width: 600, isTopMost: true); // ... even with the required parameters

Simple, eh? The need for named and optional parameters may have come from the need to simplify COM automation, but they may prove just as useful in many other cases. But before you go start creating methods with tens of optional parameters, note that this is not the ultimate solution, and one thing worth noting is although the calls above look like they are passing the specified parameters only, the compiler in fact generates them with all parameters in place. This is how the Reflector sees that last batch of calls:

bool CS$0$0000 = true;
double CS$0$0001 = 600.0;
double CS$0$0002 = 200.0;
this.PositionWindow(CS$0$0000, 0.0, 0.0, CS$0$0001, CS$0$0002);
CS$0$0001 = 600.0;
CS$0$0002 = 200.0;
this.PositionWindow(true, 0.0, 0.0, CS$0$0001, CS$0$0002);
CS$0$0001 = 200.0;
CS$0$0002 = 600.0;
this.PositionWindow(true, 0.0, 0.0, CS$0$0002, CS$0$0001);
CS$0$0001 = 200.0;
CS$0$0002 = 600.0;
CS$0$0000 = true;
this.PositionWindow(CS$0$0000, 0.0, 0.0, CS$0$0002, CS$0$0001);

Potential architectural issues aside, I’m quite happy to see this feature come to Silverlight as well. How about you?



Add version 4 components to your Silverlight 3 application with MEF

Note: this post and accompanying source code was updated to reflect the latest MEF build on Codeplex. This build is much more aligned with the version of MEF that is available from Silverlight 4 Beta SDK.

The current Silverlight version is v3, with v4 in the making (in Beta 1 at the time of this posting). Silverlight 4 is bringing a lot of new features in the core framework and to use them, you would have to migrate your applications to the latest version, once it gets released. And that would require all the potential users to upgrade their machines to the latest version as well.

But there’s another way. By using MEF (Managed Extensibility Framework), you can extend your existing Silverlight 3 application with optional package, which would contain Silverlight 4 components only.

Here’s an example: user can select an image file from your local disk in Silverlight 3 only through an OpenFileDialog, while with the new drag/drop feature in Silverlight 4, she would be able drag a picture from the file system and drop it onto the application. Why not allow those with Silverlight 4 installed do it the easy way?

To make this work, the main application should be all Silverlight 3. We’d provide additional Silverlight 4 features in a separate XAP package, which would be downloaded later and tested for the right runtime version. In case user had the latest Silverlight runtime installed, we could bring in additional features in the application. For this post, I’m going to implement the abovementioned picture select feature by providing two controls:

  • a select button for choosing the picture through an OpenFileDialog (Silverlight 3 feature)
  • a drop canvas where user can drop the picture from the file system (Silverlight 4 feature)

Silverlight 3 control

Here’s how the BrowseForPictureControl would look like:

imageThis control would be contained in the main application. It exposes the PictureSelected event, with the FileInfo data passed as an event argument. Because the application is going to subscribe to this event for each control that exposes it, we need to make an interface for it and put that into a new project that would be shared among the both packages.

public interface IPictureControl
{
    event EventHandler<PictureSelectedEventArgs> PictureSelected;
}

public class PictureSelectedEventArgs : EventArgs
{
    public FileInfo File { get; set; }

    public PictureSelectedEventArgs(FileInfo file)
    {
        File = file;
    }
}

The control implements the this interface as:

private void OnBrowse(object sender, RoutedEventArgs e)
{
    OpenFileDialog dialog = new OpenFileDialog();
    bool result = dialog.ShowDialog() ?? false;
    if (result)
    {
        OnPictureSelected(dialog.File);
    }
}

Silverlight 4 control

The improved Silverlight 4 control should be created in a new Silverlight 4 application project, that would be disconnected from the main project, but referencing the previously created shared project. The control looks simpler too:

image

And the interface implementation:

private void OnDrop(object sender, DragEventArgs e)
{
    IDataObject dataObject = e.Data as IDataObject;
    if (e.Data == null)
    {
        return;
    }
    FileInfo[] files = dataObject.GetData(DataFormats.FileDrop) as FileInfo[];

    OnPictureSelected(files[0]);
}

OK, controls done. Now, on to MEF.

Bringing in MEF

MEF for Silverlight 3 is available for download from Codeplex. You’ll need the following assemblies added as a reference in your main application:

  • System.ComponentModel.Composition
  • System.ComponentModel.Composition.Initialization.dll

The second assembly is only required to use from the main project, where composition is performed. The project that is shared between the SL3 and SL4 projects can reference just the first assembly from the list. Also, one downside of maintaining the compatibility with Silverlight 3 is that the Silverlight 4 project must reference the same System.ComponentModel.Composition assembly as other projects. No ‘native’ SL4 MEF there…

Attribute for version

Obviously, loading any Silverlight 4 based code into a Silverlight 3 application should be impossible, therefore we need to mark both of controls with information about the Silverlight runtime they require. Something in a way of:

[ExportablePictureSelector(RequiredVersion = "3.0")]
public partial class BrowseForPictureControl : UserControl, IPictureControl
{
    ...
}

for Silverlight 3 control, and:

[ExportablePictureSelector(RequiredVersion = "4.0")]
public partial class DragDropPictureControl : UserControl, IPictureControl
{
    ...
}

for Silverlight 4 control.

The ExportableSelector attribute is derived from MEF’s ExportAttribute and is declared as:

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

    public string RequiredVersion { get; set; }
}

Putting it all together

The main application provides a catalog of all the controls that were discovered:

[ImportMany(AllowRecomposition = true)]
public ObservableCollection<Lazy<IPictureControl, IPictureSelectorMetadata>> PictureControls { get; set; }

The PictureControls collection will change whenever a new export is discovered by MEF. When that happens, the newly discovered control will be added to the main form:

private void OnPictureControlsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    foreach (Lazy<IPictureControl, IPictureSelectorMetadata> view in Views)
    {
        Control c = view.Value as Control;
        if (!panel.Children.Contains(c) && Application.Current.Host.IsVersionSupported(view.Metadata.RequiredVersion))
        {
            panel.Children.Add(c);
            view.Value.PictureSelected += OnPictureSelected;
        }
    }
}

The above code shows that the main criteria for adding the control on the form is that it’s RequiredVersion is supported by the runtime – and that is checked with the interop IsVersionSupported method of the plugin host.

When picture is selected, the PictureSelected event is fired by the control and handled to display the picture:

private void OnPictureSelected(object sender, PictureSelectedEventArgs e)
{
    BitmapImage bi = new BitmapImage();
    bi.SetSource(e.File.OpenRead());
    image.Source = bi;
}

Of course, BrowseForPictureControl control being included in the main project, it will immediately be picked by MEF and inserted in the PictureControls collection. For Silverlight 4 based XAP package, however, we need to download it first. Here’s the InitializeContainer method, which initializes a new composition container and triggers the package download:

private void InitializeContainer()
{
    PackageCatalog catalog = new PackageCatalog();
    catalog.AddPackage(Package.Current);
    CompositionContainer container = new CompositionContainer(catalog);
    container.ComposeExportedValue(catalog);

    CompositionHost.InitializeContainer(container);

    Package.DownloadPackageAsync(new Uri("CrossVersioning.Version4Enhancements.xap", UriKind.Relative), (e, p) =>
    {
        if (p != null)
        {
            catalog.AddPackage(p);
        }
    });

    PartInitializer.SatisfyImports(this);
}

The Silverlight 4 package is asynchronously downloaded from the server and added to the package catalog. The last line is there to start the initial composition, causing the v3 control to immediately show up.

Conclusion

There… the application is set up. Users, having the Silverlight 3 runtime installed, will see the it as:image… and Silverlight 4 users will also see that additional feature:

image

This approach will let you gradually update your applications to use Silverlight 4, not forcing the users to update to the latest runtime immediately (although there would probably be no reason not to ;))

You can test the application right here:

Or download the source code from here. Enjoy.



My MEF articles published on SilverlightShow

My two-part article on rebuilding an existing Silverlight application to use MEF (Managed Extensibility Framework) for “selective composition” is now live on SilverlightShow.net (part 1, part 2). I took my Halloween Gallery application and made it pluggable so I can pull in different themes throughout the whole year (current themes include Halloween and Christmas).

Halloween Live Gallery Christmas gallery 

The original features are still there – geotagged photos are retrieved from Flickr API and the location where they were shot is shown on the Bing Map. If you’re interested in MEF, take a look at let me know what you think. The application will be released to Codeplex soon.