void HandleListCountChanged(object sender, PropertyChangedEventArgs e) { Device.BeginInvokeOnMainThread(() => { if (e.PropertyName == "Count") { var nodeView = ChildTreeNodeViews.Where(nv => nv.BindingContext == sender).FirstOrDefault(); if (nodeView != null) { nodeView.BuildVisualChildren(); } } }); }
// [recursive down] create item template instances, attach and layout, and set descendents until finding overrides protected void BuildVisualChildren() { var bindingContextNode = (ITreeNode)BindingContext; if (bindingContextNode == null) { return; } // STEP 1: remove child visual tree nodes (TreeNodeViews) that don't correspond to an item in our data source var nodeViewsToRemove = new List <TreeNodeView>(); var bindingChildList = new List <ITreeNode>(bindingContextNode != null ? bindingContextNode.ChildNodes : null); // which ChildTreeNodeViews are in the visual tree... ? foreach (TreeNodeView nodeView in ChildTreeNodeViews) { // but missing from the bound data source? if (!bindingChildList.Contains(nodeView.BindingContext)) { // tag them for removal from the visual tree nodeViewsToRemove.Add(nodeView); } } BatchBegin(); try { // perform removal in a batch foreach (TreeNodeView nodeView in nodeViewsToRemove) { MainLayoutGrid.Children.Remove(nodeView); } } finally { // ensure we commit BatchCommit(); } // STEP 2: add visual tree nodes (TreeNodeViews) for children of the binding context not already associated with a TreeNodeView if (NodeCreationFactory != null) { var nodeViewsToAdd = new Dictionary <TreeNodeView, ITreeNode>(); foreach (ITreeNode node in bindingContextNode.ChildNodes) { if (!ChildTreeNodeViews.Any(nodeView => nodeView.BindingContext == node)) { var nodeView = NodeCreationFactory.Invoke(); nodeView.ParentTreeNodeView = this; if (HeaderCreationFactory != null) { nodeView.HeaderContent = HeaderCreationFactory.Invoke(); } // the order of these may be critical nodeViewsToAdd.Add(nodeView, node); } } BatchBegin(); try { // perform the additions in a batch foreach (KeyValuePair <TreeNodeView, ITreeNode> nodeView in nodeViewsToAdd) { // only set BindingContext after the node has Parent != null nodeView.Key.BindingContext = nodeView.Value; nodeView.Value.ExpandAction = () => nodeView.Key.BuildVisualChildren(); nodeView.Key.ChildrenStackLayout.IsVisible = nodeView.Key.IsExpanded; ChildrenStackLayout.Children.Add(nodeView.Key); ChildrenStackLayout.SetBinding(StackLayout.IsVisibleProperty, new Binding("IsExpanded", BindingMode.TwoWay)); // TODO: make sure to unsubscribe elsewhere nodeView.Value.PropertyChanged += HandleListCountChanged; } } finally { // ensure we commit BatchCommit(); } } }