MVVM and ViewDiscovery

Topics: Prism v2 - WPF 3.5
Oct 9, 2009 at 11:35 AM

Background:

So I've tried and tried to get my head around CAL as I can see the benefits and really want to take advantage of them.
However, there's a lot to learn, so I thought I'd start by breaking down the proverbial elephant into smaller more manageable pieces.

I think I understand Unity.
I'm also pretty sure I've got the MVVM pattern figured out.
I'm comfortable with the basic concepts of CAL, but implementing them is sometimes a bit confusing.

So now I have some kind of foundation to build on I'm trying to put the pieces together using CAL.

Questions:

In my approach to MVVM I've always tried to have the purest implementation possible.
(You may well question my definition of pure but here goes).

The view knows absolutely nothing about the view model and the view model knows absolutely nothing about the view.
My view model implements INotifyPropertyChanged and exposes properties that the view can bind to.
Now I don't know if I'm doing this right, but I then have another class (which I don't have a name for) which instantiates a view, instantiates a viewmodel and wires the two together (view.datacontext = viewmodel).

Question 1; Am I doing this right? or is my interpretation of the MVVM pattern not the norm?

Question 2; CAL View Discovery.
The quickstarts all suggest that the viewmodel exposes a view property and that's what they use for registering the view in the viewregistry.
My viewmodels don't do this however, which leaves me confused.
Obviously I can use the Unity to resolve my view class when calling RegisterViewWithRegion, which works in terms of it successfully shows the view, but how do I then wire that up to a viewmodel to make all the good stuff happen?

I'm thinking along the lines of....

In my module.initialise use the unity container to resolve both the view and the viewmodel as ContainerControlledLifetimeManaged objects (ie. single instance).
Then grab a reference to each of those objects and wire them together.
Finally, register the view with the view registry, again, using unity to resolve the view.

I think that would work, to be honest I haven't tried it, but in truth I'm not completely convinced that this is the way it was supposed to work.

Comments, advice and feedback would be appreciated.


Many thanks,

 

Oct 9, 2009 at 3:13 PM

A bit weird replying to my own post... but I've made further progress.

Once again, I couldn't say whether this is best practice or not but my module initalize code now looks like....

 

ViewModel myViewModel = new ViewModel;
View myView = new View;

myView.DataContext = myViewModel;

this.regionViewRegistry.RegisterViewWithRegion("LeftRegion", () => myView);

I now have a view model and a view that know nothing about each other but are wired up through the power of XAML/WPF databinding.

As before, comments/advice/feedback would be appreciated.

I'm just a little concerned that if this isn't the recommended way to use this framework I may have started a timebomb ticking which may go bang in my face at a later date?

 

Many thanks,

 

CA.

 

Oct 9, 2009 at 3:32 PM

Hi mqca,


I'm not sure if this is at all helpful...

Not going into too much detail but my interpretation of MVVM is to have minimal codebehind for the view and no logic residing there. Thats not to say there is ABSOLUTELY NO codebehind. When it makes sense put code there. To that end the codebehind of each of my views consists of the following:

    public partial class SearchControl : UserControl
    {
        public SearchControl(SearchViewModel viewModel)
        {
            this.DataContext = viewModel;
            InitializeComponent();
        }
    }

As far as registering with the view, a VM having reference to a V, etc. In my implementation the viewmodel doesnt have a reference to the view. This has made for some tricky spots: a lot of custom control development and command implementations were necessary. But it kept the two fairly decoupled.

As far as the view registering, I did that in the initialize method of my module like you had mentioned.

        public void Initialize()
        {
            _Container.RegisterType<ISearchModel, SearchModel>();
            ISearchModel _Framework = _Container.Resolve<ISearchModel>();
            this._RegionManager.RegisterViewWithRegion(_Framework.CurrentRegion, typeof(SearchControl));
        }

The only reason I (me personally in my project) would not use the approach you used is because your approach doesnt put the view and view model through the DI pipeline. Because I use an abstraction for the model I'd want to have the view model created in this way so that it gets a proper reference to the ISearchModel implementation.

I think the purpose of MVVM is testability (am I incorrect here?) So as long as your implementation make the individual units as testable as you need then you are golden. As I mentioned above I have an interface to my model. This is because I mock up a lot of model data. Also I am currently in the process of moving from SQL to AmazonSimpleDB and this pattern has made that move particularly easy :)

Oct 9, 2009 at 3:58 PM

Hi Idoolitt, and thanks for your reply.

Like you, to me MVVM is all about testability and in that sense my approach works for me so that's good enough (for now).

I'm curious though, the one thing I haven't commented on in my questions is the use of Interfaces.

