Latest Tweet:
  • Loading...

There has been lots of talk in the Silverlight community about what is the best way to implement the INotifyPropertyChanged interface. During Christmas I blogged about how you can use dynamic proxies to get INPC implemented automatically. Since then both Einar Ingebrigtsen and Justin Angel have blogged about an interesting approach to INPC using MSIL weaving. I really recommend checking out Justin’s post, as he covers some of the pros and cons of different INPC implementations, as well as purposing an elegant solution using post-build MSIL weaving.

One of the things Justin mentions as a drawback of the dynamic proxy approach is that you cannot simply new up your ViewModel directly and get change notification automatically. You have to explicitly create the ViewModel instance through a proxy creator. Einar also mentioned that he had a hard time finding a way to integrate the proxy creator with an IoC container.

When I write code I’m always careful about where I instantiate my objects, and lately all projects I’ve worked on have used some sort of IoC container. Having an IoC container gives you a single place in your code base to create- and register objects. If the dynamic proxy implementation of automatic INPC is going to be useful it has to be as simple requesting a ViewModel instance from the IoC container. In this blog post I’m going to show how you can combine automatic INPC using dynamic proxy with the Ninject IoC container.

If you have read my blog you may have noticed I got a soft spot for Ninject. I mean, who cannot love a framework whose name, graphic profile and code examples are all about Ninjas? When I first set out to integrate my automatic INPC interceptor with Ninject I wasn’t quite sure where to start. Ninject 1.0 had AOP concepts built in, but in 2.0 (which are under development) this has been moved out of the core and into a separate interception extension module. This is part of the new modular design of Ninject 2.0. Features you may not need all the time are moved out to separate extensions, leaving the core really small and simple (~90kb).

ninject-ninja

My first plan was to use the Ninject interception extension. The extension uses the LinFu framework for dynamic proxies, and I wasn’t sure how to get my Castle Dynamic Proxy based implementation to work directly. I later got contacted by Ian Davis, the owner of the interception-extension project. He asked if I needed some help getting automatic INPC working with Ninject. After some back-and-forth on Twitter Ian had an implementation of automatic INPC added to the Ninject.Extension.Interception project. The code is commited to the trunk, and is available on github if you want to check it out. Ian’s implementation is probably worth a blog post on its own.

A comment from Miguel Madero pointed me in the right direction to get my interceptor working with Ninject. Miguel had integrated it himself by implementing the interceptor as a Ninject Provider. Ninject lets you register types against providers which let you write code that creates the instance when the type is requested from the container. The interface is really simple, having one Create-method. In this method you have to create the instance being requested.

The implementation for the automatic INPC provider is fairly simply. It finds the largest constructor of the ViewModel being requested, creates instances of all constructor parameters, before calling the dynamic proxy creator I implemented in my previous two blog posts.

ProviderCode

In Ninject all configuration is done through code using an internal DSL. You configure the container by creating module classes specifying the bindings of the different types you want to be able to create. In this example I have a simple logging service (to demonstrate constructor injection combined with automatic INPC) as well as a simple ViewModel. The ViewModel is bound to the provider, which will call the proxy creator when the ViewModel is requested.

ConfigurationExample

This unit tests shows how to request an instance of the ViewModel from the container. When the Name-property is set the ViewModel will log the action to the fake logger which was injected into the ViewModel constructor.

ExampleUnitTestOfViewModelFromKernel

Having to register every single ViewModel against the provider is tedious and repetitive. Miguel Madero also suggested that you can override the GetBinding method of the Ninject StandardKernel and use convention over configuration. By overriding the GetBinding method we can check if the type being requested is a ViewModel, and if it is we can create a binding on the fly tying the ViewModel type against the automatic INPC provider.

The implementation of the AutoNotifyKernel is really simple. It checks if the name of the type being requested contains “ViewModel” and implements the IAutoNotifyPropertyChanged interface. If it does we create a binding for the type.

AutoNotifyKernel

Having a convention based approach in place we do not have to manually register every single ViewModel.

Some of this code might seem complicated, but I really wanted to cover the details of how to integrate it with Ninject, as similar approaches probably work for other containers. Once you got a framework for automatic INPC in place the usage becomes really simple. In the example application for automatic INPC the code needed to implement the ViewModel, configure the container and tie the ViewModel to the View looks something like this:

FullExample

It’s funny how such a simple interface can trigger so many different implementations. I hope you found my blog post on combining a dynamic proxy approach with an IoC container useful. It will be interesting to see which approach emerges as the most used, and which frameworks that will provide implementations of the different techniques.

