WPF ListBox displays duplicate items. How to get around?
I have a ListBox with a nested ListBox inside. Both have ObservableCollections as their ItemsSource set with the inner ListBox's collection being a member of the outer one's Objects...
The collections are filled by a BackgroundWorker which gathers data from a we开发者_Go百科bservice. I had to change from ObservableCollection to an AsyncObservableCollection in order to be able to add items from within the worker's code. AsyncObservableCollection code is from here: Have worker thread update ObservableCollection that is bound to a ListCollectionView
My problem is that the inner ListBox keeps to display duplicate items. It seems as if it always duplicates the first item if it decides to duplicate. I have no clue why this happens. With an event listener attached to the CollectionChanged event of the collection I found out that the event is being fired fine once per item.
Do you have any ideas?
Thanks, Stephan
If you bind your ItemsSource to an AsyncObservableCollection, you must using a VistualizingStackPanel to correct this problem :
<ListBox
ItemTemplate="{StaticResource YourItemTemplate}"
ItemsSource="{Binding Path=YourAsyncObservableCollection}"
ScrollViewer.CanContentScroll="False"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
Style="{DynamicResource YourListBoxStyle}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
I had the same issue with my custom INotifyCollectionChanged
collection and a TreeView
the other day. It took my a few hours of debugging to figure out what the main problem was. As I didn't find any information on what causes this kind of behavior on the web, I decided to share my results here.
The root cause of this behavior is that apparently the underlying CollectionView
that is responsible for handling CollectionChanged
events raised by the collection in ItemsControl
controls, does not solely depend on the information provided by the NotifyCollectionChangedEventArgs
instances to update the UI. It also takes the contents of the collection at the time of receiving the notification into account.
Consider performing the following actions to the collection:
- Clear the collection (without raising
CollectionChanged
) - Add item A to the collection (without raising
CollectionChanged
) - Raise
CollectionChanged
event for Clear action performed in step 1 (NotifyCollectionChangedEventArgs.Action = NotifyCollectionChangedAction.Reset
) - Raise
CollectionChanged
event for Add action performed in step 2 (NotifyCollectionChangedEventArgs.Action = NotifyCollectionChangedAction.Add
)
Doing so will make item A appear twice in the UI. The reason is that when the CollectionView
receives the first CollectionChanged
notification (step 3), it doesn't care if the Action
of the event args is Reset
, it looks at the collection and sees there is one item in the collection. So it adds the item to the control. Then when it receives the second notification (step 4), it thinks a new item has been added to the collection and adds the item again to the control!
I'm not sure if this behavior is expected or not, but it's there.
I found out that the AsyncObservableCollection caused the problems. Obviously it messed up with some events or whatever. I ended up in adding items to the collection in the worker's ProgressChanged method.
精彩评论