WPF DataBinding with MVVM and User Controls - wpf

Let's say I have a Customer Window showing information about a customer, like Name, address and phone number. On the bottom there is a DataGrid of their orders. Of course the Customer has an Orders property, so if you're using MVVM, you would just set:
ItemsSource = "{Binding Customer.Orders}"
However, now let's say that the data grid is now part of a user control, which also includes controls for editing/adding/removing Orders. I want to use this same set of controls in multiple places, and I would like all the logic for editing/adding/removing Order objects to be encapsulated in the user control. And because I want to use commands, rather than event handlers, I would like the user control to have its own view model.
So now the question is: how do I pass the orders from the Customer view model to the Orders user control's view model? Because the Orders user control will be bound to a view model, I can't say:
<local:OrdersUserControl DataContext="{Binding Customer.Orders}" />
because the user control has it's own view model. It would expect to see Customer.Orders there, and of course it's not.
I guess this is kind of a chicken or the egg situation.
Your help is always appreciated.
Aaron

And now for my weekly "don't do that" answer...
I can't say ... because the user control has it's own view model.
To which I say
Creating a ViewModel for your UserControl is a code smell.
You're experiencing this issue because of that smell, and it should be an indication that you're doing something wrong.
The solution is to ditch the VM built for the UserControl. If it contains business logic, it should be moved to an appropriate location in another ViewModel.
You should think of a UserControl as nothing more than a more complex control. Does the TextBox have its own ViewModel? No. You bind your VM's property to the Text property of the control, and the control shows your text in its UI.
MVVM doesn't mean no codebehind. Put your UI logic for your user control in the codebehind. If it is so complex that you need business logic inside the user control, that suggests it is too encompassing. Break it down into two or more.
Think of UserControls in MVVM like this--For each model, you have a UserControl, and it is designed to present the data in that model to the user. You can use it anywhere you want to show the user that model. Does it need a button? Expose an ICommand property on your UserControl and let your business logic bind to it. Does your business logic need to know something going on inside? Add a routed event.
Normally, in WPF, if you find yourself asking why it hurts to do something, it's because you shouldn't do it.

There are many ways to skin a cat. The way I've been doing this is by having my CustomerViewModel have a property of type OrdersViewModel. Then in the constructor (or wherever you are setting the customer) have it set the "OrdersContext" with a new OrdersViewModel passing in the customer.orders.
XAML:
<local:OrdersUserControl DataContext="{Binding OrdersContext}" />
ViewModel:
public CustomerViewModel(Customer customer)
{
Customer = customer;
OrdersContext = new OrdersViewModel(customer.Orders);
}

Related

How to bind to a method on ViewModel with data from View

I currently have one view with 3 fairly simplistic view models. For the sake of this discussion, we will focus on 2 of the three view models.
The View is a User Management user control. It contains a DataGrid that has its ItemsSource binding set to a UserListViewModel. This view model simply displays user information in the data grid.
The User Management View also contains some other controls, such as buttons for adding new users and removing users. Those buttons are currently bound to a second view model called UserManagementViewModel. For example, the Remove button will successfully call the RemoveUser method on the UserManagementViewModel.
My question is, via XAML (as I hate code-behind), how can I pass the SelectedItem property of the DataGrid (bound to UserListViewModel) into the RemoveUser method call on the UserManagementViewModel? I realize that, in the MVVM design pattern, my view model can't look into the view to retrieve the information necessary, so there must be a way via binding to pass that information into the method.
XAML code examples (or links that show how) to perform similar functionality would be appreciated. Thanks for any help!
you can simply use a commandparameter
<Button Command="{Binding RemoveCommand} CommandParameter="{Binding Elementname=gridUser, Path=SelectedItem}" />
or your UserManagementViewModel have access to the UserListViewModel then you need a command without commandparameter and simply use the SelectedUser property of your UserListViewModel instance
public void ExecuteRemove()
{
var userToRemove = this._myUserListViewModelinstance.SelectedUser;
...
}
I believe what you seek is commanding with a command target bound to the datagrid's selecteditem where one can route such information from the datagrid; say when a button is pressed.
See Commanding Overview on MSDN

MVVM and Custom Controls?