Monday, January 18, 2010 8:00:09 AM (W. Europe Standard Time, UTC+01:00)
Good stuff!! There's another way to plug this into Ninject as well. You can replace Ninject's internal IInjectorService. This is the way we plug DP2 into Ninject for Caliburn's AOP support (in trunk). Here's a link to the discussion thread with the solution I came up with: http://ninject.codeplex.com/Thread/View.aspx?ThreadId=80717
Tuesday, January 19, 2010 3:04:19 PM (W. Europe Standard Time, UTC+01:00)
Wow, you're quick with all this blogging. I just read your comments on the other posts. I made some changes to your original implementation.
* I removed the need to implement a particular interface and expose a public method to Raise Property Changes.
* Instead of using GetBindings I overrode HandleMissingBindings. I made a mistakte when I mentioned you about GetDefaultBinding.
* Added some tests
* Fixed an issue that create "Duplicated Members" since we were missing to override the getters.
* Did other micro optimizations (I've not done any performance testing).

I'm looking into having a hybrid approach (IL weaving for Release, Dynamic Proxy for Debug).

I completely overlook the fact of the constructor parameters. I didn't face that issue since I, by convention, always use a parameterless constructor and Property Inject. The main reason for this is Blend (and testing to a certain extent).

Anyway, here's the code:
http://snipt.org/qpM

Note the Kernel also has some conventios to bind ServiceContracts and Interfaces to their default implementations. You can ignore that part and focus on the IsViewModel and ViewModelProvider

I'm falling sleep in the keyboard. I'll try to make more sense our of it tomorrow after my coffee.

Nice work.

@Rob, I'll take a look at your apporach. Seems interesting.
Sunday, January 31, 2010 12:52:13 PM (W. Europe Standard Time, UTC+01:00)
Great example! I have some questions and feedback:

Why do you new up the AutoNotifyKernel in the MainPage constructor? You've already hooking up the DataContext in the XAML markup, why do it again in the code behind?

Am I suppose to add a property in the ViewModelLocator for every individual ViewModel, or is that just for the main (first) viewmodel? I would prefer using a generic method returning my viewmodel instance, but perhaps that not possible from markup?

May I suggest extending the sample with two-three services, additionally one which does async operations.

How about adding some XML documentation to your AutoINPC framework? It can't hurt ;-)
Sunday, January 31, 2010 10:45:03 PM (W. Europe Standard Time, UTC+01:00)
There might possibly be a problem with the NinjectAutoNotifyProxyProvider and it's Create method. I'm seeing a problem with the Ninject Kernel creating multiple instances of my View Model, even though it's registered as a singleton.

This binding should only create a single instance, but the proxy provider doesn't seem to respect this. Am I right?

Bind<CatalogListViewModel>().ToSelf().InSingletonScope();
Tuesday, February 02, 2010 9:36:30 PM (W. Europe Standard Time, UTC+01:00)
Miguel,

Thanks for the feedback on my posts, and suggestions for improvements. Hopefully this type of functionality will be rolled into Ninject and Windsor containers in the future. It's be a fun challenge, and it's cool to try different approaches to solving INPC.

Sondre,

I'm really glad you like the examples! The instantiation of the VM in the codebehind is a "bug" in the demo. It is supposed to be bound from the ViewModelLocator. That's the pattern I often end up using (exposing VM's from the kernel as properties on a Service/ViewModelLocator).

You have to expose each VM as a property to get binding through markup. The benefit is that the binding will be applied at design time, thus giving you (if you do some tricks in the VM/inject a dummy VM) a great experience in Blend.

As for async examples and more services that isn't really specific to AutoINPC, but would make it more usefull as a MVVM+IoC example. Good tip.

XML comments? Nah ;) Good naming + unit tests is my documentation.

As for SingletonScope, I haven't tested that. Did you get anyway with that bug? I was assuming that should work, as we only plug into the binding and creation of the object, not the life cycle management. But, then again adding that "convention" to apply AutoINPC might also override any configured life time management. Did you get any feedback from Ian on this?

Looking forward to seeing the app you are working on.
Tuesday, March 02, 2010 10:44:29 AM (W. Europe Standard Time, UTC+01:00)
I need a help from you on a application i am developing:

I have created a audio player in silverlight.

within that player user is able to select a portion of song to save it as ringtone.

but i got the time duration from .. but I have to cut the partial portion of stream or audio stream and save it to the server dick.

Plz suggest me how I can convert the selected audio time duration into the stream or byte array..?

Ajit
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, strike) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789