Cascading ItemsSource Bindings in Silverlight

by Administrator 15. March 2010 21:35

When building a complex data visualization application in Silverlight, I discovered a disturbing issue when dealing with multiple DataGrids on the same screen.  If the ItemsSource of a particular DataGrid gets updated as the result of a SelectedItem change in another DataGrid the child grid would not display any items.  Worse, adding code to query the ItemsSource of the child grid shows that does have a valid and correct ItemsSource, so why doesn’t it display?  In this article we’ll quickly demonstrate the problem and show a solution.

Sample App

I’ve created a simple example with a ‘parent’ DataGrid containing Orders and a ‘child’ DataGrid meant to display the Order Details of the selected Order.  Throw in a small amount of sample data and we wind up with this:

dbf0

You can see that we have selected the first and only row in the top DataGrid and it has a valid OrderDetails property.  Clicking on the Check Items Source button reveals that something should be shown in the bottom DataGrid:

dbf1

So what’s going on?  Let’s take a look at the XAML and data binding code to see if anything is amiss.

Data Binding Code

I have created a simple ViewModel for this screen, with code as follows:

public class ScreenModel : BindableType
{
    public ScreenModel()
    {
        Orders = new ObservableCollection<Order>();
        Orders.Add(new Order());
    }


    private ObservableCollection<Order> _Orders;

    public ObservableCollection<Order> Orders
    {
        get { return _Orders; }
        set
        {
            _Orders = value;
            OnPropertyChanged("Orders");
        }
    }

    private Order _SelectedOrder;