I'm working on PRISM application with modules, MVVM and so on. I understand PRISM pretty good now and I understand value of MVVM. All those things good to deliver business value which comes from testability, "uniformity" and so on.
But now I'm stuck with certain interaction issues. I already spent hours and hours trying to see how I set focus in Silverlight via MVVM. All this additional behaviors, attached properties, triggers. It just seems like bunch of junk code with MVVM being root cause.
For example, I need to create Lookup control which is basically textbox with button and popup window. This control itself needs lot of focus control, it needs to overlay view over parent (popups) and so on. It seems to be pretty easy to create it with code-behind, stick it into separate library and move on. My business forms will use this control inside my nice MVVM PRISM.
So, question is.. Is it justified to use code-behind in isolated islands like controls and keep MVVM and TDD for actual code that brings business value?
Is there line where you say "MVVM is not going to be used here" ?
I see absolutely nothing wrong with using Code Behind providing that the code is related to view-specific properties, such as setting Focus. Your ViewModel should never need to know about or care who or what has focus, since that is a View-Specific concept.
Usually I build UserControls in two ways: they are either built for a specific Model or ViewModel, or they are meant to be generic and have their values provided by whoever calls them.
In the case of the former, such as if I wanted a SearchResultsPopup, I would build the UserControl expecting to have something like a SearchResultsViewModel as the DataContext.
For example, my UserControl would expect to find the following properties on it's DataContext, and would use them in bindings to build the View.
ObservableCollection<SearchResult> Results
SearchResult SelectedResult
bool IsOpen
ICommand OkCommand
ICommand CancelCommand
I could then use the UserControl like this:
<local:SearchResultsPopup DataContext="{Binding MySearchResultsVM}" />
In the later situation, where I am creating something generic which can be used by any Model or ViewModel, I would use custom Dependency Properties to provide my UserControl with the values it needs to bind to.
So in this example, I would have DependencyProperties for
bool IsOpen
ICommand OkCommand
ICommand CancelCommand
And my XAML would look something like this:
<local:GenericPopup local:GenericPopup.IsOpen="{Binding IsPopupOpen}"
local:GenericPopup.SaveCommand="{Binding SavePopupCommand}"
local:GenericPopup.CancelCommand="{Binding HidePopupCommand}">
<local:MySearchResultsView ... />
</local:GenericPopup>
In summary, your UserControl is either a reflection of your ViewModel (meaning it becomes a View), or it is provided values by the View. The ViewModel doesn't care either way.

Can MVVM Usercontrols have property defined in codebehind?

I have a WPF user control ...which is in MVVM. The user control(which contains a listview) need data from the page (where it is included). I have to set a property to get this data input. Will this comply with MVVM...if not, what is the way for the same?
I'm afraid this won't be correct in MVVM design pattern. try to stick to your view model to define properties. Why don't you consider moving that property to control's vm?
Use an ObservableCollection rather.
ObservableCollection<myModel> myOC = new ObservableCollection<myModel>();
where myModel is a class that has to be constructed transforming your columns in the DataTable to Properties.
In your MainViewModel, loop through the DataReader and create myOC out of it.
Now bind myOC to a ListView in your page.
The DataTemplate of ListView should be a view(UserControl) drawing data from a ViewModel constructed out of myModel
But your UserControl has the entire ListView inside. If that is on purpose, then let me know the entire design to give a better idea.

MVVM scenario with main window and many user controls

I have a main window and many user controls that I want to show/hide depending on the user choice. For example there is a user control called Customer that should get all the customers from a database or a user control that is a form to sign up for a service. And so on. Each of this controls have viewmodel that should get the data from the database. The problem is I don't know hot to set the data context in the right way. My model is an ado.net entity data model for simplicity purposes.
I tried:
<UserControl.DataContext>
<vm:CustomerViewModel/>
</UserControl.DataContext>
And I'm binding the fields to the model fields but no data are visible. Before I used the methods in MainWindowViewModel and set the viewmodel to a view in App.xaml.cs and called the method:
Views.MainWindow newMainV = new Views.MainWindow();
ViewModels.MainVM mainVM = new ViewModels.MainVM();
mainVM.LoadCustomers();
newMainV.DataContext = mainVM;
newMainV.Show();
But I thought that the main window shoudl have its own viewmodel that would handle commands only and each user control should have its own viewmodel that will get the needed data.
What is wrong with my approach?
Thanks for any help.
In principle there's nothing wrong with setting the DataContext on a UserControl in the manner you've described. So I'd suspect there's something wrong in how your binding is set up, or in how your view model's constructor is working. You should be looking in the Output Window for binding errors and putting a breakpoint in the constructor to see what's actually happening when your UserControl gets instantiated.
You might have a look at the BookLibrary sample application of the WPF Application Framework (WAF).
This MVVM sample application uses Entity Framework data models as well and it is composed of various Views (UserControls).

