New Posts New Posts RSS Feed: Digging Deeper!
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Digging Deeper!

 Post Reply Post Reply
Author
BenHayat View Drop Down
Groupie
Groupie
Avatar

Joined: 06-Jan-2009
Location: Estero, FL USA
Posts: 86
Post Options Post Options   Quote BenHayat Quote  Post ReplyReply Direct Link To This Post Topic: Digging Deeper!
    Posted: 21-Apr-2009 at 6:24am
Hi Ward;

As I'm looking at the code that the template produces, I thought i ask a few questions and anyone else interested in the MVVM implementation. As you mentioned, there many different text and theories on this subject and I'm sure yours is as good as the rest. But since you're providing that pattern here, I thought I ask you these:

The ModelExplorer page, you have:
  1 - ModelExplorer_ViewModel.cs
  2 - ModelExplorer_View.xaml/cs
  3 - ModelExplorer_PersistenceService.cs

The data form entry, you have:
  1 - Form_ViewModel.cs
  2 - Form_View.xaml/cs
  3 - Form_ViewController.cs
 
And then you have one:
  Model.Designer.cs

And you also have the "Persistence" Folder with more classes.

a) What I'm trying to find a pattern and a description of what goes where to start with?
b) Should every form in the Silverlight project have (ViewModel.cs, View.xaml/cs, ViewController.cs)?
c) Is the PersistenceService.cs a class that belongs to one form or is it more like shared among all forms?
d) Suppose, I need to create a new Order entry form, based on your formula, what does a developer need, every time he needs to add more forms to the project.
e) I also wanted to ask, if it would be possible to give a layout of classes that need to be created and how each interacted with each other. If that's too much to ask, do you have any links that describes your direction in more along with a pattern and guidelines.

Perhaps you would like to answer these here or create a blog that gives a more detail and education on how MVVM and DevForce should be designed together.

Much appreciated!


Edited by BenHayat - 21-Apr-2009 at 6:41am
Best Regards!
..Ben

WPF & Silverlight Insider
http://www.MicroIntelligence.Com
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 22-Apr-2009 at 11:40am

Great questions. Give me another day to compose a reply. And hold me to it! :-)   Ward

Back to Top
bigfish View Drop Down
Newbie
Newbie


Joined: 20-Mar-2009
Location: Australia
Posts: 36
Post Options Post Options   Quote bigfish Quote  Post ReplyReply Direct Link To This Post Posted: 22-Apr-2009 at 2:25pm
I agree with Ben, I was eluding to this on point 4 of this post.  http://www.ideablade.com/forum/forum_posts.asp?TID=1218
Can't wait for your response Ward. Thanks.
Back to Top
WardBell View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 31-Mar-2009
Location: Emeryville, CA,
Posts: 338
Post Options Post Options   Quote WardBell Quote  Post ReplyReply Direct Link To This Post Posted: 23-Apr-2009 at 2:24am

Thanks Ben and Dom.

 

I think the issues / questions you both raise require more explication then a poor forum post can manager.

 

I'm not sure how helpful this will be but I will try to answer Ben's questions BRIEFLY in hopes that my answer will hold the fort until I can express myself more expansively.

 

First a caveat: the Model Explorer is not definitive on patterns or "best practices". The way we tackle MVVM and encapsulation of persistence operations is intended to be suggestive. But we had to sacrifice practices in order to keep M.E. small enough to be easily understood ... at least that was an important objective.

 

Second, another caveat: no one has enough experience to say what the "best practices" really are. MVVM is itself a much debated pattern in its details; most everyone thinks it's the right approach but there are violent disagreements about the details.

 

Ok ... onward.

 

ModelExplorerPersistenceService

 

The ModelExplorerPersistenceService is NOT part of the MVVM world. It a means of encapsulating persistence operations so that no other class has to know the intimate details of fetching and storing entities. We especially don't want our ViewModels doing that. They shouldn't be logging in or formulating queries or sorting out what went wrong if a save fails ... none of that.  The PersistenceService is a facade over whatever mechanism you choose to use (DevForce, RIA Services, your custom WCF solution) to manage the data.

 

