Merged ObservableCollection

Zefo picture Zefo · Apr 22, 2009 · Viewed 10.8k times · Source

I have two ObservableCollections and I need to show them in one ListView control together. For this purpose I created MergedCollection which presents these two collections as one ObservableCollection. This way I can set the ListView.ItemsSource to my merged collection and both collections are listed. Adding works fine but when I try to Remove an item, unhandled exception is shown:

An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationFramework.dll
Additional information: Added item does not appear at given index '2'.

The code of MergedCollection follows:

public class MergedCollection : IEnumerable, INotifyCollectionChanged
{
    ObservableCollection<NetworkNode> nodes;
    ObservableCollection<NodeConnection> connections;

    public MergedCollection(ObservableCollection<NetworkNode> nodes, ObservableCollection<NodeConnection> connections)
    {
        this.nodes = nodes;
        this.connections = connections;

        this.nodes.CollectionChanged += new NotifyCollectionChangedEventHandler(NetworkNodes_CollectionChanged);
        this.connections.CollectionChanged += new NotifyCollectionChangedEventHandler(Connections_CollectionChanged);
    }

    void NetworkNodes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        CollectionChanged(this, e);
    }

    void Connections_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        CollectionChanged(this, e);
    }

    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
        for (int i = 0; i < connections.Count; i++)
        {
            yield return connections[i];
        }

        for (int i = 0; i < nodes.Count; i++)
        {
            yield return nodes[i];
        }
    }

    #endregion

    #region INotifyCollectionChanged Members

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    #endregion
}

Regards

Answer

Kent Boogaart picture Kent Boogaart · Apr 22, 2009

Is there any reason you can't use CompositeCollection?

The reason the exception is being thrown is because you're not translating the indexes of the inner collections to the outer. You're just passing the exact same event args to the outer event (on MergedCollection), which is why WPF doesn't find the items where the index is telling it to find them.

You use a CompositeCollection like so:

<ListBox>
  <ListBox.Resources>
    <CollectionViewSource x:Key="DogCollection" Source="{Binding Dogs}"/>
    <CollectionViewSource x:Key="CatCollection" Source="{Binding Cats}"/>
  </ListBox.Resources>
  <ListBox.ItemsSource>
    <CompositeCollection>
      <CollectionContainer Collection="{Binding Source={StaticResource DogCollection}}"/>
      <CollectionContainer Collection="{Binding Source={StaticResource CatCollection}}"/>
    </CompositeCollection>
   </ListBox.ItemsSource>
   <!-- ... -->
</ListBox>

For details, see this answer.