Should a user control have its own view model?

I have a window made up of several user controls and was wondering whether each user control have its own view model or should the window as a whole have only one view model?
Absolutely, positively
NO
Your UserControls should NOT have ViewModels designed specifically for them. This is, in fact, a code smell. It doesn't break your application immediately, but it will cause you pain as you work with it.
A UserControl is simply an easy way to create a Control using composition. UserControls are still Controls, and therefore should solely be concerned with matters of UI.
When you create a ViewModel for your UserControl, you are either placing business or UI logic there. It is incorrect to use ViewModels to contain UI logic, so if that is your goal, ditch your VM and place the code in that control's codebehind. If you're placing business logic in the UserControl, most likely you are using it to segregate parts of your application rather than to simplify control creation. Controls should be simple and have a single purpose for which they are designed.
When you create a ViewModel for your UserControl, you also break the natural flow of data via the DataContext. This is where you will experience the most pain. To demonstrate, consider this simple example.
We have a ViewModel that contains People, each being an instance of the Person type.
public class ViewModel
{
public IEnumerable<Person> People { get; private set; }
public ViewModel()
{
People = PeopleService.StaticDependenciesSuckToo.GetPeople();
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
To show a list of people in our window is trivial.
<Window x:Class="YoureDoingItWrong.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:YoureDoingItWrong"
Title="Derp">
<Window.DataContext>
<l:ViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type l:Person}">
<l:PersonView />
</DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding People}" />
</Window>
The list automatically picks up the correct item template for the Person and uses the PersonView to display the person's information to the user.
What is PersonView? It is a UserControl that is designed to display the person's information. It's a display control for a person, similarly to how the TextBlock is a display control for text. It is designed to bind against a Person, and as such works smoothly. Note in the window above how the ListView transfers each Person instance to a PersonView where it becomes the DataContext for this subtree of the visual.
<UserControl x:Class="YoureDoingItWrong.PersonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Label>Name</Label>
<TextBlock Text="{Binding Name}" />
<Label>Age</Label>
<TextBlock Text="{Binding Age}" />
</StackPanel>
</UserControl>
For this to work smoothly, the ViewModel of the UserControl must be an instance of the Type it is designed for. When you break this by doing stupid stuff like
public PersonView()
{
InitializeComponent();
this.DataContext = this; // omfg
}
or
public PersonView()
{
InitializeComponent();
this.DataContext = new PersonViewViewModel();
}
you've broken the simplicity of the model. Usually in these instances you end up with abhorrent workarounds, the most common of which is creating a pseudo-DataContext property for what your DataContext should actually be. And now you can't bind one to the other, so you end up with awful hacks like
public partial class PersonView : UserControl
{
public PersonView()
{
InitializeComponent();
var vm = PersonViewViewModel();
// JUST KILL ME NOW, GET IT OVER WITH
vm.PropertyChanged = (o, e) =>
{
if(e.Name == "Age" && MyRealDataContext != null)
MyRealDataContext.Age = vm.PersonAge;
};
this.DataContext = vm;
}
public static readonly DependencyProperty MyRealDataContextProperty =
DependencyProperty.Register(
"MyRealDataContext",
typeof(Person),
typeof(PersonView),
new UIPropertyMetadata());
public Person MyRealDataContext
{
get { return (Person)GetValue(MyRealDataContextProperty); }
set { SetValue(MyRealDataContextProperty, value); }
}
}
You should think of a UserControl as nothing more than a more complex control. Does the TextBox have its own ViewModel? No. You bind your VM's property to the Text property of the control, and the control shows your text in its UI.
MVVM doesn't stand for "No Codebehind". Put your UI logic for your user control in the codebehind. If it is so complex that you need business logic inside the user control, that suggests it is too encompassing. Simplify!
Think of UserControls in MVVM like this--For each model, you have a UserControl, and it is designed to present the data in that model to the user. You can use it anywhere you want to show the user that model. Does it need a button? Expose an ICommand property on your UserControl and let your business logic bind to it. Does your business logic need to know something going on inside? Add a routed event.
Normally, in WPF, if you find yourself asking why it hurts to do something, it's because you shouldn't do it.
This is not a yes or no question. It depends on whether having extra view models affords you better maintainability or testability. There's no point adding view models if it doesn't gain you anything. You'll need to gauge whether the overhead is worth it to your particular use case.
[should] each user control have its own ViewModel or should the window as a whole have only one ViewModel?
Unfortunately, the highest-voted answer to this question is misleading, and based on comments I've exchanged in other questions, providing poor guidance to people trying to learn WPF. That answer replies:
Your UserControls should NOT have ViewModels designed specifically for them.
The problem is, that's not the question that was asked.
I would agree with the general sentiment that when you write a UserControl, the public API of the control should not involve creating also a view model type that is specifically designed to be used for that control. The client code must be able to use whatever view model it wants.
But, that does not preclude the idea that "each user control [might] have its own ViewMomdel". There are at least two obvious scenarios I can think of where the answer to that would be "yes, a view model for each user control":
The user control is part of a data template in an items presenter (e.g. ItemsControl). In this case, the view model will correspond to each individual data element, and there will be a one-to-one correspondence between the view model object and the user control that presents that view model object.In this scenario, the view model object is not "designed specifically for them" (so no contradiction with the questionable answer), but it certainly is the case that each user control has its own view model (making the answer to the actual question "yes, each user control may have its own view model").
The user control's implementation benefits from, or even requires, a view model data structure specifically designed for the user control. This view model data structure would not be exposed to the client code; it's an implementation detail, and as such would be hidden from the client code using the user control. But, that certainly still would be a view model data structure "designed specifically for" that user control.This scenario is clearly not problematic at all, which directly contradicts the claim that "Your UserControls should NOT have ViewModels designed specifically for them."
Now, I don't believe it was ever the intent of the author of that answer to rule out either of these scenarios. But the problem is, people who are trying to learn WPF may not have enough context to recognize the difference, and thus may incorrectly generalize with respect to user controls and view models, based on this emphatic, highly-upvoted, and misleading answer.
It is my hope that by presenting this alternative view point as a point of clarification, and answering the original question in a less narrow-viewed way, those who found this question while learning more about WPF will have better context, and a better idea and when a view model might be implemented specific to a user control and when it should not be.
I would say that each user control should have its own ViewModel, because that would allow you to reuse the ViewModel/UserControl pair in new constellations in the future.
As I understand it, your window is a Composite of user controls, so you can always create a ViewModel that composes all the separate ViewModels for each of the user controls. This will give you the best of both worlds.
I'd be inclined toward a viewmodel.
Bear in mind that all of these patterns are designed to fragment your code to make it more maintainable in the future. Including MVVM. The view has certain responsibilities, so too the viewmodel, so too the model. A fresh developer can come in, can recognise this pattern, will have a better idea where to find and maintain things. Better than if it were a heap of spaghetti.
So, within that, if you have logic which correctly pertains to the usercontrol, which correctly belongs in the vm, then why not?
But there is a caveat here. Bear in mind what a UserControl is. It's something that is a tiny snippet of UI that can be reused from place to place. Your vm should be the same - reusable. The last thing you want to end up with is a vm which behaves one way in one scenario, and a different way in another scenario.
Note, no technology talked. I'm just talking about the logical structure of the pattern.
I guess your application is doing some sort of view composition, so if you make your user controls to have its own view model, you'll have more freedom to embed them in other host windows without changing the window global view model.
As an added bonus, your application will be more suited to evolve to a more architecturally-sound composition model as that provided by Prism or Caliburn frameworks, if the application requirements arise.

Resources