5

I am working with a 2 lists in a backend class. Each list is a different type. Would like to present the user with a single list (containing a union of both lists) of which when an item in this list is selected the item's details appear.

The code will look something like:

My backend class looks somethings like this

public ObservableCollection<Person> People {get;}
public ObservableCollection<Product> Products {get;}

My XAML Looks Something Like This

<ListBox x:Name="TheListBox" ItemsSource={Some Expression to merge People and Products}>
   <ListBox.Resources>
         People and Product Data Templates
   </ListBox.Resources>
</ListBox>
      ...
<ContentControl Content={Binding ElementName=TheListBox, Path=SelectedItem }>
   <ContentControl.Resources>
         Data Templates for showing People and Product details
   </ContentControl.Resources>
</ContentControl>

Any suggestions?

Gus
  • 649
  • 5
  • 14
  • I'm looking for something similar which I can use directly from markup and which does not pollute my view model interface. It should basically resolve the mismatch between items provided by the view model, which might be multiple collections or just a few independent properties and what WPF expects, which is a single enumerable. Ideally I'd even like to add items directly in markup which doesn't even correspond to anything in the view model, but merged into the same list. – Christo Feb 14 '11 at 07:26

3 Answers3

10

You can use a CompositeCollection for this. Have a look at this question.

Community
  • 1
  • 1
Christo
  • 1,802
  • 4
  • 20
  • 31
2

I don't understand why you don't just have expose a property like this in your ViewModel:

ObservableCollection<object> Items 
{
  get 
  {
    var list = new ObservableCollection<object>(People);
    list.Add(Product);
    return list;
  }
}

and then in your xaml you do this:

<ListBox x:Name="TheListBox" ItemsSource={Binding Items}>
   <ListBox.Resources>
         People and Product Data Templates
   </ListBox.Resources>
</ListBox>
      ...
<ContentControl Content={Binding ElementName=TheListBox, Path=SelectedItem }>
   <ContentControl.Resources>
         Data Templates for showing People and Product details
   </ContentControl.Resources>
</ContentControl>

UPDATE:

If you need to manipulate your model differently do the following:

ObservableCollection<object> _Items 
ObservableCollection<object> Items 
{
  get 
  {
    if (_Items == null)
    {
      _Items = new ObservableCollection<object>();
      _Items.CollectionChanged += EventHandler(Changed);
    }
    return _Items;
  }
  set 
  { 
    _Items = value;
    _Items.CollectionChanged += new CollectionChangedEventHandler(Changed);
  }
}

void Changed(object sender,CollectionChangedEventArgs e)
{
  foreach(var item in e.NewValues)
  {
    if (item is Person)
      Persons.Add((Person)item);
    else if (item is Product)
      Products.Add((Product)item);
  }
}

This is just an example. But if you modify the above to meet your needs, it might get you to your goal

Jose
  • 10,891
  • 19
  • 67
  • 89
  • I considered doing it in a way similar to what you proposed. What complicated my scenario was that I needed to have a way to add and remove items from the lists through the UI. – Gus Jul 21 '10 at 15:53
0

I found a blog post here that got me most of the way. I used the authors AggregateCollection along with a multivalueconverter to get the job done.

Gus
  • 649
  • 5
  • 14