Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VisualCollection throwing out of range exception, bound to Observable collection

So I've got an observable collection bound into an ItemsControl.

When I add items to the collection I get an exception of index out of range from the Visual collection.

<ItemsControl x:Name="ReportPages" ItemsSource="{Binding History}" DockPanel.Dock="Top">
    <ItemsControl.Template>
        <ControlTemplate TargetType="ItemsControl">
            <ItemsPresenter HorizontalAlignment="Center"/>
        </ControlTemplate>
    </ItemsControl.Template>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ItemsControl ItemsSource="{Binding ChildWindows}">
                <ItemsControl.Template>
                    <ControlTemplate TargetType="ItemsControl">
                        <Grid Margin="0,10,0,10" >
                            <ItemsPresenter />
                            <Border x:Name="ResizeFrame" BorderThickness="4" BorderBrush="LightBlue"  Visibility="{Binding Active, Converter={StaticResource BooleanToVisibilityConverter}}"/>
                        </Grid>
                    </ControlTemplate>
                </ItemsControl.Template>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas x:Name="LayoutCanvas" Background="white" ClipToBounds="true"
                    MouseDown="History_MouseLeftButtonDown" PreviewMouseDown="ClosePanels"
                    Width="{Binding PageSizeProp.PageWidth}" Height="{Binding PageSizeProp.PageHeight}"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

The inner ChildWindows is the collection I'm adding items to. One think of note is that ChildWindows is a ReadOnlyObservableCollection, I'm adding via a method that has access to the Collection it is based on.

I'm at a total loss for why this is happening (and only some times).

edit: here is the actual stack trace

at System.Windows.Media.VisualCollection.Insert(Int32 index, Visual visual)
   at System.Windows.Controls.Panel.addChildren(GeneratorPosition pos, Int32 itemCount)
   at System.Windows.Controls.Panel.OnItemsChangedInternal(Object sender, ItemsChangedEventArgs args)
   at System.Windows.Controls.Panel.OnItemsChanged(Object sender, ItemsChangedEventArgs args)
   at System.Windows.Controls.ItemContainerGenerator.OnItemAdded(Object item, Int32 index)
   at System.Windows.Controls.ItemContainerGenerator.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
   at System.Windows.Controls.ItemContainerGenerator.System.Windows.IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e)
   at System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list)
   at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args)
   at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
   at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
   at System.Windows.Controls.ItemCollection.System.Windows.IWeakEventListener.ReceiveWeakEvent(Type managerType, Object sender, EventArgs e)
   at System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list)
   at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args)
   at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
   at System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
   at System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32 adjustedOldIndex, Int32 adjustedNewIndex)
   at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)
   at System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
   at System.Collections.ObjectModel.ReadOnlyObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
   at System.Collections.ObjectModel.ReadOnlyObservableCollection`1.HandleCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item)
   at System.Collections.ObjectModel.Collection`1.Add(T item)
   at CalManv4UI.DataHistoryReportPageBase.AddNewChart(ChildWindowSaved cws, Boolean activate) in C:\Users\Joel Barsotti\Documents\Visual Studio 2010\Projects\CalMAN V4\CalMANv4-WPF\CalManv4UI\Workflow\DataHistoryReportPageBase.cs:line 72
like image 640
Joel Barsotti Avatar asked Jan 08 '11 01:01

Joel Barsotti


1 Answers

I had the same problem and my understanding of it
(credits to https://stackoverflow.com/users/249723/vivien-ruiz for the link)
is simply that you are "bound" to have problems if you modify an ObservableCollection which takes part in an ItemSource binding. I found that inserting at index 0 "solves" my problem, but it could still crash.
It shouldn't be modified because it isn't a thread-safe class.
A better solution is to act on a copy of the list and assign the copy to the bounded collecion once the operation is completed.
For example: ObservableCollection<ListViewItem> newList = new ObservableCollection<ListViewItem>(mCurrentList); ... ListViewItem item = new ListViewItem(); item.Content = image; newList.Add(item); ... mPictures = newList;

like image 69
Rubarb Avatar answered Sep 21 '22 19:09

Rubarb