    public Order SelectedOrder
    {
        get { return _SelectedOrder; }
        set
        {
            _SelectedOrder = value;
            //Doesn't work:
            OnPropertyChanged("SelectedOrder");

BindableType implements the basic INotifyPropertyChanged functionality.  Hopefully you agree that this is extremely vanilla code, and that it’s a bit odd that this does not work.  Maybe something is wrong with the XAML?

            <TextBlock>Master Grid</TextBlock>
            <my:DataGrid x:Name="MasterGrid" MinHeight="100"
                         ItemsSource="{Binding Orders}" SelectedItem="{Binding SelectedOrder, Mode=TwoWay}" />
            <TextBlock>Detail Grid</TextBlock>
            <my:DataGrid x:Name="DetailGrid" MinHeight="100" ItemsSource="{Binding SelectedOrder.OrderDetails}" />
            <Button x:Name="ChkBtn" Content="Check Items Source" Click="ChkBtn_Click"></Button>

The XAML is extremely basic as well.  How can you fix this?  Searching through forums it seems that when Silverlight 3 was in BETA changing the bottom DataGrid to have a TwoWay binding to its ItemsSource would fix this but I didn’t have luck with this.

Problem Solution

By groping in the dark and changing a single line of code I was able to get the correct behavior:

dbf2

The only code change is this:

private Order _SelectedOrder;

public Order SelectedOrder
{
    get { return _SelectedOrder; }
    set
    {
        _SelectedOrder = value;
        //Doesn't work:
        //OnPropertyChanged("SelectedOrder");

        //Works:
        Deployment.Current.Dispatcher.BeginInvoke(() => OnPropertyChanged("SelectedOrder"));
    }
}

All I’ve done here is to invoke the Property Change Notification for SelectedOrder back onto a Dispatcher thread.  Why is this necessary?  I can’t say for sure.  My guess is that something down in the bowels of Silverlight is attempting to detect some sort of layout cycle or infinite recursion here.  If you find this situating in your code this should work for you.

Tags:

AddRange for ObservableCollection in Silverlight 3

by Administrator 4. March 2010 01:43

It’s great that the built-in controls in Silverlight understand INotifyCollectionChanged, and that ObservableCollection<T> ships with Silverlight.  However, when adding large data sets to ObservableCollection<T> the performance  can be brutal due to the fact that ObservableCollection<T> fires an event with every operation on the collection.  Most of the time this is what you want however some bulk operations like AddRange would be nice.  Let’s take a look at a way to add AddRange() to ObservbleCollection<T> using a technique that vastly increases performance.

Example UserControl

We’ll use a simple Silverlight root visual with a DataGrid on it to demonstrate this technique. Note that we are using a new class called SmartCollection<T> and an Item class with some randomly generated field values.

namespace HandWaver.AG.OCAddRange
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            _collection = new SmartCollection<Item>();
            DasGrid.ItemsSource = _collection;            
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            Dispatcher.BeginInvoke(() => BuildItems());
        }

        TimeSpan Time(Action a)
        {
            var start = DateTime.Now;
            a();
            var end = DateTime.Now;
            return end - start;
        }

        SmartCollection<Item> _collection;
        
        private void BuildItems()
        {
            Action slow = () =>
            {
                for (int i = 0; i < 25000; ++i)
                {
                    _collection.Add(new Item());
                }
            };

Using this technique and displaying the time it took to add these items to the data grid gives me this result.  Note that Stopwatch is not present in Silverlight 3.

time0

Nearly 10 seconds to add 25,000 items to the DataGrid even though most of them are not visible.  Let’s see what SmartCollection<T> can do with slightly different code:

Action fast = () =>
{                
    var sourceList = new List<Item>();
    for (int i = 0; i < 25000; ++i)
    {
        sourceList.Add(new Item());
    }
    
    _collection.AddRange(sourceList);                
};

var time =
    //Time(slow);
    Time(fast);

So we’ve built a source collection and used the AddRange implementation.  How does it do?

time1

That’s a pretty significant speed up! Let’s go ahead and look at the code for SmartCollection<T> now.

using System;
using System.Linq;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Collections.Specialized;

namespace HandWaver.AG.PresentationModel
{
    public class SmartCollection<T> : ObservableCollection<T>
    {
        public SmartCollection()
            : base()
        {
            _suspendCollectionChangeNotification = false;
        }


        bool _suspendCollectionChangeNotification;

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            if (!_suspendCollectionChangeNotification)
            {
                base.OnCollectionChanged(e);
            }
        }

        public void SuspendCollectionChangeNotification()
        {
            _suspendCollectionChangeNotification = true;
        }

        public void ResumeCollectionChangeNotification()
        {
            _suspendCollectionChangeNotification = false;
        }


        public void AddRange(IEnumerable<T> items)
        {
            this.SuspendCollectionChangeNotification();
            int index = base.Count;
            try
            {
                foreach (var i in items)
                {
                    base.InsertItem(base.Count, i);
                }
            }
            finally
            {
                this.ResumeCollectionChangeNotification();
                var arg = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                this.OnCollectionChanged(arg);
            }
        }

    }

}

Note that we could do an AddRange implementation via an extension method but we would not gain the performance improvements since events would still fire for every operation.  By extending ObservableCollection<T> we gain the ability to create our own AddRange method.  The AddRange method sets a flag that temporarily suppresses the collection changed notification for ObservableCollection<T>.   At the end it uses NotifyCollectionChangedAction.Reset to indicate that a significant change was made to the collection.  The UI rebuilds itself in a fraction of the time it took to add the items one by one.  You can use this technique to gain huge performance improvements for your Silverlight 3 apps dealing with large data sets.

Tags:

Speaking at FVNUG Day of .Net

by Administrator 2. March 2010 02:40

I have the privilege for the second year in a row of speaking at the Fox Valley Day of .NET.  Last year the event was a little later in the year (or MIX was earlier?) and I gave the keynote as part of the MIX It Up! tour.  This year I am actually going to MIX so maybe I’ll have to come back.

I will be giving the MEF talk I mentioned not too long ago and while I will have some good Silverlight content this is more about MEF itself.  The guys up there are gracious hosts and I am looking forward to getting up there and sharing one of my favorite new technologies.

If MEF is not your thing, please consider seeing my colleague Christopher Barwick’s talk on Business Intelligence: “BI: from Database to Warehouse  to OLAP to Excel with SQL Server 2008 & Excel 2007” running in the same time slot as my presentation.  Chris has really been stepping up his involvement in the community and he has a lot to share.

For my part I will be watching Dave Bost talk about Silverlight 4 right after my talk.  While I imagine I’ve already consumed this content I can’t get enough Silverlight and Dave is a good presenter so I’ll be sitting in.

Please check out their site and come see us!  They have a lot of swag this year so your chances of coming home with something extremely useful are very good.

Tags:

BigHammer/EdgeNet is hiring

by Administrator 27. February 2010 20:13

If you’ve ran into me at a community event lately you may have caught me saying something along the lines of working too many hours.  You no doubt felt bad for me and wished you could do something, anything, to help me in my predicament.  Most of the time your sympathy came in the form of beer, which is greatly appreciated.  However if you really want to contribute to the Save Damon Foundation you should come and work for me!

Ok, bad jokes aside, we are hiring for my team.  We currently have offices in Waukesha (WI), Nashville, and Atlanta, although people have worked remotely from all over the place in the past.

What would you be working on?  A large family of applications with terabytes of data.  Our current process and technology mix looks something like this:

  • Asp.net
  • jQuery
  • WCF
  • All Microsoft application stack
  • Team System
  • Scrum
  • Silverlight 3
  • Silverlight 4
  • MEF
  • Unity
  • PRISM
  • AbunchofotherstuffIcanthinkofrightnow

Leave me a comment or contact me for more details.

Tags:

Would you go see this talk? (MEF)

by Administrator 14. February 2010 20:56

I am preparing a talk for the spring code camps and conferences.  Would you go see this talk?

What can I do with MEF?

The Managed Extensibility Framework has left excitement and confusion in its wake as .NET 4 moves towards release. What can I use this for? What should I use this for? Is this another IoC/DI container? What about Unity? What about the System.AddIn namespace? In this talk we will explain the workings of MEF using straightforward examples and then dig deep into the real power of MEF using examples including MEF for Silverlight, MEF for WPF, and MEF for Enterprise services.

Leave a comment, and thanks!

Tags:

Preparing for the 2010 Global MVP Summit

by Administrator 14. February 2010 20:24

Starting tomorrow I’ll be attending the 2010 Global MVP Summit in the Seattle area.

After working way too hard since, well, pretty much since July of 2009, I will be taking some me time.  Not everyone would consider this kind of event a break but for me this is as exciting as an exotic vacation.  Of course I can’t talk about anything that’s going on during this week, so to the untrained eye following me on twitter it may appear that I am merely goofing off and drinking beer for five days.  In the past I have always found events like this to be a mix of actual learning value and chance to take one’s self out of the daily grind of deadlines and features to gain perspective and recharge.  While I expect this to be the most learning-heavy event I’ve ever attended I’ve also really never needed to recharge as badly as I do right now.  Between the actual session content, putting faces with virtual names, and the organized social events it looks like sleep is going to be hard to come by.  This means my recently worsening insomnia may prove to be a valuable (well, OK, tolerable) asset.

Work and personal factors have kept me from writing much for the past month (since December, really) so I have three personal technical goals for this week as well.  I hope to have time to hack on some personal items as well.

I’ll be using the twitter tag #mvp10.  Here’s to a great geek holiday.

Tags:

Going to MIX 2010

by Administrator 30. January 2010 20:53

I haven’t decided where I’m staying yet, but I will be attending MIX 2010 March 15th – 17th.  Are you going to MIX? Drop me a comment!  I will likely be accompanied by someone from BigHammer but I’m always looking for other people to drink beer learn with!  I’ll obviously be leaning heavily towards the Silverlight sessions.  If MIX 2009 is any indication there should be some great content in March. 

Of course, I am hoping to finally see a completely awesome Windows Mobile 7 announcement.  Please?

Tags:

First Post

by Administrator 4. January 2010 02:31

After having taken most of December 2009 and the first few days of January off of blogging I’m back with my traditional first post of 2010.  There are six years worth of blogging history listed to the right, and I was blogging for 6 years before that, starting as so many people did on Geocities.  I do enjoy using the new year as a moment of reflection, and I do enjoy putting a subset of that reflection online as a public record I can go back and check.

How was 2009?

Blogging & Community

I’m not sure if I’ve ever come out and said this, but my goal with blogging has never been to write a Widely Accessible blog.  I’ll leave that to people who are extremely good at it like Shawn Wildermuth and Tim Huer.  There are plenty of people who will write the “Quick tour of Silverlight 4” articles and bless them for it, I know I benefit from their work.

I like to write more in depth articles, things not everyone will get their head around.  Things involving design patterns, Reflection Emit, and approaches to wrangling complexity.  On one hand maybe that makes me an elitist, on the other hand I like to think I’m just catering to a different (smaller) audience.  If you want to know how to do TwoWay binding to dictionaries in Silverlight 3 or handle single-import Recomposition in MEF then I’m your man.

From that perspective I think I did pretty OK in 2009.  I would have liked to have gotten much further in the development of the AGT project and possibly blogged a little bit more in general.  In Q4 2009 I tried to settle on a 1 article per week rhythm that I didn’t quite meet.

Community wise I exceeded my own goals in all areas but one.  I was re-awarded the Microsoft MVP, I did something like 9 public speaking events and attended several first party Microsoft events like MDC.  What I wish I’d done more of was to attend my own local .NET User Group meetings.  I have a valid excuse for this, however.  These are always on Tuesdays, and Tuesday night is extremely overloaded for me.  I have the BigHammer Patterns and Practices group which is usually followed by a wine tasting in downtown Milwaukee, a trivia game, and the occasional CarSpot Reunion.

Personal

2009 was a hard year.  I worked way too much in 2009.  This cannot continue.  My kids are growing up so fast and they are outrageously fun.  While we managed to have some family fun, I did goof in not taking my wife on a kid-less vacation in 2009.  Hopefully my friends and family will agree that I took my cooking to the next level, though there are many levels yet to go.  Despite some hard stretches this year, I did get my dream car and stockpiled a lot of wine in my basement.

The biggest personal defeats of 2009 were just plain not finding time for some of my personal projects and not exercising at all.

Professional

Professionally, 2009 was murder.  I went from being Director of Solution Strategy at CarSpot at the end of 2008 to freelance consultant while looking for work to Guy who Writes Code at BigHammer.  I worked way too much and every other area of my life suffered as a result.  Enough said about that.

Goals for 2010

Blogging & Community Goals

  • Consistent with my stated blogging goals, I’ve got a lot of solid technical content coming in 2010.  I’m shooting for a rhythm of one technical and one personal/cultural article per week.  I would also like to pull of one Political article per month – I’m sure there will be plenty to talk about in 2010.
  • I need to make it to the Milwaukee-area Wisconsin .NET User’s group more often when there’s not delicious wine to be tasted.
  • I am attending the 2010 Global MVP Summit next month, which should be completely awesome.
  • There’s a good chance I’m going to MIX in March, which should also be awesome.
  • I would like to do at least six Regional speaking events in 2010 ranging from nearby to Indianapolis to Minnesota.
  • I would like to possibly encourage the reformation of the local Silverlight Special Interest Group
  • I would like to schedule some Nerd Lunches and Nerd Dinners, which I did VERY little of in 2009

Personal

I need to work less in 2010, and I need to take my wife on a vacation. 

  • I also absolutely need to make time for some of my personal projects. 
    • Assuming Windows Mobile 7 ever happens I’d like to have one mobile application and one website pulling in a few bucks by the end of the year.
  • Light exercise, like 30 sit-ups a day (starting tomorrow)
  • I need to re-engage with the Klipsch community !
  • Buy a snow blower or contract a service (my neighbors know what I mean)

Other than that my personal goals are none of your business ;)

Professional

I need to work less in 2010.  I also have some goals specific to my current position that I can’t really talk about.  There’s also a lot of overlap here with the Blogging and Community Goals.  Professional-wise I think 2010 may be a year to shore up and make sure I’m as good in certain areas as I think I am. 

I am also going to get at least “C+ competent” at regular expressions this year.  I’ve avoided becoming even familiar with regex for the past 15+ years and this must stop.  A very simple URL rewriting regex for IIS 7 took me WAY too long to get right today.

I wish you all a happy and productive 2010.

Tags:

Using MEF to Work Offline in Silverlight 3

by Administrator 8. December 2009 02:22

Silverlight 3 ships with out of browser support which is a particularly useful feature.  Combining OOB with the ability to detect network status can allow your users to consume your Web app without a connection.  Combining both of these features with Isolated Storage and the right design approach can provide a seamless Occasionally Connected application experience using Silverlight 3.

Wine Research

I will need another sample application to demonstrate these concepts, this time I’m going with HandWaver Wine Research:

wineresearch0

When we navigate to [Questions] we’re going to see a list of questions about things like Wine/Food pairing and similar topics; the questions were submitted using another system.  The green orb in the upper right hand corner indicates the app is online and connected.  I have also included a button to toggle the online/offline status which is easier than pulling my plug or disabling my network device in Windows.  I will be using the HandWaver.AG Silverlight Guidance project from previous articles.

Application Goals

We only have a couple of functions for this application.  We need to read questions people send us about wine, answer those questions, and send a message to the question asker.  Because some of these questions may take careful thought and I don’t always have an internet connection, I want the application to seamlessly work no matter my connection state.  I have only two modules, abstracted behind interfaces, for accomplishing this: IQuestionRepository and IResearchMessageSender.  I would like to use a dependency-injection like approach for configuring these modules, but I must be able to react to environmental changes as well.

Initializing MEF

MEF is much more than an IoC container and in this article we will explore one of the more intriguing features.  Recomposition in MEF is easy to turn on, not straightforward to get working, and you must design for it.  This should not be taken as a general introduction to MEF but we can review:

MEF works by satisfying [Import]s with matching [Export]s.   Instances with either Imports or Exports are typically called Parts in MEFspeak.  Parts can either be handed to MEF of discovered from some type of Catalog.

Since we have two different parts which need to change in concert, the idea of a Catalog works well here.  I am using a Presenter combined with ViewModel to drive the question/answer screen.  The presenter utilizes MEF to satisfy module needs as follows.

namespace HandWaver.AG.WorkOfflineDemo.PresentationModel
{
    public class ResearchPresenter : IPartImportsSatisfiedNotification
    {
        public ResearchPresenter(IResearchView v)
        {
            _view = v;
        }

