I have a service returning an array of type Party. Party has two subtypes, Person and Organization. I’m consuming this service in my WPF application (Prism, MVVM) from a view model. In the constructor of this view model I populate an observable collection of type Party:
public PhoneBookViewModel(IPhoneBookService phoneBookProxy)
{
_phoneBookProxy = phoneBookProxy;
var parties = _phoneBookProxy.GetAllParties();
_parties = new ObservableCollection<Party>(parties.ToList());
}
So far so good. In my PhoneBookView I have an ItemsControl that binds to this collection. In this control I want to render each Party by using another View (and its view model). So when Party is of type Person, inject PersonView and pass the Party object to the constructor of the PersonViewModel, and when Party is of type Organization, render OrganizationView, and so on... You get the picture (or?).
But I can't figure out how to do this in XAML. Any ideas? This is probaly not the best way of doing it, so if you can recommend a better approach, please enlighten me :-)
Thanks!
Lets examine this from the view towards the model:
Lets assume we have 2 different types of views, 1 type of view model:
ViewA --> Created within an items control using DataTempate/DataTemplateSelector, Binded > to ViewModelA
ViewB --> Created within an items control using DataTempate/DataTemplateSelector, Binded to ViewModelA
If both views are binded to the same view model, you would end up with the same view.
Lets try again with 2 different types of views and 2 different types of view models:
ViewA --> Created within an items control using DataTempate/DataTemplateSelector, Binded to ViewModelA --> Binded to ModelA
ViewB --> Created within an items control using DataTempate/DataTemplateSelector, Binded to ViewModelB --> Binded to ModelB
This IS possible.
Now if you model your view-models and models like this (pseudo code):
public PhoneBookViewModel
{
public PhoneBookViewModel()
{
_parties = new ObservalbeCollection<PartyViewModel>();
}
private PhoneBook _dataContext;
// This is the property the VM uses to access the model
public PhoneBook DataContext
{
get { return _dataContext; }
set
{
if (_dataContext != null)
{
_dataContext.Parties.CollectionChanged -= OnModelPartiesChanged;
}
_dataContext = value;
if (_dataContext != null)
{
_dataContext.Parties.CollectionChanged += OnModelPartiesChanged;
}
}
}
private ObservableCollection<PartyViewModel> _parties;
// This is the property the view uses to access the collection of VM parties
public ObservableCollection<PartyViewModel> PartiesViewModels { get { return _parties; } }
private void OnModelPartiesChanged(...)
{
// Add/remove VMs to/from PartiesViewModels here
}
}
// Model
public PhoneBook
{
public PhoneBook()
{
_parties = new ObservalbeCollection<Party>();
}
private ObservableCollection<Party> _parties;
// This is the property the VM uses to access the model's parties
public ObservableCollection<Party> Parties { get { return _parties; } }
}
public PersonViewModel : PartyViewModel
{
new Person DataContext { get; set; }
}
public PartyViewModel
{
public Party DataContext { get; set; }
}
then you will get correct type of VMs for each model item, view will be binded to VM items, not model items.
View's datatemplates:
<DataTemplate x:Target={x:Type myVmNamespace:PersonViewModel}">
<PersonView/>
</DataTemplate>
<DataTemplate x:Target={x:Type myVmNamespace:GroupViewModel}">
<GroupView/>
</DataTemplate>
View's itemscontrol:
<!-- Bind to Parties property of PhoneBookVM -->
<!-- Uses datatemplates for items -->
<ListView ItemsSource={Binding Parties}"/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With