This project is read-only.

How to resolve view models in referenced assemblies (SL4)?

Oct 10, 2010 at 7:57 AM

In my Silverlight 4 project, all of my Views and ViewModels are in assemblies that are referenced by the main project.

How can I make a ViewModel resolver that can find those?

Oct 10, 2010 at 4:11 PM

I tried making a centralized ViewModel locator/resolver that lives in the main project and attempted to load all types from all referenced assemblies.

It didn't work at all, and I decided that it's not a good idea anyway especially when you have Prism module DLL's that aren't even referenced by the main assembly.

I think the best solution is to have a resolver per assembly.

Oct 10, 2010 at 8:57 PM

Wayne,

I guess I am a bit confused to what the problem is?

The locator assumes that you implement your own resolver via IViewModelResolver which takes a name, and it is up to you to resolve the view models by name.  I have an example of doing in Silverlight with MEF in the source code.  Since MEF is specifically designed to find things from external DLLs, it should be no trouble at all.  I have similar examples in WPF using MEF, Unity and Activator.CreateInstance.

What resolution technology are you using?  You mention that you are using Prism.  Are you using MEF or Unity with Prism?  You should be able to implement your IViewModelResolver in terms of your resolution technology you are using with Prism.  That way, when modules initialize themselves, the Prism resolver should be able to get at DLLs from other assemblies.

I think I need to understand your use case and problem better to comment more.

Brian

Oct 11, 2010 at 5:41 AM
Edited Oct 11, 2010 at 5:42 AM

Hi Brian,

I am looking at your example ViewModelExamples_SL MEFViewModelResolver class and I see that it uses AssemblyCatalog. According to MSDN [1], AssemblyCatalog "Discovers attributed parts in a managed code assembly." also in the MSDN remarks it says "An AssemblyCatalog is used to parse all the parts present in a specified assembly.", it doesn't say that it finds all attributed parts in referenced assemblies.

Looking at the UnityViewModelResolver example in the same project, I see this code in the Resolve method:

var foundType = GetType().Assembly.GetTypes().FirstOrDefault(type => type.Name == viewModelNameName);

This will not search referenced assemblies either. I would be able to search all assemblies with Linq and Reflection if Silverlight supported Assembly.GetReferencedAssemblies(). There is only one way that I know of, in Silverlight, to get the references and that is if you use Deployment.Current.Parts and you load a new instance of the assembly via a Application.GetResourceStream for each part.

Thanks,

Wayne

[1] http://msdn.microsoft.com/en-us/library/system.componentmodel.composition.hosting.assemblycatalog.aspx

 

Oct 11, 2010 at 5:44 AM

I guess I'm wondering if you have ever done it in Silverlight and if you have some info on how to do it since you're obviously very knowledgeable about MEF and Prism having worked with them so much.

Oct 11, 2010 at 8:47 PM

So, yes.  I have certainly used MEF and Unity with multiple assemblies in Silverlight.  

With every container-based resolver, you need to configure the container.  This is a constant.  

This is why in Prism, each module has a method called Initialize() in which you configure the container with your dynamic stuff.  It is a way of saying "when this module is loaded, tell the container about it".  This can be with Unity, or with MEF (or with any other DI container, for that matter).

In the case of MEF, there are several types of catalogs.  I used the AssemblyCatalog in that example (just an example, of course... you should implement and configure your resolver customized for your architecture), because it will take that single assembly and use it with MEF.  That is all I needed for the example.  If you need more than one assembly to be added to MEF, you can use the AggregateCatalog and build it with several AssemblyCatalogs, or TypeCatalogs.  This is real easy if your referenced assemblies are statically referenced.  If they are dynamically referenced, then you might need to add an AssemblyCatalog to the AggregateCatalog once the assembly is loaded, but as we see by how Prism does it with the Modules (via IModule.Initialize), this can be relatively easy.  

MEF also has something specific to Silverlight called the DeploymentCatalog, designed to load down modules when needed. There is also an XML-based catalog (I think) in MEF that lets you put an XML file on the server that tells MEF which DLLs to use.

That is a long answer to say the same thing: containers have to be configured, regardless of which container they are.

