I'm getting a little confused about how to layout my code in MVVM - if I have a UserControl with a corresponding VM class, how should other controls consume my UserControl?
Should consumers bind directly to the VM or should I duplicate only a subset of these properties I want to actually be used as DependencyProperties of the UserControl?
For that matter, should the UserControl's VM be injected into the UserControl's code-behind or should the VM of any control that uses this UserControl contain it as a dependency and bind it to the UserControl instead?
Just to make it clear: Suppose I have a ListBox in a UserControl and use it in a Window that is already implemented with MVVM. But I'm confused about the implementation of the UserControl VM and the corresponding bindings.
I would think the ideal solution would be to expose the SelectedItems of the ListBox via dependency properties in the UserControl, and then the Window which uses the UserControl would bind to these.
Or should the Window's VM have a reference to the VM as a property, have it injected and bind directly to the properties on that instead?
Should dependency properties only be defined in UserControls or can / should they be defined in the VM?
I'm thinking the Window would bind, from within the XAML of the Window, either via
{Binding ElementName=myUserControl, Path=SelectedItems}
or
{Binding Path=MyViewModel.SelectedItems}
It just seems to make more sense to do it via the former, since the latter requires that the View knows about another VM?
> how should other controls consume my UserControl?
Via exposed dependancy properties on the usercontrol only.
>Should consumers bind directly to the VM or should I duplicate only a subset of these properties I want to actually be used as DependencyProperties of the UserControl?
Each control should be a stand alone entity, there shouldn't be any secret handshake (either to or from) to use the control. Think of the design like you are Microsoft and many different users will use your controls. So answer #1 is just as relevant; think a stand alone entity.
>I would think the ideal solution would be to expose the SelectedItems of the ListBox via dependency properties in the UserControl, and then the Window which uses the UserControl would bind to these.
The window which hosts your controls will have a View Model which contains a Observable list of data items. That will hold the data which the user control(s) will bind via their dependency properties. THink of it as a producer pattern with many consumers. The consumers are the controls. Whether the controls have VMs or not is immaterial to the running of the main program; for each control is its own island.
Keep in mind when working with WPF and MVVM that your View
layer is merely a user-friendly way of drawing your Models
and ViewModels
, and that your View
is not actually your application. Your View
actually has to know the basics about your data layer so it can define how to draw it.
So if your application needs to display a list of Items
and maintain a SelectedItem
, than that should be in your ViewModel or Model somewhere, not in the actual View layer.
Typically for me UserControls are one of two things:
Either a standalone UserControl
that can be used anywhere without a specific DataContext
, and that expose DependencyProperties
for any control-specific values. Examples are things like a Calendar
control or a Popup
control
<local:MyUserControl Items="{Binding SomeItemList}"
SelectedItem="{Binding SomeItem}" />
Or they are a UserControl
that is meant to be used with a specific ViewModel
only. This is far more common for me. The ViewModel is a property somewhere in the data layer, and I usually have an implicit DataTemplate
in the application somewhere to tell WPF to use that UserControl
anytime it needs to render that specific ViewModel
<DataTemplate DataType="{x:Type local:SomeViewModel}">
<local:MyUserControl />
</DataTemplate>
<ContentPresenter Content="{Binding SomeViewModelProperty}" />
Also, at no time should you set the DataContext
of a UserControl
from inside the UserControl
itself, because the UI layer is only meant to be a UI representation of your data layer (your Models
/ViewModels
), and by setting the data layer from inside the UserControl
you are making it so that the UserControl
cannot be used to draw any other data object.