This is how I see things too. Note that in Silverlight, you cannot bind to ElementName (yet) so the high road is the only road available ;)
found in this incoming message.
Checked by AVG - http://www.avg.com
Version: 8.0.176 / Virus Database: 270.9.12/1822 - Release Date: 12/1/2008 8:23 AM
1. If the value you need is unique to presentation, you should
consider still using a converter. Visibility is a classic example.
If one of your reasons to be using MVPoo is to be able to use multiple
presentation frameworks (WPF, WinForms, WebForms, ASP.NET MVC, etc.)
then the last thing you want to do is expose a property of type
Visibility. Even if you're sticking to WPF, there's two possible
"hidden" values with differing characteristics (hidden and collapsed).
Choosing among these is a view concern, not a view model concern.
(It actually bugs me that the BooleanToVisibilityConverter doesn't
support this choice out of the box!)
2. Formatting is generally a presentation concern, and should be
handled by the view. It may be tempting to add a property that
formats that date in some specific way, but down the road when you use
a different view that wants to format that date in another way, you
have friction between views that may not be easily resolved. Again,
if the conversion is to facilitate presentation, let the view handle
Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.
War is peace. Freedom is slavery. Bugs are features.
Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.
War is peace. Freedom is slavery. Bugs are features.
wow.. you all folks think (and email) faster than I can read : ) …. So I apologize for keeping the thread alive ( specially life cycle) if you had all moved on..
1) On avoiding ValueConverters when you have a ViewModel … I agree with Bill … Value Converters are OK for me (some times). Imo, ViewModel has logic and if it makes it readable to use Booleans instead of Visibility, I do it.. I try to keep ViewModel agnostic of presentation details like visibility, and ValueConverters does this nicely..
a. I am
also a TypeDecriptorProvider virgin so I need to learn more about it…
2) On the “life cycle” of ViewModel (and Initialize method) … I would love to better understand the decomposition of your lifecycle.. Does anyone have a hardcore rule?
a. When is the data fetched?
b. When are Commands wired and exposed??
c. Does the ViewModel wire up for Loaded ?? I kind of read on that…. Or Does the ViewModel implement an Interface that the view calls?? ( I opted for the latter the few times I did this, it is interface driven so generic) ..
() on a view model is new to me …. Never needed it before…
what kind of scenarios need it??
I hate thick constructors and I hate to delay Views… but a common gotcha for me is that if I wire up a DataContext to a form and it has not been fully initialized, then my Commands either do two or three times as much work (if I wire them after initialization) or can get into funny states where a command’s CanExecute logic returns wrong result just because proper state was not ready…
If any one can share their practices on Initialize () of a ViewModel I would love to know more about the logical and consistent approach…
[Yes, the issues below have easy workarounds…. I am just trying to better read pros & cons to other’s experiences J ]. .
I’m with Marlon on this, while I agree that the VM can eliminate all converters I don’t like the idea of having a ViewModel too tied to the view and, after all, converters are very reusable J.
Just had a look at Silverlight validation model, think there’s a lot of work to do to fit it in a M-V-VM environment…
I also think that this should be 50% 50%... If there is something strongly UI coupled then I would probably put it in a ValueConverter...
yet I must say I hate those creatures so called IValueConverters :/
WPF Blog - http://marlongrech.wordpress.com/
I want to chime in on that one.
Yes, patterns are guidelines more than rules. I followed that discussion with very much interest and can’t wait to try some of that in my next app, and it’s really interesting to see the different streams of thoughts. So far I think I see two major variations in the exposed practices, one which considers that VM is a kind of replacement for code-behind (let’s call it a top-down approach) and thus a VM is very tightly bound to a View. The other is rather a bottom-up approach and puts the VM as an extension of the model, but formatted for the View.
In the project I worked last, we took a very pragmatic approach, and used VM for various reasons, the most important being avoiding that our designers have to write any code. Josh’s point is really valid, designers should not have to worry about code, period. It’s not their job. My role as an integrator (IM calls that “Interactive Developer”) was to specifically avoid designers to have that kind of problems. This results in a series of roundtrips between developers and designers coordinated by the integrator. In that sense, a well thought VM can avoid a number of roundtrips. To me, this is the most important aspect of the VM, because every roundtrip costs a lot of money, and designers are damn expensive in a project.
When I say we were pragmatic, I mean that because some in the team were quite unexperienced, we ended up having quite some code in the code-behind. If I had to do it again today, I would probably be stricter about that. But on the other hand, I saw another team take a much stricter approach (Josh: That was Linus’ team, you probably remember him from our memorable dinner in NY) and they spent a lot more time on some details than we did. Also, some of the development was done in India, and their strict approach cost quite a lot of time round tripping between India and Switzerland, or worse, having to refactor much of the code that the Indian team delivered.
Anyway… my next project should be a much smaller one (Silverlight), and I want to apply MVVM in a stricter way there. That should be interesting J
I love this kind of discussions they helps spreading opinions and helps me (and hope others) play better with this “quite young” but promising pattern.
I’m not absolutely saying your solution is bad, e.g. I use it when I need to enable an element as result of a complex condition (DataTrigger/Multibinding? No thanks! J) and, my point of view is that patterns are ‘indications’ and I feel free to adapt them in the way the best fits my solution.
Unfortunately I keep seeing architects that apply patterns “as-is” even if that results in more complex code.
Thanks Corrado. I get
where you're coming from with this, but I'm still unsure of where the
"boundary" is. One could take this reasoning and push it to the
extreme by stating "Why bother with a ViewModel at all? Why not just
bind directly to the Model and use Value Converters to handle all other
transformations that need to be applied to make the Model show up in the UI
Clearly, I know that nobody here is promoting that idea. The balance of power, so to speak, between ViewModel and View is a spectrum in which I lean toward the left and many others seem to lean more toward the right. I'm wondering what guiding principles one should use to find the sweet spot between the two opposing forces.
You know, thinking about what I wrote earlier, I think that the “sweet balance” really depends on a lot of factors.
- Does your project have designers or not?
- How experienced is your team?
- How much unit testing do you do (don’t laugh, I love unit tests but many managers hate it and don’t see the value of it, true story)
- What is your model made of and where does it come from?
- and of course personal preferences.
Jer, using the Silverlight toolkit you can now define implicit styles so I *suppose* (but I didn’t try it) that you could also use the ImplicitStyleManager to define a View for a given view model type… interesting thought, I have to try that… tomorrow. ;)
This is a GREAT discussion! Sorry I’m so late to it and apologies in advance for the lengthy reply... too much fodder!
I agree with many things already stated. Josh originally proposed the purpose of the VM as follows:
[It] takes "raw" data and converts it into something presentation-friendly, and vice-versa.
That is a good description of the purpose of the VM, but the question then becomes just how far should the VM go to make the data “presentation-friendly”? Should it, for instance, have specific knowledge of the presentation technology? Generally, I try to avoid creating a VM that has a dependency on a specific V technology. Rather, I tend to agree with Paul’s comment here:
The VM manages state, the view manages how it's visualized... I think of the "state" of my VM as the conceptual state, not the real state. It's kind of like the difference between the Logical tree and the Visual tree, but at a domain level.
Incredibly well stated. That is exactly how I think of the VM.
I agree with most of Bill’s comments too. Ideally, changes to the view should not require significant changes to the VM. Value converters are great for maintaining a loose coupling between VM and V.
Josh also said:
To me, the state of the UI includes the state of the functional areas in the UI, such as whether some panel is open or closed. In my way of thinking, that state belongs in the ViewModel.
I agree. This is where the VM gets muddy. The muddiness comes from the differences between what Josh describes as ViewModel and ModelView classes. Most of my VM classes can be broken up along these same two categories. I have some VM classes that exist solely to support the view and some VM classes that exist to support the model. The classes that support the model obviously belong in the VM (even though a better term would be MV). But just about every user control, window, page, (sometimes even tabitem), etc, I create will also have a VM class that provides state for that control.
The cleanest approach might be to clearly separate these within folders called VM and MV, but so far I’m way too lazy for that. Instead, I tend to explain this muddiness away as part of the “poo”. ;-)
I probably differ with Josh a little on how the UI-specific VM classes are used by the view. Typically, if I have a VM class that supports a user control, for example, the VM class will still only provide a “conceptual” state for the control (and may thus require value converters). The control, itself, will then expose the necessary DPs to change state (hide and show the dialog, trigger template changes, etc) and those DPs will be bound directly to properties in the VM class. This allows the VM to still drive the application conceptually, but view-specific code stays contained within the view class.
One of the coolest suggestions in this thread was by Paul:
For a specific problem like that, for adapters, I always think of TypeDescriptor Providers. It would be trivial to build a very generic adapter to turn those methods into properties and exceptions into IDataErrorInfo, and you'd only code it once.
Dude, that is begging for a CodeProject article! :-D
Mike noted a suspicion that DPs are enabled via a custom type descriptor provider. There is definitely a link here, but maybe not the one suspected. The binding engine actually doesn’t rely on the provider to establish the binding at all. (It is much more optimized when binding to a DO... It knows that the DO has a property bag and it uses the supplied property path to look up the property.) However, the framework does expose a custom DependencyObjectProvider (which is a TypeDescriptionProvider) to surface DPs to designers like Cider and Blend. More importantly, if you were to expose a custom provider on a non-DO, then it would be used by the binding engine to look up properties (since those bindings are resolved via type descriptor/reflection).
Moving on... Josh noted:
While working on Crack.NET I created very dumb, passive Views and smart, demanding ViewModels.
. . .
I'm glad Crack has had the fringe benefit of being educational! That's great news for me!! :)
Cheers, dude! Well done. :-)
I think the MVVM implementation in Crack.NET is very clean and exemplary. I especially like the template-instantiated view approach there. Using this approach, you can create and manipulate VM objects, regardless of whether there is a view associated with those objects. For me (as a developer), writing an application is more about writing the VM anyway. (Whereas, for our designers, writing an application is more about creating the views.)
And finally, I think Laurent nails it when he says the balance depends on the scenario and resources at hand... including personal preferences. My preferences seem to change slightly with each new project. Bottom line... It’s great to have this dialog so we can all benefit from each other’s experience.
Dr. WPF - Online Office at http://www.drwpf.com/blog/
No, not at all in your VM code. I haven't even noticed any place where you leveraged the VM to perform value conversion in Crack.NET. Your code seems very pure and view-agnostic to me.
Now as for my code... there is definitely view-specific logic in the VM code that I added! It made my brain hurt trying to devise a VM approach for the Snoop-like element tree explorer. In fact, I went through several rounds of inner turmoil before I reconciled that it was indeed appropriate to have Visual references in the VM. (It certainly felt wrong though.)
This is where Crack.NET differs from most apps. It is a debugging tool. And the specific part I was working on was aimed at debugging the "view" of a WPF application. So the fact that I had routines within the VM to walk the visual tree was actually quite appropriate. The key thing to note is that I was *not* walking elements of Crack.NET's view... rather, I was walking elements of the debuggee's view. Those were the very elements represented within the view model.
(In fact, there was even a property on a VM class of type VisualBrush. Boy did that feel wrong! Brush and Visual are examples of presentation classes that I would *never* expect to see referenced in the VM. But again, it's appropriate when you recognize that these are actually VM objects in Crack.NET. Weird, but appropriate.)
Crack.NET also gets a big pass from me on how strict I would be in keeping the V and VM separate. It is a special purpose tool whose UI will most likely only ever be presented using WPF (again, since its a full-trust, Windows-specific debugging tool). That makes poo more forgivable, imho, although I haven't observed any yet. ;-)
So Crack.NET is a great "implementation" example of MVVM, but it is not necessarily analogous to more typical data visualization apps where you might want to support both a WPF and SL view.
Whew I am so relieved to wake up and find only 13 new posts in that thread, instead of the 242 I was dreading.
Josh, you say you love working on the M and VM ;) I love that too but I have to say I really like working on the View too and especially XAML. Yes you heard that right, I love XAML ;) Man this is such a change from WinForms, where I just *hated* the part where I had to re-layout all the controls when the window’s size was changing just a tiny bit… I love the way that XAML and the flow layout are taking care of that for me. There is such an amazing elegance in that. I guess that puts me a little more between the developer and the designer, which is exactly what we, at IdentityMine, call an interactive developer (or integrator). (notice how I say “we” after just a day? ;))