views:

163

answers:

2

I'm binding an ItemsControl to an EntitySet in a WPF application. Its not acting as expected, however. The ItemsControl is behaving as if it is caching the contents of the EntitySet between binds!

Here's the stripped down code:

The entity:

public partial class Item : INotifyPropertyChanging, INotifyPropertyChanged
{
    private EntitySet<Item> _Children;
    public EntitySet<Item> Children {get{return _children;}}
    /*...*/    
}

My partial class:

public partial class Item
{
    public void RemoveChild(Item child)
    {
        Children.Remove(child);
        // this finds PropertyChanged; defined in the Entity class
        SendPropertyChanged("Children");
    }
}

The UI:

<ItemsControl
    Name="ItemChildren"
    Background="CornflowerBlue"
    ItemsSource="{Binding Children}">
    <ItemsControl.ItemTemplate>
        <DataTemplate
            DataType="{x:Type d:Item}">
            <DockPanel>
                <TextBlock
                    Text="{Binding Name}/>
            </DockPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Code that demonstrates the behavior (assume >2 Items, each having a single child):

this.ScrewyItem = Db.Items.First();
this.DataContext = ScrewyItem;
return;

Later, I remove the child from the entity:

ScrewyItem.RemoveChild(ScrewyItem.Children.First());
return;

After this code runs, the UI does not update and the Item is shown to have all children. Notice that this method calls NotifyPropertyChanged, so the bindings should update!

Later, we remove this item from the UI bindings:

this.DataContext = Db.Items.Last(); //different item
return;

And then bind it to the UI again later

this.DataContext = ScrewyItem;

You would assume that AT LEAST at this point the UI would show the correct child list. This is not the case, however! It shows the same list of children as originally shown!

What's even more bizarre, if I put a breakpoint on my Children accessor, I can see that the list is accessed when I rebind to the UI and the list does not contain the child I removed.

The only way I can see that the UI could be doing this is if the contents of the Children collection are cached between binds.

What is going on here? What am I missing???

A: 

I have found a solution for this. It kind of sucks.

I can wrap the Children collection in a BindingList:

public IBindingList BindableChildren
{
    get
    {
        return new BindingList<Item>(Children);
    }
}

and then modify my RemoveChild method thusly:

this.Children.Remove(arg);
SendPropertyChanged("BindableChildren");

This results in the UI updating the list immediately and stops exhibiting the caching behavior.

The question still remans: WTF? and Is there another way?

Will
A: 

I'm not sure about this, but perhaps the ItemsControl is listening for events from IBindingList or INotifyCollectionChanged and not INotifyPropertyChanged.

Martin Liversage
Bindings don't cache values, do they?
Will
No, I'm pretty sure that the behavior you see is not a result of caching but a result of binding not wokring, that is updates to your data is not seen by the control.
Martin Liversage