WPF data binding and type conversion - wpf

I have a question regarding WPF binding and converting the data types seen by the UI objects in XAML.
I have a user control that I would like to reuse in different applications. The user control displays a thumbnail image and several TextBlocks to display person demographic information such as name and address. The user control is used in an MVVM design, so it’s bound to a ViewModel specific to the user control.
Following typical MVVM design principles, The ViewModel for the user control is often embedded in other ViewModels to make up a larger UI.
The user control view model expects a certain type (class) as its binding object.
However, the ViewModels in which the UC’s VM in embedded have entirely different object models, so they cannot simply pass-through their data to the UC’s VM. There needs to be a conversion of the parent VM’s data model to the UC VM’s data model.
My question is this: Is there a sanctioned way to perform this conversion?
I looked at IValueConverter and IMultiValueConverter and these do not look like the way to go.
I guess what I need is a sort of shim between the parent VM and the embedded UC VM where the parent VM’s data is converted to the format required by the UC VM.
Or, does it basically come down to I have to write a custom UC VM to handle whatever types the parent VM provides?

I agree with Ken, I think he has the answer. If you have n many configurations of your data that you want to pass into a common user control, then you want the owner of that configuration of data to convert it into a common form to be bound to the user control.
Each view that uses the control would have a corresponding view model that exposes a property in a common format:
public class SampleViewModel {
...
IUserControlData ControlData
{
get
{
// Do conversion here or do it early and cache it.
}
}
...
}
Then you would bind that property to your user control in the view
<common:CommonUserControl DataContext={Binding Path=ControlData} ... >

If the parent VM is a superset of the child VM, normally the parent VM would just hold a reference to the child VM. It would expose that reference as a property, and you would bind a ContentControl (or whatever) to that property.
Would this not solve your problem?

If you really want and need to do type conversions, the value converters are exactly what you want to use. That said, typically the type of conversions handled by things like IValueConverter are relatively simple and direct.
If, however, your top-level/parent/management user control needs to parse off bits and pieces of some larger type to the user controls which host its actual content, then that is the job of that top level control. Don't get all wrapped up in doing all of this in XAML. It's perfectly fine to parse off what you need and set these child control properties directly.

Probably not what you are looking for but this is a solution for DataGrid dynamic columns. With datagrid you can pass a parameter. http://www.codeproject.com/Articles/36496/Binding-a-Silverlight-DataGrid-to-dynamic-data-Part-2-editable-data-and-INotifyPropertyChanged.aspx

Related

viewmodel have to be public. How should I deal with that?

Pretty much it summarizes my problem here:
Double check - does it ever make sense to have internal viewmodel class?
I have controls.DLL and I'd like to keep this custom control bindings and viewmodel's internal. However, this doesn't seem to be possible.
How do you get around that? The only way I see it - don't use bindings..
Why do you have a view model for a custom control? I assume you're assigning the view model object to the DataContext property, but this is almost always a mistake: the DataContext should be available to consumers to use and abuse as they please. Stated another way, what happens if a consumer of your custom control explicitly sets the DataContext? It sounds like your control will stop working and throw a bunch of xaml binding errors.
A custom control is inherently lookless. There is no model or view model, just a view. That view is the .cs file. You supply a default look via your themes/generic.xaml file, but consumers should be able to supply their own template. If you're tying them to a view model, they also need to know how to create a view model instance and all of its dependencies. You've just created highly coupled code. DI containers can loosen the coupling, but that just downgrades the relationship between classes from "coupled" to "related". I say, why do consumers even need to know that information?
A better approach is to provide all of the properties for your control as dependency properties. Then your generic.xaml can provide a control template that uses the more efficient TemplateBinding to bind properties/objects to your control. If you need to populate these dependency properties from a business object, expose another dependency property of type IBusinessObject and set the derived values in that object's PropertyMetaData changed handler. If your IBusinessObject type contains a property which is yet another class which implements INotifyPropertyChanged, you should probably (1) rethink your object graph or (2) create a Bnding object in code using the subclass.
I think following all of the above advice will eliminate the problem about which you're concerned plus the other problems as well. Leave the view models to the UserControls. And yes, this is why custom controls are a MASSIVE headache. Doing them right is fairly involved.
Try protected internal. I suppose this should work. Although I don't think its good idea to have the ViewModel not public at all, cause one of the purposes of it is to be able to define several Views against the same ViewModel, which may come from different assemblies.

