开发者

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:

  1. Clear the collection (without raising CollectionChanged)
  2. Add item A to the collection (without raising CollectionChanged)
  3. Raise CollectionChanged event for Clear action performed in step 1 (NotifyCollectionChangedEventArgs.Action = NotifyCollectionChangedAction.Reset)
  4. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