Datacontext of nested user controls - c#

Background :-
I have a wpf view containing a combobox which gets populated by the view model using caliburn micro / ninject and mvvm pattern; this view also contains a stackpanel area. When the user selects the appropriate option from the combobox I insert the appropriate user control into the stackpanel presenting the user with a seemless transition to the related display.
Each "nested" user control which gets displayed in the stackpanel has it's own view model automatically associated by caliburn micro.
Problem :-
The "nested" user control bindings all try and refer back to the parent view model and not the view model associated with them specifically.
I can, initially, work around this by specifying :-
<UserControl.DataContext>
<vm:UserControlSpecificViewModel/>
</UserControl.DataContext>
but this requires a parameterless constructor in the view model but I need to be able to have paremeters passed to this view model so that Ninject can inject objects such as EventAggregator.
Going around in ciricles as I am fairly new to WPF so any help would be appreciated.
Thanks.
James.

One way to solve your problem could be to just initialize your view model in code behind and call the appropriate constructor. If you have a dislike of code behind in your WPF applications then I suppose you could possibly just bind your view model to the IEventAggregator object.
XAML:
<UserControl1 x:Name="myUserControl">
</UserControl>
Codebehind:
public MainWindow() // Constructor for window
{
InitializeContext();
MyViewModel vm = new MyViewModel(...);
myUserControl.DataContext = vm;
}

Related

Bind view and model in caliburn micro

How to make caliburn.micro bind child view models to child visuals?
I have an ObservableCollection of items in a VM. Items are created manually, caliburn micro is not used. Sometimes they are deserialized from disk.
Views are created by WPF framework through data binding and data templates, I don’t need to search anything, and I don’t want to use ContentControl, I want to instantiate the correct visual tree in XAML, from my data templates there.
Is there a way to force caliburn micro to bind them together without creating neither views nor VMs with it?
Specifically, I want conventions applied automatically, so <Button x:Name="act" /> from the data template calls public void act() on it’s data context when clicked. Like it happens when caliburn micro creates either view or VM using these locators. The data context is set by WPF when it created an item visual from data item.
You could bind the cal:Bind.Model attached property of the root element in the DataTemplate to the DataContext like this:
<Grid cal:Bind.Model="{Binding}"> ...

WPF MVVM Change Model

I have a UserControl where the data gets passed in via a dependency property.
The UserControl is backed by a view model and the data is assigned to a property of the view model.
The XAML binds to both properties in the view model as well as properties within the passed in data.
The problem is if the user changes the data then databinding with the UI breaks. The UI is still bound to the original data object.
How can I cause the binding to get refreshed? INotifyPropertyChanged is implemented throughout, but it is not the property that is getting stale, but the binding. Basically, how do you go about replacing a backing model?
Since I'm not sure my description is clear I will try to describe it again in pseudo code.
<MyControl Source="{Binding Data}"/>
Where source is a dependency property of MyControl. In the PropertyChangedCallback this data is handed to the view model.
MyViewModel.Data = Source;
Within the MyControl XAML things are bound to this model.
{Binding Path=MyViewModel.Data.Item}
If you are wondering why the dependency property is defined in the UserControl, it is because it is a reusable control and the end user should not know about the view model.
"The UserControl is backed by a view model" and thus breaketh the application.
The UserControl's DataContext should be the Model. Period. If you need to perform UI logic, do it in the codebehind. Need something else? Create DependencyProperties on the surface of your UserControl to supply them.
When you create a ViewModel specifically for your UserControl, you break the natural flow of the DataContext (at this point, probably the Model the UC is designed to work with) and binding within the UserControl. It's pointless in most cases and harmful in some (as you have noticed).
My canonical answer on the subject contains more details.
Are you trying to swap-out the DataContext of the usercontrol during an application's session?
If you are, then I am fairly confident that this will not work.
Have you considered spinning up a new instance of that user control with the other DataConext?

inheriting object from another class

So currently I have a RadAutocomplete box. I am able to call that object in the
public MainWindow()
But I want to be able to call it in my viewmodel. If I may get tips and suggestions Would be great.
Never in WPF create UI elements, like in your case telerik objects, from view model.
If you do so, you loose benefits of MVVM.
View model is for binding between UI and business logic itself. You have to define telerik oject in XAML and show/hide it based on model view property.

MVVM: Convert code-behind to XAML

I've got an AllTopicsViewModel and its got a property ExerciseVM which is an AllExerciseViewModel, since I want to be able to refresh the AllExerciseViewModel of an ExerciseView so I am doing it like this (not even sure if it violates MVVM, pls. tell me). Well, I want to convert the 2 lines following the InitializeComponent to XAML but not sure how, can anyone help me out?
public MainWindow()
{
InitializeComponent();
AllTopicsViewModel vm = (AllTopicsViewModel)topicsView.DataContext;
vm.ExerciseVM = (AllExercisesViewModel)exercisesView.DataContext;
}
Yes, this is a misconception, according to the idea of MVVM.
Ideally, your View's codebehind (view.xaml.cs) contains nothing more than the auto generated code. Your view only accesses the ViewModel via WPF's data binding mechanisms. Because data binding via WPF is a loose coupling between the binding view and the bound-to ViewModel, you achieve the seperation that drives people to use MVVM.
You are retrieving the ViewModel in the Views codebehind from your control's DataContexts. With this, you create a strong reference between View and ViewModel. So, to help you with your question: You should think about what you are trying to to do with your ViewModel in the View's codebehind and how you can do it differently, either in the view's XAML or in the ViewModel's code itself.
If you like, post the complete MainWindow() class for some advice...
EDIT:
Ok, so its just about setting the child ViewModel on the parent ViewModel. The parent ViewModel AllTopicsViewModel should be responsible for setting its own ExerciseVM on initialization. This is not the View's job. the parent viewModel should assemble the data from one or more models and then create the child view models which the view consumes. Does that make sense for you?

How does WindowStartupLocation CenterOwner play with a view model?

In a WPF MVVM application, you have view models that contain all the logic behind the view, and views that display things. Doing things is linked through commands, which are implemented in the view model class.
When I want to open a new dialog window at the center of the initiating window, I need to set WindowStartupLocation = CenterOwner as well as Owner = something to the new dialog window. Unfortunately, the Owner property must be set to a view, but the view is never known in a view model.
So how is that supposed to work together?
Wild guess: Do I have to bind the view's location and size to the view model and position the new dialog manually, not using the CenterOwner automatics?
but the view is never known in a view model.
Ideally the ViewModel would be totally unaware of the View(s) that use it. But as you found out that is not always practical.
It is therefore common to have a light coupling, for example as a View property in BaseViewModel.
But your VM should not use any specific Controls or other details from the View.

Categories