Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject views into ItemsControl depending on object type

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!

like image 730
Tommy Jakobsen Avatar asked Feb 02 '26 21:02

Tommy Jakobsen


1 Answers

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}"/>
like image 164
Danny Varod Avatar answered Feb 05 '26 12:02

Danny Varod