I've been spending a lot of time over the past couple of weeks reading about and playing with the Model-View-ViewModel pattern. As part of this I've had numerous conversations with my development team about what I'm finding. Unfortunately, I think I'm walking away with more questions and uncertainty than I would have expected this far into my investigation. Most of it centers around how "powerful" our CSLA business objects are and if that prevents us from really leveraging a pattern like MVVM the way other frameworks/architectures would.
So, my first question is if exposing Model as a data property is a legitimate implementation? If the purpose of the ViewModel is to abstract the Model and create an abstract view (per John Grossman), then exposing the Model via a property seems to be contradictory.
For example, if we have a PurchaseOrder business object with PONumber, Customer and BillToAddress properties along with a child list of PurchaseOrderItems, it is correct to define a single Data property on our PurchaseOrderViewModel of type PurchaseOrder or would we want to have separate PONumber, Customer and BillToAddress properties on our VM as well?
Perhaps if we consider the BillToAddress is of type Address which contains properties for Street, City, State, Zip and Country. We could certainly bind our UI element to Data.BillToAddress.City but now our UI has (some) knowledge of our business object model. Wouldn't it be better for our ViewModel to expose a BillToCity property as:
public System.String BillToCity
{
get { return _model.BillToAddress.City; }
set { _model.BillToAddress.City = value; }
}
Now we have some semblance that we are refactoring our Model into an abstract view - or the API that a View may bind to.
Second question: one of the definitions of a ViewModel presented by Grossman is the idea that the ViewModel's purpose is to wrap our Model and make it suitable for data-binding. However, one of the great things Rocky has done with Csla is build our business objects with the intent that they are used as data sources (for data-binding) in the UI. This means that all of the stuff our ViewModel would do for us is already in our BOs. For instance, raising the PropertyChanged event. All our ViewModel would do is bubble the event from our Model to the UI. So where is the value of the ViewModel?
Another aspect of the wrapper is to implement functions like Save and Cancel - which are also implemented on our BO. So again our ViewModel is simply delegating to our BO.
So, are we trying to find a way to implement this pattern just for the sake of doing so or does it really make sense in the CSLA world? It seems to me that given the way our business objects are designed that simply including our Model as a StaticResource (talking XAML, of course) accomplished the same thing without the intermediary object.
Now I'm not necessarily advocating that because I firmly believe a separation needs to exist between layers and roles (designer vs. developer) so if there is a valid and strong argument against the pattern because our BO are too smart, then perhaps we should consider if this intelligence is implemented in the right place. Is the MVVM pattern telling us that our BOs should not be implementing INotifyPropertyChanged because this is the responsibility of the ViewModel?
What do you think?
Well, another thing I just picked up on reading a little more into MVVM, following my example of a PurchaseOrderViewModel, and going with the notion that we should be exposing the individual properties we want for our View and not a single property for the Model, the Items property on our VM should actually be returning another VM! In this case, the child VM would represent the PurchaseOrderItems collection contained in our PurchaseOrder Model object.
The complexity of the solution increases! What is the payoff?
I think if you worry less about conforming to the endless blog
postings and more on what makes sense to the situation and what is manageable
you won't stress as much. I spent and wasted countless hours and late
nights trying to twist and manipulate my understandings to fit what I thought /
hoped was the way to do things. Then you find you can't make the XAML do
what you want any ways or you can't bind a certain way and you just end up in
circles. Throw in being very new to CSLA and every issue I came to became
a theoretical vs. technical understanding/implementation. I didn't know
if things should work and if they did I worried that I was doing it the wrong
way. I think it's better to almost do it the wrong way and then refactor
than spend time trying to figure out what the right way is. By the time I
figured out what I hoped was the right way my project was already late and I
still had to make it work. Of course I'm working for myself so there is a
team of people waiting for my advice :-)
I haven't looked at the new 3.8 ViewModel but if you look at the
CSLADataProvider as a pseudo model then exposing it as no different than
exposing a child model.
I've tried to sticking to the 'No Code Behind unless eye Candy'
(which also includes making 3rd party controls work in some cases where I can't
bind to the VM). Rocky has blogged about the problems with ListBoxes -
wait till you try to deal with a 3rd party treeview that supports multiple
selection.
- anything that is strictly UI or is made easier via UI I'll
re-expose a BO property (say I'm making a wizard to help set 5 properties)
- anything that will be re-used across views or I can use
outside the UI I'll push back into the BO
- merge Can/Is properties where applicable (ie IsBusy in my
ViewModel is IsBusyUI + IsBusyCsla).
- I'm trying to make ChildVM's and databind them to ChildViews where
I can but I've had quite a few gotcha's where the ChildModel is generated and
binded but of course the binding keeps the same instance unless you raise
ChangeNotifications at the right time which can actually be hard when you try
to open a form via XAML
- I've struggled mightily with the idea of the view reacting to
changes in the ViewModel to do something vs. just telling the view to do it.
- I've also found I have to wrap certain collections (especially
from linq selects) as in SL we don't have the LinqBindingList. I've
peeked at some of the LiveLinq or other implementations out there (ComponentOne
has a nice optimized LinqCollection but it doesn't support SL yet). Once
I wrap them in my ViewModel I can respond to CSLA notification events and then
easily raise change notifications for my UI lists so that the binding re-fires
and my UI list updates its original LINQ query results.
But I am liking the MVVM more and more. I think if you
value a smart intuitive UI then a VM is a saving grace. I'm really into
Visual Design and intelligent UI's vs. the old standard 40 CRUD windows and
drill down 5 layers with endless prompts to the user etc. My problem is
still getting from my paper design through to the XAML and then hooking the
pieces together. However to build all the intelligence in to the UI you
really do need that middle piece and I think that is where the VM shines.
My BO can be powerful and leverage CSLA and deal with all the
Business Logic, the View is eyecandy, and the VM is the glue to really keep it
all together and manipulate the parts to make a intuitive UI. I'm trying
to work efficiently and get my BO - VM - View working and then I find I can
almost shut down work on the other two and focus on the VM to improve the UI
Experience.
Bottom-line if you have a simple CRUD window that you want to
popup to enter some details then you have no real VM and hopefully you've put
enough logic into a re-usable base class that there is very little to do other
than maybe navigation or message notification back to a parent or something and
you simply expose your CLSA BO as 'Data'.
I don't know if that helps you at all - but as Rocky has said a
few times, it is somewhat of a 'trend' and it is very very new. Throw in
the hacks from SL2 to do things and then trying to undo them with SL3 but not
quite being the same as WPF and it gets very difficult to keep up.
I also did go down the path with PRISM and found I was
writing way too much extra stuff and was very confused with Navigation. I
moved away and starting leveraging Silverlight.FX but again I'm finding
limitations with that and there is next to no support - it is more a proof of
concepts plus some slick eyecandy. I actually think now that I have some
more experience I'll liekly go back to PRISM again and see where it can help
out. I believe their SL3 compatible version is suppose to link in
Navigation which is really the bit they were missing. I've really
struggled with CompositeViews and injecting my VM's into the childViews at the
moment I want.
Also once a bit more of 3.8 is out I'll re-visit how I'm
interfacing with CSLA and likely adopt as much as I can there.
Anyhow just a few rambling thoughts on a Friday afternoon.
jack
From: SonOfPirate [mailto:cslanet@lhotka.net]
Sent: September-04-09 11:19 AM
To: jaddington@alexandergracie.com
Subject: Re: [CSLA .NET] Is CSLA too smart for MVVM?
Well, another thing I just picked up on reading a little more into MVVM,
following my example of a PurchaseOrderViewModel, and going with the notion
that we should be exposing the individual properties we want for our View and
not a single property for the Model, the Items property on our VM should
actually be returning another VM! In this case, the child VM would
represent the PurchaseOrderItems collection contained in our PurchaseOrder
Model object.
The complexity of the solution increases! What is the payoff?
This, right here, is where I started hating MVVM. Fortunately it turns out to be a misunderstanding of the pattern, promoted by people who just haven't thought through things far enough.
There are really two MVVM patterns - one for anemic Models and one for rich Models.
CSLA obviously is a rich Model world, and so the anemic MVVM pattern is really inappropriate. Sadly, I've seen that put forth as "the one true way", which means you could think MVVM itself sucks (which is where I was a few months ago).
I've come to realize that there's a large community of people who recognize this broader truth, and in fact it seems that more and more of the MVVM thinkers are realizing that the anemic model largely sucks in general.
So what's the difference?
In the anemic MVVM model, the View communicates only with the VM. And the VM delegates to the Model. This is almost required if your Model is composed of dumb DTO or Entity objects, because those objects just don't do the things you need to make the UI work nicely.
In the rich MVVM model, the View communicates with the VM, but the VM exposes the Model as a property. This allows the View to bind to properties of the Model and/or ViewModel as appropriate. And it allows the View to bind to methods (verbs/actions) on the ViewModel - assuming you have some commanding model that actually works with MVVM.
Obviously CSLA works much better with this second approach, because your Model is already super-smart and it is a total waste of time to implement containment-and-delegation around it. In fact, applying the anemic MVVM technique to a CSLA object means you need to bi-directionally wrap not only the properties, but all the data binding interfaces and everything. Your ViewModel class will be HUGE - and all full of stupid plumbing code CSLA already did for you in the business object!
Realizing all this, I'm finding the MVVM pattern to be really nice. Really nice.
Creating a ViewModel is a matter of exposing the Model as a property, and implementing code to manage the business object's lifetime appropriately. And the ViewModel can have extra UI-oriented properties (like IsNotSavable if that makes some UI widget easier to bind).
And the ViewModel of course implements verbs/commands/actions. Possibly these include Refresh() or Save(), but might also include ShowDetails() or OpenDialog().
Remember that the ViewModel is tightly coupled to the View. It exists purely to service the needs of the View. If the View has a button that does something, the ViewModel will have a method that is invoked when the button is clicked. So the ViewModel might have all sorts of UI-specific methods and properties.
All that, while the Model remains purely focused on the underlying business use case. Remember, you should be able to take your Model and use it behind a web service unchanged. If you can't do that, you blurred the lines between the Presentation and Business layers.
Conversely, if you can't take your Model and build a web service because you'd lose important business rules or functionality, then you've allowed business logic to creep into the Presentation layer and that's also really bad.
MVVM isn't magic. While it provides a home for what would have been code-behind, it is a UI construct and doesn't change the need to keep your business logic in your business objects, and your UI logic in the UI (in this case in the View and ViewModel).
As usual very elegantly put and I agree whole heartedly.
From: RockfordLhotka [mailto:cslanet@lhotka.net]
Sent: September-04-09 2:30 PM
To: jaddington@alexandergracie.com
Subject: Re: [CSLA .NET] Is CSLA too smart for MVVM?
This, right here, is where I started hating MVVM. Fortunately it turns out
to be a misunderstanding of the pattern, promoted by people who just haven't
thought through things far enough.
There are really two MVVM patterns - one for anemic Models and one for rich
Models.
CSLA obviously is a rich Model world, and so the anemic MVVM pattern is
really inappropriate. Sadly, I've seen that put forth as "the one true
way", which means you could think MVVM itself sucks (which is where I was
a few months ago).
I've come to realize that there's a large community of people who recognize
this broader truth, and in fact it seems that more and more of the MVVM
thinkers are realizing that the anemic model largely sucks in general.
So what's the difference?
In the anemic MVVM model, the View communicates only with the VM.
And the VM delegates to the Model. This is almost required if your Model is
composed of dumb DTO or Entity objects, because those objects just don't do the
things you need to make the UI work nicely.
In the rich MVVM model, the View communicates with the VM, but the VM
exposes the Model as a property. This allows the View to bind to properties of
the Model and/or ViewModel as appropriate. And it allows the View to bind to
methods (verbs/actions) on the ViewModel - assuming you have some commanding
model that actually works with MVVM.
Obviously CSLA works much better with this second approach, because your
Model is already super-smart and it is a total waste of time to implement
containment-and-delegation around it. In fact, applying the anemic MVVM
technique to a CSLA object means you need to bi-directionally wrap not only the
properties, but all the data binding interfaces and everything. Your ViewModel
class will be HUGE - and all full of stupid plumbing code CSLA already did for
you in the business object!
Realizing all this, I'm finding the MVVM pattern to be really nice. Really
nice.
Creating a ViewModel is a matter of exposing the Model as a property, and
implementing code to manage the business object's lifetime appropriately. And
the ViewModel can have extra UI-oriented properties (like IsNotSavable if that
makes some UI widget easier to bind).
And the ViewModel of course implements verbs/commands/actions. Possibly
these include Refresh() or Save(), but might also include ShowDetails() or
OpenDialog().
Remember that the ViewModel is tightly coupled to the View. It exists purely
to service the needs of the View. If the View has a button that does something,
the ViewModel will have a method that is invoked when the button is clicked. So
the ViewModel might have all sorts of UI-specific methods and properties.
All that, while the Model remains purely focused on the underlying business
use case. Remember, you should be able to take your Model and use it behind a
web service unchanged. If you can't do that, you blurred the lines between the
Presentation and Business layers.
Conversely, if you can't take your Model and build a web service because
you'd lose important business rules or functionality, then you've allowed
business logic to creep into the Presentation layer and that's also really bad.
MVVM isn't magic. While it provides a home for what would have been
code-behind, it is a UI construct and doesn't change the need to keep your
business logic in your business objects, and your UI logic in the UI (in this
case in the View and ViewModel).
Copyright (c) Marimer LLC