Unity is the same game.  Instead of catalogs, you register types.  This can be done however you need, based on your architecture, and it can span multiple assemblies as well.  As long as you know a type in the other assembly, you can get the type and pull it out.  If you don't know it, you can (again) do something like what Prism does, where there is a module that registers itself with the locator.

Does this help?

Brian

Oct 11, 2010 at 9:04 PM

Excellent, thank you very much for that reply.

My only question now, is how to get the satellite assemblies registered with the resolver at _design_ time since none of the Unity module initialization code runs at design time. I'm not asking you to answer this question (unless you feel like it!) I think I understand the basic gist at this point.

Thanks again,

Wayne

Oct 11, 2010 at 10:25 PM

To do this in a dynamic way can be difficult, because DLL paths are different at runtime compared to design-time...  It can be done, but is it worth it???

What I am about to say is probably more philosophy than anything else, but bear with me.  It flows to what I think is a logical conclusion.

A ViewModel exists to encapsulate view behavior -- read dynamic behavior.  When you are in design mode, your view is static, so any behavior encapsulated in the VM is moot.  Further, you want some sort of design-time data to be present, which your ViewModel doesn't usually have in design mode.  You can always put some design-time data in your ViewModel (there is even a flag in my ViewModel base class indicating when you are in design mode), but that often feels messy.

Because of this, there is no reason why the ViewModel at design time needs to be the same as runtime.  It might even be argued that you want your design-time data to be separate anyways.  Add that to your difficulty in resolving ViewModels from other assemblies (you have a reason for your separation, why conflate in design time), and I would really question if it makes sense to bring forward your exact ViewModel at design-time.

Still, you almost always want design-time data available to you.

This is one of the primary reasons why my ViewModelLocator example uses string-based lookup for classes.  This allows you to use convention, if you want, to load ViewModels.

In the example cases, binding to a VM named MyViewModel is simply looking for a class named MyViewModel.  BUT, that doesn't mean you couldn't have different ViewModels based on convention.  For instance, you could change your behaviors based on the season (contrived example) and map the name MyViewModel to search for a class named FallViewModel or SpringViewModel.

Take that a step further, and you could very easily detect that you are in design mode and search for a class named MyViewModel_DesignData.  This class can be nothing but data -- public properties and lists of data.  They can sit right next to your views, and you get around your resolution problem, since they are actually in the same assembly.  Doing this is more than a cute trick... I believe it is proper separation of design-time and run-time behavior.  Honestly, the more complex your VMs get, the harder it is to instantiate them at design time -- they require more and more services, and tend to fail to get new'd up at design time.

... 

I just wrote a lot, I know.  Thinking that this should actually make it into a blog post.  

Does this help?

B

Oct 11, 2010 at 10:42 PM

Yes, it does help. A lot!

I was under the impression that one of the primary functions of the resolver was to locate the design time ViewModel at design time and the run time ViewModel at run time. After trying to make this happen, I gave up and just used d:DataContext="....", which works great for me.

I think one of the big problems with the MVVM pattern is that it's so flexible that there's no "one way" to do it and you're kinda left to your own. I had read so many articles, seen so many ViewModelBase implementations and had done many experiments before I really felt like I knew what I was doing with it. That said, I have used it successfully in WinForms and in Silverlight so far and it really is a great design pattern.

What I had settled on before reading about your resolver was simply doing this in Silverlight: <UserControl.DataContext><local:MyViewModel/></UserControl.DataContext> and then doing the d:DataContext="..." thing. This works pretty well, but in every View I have to do this in the constructor: var vm = (MyViewModel)DataContext; vm.Initialize(unityContainer_Passed_Into_View_Constructor);

I think I'll give the resolver another chance so I don't have to pass that unity container all over the place.

- Wayne

Oct 11, 2010 at 10:45 PM

Yeah, I have had success also in WinForms with MVVM. I am doing Flex work right now, and it ALSO works great.  I fact, the MVVM (Presentation Model) pattern is much easier to implement in Flex than it is in WPF/Silverlight.  Not sure why it isn't being used more in that environment.

Glad to help :)