Multiple DataContext in data binding, necessary? - c#

In an MVVM design, is it necessary, or even a bad idea, to have multiple DataContext in data binding?
How I thought about MVVM is that the ViewModel should be the one having all the data needed for the View. Thus, the only source object for the DataContext specified in the View is only the ViewModel. The ViewModel will have all the source data the View would want to bind to.
However, I am not sure whether my thoughts are correct and if there are certain situations that really require multiple DataContext that the View would want to bind to.
So, is it a bad idea or practice to have multiple DataContext for the View in data binding? Will just the ViewModel being the only DataContext be sufficient?

Yes, the ViewModel should be the only top-level DataContext and it should be set at the root of the View. However, there may be other sub-DataContexts. For instance, a ListBox may be bound to a list of data, where the DataContext for each row of the ListBox is bound to one item in the list of data.

Related

How can I pass in parameters from one to another ViewModel for its View to use?

I have an app that should display data based on variables from parameters received from calls of the ViewModel.
I have noticed two places in which the ViewModel gets called from, one is the intended call by the parent ViewModel for displaying the View of the child ViewModel with the help of ViewLocator.cs. Another is the DataContext required by the View to enable data binding.
Former: [ParentViewModel.cs]
public ParentViewModel()
{
UserControlContent = new ChildViewModel(genericParameter: "actual parameter");
}
Latter: [ChildView.axaml.cs]
public ChildView()
{
InitializeComponent();
DataContext = new ChildViewModel(genericParameter: "not the parameter I want");
}
So I want to pass in the "actual parameter" as shown above for show in the resulting View. I expect the final view to look like this:
But in reality I get this:
So, how can I work around this and get the View to display the right data?
Appreciate any input!
Turns out, only the call from the ParentViewModel is required. DataContext under ChildView can be removed and the correct parameter can be used.
Thanks to the answer here for this question.
I think you have some fundamental misunderstandings of MVVM.
Firstly, you have two ChildViewModel instances.
So calls made in your ParentViewModel on the UserControlContent instance of the view model will never be reflected in the UI as the ChildView creates a new instance of the ChildViewModel itself and then uses this instance for as it's DataContext.
You should make use of some form of IoC and DI your dependencies.
MVVM discourages the use of manual view model creation through the new keyword.
Unless there is a very specific use case, try to keep some relationship between the UI structure and your view models as flat as possible.
By this I mean if there is a use case where the parent view model needs the same things as the child view mode. It may make sense to flatten and merge those two view models.
This in turn simplifies the VMs themselves and the bindings.

Binding single control to different Datacontext in wpf

I have a button button_extract. I want to bind it to two different data contexts (2 classes in different namespaces)
I want to set the Command and IsEnabled properties to different data context.
I have one datacontext set for Command property. But how to I specify the datacontext of IsEnable property which is in different class and namespace. Here is the scenario:-
I have a project named Environments with three namespaces:Viewmodel,Data and View
Viewmodel has class A
Data has class B
View has xaml C with button button_extract.
The data context for C is set to class A.The xaml is as follows
<UserControl x:Class="Enviornment.Views.C"
DataContext="Environment.Viewmodel.A">
<Button Name="button_extract" Command="{Binding ExtractButtonClick}" IsEnabled="{Enviornment.B.SelectedEnvionment}" >Extract</Button>
The above code does not work. The binding of IsEnabled throws error. How can I set the datacontext of IsEnabled to that of Enviornment.B???
You seem to have a common misconception about WPF regarding the need to set the DataContext. In fact, there is rarely any need to set a DataContext on any control as typically the Window has had its DataContext set and each control's DataContext will automatically inherit from that.
So, how to data bind to two different places? Generally, one place would use a normal Binding Path and the other would use a RelativeSource Binding Path. However, that would be more for the case where you wanted to data bind to properties of the set DataContext and properties of a control's code behind.
It is more common in your scenario to simply prepare a view model. That is a custom class that implements the INotifyPropertyChanged interface and provides all of the properties and functionality that your Window, UserControl, or 'view' requires. You would then set an instance of this single object as the DataContext.
Therefore, simply add properties of the relevant classes into your view model and then you will be able to access them all using the one single DataContext object. Please search online for MVVM for further information.

Setting property of child viewmodel from parent

