views:

1180

answers:

4

Let's say I have a View that is bound to ViewModel A which has an observable collection Customers.

An advantage of this MVVM pattern is that I can also bind the View to ViewModel B which fills it with different data.

But what if in my View converter Converters to display my customers, e.g. I have a "ContractToCustomerConverter" that accepts a Contract and returns the appropriate Customer to be displayed.

The problem with this is that the converter exists outside the MVVM pattern and thus doesn't know that my ViewModel has another source for customers.

  • is there a way for the View to pass the ViewModel into the Converter so that it participates in the decoupling that the MVVM pattern provides?
  • is there a way for me to somehow include the Converter in my ViewModel so that the converter uses the current dependencies which ViewModel has available?
  • or are converters just glorified code-behind and thus not used in the MVVM pattern, so if you are using MVVM then you just create your own "converters" (methods on your ViewModel class) which return things like Image objects, Visibility objects, FlowDocuments, etc. to be used on the view, instead of using converters at all?

(I came upon these questions after seeing the use of Converters in the WPF demo application that comes with the MVVM Template Toolkit download, see the "Messenger Sample" after unpacking it.)

+2  A: 

Converters should rarely be used with MVVM. In fact, I strive not to use them at all. The VM should be doing everything the view needs to get its job done. If the view needs a Customer based on a Contract, there should be a Customer property on the VM that is updated by VM logic whenever the Contract changes.

An advantage of this MVVM pattern is that I can also bind the View to ViewModel B which fills it with different data.

I dispute that claim. In my experience, views are not shared across different VM types, and nor is that a goal of MVVM.

HTH, Kent

Kent Boogaart
OK I see your point about views should not be shared across different VMs, but a ViewModel should be able to be shared by different Views, hence the advantage of testability of MVVM, right? You should be able to hook up a mock view and mock model to ViewModel to make sure that all data combinations that it receives from the mock model produce the correct property values that get exposed to the view. Would you agree?
Edward Tanguay
+4  A: 

I usually don't use converters at all in MVVM, except for pure UI tasks (like BooleanToVisibilityConverter for instance). IMHO you should rather declare a Customer property of type CustomerViewModel in your ContractViewModel, rather than use a ContractToCustomerConverter

Thomas Levesque
+1  A: 

In this conversation there is a comment that agrees with Kent's position, not to use Converters at all, interesting:

A ViewModel is basically a value converter on steroids. It takes "raw" data and converts it into something presentation-friendly, and vice-versa. If you ever find yourself binding an element's property to a ViewModel's property, and you're using a value converter, stop! Why not just create a property on the ViewModel that exposes the "formatted" data, and then drop the value converter altogether?

And in this conversation:

The only place I can see a use for value converters in an MVVM architecture is cross-element bindings. If I'm binding the Visibility of a panel to the IsChecked of a CheckBox, then I will need to use the BooleanToVisibilityConverter.

Edward Tanguay
+2  A: 

For those effectively saying no "non-trivial converters" in the view, how do you handle the following?

Let's say that I have a Model of climate sensors that represents time series of readings from various instruments (barometer, hygrometer, thermometer, etc.) at a given location.

Let's say that my View Model exposes an observable collection of the sensors from my Model.

I have a View containing a WPF Toolkit DataGrid that binds to the View Model with the ItemsSource property set to observable collection of sensors. How do I represent the view of each instrument for a given sensor? By displaying a small graph (think Edward Tufte sparkline here) that is generated by converting the time series to an image source using a converter (TimeSeriesToSparklineConverter)

Here is how I think of MVVM: The Model exposes data to View Models. The View Model exposes behavior, Model data and state to View. Views do the job of representing Model data visually and providing an interface to behaviors consistent with the View Model state.

Thusly, I don't believe that the sparkline images go in the Model (the Model is data, not a particular visual representation of it). Nor do I believe that the sparkline images go in the View Model (what if my View wants to represent the data differently, say as a grid row just showing min, max, average, standard deviation etc. of the series?). Thus, it seems to me that the View should handle the job of transforming the data into the desired representation.

So if I want to expose the behaviors, Model data and given state for a certain View Model in a command-line interface instead of a WPF GUI, I don't want my Model nor my View Model containing images. Is this wrong? Are we to have a SensorCollectionGUIViewModel and a SensorCollectionCommandLineViewModel? That seems wrong to me: I think of the View Model as an abstract representation of the view, not concrete and tied to a particular technolgy as these names suggest they are.

That's where I am in my continually evolving understanding of MVVM. So for those saying not to use converters, what are you doing here?

Jason
I see the problem you describe like this: With a value converter, you would make a ClimateSensorToSparklineGraphConverter which takes a collection of climate sensors and outputs an image. For something like creating a bitmap image, you aren't going to be doing this with a DataTemplate and a collection of ViewModels containing ViewModels, at some point you need C# code to create the image. The problem comes when in the converter you also access e.g. a Users collection to determine what the current user is allowed to see. This would break MVVM since the ViewModel should have users injected.
Edward Tanguay