New Posts New Posts RSS Feed: I lost you at "Talk to the View"
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

I lost you at "Talk to the View"

 Post Reply Post Reply
Author
mikedfox View Drop Down
Newbie
Newbie


Joined: 29-Apr-2010
Posts: 21
Post Options Post Options   Quote mikedfox Quote  Post ReplyReply Direct Link To This Post Topic: I lost you at "Talk to the View"
    Posted: 09-Apr-2012 at 2:16pm
In the Happy Hour sample, I was following your reasoning for doing what you did, and was
pretty happy with the approach you took. Having code behind call a method in the viewmodel, for example, was a great example of pragmatism over purism.
 
But the interface mechanism int "Talk to the View" seems not only a real violation
of the MVVM model, but an unnecessary one, as well. I'm trying to figure out why you went
wth the approach you did (the interface) instead of something that works similarly without breaking
the model: putting an event in the ViewModel, and hooking it from the view.
 
So for the problem given, I would:
- in MainPageViewModel, add

public event EventHandler DrinkOrderAdded;
- in AddDrinkOrderMethod of MainPageViewModel, add 

if (DrinkOrderAdded != null)
	DrinkOrderAdded(thisnew EventArgs());
 
- in constructor of MainPage.xaml.cs, add

this.DataContextChanged += MainPage_DataContextChanged;
 
- in MainPage.xaml.cs, add
 

void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
MainPageViewModel vm = (sender as MainPage).DataContext as MainPageViewModel;
vm.DrinkOrderAdded += _viewModel_DrinkOrderAdded;
}
 
void _viewModel_DrinkOrderAdded(object sender, EventArgs e)
{
DrinkName.Text = string.Empty; 
DrinkName.Focus();
}
 
 
It's a little more verbose (mainly because there's no built in event 
where we can hook the viewmodel event, but seems to do the job without 
violating the model on one hand, or requiring a whole message passing 
engine on the other.
 
Thoughts? Am I missing something?
 
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: 09-Apr-2012 at 4:35pm
Hi Mike. Excellent question. 

You're absolutely right that this approach departs from the MVVM pattern. I tried to be clear about that. It is most definitely an example of a different MV* pattern, a flavor of Model-View-Presenter known as "Supervising Controller".

Had I insisted on maintaining the MVVM pattern, come hell-or-high-water, I would have implemented an event such as you've described. I would have felt it necessary to reduce the code behind too so I'd either write an attached property to (a) look for the event and, if found, (b) bind the event. I could do that with a re-usable helper instead (that's really what an attached property is). 

Notice that my purist instincts would drive me beyond adding an event handler. I'd worry that the VM might not expose that event. I don't want my View to be statically dependent upon the VM any more than I want the VM to be statically dependent upon the View. So I'd invent some way to cope. 

Maybe I'd give the VM an interface (instead of the View interface that was used here). Then I could see if the VM implemented that interface and only attach the handler if it did. Keeping the coupling loose would mean the  the View wouldn't care if the VM did or did not expose such an event and the VM can raise the event whether or not a view is subscribing. 

But then where would I store the interface if the View and VM are divided in separate assemblies (it happens)? Maybe I'd have to use reflection (that's what the Data Binding machinery does). Definitely going to need a helper for that. More work ahead.

The greatest advantage to the pure MVVM approach you suggest is that VMs do not have View references. The same VM can drive any number of views simultaneously. That might be important if this were a Windows Metro app in which it is likely that multiple Views (Landscape, Portrait, Snapped) are bound to the same VM. This particular Happy Hour implementation does NOT support multiple bound Views; I'd have to come up with some way to hold multiple views and visit each of them when a DrinkOrder is added. Doable but not so much fun.

The last point seems to argue in favor of your proposal. And yet ... I didn't do it that way. Why?

Well you made the case for me. You had to write some less-than-obvious code in both the VM and the View to use events ... two events at that (DC Changed and DrinkOrderAdded)! 

[aside: DataContextChanged is in Silverlight 5 but not in Silverlight 4. The sample supports both.]

Eventing is inherently more indirect and therefore always at least a little harder to follow than imperative code of the kind used in this sample. Extra complexity and obscurity has to return value. It often does.  Does it pay off here?

Different developers will feel differently from case to case. In this example I wanted to show that Cocktail (Caliburn) supports a hybrid approach. This screen is mostly MVVM with a touch of Supervising Controller.

It comes down to what YOU want to do. I personally don't mind a little Supervising Controller ... and it's good to see how Caliburn supports it. If you do mind, go right ahead and introduce the event mechanism.

Gold star for bringing this topic up. A discussion of options and how-we-choose benefits everyone.

p.s.: As the sample evolves, the need to set the focus becomes irrelevant because the TextBox disappears. All your hard work to preserve MVVM through eventing will be discarded. Oh well ... that's programming for you :)


Edited by WardBell - 09-Apr-2012 at 4:41pm
Back to Top
mikedfox View Drop Down
Newbie
Newbie


Joined: 29-Apr-2010
Posts: 21
Post Options Post Options   Quote mikedfox Quote  Post ReplyReply Direct Link To This Post Posted: 10-Apr-2012 at 6:22am
Ward,
 
Thanks for your quick reply. It's one of the things I've really appreciated about working with IdeaBlade.
 
I understand your argument. I'm not sure where I come down on this yet.
 
I actually like the PRISM approach to this,  of using decoupled pub/sub messaging.
 