        IResearchView _view;        
        IQuestionRepository _qRepo;

        [Import(AllowRecomposition = true)]
        public IQuestionRepository QuestionRepo
        {
            get { return _qRepo; }
            set
            {
                _qRepo = value;
                if (null != _view.ViewModel)
                {
                    _view.ViewModel.QuestionRepo = _qRepo; 
                }
            }
        }

        [Import]
        public NetworkStatusMonitor NetworkStatusMonitor { get; set; }

        public void OnImportsSatisfied()
        {
            NetworkStatusMonitor.GoOnline += new Action(NetworkStatusMonitor_GoOnline);
            NetworkStatusMonitor.GoOffline += new Action(NetworkStatusMonitor_GoOffline);
        }


        public void InitView()
        {
            var mdl = new WineResearchViewModel();
            QuestionRepo.FindUnanswered((qs) =>
            {
                mdl.UnansweredCount = qs.Count;
                mdl.Questions.Clear();
                mdl.Questions = new ObservableCollection<Question>();
                qs.ForEach((q) => mdl.Questions.Add(q));
            });

            mdl.QuestionRepo = QuestionRepo;

            _view.ViewModel = mdl;            
        }

        public void SaveSelected()
        {
            var q = _view.ViewModel.SelectedQuestion;
            QuestionRepo.MarkAnswered(q, () => _view.ViewModel.Questions.Remove(q));
        }

There are two Import definitions for this class.  One is a NetworkStatusMonitor that tells us when connection status changes using the baked-in Silverlight 3 APIs and uses the bare Import attribute.  The second is more interesting as it also sets AllowRecomposition to be true.  What this tells MEF is that we can re satisfy this import later if the situation arises.  This will help us meet our goals if we design carefully: when online, I’ll use a WCF based implementation of IQuestionRepository, when offline I’ll save messages to Isolated Storage to be forwarded on later.  Because I’m setting the current IQuestionRepository as a property of the ViewModel I can actually see this at work:

OnlineQuestionRepo

OfflineQuestionRepo

In each case, note the area highlighted in red and the green/red orb indicating connection status .  How did we accomplish this?

Groups of Services and Re Composition

The high level static structure for the different pieces needed to make this work is pictured here. 

staticstructure

Some extra work is needed to translate this into something MEF can help with.  MEF provides Catalogs, Imports, Exports, and of course the CompositionContainer however the out of the box components did not quite do what I wanted in a straightforward way so some extensions were required.  Let’s walk through the code needed to let ServiceFactory switch between OnlineServices and OfflineServices.

When first starting, we setup the MEF container based on the current connection status:

public class ServiceFactory
 {
     [Import]
     public NetworkStatusMonitor StatusMonitor { get; set; }