How to handle bindable application wide variables in a WPF MVVM application?

I am writing a fairly large scale WPF desktop application using the MVVM pattern. I have been stuck for a while on getting my common properties to update in a View other than the one that updated it.
I have a RibbonWindow MainView that contains a ContentControl that displays the remaining Views one at a time dependant on the user's selection. I have a BaseViewModel class that all the ViewModels extend. Among other things, this class exposes the INotifyPropertyChanged interface and contains a static property of type CommonDataStore. This class also implements the INotifyPropertyChanged interface and contains the properties that are to be available to every ViewModel.
Now, although I can access and successfully update the CommonDataStore properties from any ViewModel, the problem is that the WPF Framework will only notify properties that have changed in the current View. Therefore, although the common values have been updated in other ViewModels, their associated Views do not get updated.
One example from my application is the login screen: As the user logs in, my LogInView updates with the new information (ie. full name) from the database, but the user details in the MainView do not.
After reading a few other posts, I also tried implementing the CommonDataStore class as a Singleton, but that didn't help. I could also just pass a reference to this common data object to the constructor of each ViewModel from the MainViewModel, but I'm not sure if this is the right way to go.
I have also discovered that in WPF, static properties are treated a bit like constant values. It seems that they just read the value once.
So anyway it's clear, my attempts have all failed. I was wondering what the standard way of doing this was? In particular, I need to be able to bind to the common properties and have all of my ViewModels and Views update when any common value is changed. Any help would be greatly appreciated. Many thanks in advance.
Edit >> Really? No one uses application wide variables in an MVVM WPF application?
I have now removed the static part of the Common property declaration and am simply passing a copy into each ViewModel individually. This seems to work, but I'd really like to know how others approach this situation. Please answer by simply letting me know how you organise this application wide data.
I have done something similar to what you describe last. I have class called SecurityContext that holds some of the application-wide data. One instance is created when the application starts up and then that instance is passed into the constructors of all the ViewModels through dependency-injection. I have a base class for ViewModels which exposes that object through a regular instance property (implementing INotifyPropertyChanged).
Have you looked into implementing the Observer Pattern? We have done so with IObservable and IObserver. This describes the "IObservable/IObserver Development Model" as follows:
The IObservable/IObserver development model provides an alternative to using input and output adapters as the producer and consumer of event sources and sinks. This model is based on the IObservable/IObserver design pattern in which an observer is any object that wishes to be notified when the state of another object changes, and an observable is any object whose state may be of interest, and in whom another object may register an interest. For example, in a publication-subscription application, the observable is the publisher, and the observer is the subscriber object. For more information, see Exploring the Observer Design Pattern on MSDN.

Should a ViewModel in MVVM reference the View?

In the MVVM (Model-View-ViewModel) pattern should the ViewModel reference the view. I would think that it should not. But how should the following scenario be handeled? I have a view that has a tab control as the main container, the viewmodel for this view implements a command to add a new tab to the tab control. The easy way would be to allow the viewmodel to reference the view and then in the command implementation to just programmatically add the new tab to the tabcontrol in the view. This just seems wrong. Should I somehow bind the tabcontrol to the viewmodel and then implement a data/control-template to add the new tabs. I hope this makes some kind of sense to somebody :)
In "pure" MVVM, the ViewModel shouldn't really reference the View. It's often convenient, however, to provide some form of interface in the View whereby the ViewModel can interact with it.
However, I've found that I almost never do that anymore. The alternative approach is to use some form of attached property or blend behavior within your View, and bind it to your ViewModel properties. This allows you to keep the View logic 100% within the View. In addition, by creating a behavior for this, you create a reusable type that can be used to handle this in every ViewModel->View interaction. I strongly prefer this approach over having any View logic within the ViewModel.
In order to demonstrate this technique, I wrote a sample for the Expression Code Gallery called WindowCloseBehavior. It demonstrates how you can use a Behavior within the View bound to properties in the ViewModel to handle controlling a Window's life-cycle, including preventing it from being closed, etc.
Reed and Dan covered the general approach but in reference to your specific case, TabControl is an ItemsControl and so can bind its ItemsSource to a data collection in your ViewModel representing the set of tabs to display. The UI for each type of tab can then be represented by a DataTemplate specific to the data type of an item (either using DataType or a DataTemplateSelector). You can then add or remove data items as needed from your VM and have the tabs update automatically without the VM knowing anything about the TabControl.
I find that it's often a helpful compromise to expose an interface on the View that handles View-specific functionality. This is a good way to handle things that are awkward to accomplish with pure binding, such as instructing the form to close, opening a file dialog (though this often gets put in its own service interface) or interacting with controls not designed well for data binding (such as the example you provided.)
Using an interface still keeps the View and ViewModel largely decoupled and enables you to mock the specific IView during testing.
One of us is missing something obvious. Your tab control is an ItemsControl. You should bind the ItemsSource of your tab control to an ovservable collection in your view model. When you handle the command in your view model to add a tab, you simply add a new element to this collection and, voila, you've added a new tab to the control.

