Hello!I used the CustomXamDataTree obtained from http://ko.infragistics.com/community/forums/p/58081/296039.aspx#296039(BindingSelectedNode.zip)
This allows me to programmatically select the to-be-selected (active) node in my view-model, and, through data-binding, get the appropriate node in the XamDataTree activated. That works.
However, with data-sets of even a few thousand lines, scrolling becomes ridiculously slow.It seems to be spending much of its time in the FindCorrespondingNode() method, which matches the value object, really my view-model object,with the appropriate node in the XamDataTree, so that it can be selected.This is a recursive method, which check the current node for a match and if one is not found, its children are checked.
Something is going on here in this method! It recurses based on your data-structure "XamDataTreeNodesCollection".Why is it so very slow? What is the data-structure used there? A Map? A List? Just the tree structure itself?
Many thanks,Mark
P.S. The call in "OnPropertyChangedCallback()" to "FindCorrespondingNode()" in my opinion only needs to be called when the user DID NOT click on a graphical tree-node item, but rather only when the View-Model SelectedItem (bound property) is programatically selected. Can you please confirm?
Here is a copy of the code posted in the above-mentioned link:
namespace GraphicalTree{ public class CustomXamDataTree : XamDataTree { private static XamDataTreeNodesCollection nodes; private static bool mMouseLeftButtonDownOrKeyDownCame; public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register( "SelectedItem", typeof(object), typeof(CustomXamDataTree), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnPropertyChangedCallback))); public CustomXamDataTree() { base.ActiveNodeChanged += new EventHandler<ActiveNodeChangedEventArgs>(CustXamDataTree_ActiveNodeChanged); nodes = Nodes; } public static void OnPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { FindCorrespondingNode(nodes, e.NewValue); } void CustXamDataTree_ActiveNodeChanged(object sender, ActiveNodeChangedEventArgs e) { if (e.NewActiveTreeNode != null) SelectedItem = e.NewActiveTreeNode.Data; } public object SelectedItem { get { return (object)GetValue(SelectedItemsProperty); } set { SetValue(SelectedItemsProperty, value); } } private static void FindCorrespondingNode(XamDataTreeNodesCollection nodes, object value) { foreach (XamDataTreeNode node in nodes) { if (node.Data.Equals(value)) { node.IsActive = true; node.IsSelected = true; return; } if (node.HasChildren) { FindCorrespondingNode(node.Nodes, value); } } } }}
Hello Mark,
As I said it is expected for this method to be slow, becasue there could be a lot of recursive calls. I can log a product idea on your behalf, so either the type of XamDataTreeNodesCollection could be changed or a functioanlity for binding the ActiveDataItem could be added.
Looking forward for your reply.
Hi Again!I profiled a sample application that uses the CustomXamDataTree and 10,000 nodes, with dotTrace. The App's output is in the attached file "App.png".
I started the profiler. I then clicked on the element shown in "First Click was here" in the graphic.After the initial delay, I then clicked on the element shown in "Second Click was here" in the graphic.Two clicks, that's all! And, as you can see, I am clicking very high up in the tree!I started measuring AFTER the first click was fully completed so that the only thing measured was what happens when I click the second time. Just a few seconds of "action" in the XamDataTree was all I measured.The output of the profiling is in attachment "profiling_1.png".
I think your forum service only allows the attachment of one single file so the App.png is not included!But basically, I clicked on approx. the fifth viewable element, then the tenth element. I've pasted the screen-shot of "App.png" here but I don't know if you receive it.Please examine the profiler output. As you can see, your method FindCorrespondingNode() is making literally tens of thousands of calls to "HasChildren", "ChildNodesManager", "FullNodeCount", "Visibility", "DataCount", "Count", etc.
All this is simply killing the performance, and all I did was click from one element to another.
Could you please advise me about this, or my previous post?That would be much appreciated.
Kindest Regards,Mark Horowitz
So am I to understand that because XamDataTreeNodesCollection is based on CollectionBase that I cannot use XamDataTree if I must
- bind to the selected node, and select it programatically in my view-model in addition to selecting it in the view with the cursor or mouse- have a medium sized data set of say 5000 - 200,000 lines
that I cannot use your component?That is somewhat hard to believe.
I need an alternative way to select the correct view-item in method "FindCorrespondingNode()" based on the "value" parameter.
Can you think of no alternative? Is there no other way to organise the collection returned by XamDataTree::Nodes()so that random access via the "value" parameter, which is just a reference to my view-model object, is quick and efficient?
Essentially a simple map would do, mapping the <view-model-object-reference> to the <view-item-reference>so that I could, in method "FindCorrespondingNode()", write the following:
private static void FindCorrespondingNode(XamDataTreeNodesCollection nodes, object value) { var node = nodes.GetNode(value); node.IsActive = true; node.IsSelected = true; }
I would create the map myself but I cannot because the reference returned by XamDataTree::Nodes() is never updated.I.e., I could get the nodes in the constructor, and build my own map structure, and use it upon selection.However, if the view-model changes out the tree, which happens often in our app (select a different data-set to display), I would get no notification of that so as to re-build my map.
Cheers,
Mark
Thank you for your post. I have been looking into it and I can say that the XamDataTreeNodesCollection that is iterating in the FindCorespondingNode method is inheriting from CollectionBase class. Here you can find more information about it:
http://msdn.microsoft.com/en-us/library/system.collections.collectionbase.aspx
Also I can say that it is expected to have slow performance when you have a large data-sets and you try to select an object from the end of the collection. I can suggest you use “for” loop, instead of “foreach”, because in the foreach a new instance is created for every item in the collection.
Hope this helps you.