You mention using Interfaces on your model? could you give me an insight into that? it's not something I'm familiar with (or maybe I just don't recognise it).

I'm also curious as to why so much of CAL is built around interfaces - IView, IViewModel?

If you've built a project out of modules and you want to swap out 1 module for another there's fairly obvious/straight forward way to achieve it.

I guess that comes from the fact modules are built around IModule, but fundamentally, this is what CAL is for, so no issues there.

If you've built your modules using the MVVM pattern then your presentation and business logic aren't coupled together.

MVVM gives you the power to swap out your view for a different view (be that a unit test/mock view whatever).  So why would you interface your view when you don't need to?

The relevance of this is that most of the quickstarts use unit to resolve a view based on an interface and in my solution, those interfaces don't exist?

 

I'm sure that one day the someone will switch on the light at the end of the tunnel, but for now I'll keep feeling my way along the edge! :o)

 

CA.

 

Oct 9, 2009 at 4:46 PM
Edited Oct 9, 2009 at 4:47 PM

mqc,

What you wrote was...

ViewModel myViewModel = new ViewModel;
View myView = new View;

myView.DataContext = myViewModel;

this.regionViewRegistry.RegisterViewWithRegion("LeftRegion", () => myView);

Which, in my opinion, is not "pure" MVVM because you are explicity setting the DataContext on the View, which means the View must "know" about the ViewModel.

To do MVVM with CAL, you would need to actually add myViewModel to "LeftRegion" and create a DataTemplate for the ViewModel which is set as myView.

Get an IUnityContainer and IRegionManager through dependency injection in the constructor of your ViewModel:

In your initialize event, resolve a ViewModel and add it to a Region.

Also add a dictionary in the initialize event of the Module:

         Uri uri = new Uri("/MyModule;component/Resources/ViewModelResources.xaml", UriKind.Relative);

            ResourceDictionary dict = new ResourceDictionary();
            dict.Source = uri;
            Application.Current.Resources.MergedDictionaries.Add(dict);

...and in the dictionary you would put:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyModule;assembly=MyModule"
>
      
    <DataTemplate DataType="{x:Type local:MyViewModel}">
        <local:MyView />
    </DataTemplate>
</ResourceDictionary>

This is "pure" MVVM" that completely decouples the ViewModel from the View.  View does not need to know about the ViewModel.

The problem with CAL is that it expects anything that is added to a region to be a DependencyObject.  Since ViewModel classes are rarely DependencyObjects, the ViewModel does not get a RegionManager attached to it and does not display.

A "pure" MVVM implementation in CAL is not presently possible.  You have to use the  [this.View = view; this.View.Model = this] technique in CAL.  You can call it MVVM, if you want, but it's not really.

 

Note: There is a similar post going on at http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=71430

Oct 9, 2009 at 5:30 PM
mqca wrote:

Hi Idoolitt, and thanks for your reply.

Like you, to me MVVM is all about testability and in that sense my approach works for me so that's good enough (for now).

I'm curious though, the one thing I haven't commented on in my questions is the use of Interfaces.

You mention using Interfaces on your model? could you give me an insight into that? it's not something I'm familiar with (or maybe I just don't recognise it).

I'm also curious as to why so much of CAL is built around interfaces - IView, IViewModel?

If you've built a project out of modules and you want to swap out 1 module for another there's fairly obvious/straight forward way to achieve it.

I guess that comes from the fact modules are built around IModule, but fundamentally, this is what CAL is for, so no issues there.

If you've built your modules using the MVVM pattern then your presentation and business logic aren't coupled together.

MVVM gives you the power to swap out your view for a different view (be that a unit test/mock view whatever).  So why would you interface your view when you don't need to?

The relevance of this is that most of the quickstarts use unit to resolve a view based on an interface and in my solution, those interfaces don't exist?

 

I'm sure that one day the someone will switch on the light at the end of the tunnel, but for now I'll keep feeling my way along the edge! :o)

 

CA.

 

For interfaces I don't go overboard.

For me there really is no reason to have an IView because I don't ever reference the view anywhere. But I could see where you would in a pattern as mentioned above, where the view model has a reference to the view. Also I dont have an IViewModel for the same reason; I dont reference the view model anywhere else but in the constructor of the codebehind. Since there are no constraints on the object type (view.datacontext takes an object) I dont see the need to make a IViewModel for myself.

I use an IModel because the view model makes heavy reference to the model (obviously.) Right now I'm using .NET RIA services to provide model data to each module but that will likely change in the future so I keep that interface decoupled.

As far as the views go I actually haven't done a lot of view swapping or anything like that. However it would be easy to do; just ensure that the view you swapped in uses the same commanding interface as the view it replaced.