views:

182

answers:

3

I have a ListBox bound to an observable collection of DiceViewModel. Whenever I click a button to add a new item, the ListBox displays the new item like I expect. Everything so far is working well.

<ListBox
  ItemsSource="{Binding Path=AllDice}"
  DisplayMemberPath="Value"/>

However, I have another button to roll all existing dice. The items already listed in the box don't get updated, and I'm not sure how to enforce this while keeping to the MVVM design pattern.

Also, my DiceViewModel already implements INotifyPropertyChanged.

Any suggestions?

A: 

You need to implement the INotifyCollectionChanged interface on the collection that the items are bound to and then have it fire the CollectionChanged event to indicate that the collection changed.

This will cause a refresh of the entire list.

casperOne
Well, the ObservableCollection that I'm using does implement INotifyCollectionChanged, and the ListBox does add new entries when I add items, but it does not update displayed values when the contents of the underlying item data.
Tim Rupe
+4  A: 

After some more digging around, here's what I've found. The ObservableCollection doesn't automatically register itself with my DiceViewModel's INotifyPropertyChanged event. So any property changes don't get handled.

However, there is a way to do it in the xaml file:

I added this namespace definition to my Window element.

xmlns:vm="clr-namespace:Rolling.ViewModel"

Then I modified my ListBox to use a DataTemplate with a specified DataType:

<ListBox ItemsSource="{Binding Path=AllDice}">
  <ListBox.Resources>
    <DataTemplate DataType="{x:Type vm:DiceViewModel}">
      <TextBlock Text="{Binding Path=Value}"/>
    </DataTemplate>
  </ListBox.Resources>
</ListBox>

With the specified DataType, the ObservableCollection could register itself with my collection items, receive their events, and then fire it's own CollectionChanged event.

I hope this helps some other people with this poorly documented feature.

Tim Rupe
This is probably due to the fact that the default template uses ToString, and you can't watch ToString for changes since it's a method. Nice pickup.
Cameron MacFarland
You know, I went back and did some experiments. I removed all of the DataTemplate stuff and reverted to the original simple code..... And it still works. I'm not really sure why it was failing in the first place. Somewhere in the meantime while searching, I inadvertently fixed my original problem, and thought the content of this post fixed it.
Tim Rupe
A: 

In the case of ObservableCollection INotifyPropertyChanged will only notify on changes to the structure of the collection, generally this is the addition and removal of items. The collection has no knowledge of changes to the properties of an individual item within the collection. Instead that individual item itself is responsible for sending notification of its properties changing.

The reasoning behind this goes back to class responsibility and separation of concerns. Since the DiceViewModel likely has data related rolling a die and the value of its last roll then it would follow that it would send notification when its own properties change.

Richard C. McGuire