How to call a user control method using MVVM?

I'm working in a WPF project, I'm using the MVVM patter in my project.
I created a user control (also in WPF) and I want to use it in my project, now, my problem is that I have a method in my user control that I need to call from my View Model, but I don't know how to do that, how to bind to the method inside my control from the view model.
If I use code behind, obviously there is no problem since I have a direct reference to my control, so I can do "mycontrol.MyMethod();"m, but of course, doing in this way will go against the logic of the MVVM pattern.
I tried to use a Dependency Property in my user control, and use that Dependency Property to bind to it in the xaml of my project but it didn't worked, the compiler says that the property was not found or is not serializable.
So I will appreciate if someone can share some light about how can I accomplish this.
Edited
As far as I understand you have the view, which is all the GUI, then you have the model, which is all the logic, and them you have the view-model which is like an intermediate layer used to bind the view with the model, right?
In this way I have developed my project, however I came to the problem that I need a custom control, a TextBox that remember what the user entered, and when he start typing, if there are words that start with that letter, those words are shown as a suggestion, as Google does it.
This TextBox is used as a search filter; so I created a user control to do this, I added a method to my user control to allow whatever application that uses my control to add items to an internal array that holds all the strings that the user has entered.
I created a user control because I couldn't find any control that behaves the way I want.
So my problem is when I add my user control to the main project, because I need to someway be able to call the method that add the items to the internal array, but maybe I'm doing things the wrong way, so if any of you has a better idea, I will appreciate if you shared it with me.
You should never call View methods from ViewModel, and vice versa.
Make a property (ObservableCollection?) on your ViewModel, it will have CollectionChanged event, subscribe to it to monitor changes (if needed).
When you add an item to the collection in your ViewModel, GUI will be updated accordingly (you have to perform the Add() operation on GUI thread, btw).
If you need to change the current position in your list, there are colections for that (CollectionViewSource, etc).
If you really really need to pass a string to your control, make a DependencyProperty and bind it OneWay to your ViewModel's property. When you set the value, it will call PropertyChangedCallback on your DependencyProperty.
Why does the consumer of the user control need to maintain the control's internal array? That seems like you've exposed an implementation detail that you don't need to.
Why not simply make that array a dependency property (and an IEnumerable<string> or ObservableCollection<string> besides)? Then you can simply create the corresponding property in your view model and bind it to the control. It also makes the control considerably more versatile.
You shouldn't call something in the View from the ViewModel since that breaks the model.
If the reason you want to call the method in the user control is to do with UI only, I don't see anything wrong with doing it from the view - the view's cs and the view's xaml are in the same "space" in the model. You can be overly-purist in wanting to have lean and mean view cs files.

How can WPF Converters be used in an MVVM pattern?

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.)
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
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.
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.
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?
I've been using Stackoverflow for years and this is accrual my first answer posted.
I think converters belongs to View in MVVM, consider the following situation:
App is developed by 3 teams, webapi team, webclient team and UI team. UI changed frequently so the webclient team (which receives data from webapi and put them into viewmodel) cannot always modify the viewmodel to satisfy UI needs. This becomes impossible when the UI team have different versions of design. So the UI team must have their own way to present the data and the solution is Converters.
Hope this helps someone.
I'll add my 2 cents to this discussion.
I do use converters, where it makes sense.
Explanation:
There are cases where you need to represent 1 value in Model in more ways in the UI. I expose this value through 1 type. The other is type is handled through converter. If you were to expose 1 value through 2 properties in VM, you would need to manually handle update notifications.
For example I have a model with 2 ints: TotalCount, DoneCount. Now I want both this values to be displayed in TextBlocks and additionally I want to display done percentage.
I solve this using DivisionConverter multi converter which takes 2 previously mentioned ints.
If I were to have special PercentDone in VM, I would need to update this property whenever DoneCount is updated.

Resources