By the way, it is not a "Service" in the sense of a cross-process or cross-the-wire service; it is not SOA. It lives entirely on the client. It may invoke remote services in order to do its business but it is not itself a remote service. It is code that performs some activities for other components.

 

What you will see is that ViewModels make use of PersistenceServices. In a world with Dependency Injection (DI), you will see such PersistenceServices injected into ViewModels. In this way, a ViewModel can acquire and save Model elements (the collective entities it needs such as Customer, Order, etc.) without becoming bogged down in the details of doing so.

 

We felt that requiring DI for the Model Explorer in this incarnation would have been too offputting. So we explicitly pass a concrete PersistenceService into the ViewModel ... into the ModelExplorerViewModel in particular ... when we launch the app (see App.xaml.cs). See the line:

 

viewModel.ModelExplorerPersistenceService =

  new ModelExplorerPersistenceService();

 

You should see substantial re-use of a PersistenceService, within one module. A “module” typically addresses a single, cohesive collection of tasks, each of which is a bundle of “use cases.” There are going to be many Views (many MVVMs) in a rich module. I think a PersistenceService should be oriented toward serving all of the needs of a module and, therefore, will be consumed by multiple ViewModels.

You might prefer in some situations to have more than one PersistenceService in a module. I’d think twice before I did this; it’s easy to get carried away and start creating too many fine-grained services ... at the cost of confusion and maintenance.

I realize that one big PersistenceService is a code smell too. Consider giving that PersistenceService multiple interfaces so that an individual ViewModel only depends upon the interface that meets its particular needs.

Sometimes you can use the same PersistenceService in multiple modules. I’d think twice about this too. Fortunately, M.E. is only a single module so we don’t have to think about this right now.

MVVM Actors

In my view, “M”odel is made up of the entities that are ultimately exposed in the UI. We typically expose entity properties directly to the view by means of data binding. Most of us think that’s a fine idea most of the time.

One of the jobs of the ViewModel is to acquire the entities that should be exposed and make them available to the View.  We could just get them in the View’s code-behind … but that would be “bad” … for reasons I’ll not go into here.

The ViewModel is also responsible for responding to user gestures such as button clicks. Again, we could put that handling logic in the View’s code-behind … but that would be “bad” too.

In brief, we want the View to have as little developer created code as possible and we certainly don’t want to be making decisions … to be writing conditional logic … in the View’s code-behind.

It follows that “every” View should have a corresponding ViewModel.

This is why you have ModelExplorerView and ModelExplorerViewModel … and FormView and FormViewModel.

Aside: there are always exceptions. I’m sure there is a truly dumb view that has no model to speak of and such simple controls that giving it the full MVVM treatment would be pedantry. I don’t have any examples of these so-called “autonomous views” in M.E. … but they are not hard to imagine. Confirmation dialogs might be an example.

FormViewModel drives two Views

You may not have noticed that FormViewModel is the VM for both FormView and EmployeeFormView. There is no rule in my book that says that there must be one ViewModel for every View.  Here it makes perfect sense. It would make perfect sense to have a WPF view and a Silverlight View share the same ViewModel. Views might differ depending upon the user; a View for someone who is vision impaired would be quite different from the “standard” view … and yet the two views could comfortably share the same ViewModel.

The opposite case – a View that can be driven by more than one ViewModel – is a bit more unusual. But there are good examples. A chart view might be general purpose enough to be driven by very different ViewModels (one for order volume, another for customer service calls).

What you’d need for a new “Form”

Suppose you are adding an “Order Entry Form”. You already have the Order and OrderDetails entities ready to go and have decided that it is ok to expose their properties in the view.

You will extend the PersistenceService to retrieve the right entities; you might add an IOrderEntryPersistenceService interface to reduce the surface area of the module PersistenceService to just what you need for the order entry scenarios.

You will need at least one View and corresponding ViewModel.

We haven’t talked about how to compose big views (e.g., “forms”) from smaller constituent views; these would follow the MVVM pattern as well. But view composition is a topic for another day.

How do View and ViewModel interact?

That really is too big … and controversial … a topic for this post. In brief:

·         A View “knows” its ViewModel and “talks” to the ViewModel by binding to VM properties and by calling upon ViewModel methods in its code-behind (see below).

 

