Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merged ObservableCollection

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

like image 924
Zefo Avatar asked Apr 22 '09 12:04

Zefo


2 Answers

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.

like image 179
Kent Boogaart Avatar answered Nov 05 '22 17:11

Kent Boogaart


You have to offset the index of the notification event.

Say you remove an item from the first collection at index 2. A collection changed event is fired with index 2.

If you remove an item from the second collection at index 2, the event is fired with the same index (2), but the item is actually enumerated after all of the items in the first collection.

like image 4
Josh G Avatar answered Nov 05 '22 19:11

Josh G