I have tried using the EventAggregator in my MainPageView and MainPageViewModel, but adding an import for the EventAggregator causes the Cocktail Composition helper to not recognize the contract. Is there a way to do this, or is there something inherent in Cocktail which disallows MEF Imports in ViewModels?
 
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 10-Apr-2012 at 8:42am
Cocktail most certainly allows MEF imports on ViewModels. Even on Views if you export your View, although, that's not commonly done.
 
How did you try to import the EventAggregator? The EventAggregator is exported via IEventAggregator. Cocktail also provides convenient static access to the EventAggregator via the EventFns class and it's static methods. It will internally pull the EventAggregator from the container. TempHire makes extensive use of the EventAggregator, but it uses the EventFns class and it leverages the InterceptingCatalog from MefContrib to automatically subscribe new instances to the EA.
 
Make sure you extend your bootstrapper from FrameworkBootstrapper as described here http://drc.ideablade.com/xwiki/bin/view/Documentation/cocktail-application-bootstrapper to ensure the EventAggregator is actually in the container.
 
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: 10-Apr-2012 at 12:33pm
@mikedfox - Pleased that you find our forum helpful. Marcel beat me to the EA punch. I'll turn to another matter: using pub/sub to communicate between View and ViewModel.

I feel rather strongly that one should not do this - not in Cocktail, not in PRISM.  

The V and VM are close collaborators even though they are decoupled via the binding apparatus. To drive this point home, think about how the VM tells the V (or the V tells the VM) that the FirstName has been changed. I would not imagine using pub/sub for this purpose. Someone would shoot me if I told them that the VM publishes the FirstName change expecting the V to hear it and update its TextBox. Try debugging that. Way too complicated and indirect for my tastes. 

When the VM "publishes" the FirstName change via INotifyPropertyChanged, it isn't alerting the whole world; it's just informing the bound View (or, rarely, the bound Views) with a plain old .NET event. The DrinkOrderAdded update is in the same category as the FirstName change.

I recommend that V and VM communicate through binding, .NET events, or imperative code (when using Supervising Controller). Have always felt this way going back to CAB and PRISM days.  I reserve EA for "long distance", fire-and-forget communications with no serious expectation that any particular thing is listening.

I'm pretty sure my PRISM colleagues agree. I'd be interested if you have a link to a post suggesting otherwise.

Cheers, W
Back to Top
mikedfox View Drop Down
Newbie
Newbie


Joined: 29-Apr-2010
Posts: 21
Post Options Post Options   Quote mikedfox Quote  Post ReplyReply Direct Link To This Post Posted: 10-Apr-2012 at 1:20pm
Ward,
 
Ok, so it seems like when the viewmodel needs to make a status change known to the view, I have 3 options
 
1) have the view implement an interface, and then the view model use the interface to call a method on the view. You favor this approach, but it concerns me over violation of the pattern (or more specifically, altering the pattern to supervising controller)
 
2) have the viewmodel implement an event and have the view attach to it. This holds to MVVM, but you feel this couples the V and VM too closely. I'm not sure how it is any closer than 1. In your example above about a property change, attaching to the PropertyChange event is how this works. So it seems like a good model to follow.
 
3) use pub/sub. This one is actually probably the most popularly reconmmended approach. I understand your argument about being too widely broadcast, although, at least in prism, you only get messages that fit the message type that you have subscribed too. It does seem a little heavy for a simple notice back to the view, though.
 
Thanks for taking the time to explain your choice. I've mainly used 3 in the past, but I'll have to do some more thinking about 1, and run it by our other architect here.
 
 
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 10-Apr-2012 at 1:32pm
Originally posted by mikedfox

 
3) use pub/sub. This one is actually probably the most popularly reconmmended approach. I understand your argument about being too widely broadcast, although, at least in prism, you only get messages that fit the message type that you have subscribed too. It does seem a little heavy for a simple notice back to the view, though.
 
 
In CM, too, you only get the messages you handle. The main difference between the Prism EA and the CM EA is that in CM you don't subscribe to a message directly. You subscribe to the EA and implement the appropriate IHandle<T> interface where T is the type of message you handle. The CM approach is more lightweight and supports polymorphism, meaning if you implement IHandle<A> you also get message of type B if B is a subclass of A.
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: 10-Apr-2012 at 1:37pm
@mikedfox - As long as we're in a summary mood ... :D

1) I thought this was the simplest to read, write and understand ... at the expense of MVVM purity.

2) Event is ok but has its cost - a greater cost than #1 in my view - because the code is more complicated and it couples the V to the VM ... which is just as bad a violation of MVVM as #1, again IMO.

3) "most popularly recommended" ???  I worked with the PRISM development team - I wrote a forward to the book - and we never recommended EA for V/VM communication. If it is so popular, surely you can supply a link from a reputable source. 
Back to Top
mikedfox View Drop Down
Newbie
Newbie


Joined: 29-Apr-2010
Posts: 21
Post Options Post Options   Quote mikedfox Quote  Post ReplyReply Direct Link To This Post Posted: 12-Apr-2012 at 11:57am
Ward, no, I can't pull a reference at this point, its just an impression I had gotten looking at frameworks from MVVM light to PRISM. It may well be a misunderstanding on my part. It's happened before. :)
 
I'm going to move on at this point, and try to figure out Cocktail as a whole. I got through the HappyHour tutorial fine, but there is so much content in TempHire I'm having trouble extracting what I need as next steps. I know its still early days, so I'm running into the typical bleeding edge problems. I've done an app in prism using DevForce as the database model, but if this approach is simpler/cleaner I'm all for it. Figuring out which pieces of the TempHire app do what will take a bit.
 
I can't wait to see this when its more fully documented. TempHire looks like it provides a lot of good examples of how to do stuff.
 
Thanks Ward and Marcel for being so willing to explain.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down