I have a view that I'll call View1 that has a nested user control that I'll call View2. My main application creates and shows View1 which in turn creates View2 since it is a user control on View1. Both View1 and View2 have their own viewmodels. What I need to do is get a value from View1's viewmodel to View2's viewmodel.
View2 is meant to be a completely self-contained control with its own functionality that is reusable in any other view, but it needs a piece of information from whatever view it is contained in. In the case given here, that would be View1.
My first attempt was to create a dependency property on View2 so it could be set in View1 like so:
<myUserControls:View2 MyProperty="{Binding RelativeSource={RelativeSource Self}, Path=Parent.DataContext.MyProperty}"/>
This works to set the dependency property, but that doesn't help to get the property value into View2's viewmodel where I can work with it.
I am doing this in Silverlight, if that makes any difference.
Anyone know if there is a way to do this?
I would recommend using the "Mediator" pattern, or some sort of communication between viewmodels. I personally have used galasoft MVVM light messaging to great deals of success. Rachel has also written a pretty good blog on navigation: Rachel's MVVM blog
But I would try and decrease the coupling in your program by letting the messaging handle the data context switch and viewmodel updates as opposed to creating a dependency property.
You could for instance have a baseviewmodel class which all view models inherit from, and use a polymorphic generic "view model" property which is of type baseviewmodel in your main viewmodel. Once the message was received to switch from viewmodel #1 to viewmodel #2, call a "update model" function (which you have declared in your baseviewmodel and override in your VM #2) which will then handle updating your VM #2.

How to implement WPF ValueConverter that needs data from viewmodel?

i am writing an application that has a viewmodel and a usercontrol that displays
data from this viewmodel. The viewmodel contains an entity "Appointment", and those
appointments have a property "UserName".
When I display the appointments, I want to use a value-converter to get a color for
the user (depending on "UserName"), but the colors are not contained in the entity "Appointment", so I wanted to create a value-converter that uses the entity "User" from the viewmodel.
What is the best way to use another entity from the viewmodel inside the converter?
Is it possible to access the viewmodel from the usercontrol? I tried to place the converter inside my viewmodel-class, but can I access this class from the usercontrol?
I figured out that the following possibilities might work:
Adjust the viewmodel so that each appointment also contains the color. But I don't want to do this because I don't want to mess with the viewmodel.
Set the converter-parameter from the class that also contains the viewmodel at startup. (Does this work?)
Use x:Reference to databind the converter parameter to the viewmodel that is unknown at compile-time.(Is this possible?)
Converter parameter is the way to go.
Why is the viewmodel unknown at compile time?
Bindings are not compile time checked anyway.
Is the UserControl.DataContext being set to an instance of Appointment, you should be able to set the parameter to {Binding UserName} or {Binding Appointment.UserName} depending on exactly what you are setting as the DataContext on the UserControl.
I would suggest that you re-examine your reluctance to modify the view model. The purpose of having a view model in the first place is so that everything that the view needs can be found in one place. Coming up with elaborate value converters to prevent modifying the view model is an approach that gets increasingly unmaintainable the more you do it.

WPF MVVM and nested Views with dependency properties

I have a parent view that defines a child view in Xaml. The child view has a DependencyProperty that is bound to the parent view's ViewModel. However, that value is also needed by the child view's ViewModel.
<custom:Parent>
<custom:Child ChildId="{Binding ParentFooId}" ... />
</custom:Parent>
ChildId is implemented as a dependency property of the ChildView control. If the ChildViewModel needs ParentFooId, what's the proper MVVM way of obtaining it?
I don't want to cast the DataContext of the ChildView into a ChildViewModel and set value in a OnChildIdChanged handler of the ChildView. That doesn't seem very MVVM-ish to me.
The other alternative I thought of was to create a new ChildViewModel with the value and set it as the DataContext in the OnParentFooIdChanged event (in the ParentViewModel); but that doesn't seem quite right either, since the ViewModels are supposed to be oblivious to the View (and thus don't know anything about DataContexts).
It seems like I'm missing something obvious...
If I understand the question correctly you just need to create the child view model within the parent view model, passing and keeping a reference to the parent view model. That way you can reference any property of the parent view model from the child view model and bind to either in the child view.
If you are simply trying to pass data from a dependency property to your view model I would use the PropertyChangedCallback event. Add a handler that sends the changed data to your View Model. I may be misunderstanding your intent though.

Categories

Resources