·         In this version of the M.E., the ViewModel does NOT know its View. The ViewModel needs some way to call upon the View when it is initiating the communication (e.g., when it wants the view to display a message). Binding won't work everywhere.  In this approach, the View gives the ViewModel a delegate so the ViewModel can call upon the delegate.

ModelExplorerView.xaml.cs illustrates the second bullet in this line:

ViewModel.MessageDisplayer =
  new TextBlockMessageDisplayer(_message);

The View gives the ViewModel an instance of a helper object that implements IMessageDisplayer. That interface has a Display(message, messageType) method; the ViewModel can call it anytime it has something to tell the View.

Why couldn’t we just bind the View to a property of the ViewModel? Because the ViewModel must give the view two pieces of information at the same time – the message and the type of the message. There is no easy binding to do this job.

Aside: There are people who really hate this approach. They strongly prefer that there be an IModelExplorerView interface with a Display method. The View passes itself to the ViewModel   as an instance of IModelExplorerView; the ViewModel  can then call back on the view through that interface. We will not discuss here the merits and challenges of this approach.

FormViewController

No, this controller is not a participant in the M-V-VM pattern. It is a helper class with an unfortunate name that invites comparison with the central actor in another UI separation pattern: MVC.

Perhaps I should have called it “FormViewMicroController” for it is an example of what Jeremy Miller calls a “MicroController”:  a small, re-usable controller class “to govern some atomic part of the screen.”

The ideas is that there is a chunk of purely-UI logic that gets used in multiple views. The logic doesn’t belong in the ViewModel because it is highly aware of specific UI controls.

As a rule, ViewModels should speak entirely in terms of non-UI types: strings, integers, enumerations, helper classes. They shouldn’t have a dependency on Silverlight controls, for example. If we stuck to that rule, we could re-use a ViewModel to drive a WPF client or maybe even a WinForms or ASP client (but don’t count on it). More importantly, by keeping UI dependencies out of the ViewModel, we make the ViewModel easier to test in a non-UI test harness.

The kind of logic we’re encapsulating in a MicroController is very UI-aware. The FormViewController in M.E. knows about the FormView and the EmployeeFormView for example.

Aside: I must admit that the FormViewController is a hack. I do NOT think that this is the best way to dispatch an Edit button click to the appropriate MVVM triad. But, without Dependency Injection, I couldn’t think of a clean and simple way to do what it does. I certainly wasn’t going to embed the FormViewController’s conditional logic directly into the view’s code-behind!  So I rolled this thing. Try not to follow my example.

SimpleCommandController – a better MicroController example

I am a little more comfortable with this MicroController which binds View buttons to ViewModel methods. In my latest version, it looks like this:

   CommandController = new SimpleCommandController()

     .Add(_queryButton, ViewModel.Fetch)

     .Add(_queryCombo, ViewModel.Fetch)

     .Add(_addButton, ViewModel.Add)

     .Add(_editButton, () => FormViewController.Show(_dataGrid))

     .Add(_deleteButton, ViewModel.Delete)

     .Add(_saveButton, ViewModel.Save)

     .Add(_clearButton, ViewModel.Clear)

     .Add(_toFileButton, ViewModel.CacheToFile)

     .Add(_fromFileButton, ViewModel.FileToCache)

     .Add(_connectDisconnectButton, ViewModel.ToggleConnectedness);

 

It is quite general purpose; you can imagine using it on other views that sport buttons.

This one instance manages to take the place of ten event handlers, thus eliminating a ton of code that looks pretty much the same.

Aside: you might prefer to bind the buttons to the ViewModel in xaml. Better still, you’d like to bind to implementations of ICommand. To do this right, you need a commanding infrastructure such as you’ll find in Prism. That would have been overkill for M.E.

My point is that FormViewController and SimpleCommandController are helpers. They help us factor out commonalities from view to view.  Or (as in FormViewController) we use them to eliminate conditional logic from a view’s code-behind. Because these helpers are small and focused on a single job, they can be tested easily without the baggage of any particular view class.

For More Information

There’s a ton of references to give. But I think it would be better to get this posted and follow up later. Until then, don’t be bashful about searching the web on your own.

Ward



Edited by WardBell - 23-Apr-2009 at 2:29am
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down