     [Import]
     public CompositionContainer Container { get; set; }

     IServiceGroup _services;

     public void Initialize()
     {
         if (StatusMonitor.IsOnline)
         {
             _services = new OnlineServices();
         }
         else
         {
             _services = new OfflineServices();
         }
         AddAll(_services);

AddAll performs the initial composition based on whichever group of services (Modules) were applicable at the time.  Things get interesting when we need to recompose based on an environment change.

void StatusMonitor_GoOnline()
{
    var oldSvc = _services;
    _services = new OnlineServices();
    RecomposeAll(oldSvc, _services);
}

void StatusMonitor_GoOffline()
{
    var oldSvc = _services;
    _services = new OfflineServices();
    RecomposeAll(oldSvc, _services);
}

The intent should be clear at this point.  We are going to remove the “old services” from the Composition and add the “new services” to the composition.  The rest of the code here is a little bit more verbose than need be in order to make it very clear what’s going on.

void RecomposeAll(IServiceGroup old, IServiceGroup @new)
{
    var exportQR = GetDefaultExport(typeof(IQuestionRepository), old.QuestionRepo, false);
    var exportIRM = GetDefaultExport(typeof(IQuestionRepository), old.ResearchMessageSender, false);

    var addQR = GetDefaultExport(typeof(IQuestionRepository), @new.QuestionRepo, true);
    var addIRM = GetDefaultExport(typeof(IResearchMessageSender), @new.ResearchMessageSender, true);

    var batch = new CompositionBatch();
    batch.RemovePart(new SingleExportPart(exportQR, old.QuestionRepo.Name));
    batch.RemovePart(new SingleExportPart(exportIRM, old.ResearchMessageSender.Name));

    batch.AddPart(new SingleExportPart(addQR, @new.QuestionRepo.Name));
    batch.AddPart(new SingleExportPart(addIRM, @new.ResearchMessageSender.Name));
    
    Container.Compose(batch);
}

In each case, we must provide enough information for the CompositionContainer to:

  1. Find the currently exported Part for a given contract
  2. Create a ComposablePart that maps to each
  3. Create new Exports for the new Parts
  4. Create a ComposablePart for the new Exports
  5. Create a CompositionBatch to do the Add/Remove as an atomic operation

I found that the code below was needed in order to successfully accomplish the aim.

protected Export GetDefaultExport(Type contractType, Type implType, bool add)
{
    string contractName = contractType.ToString();
    var metadata = new Dictionary<string, object>();
    metadata.Add("ExportTypeIdentity", contractName);
    Func<object> valueFinder = null;

    if (add)
    {
        valueFinder = () => Activator.CreateInstance(implType);
    }
    else
    {
        valueFinder = () => (from p in Container.Catalog.Parts where p.Metadata["ExportTypeIdentity"] == contractType select p).FirstOrDefault();
    }
    var export = new Export(contractName, metadata, valueFinder);
    return export;
}

/// <summary>
/// A simple container to work with MEF container constructs
/// </summary>
public class SingleExportPart : ComposablePart
{
    public SingleExportPart(Export e, string implVal)
    {
        _export = e;
        _implVal = implVal;
    }

    Export _export;
    string _implVal;

    public override IEnumerable<ExportDefinition> ExportDefinitions
    {
        get { return new ExportDefinition[] { _export.Definition }; }
    }

    public override IEnumerable<ImportDefinition> ImportDefinitions
    {
        get { return Enumerable.Empty<ImportDefinition>(); }
    }

    public override object GetExportedValue(ExportDefinition definition)
    {
        return _export.Value;
    }

    public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
    {
        
    }
    public override IDictionary<string, object> Metadata
    {
        get
        {
            return new Dictionary<string, object>();
        }
    }

    public override bool Equals(object obj)
    {
        return GetHashCode().Equals(obj.GetHashCode());
    }

    public override int GetHashCode()
    {                
        return ("SingleExportPart" + _implVal).GetHashCode();
    }

}

Without the source for the MEF Preview I would have had a more difficult time with this.  It seems like it should be easier to remove Parts from the composition.  To be fair, this is easier if you are using [ImportMany] instead of [Import].  The final part needed to tie everything together is to add a PartCreationPolicy to the Parts being added & removed from the composition batch:

[Export(typeof(IQuestionRepository))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class QuestionRepository :   IQuestionRepository
{

Without specifying the NonShared CreationPolicy MEF will by default create a single instance of the Part.  When trying to remove the part from the CompositionContainer MEF will throw an exception basically stating that the Part couldn’t be removed because it was still being used elsewhere to satisfy another Import.

Further Research

The example shown here is somewhat incomplete.  Because service calls in SilverLight are always asynchronous, we would probably want some thread safety as we swap Imports in and out.  It would also be appropriate to enhance the interfaces used here to notify Parts as they are being added/removed such that the Offline/Online families of services can do appropriate cleanup.

Tags:

Silverlight 4

by Administrator 25. November 2009 20:36

Before PDC 2009, I had a short wish list for the next version of Silverlight:

  1. Real support for commanding
  2. Some kind of full trust mode similar to Click Once
  3. More complete data binding
  4. Context Menus
  5. Relational (Isolated) Storage

I was pretty excited as The Gu’s keynote played out and I saw my wish list filled one item at a time.  There are some other things I’d like, but these are things that aren’t in WPF either so I don’t really dare hope for them.  These items include things like adding extensibility to the Binding framework: too many aspects are internal/sealed black boxen.

The missing #5 would probably have involved something like a cross platform SQL Compact.  The ability to drop a small relational store into Isoloated Storage (or anywhere on the file system using elevated trust) would open up a whole new avenue for Silverlight applications.  Even without tools like the Entity Framework this could be huge.

I recalled my Return of the Smart Client article where I expressed what I believe are common concerns and frustrations developers have when building Enterprise applications using the usual web development tools.  If you needed further convincing that Silverlight is a real alternative for creating browser delivered rich internet applications you need only review day two of the PDC 2009 keynote.  Silverlight is as big as anything going on at Microsoft.  I can’t wait for MIX 2010!

Tags:

About the author

Damon Payne is a Microsoft MVP specializing in Smart Client solution architecture. 

INETA Community Speakers Program

Month List

Page List

flickr photostream