Silverlight TreeView not updating when LinqObservableCollection changes

Silverlight TreeView not updating when LinqObservableCollection changes

Old forum URL: forums.lhotka.net/forums/t/10635.aspx


richardp posted on Wednesday, August 24, 2011

Hi, we are developing a silverlight 3 tier app using CSLA 4.1.0. We have been working on it for about 3 months now and have found CSLA to be a great help.

I have a problem with LinqObservableCollection.

I have a business object class that inherits BusinessBase, called MetadataGroupTreeNode.

I have a list of these objects in a class that inherits BusinessListBase, called MetadataGroupTreeNodeList.

Now each MetadataGroupTreeNode object has a child property, (called Children) of type MetadataItemTreeNodeList, which inherits from BusinessListBase.

This list consists of MetadataItemTreeNodeItem, which inherits from BusinessBase.

We want the list of MetadataItemTreeNodeList to be sorted on an int property of MetadataItemTreeNodeItem, called Sequence.

To achieve this we use a wrapper property called SortedChildren wich returns a LinqObservableCollection.

This is all displayed in a TreeView control in Silverlight, via data binding, and is working well.

 

/// <summary>

/// class for displaying a metadata node a tree

/// </summary>

[Serializable]

public partial class MetadataGroupTreeNode : BusinessBase<MetadataGroupTreeNode>

{

 

private static PropertyInfo<MetadataItemTreeNodeList> ChildrenProperty = RegisterProperty<MetadataItemTreeNodeList>(mtn => mtn.Children);

private MetadataItemTreeNodeList Children

{

get { return GetProperty(ChildrenProperty); }

private set { SetProperty(ChildrenProperty, value); }

}

 

public LinqObservableCollection<MetadataItemTreeNode> SortedChildren

{

get

LinqObservableCollection<MetadataItemTreeNode> sortedChildren= Children.ToSyncList(from child in Children orderby child.Sequence select child);

return sortedChildren;

}

}

}

 

 

The Silverlight TreeView HeirarchicalDataTemplate binds to the SortedChildrenProperty.

The parent tree nodes and child nodes are all displayed correctly.

The problem is, we want the user to be able to change to display order of the SortedChildren by modifying the Sequence property on the MetadataItemTreeNodeItem object.

The Sequence property is modified via a context menu in the tree (Move Up, Move Down).

The Sequence property is modified, and the SortedChildren property seems to return the children in the new required order.

However the Silverlight TreeView doesn't update.

 

Should I modify the Sequence property on the items in the Children collection, or the items in the SortedChildrem collection, or doesn't it matter?

How to I get the Silverlight TreeView databinding to notice that the order of items in the SortedChildren list has changed?

 

Any help greatly appreciated.

 

Regards Richard.

RockfordLhotka replied on Thursday, August 25, 2011

The TreeView should be listening for the CollectionChanged event from its binding source (the LinqObservableCollection (LOC)).

The LOC usually raises this event because the real list (the BLB) raises the event, but it can raise it when changes are made to the LOC too.

My guess though, is that this event isn't being raised when the Sequence property is changed on the child objects. Just changing a property of a child object in a collection doesn't trigger CollectionChanged - because the collection didn't really change, only the child object changed.

In your BLB, you might handle ChildChanged so you are notified when a child has been changed. If the change was to the Sequence number, you could then raise CollectionChanged (call OnCollectionChanged), and that should echo through the LOC to data binding.

richardp replied on Saturday, August 27, 2011

Thanks heaps Rocky.

That fixed it.

I included the code change below. 

 

protected override void OnDeserialized()

{

base.OnDeserialized();

this.ChildChanged +=MetadataGroupTreeNodeList_ChildChanged;

}

 

private void MetadataGroupTreeNodeList_ChildChanged(object sender, ChildChangedEventArgs e)

{

var child = e.ChildObject as MetadataItemTreeNode;

if (child != null)

{

if (e.PropertyChangedArgs.PropertyName == "Sequence")

{

this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

}

}

}

Copyright (c) Marimer LLC