Example #1
0
 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();
             }
         }
     });
 }
Example #2
0
        // [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();
                }
            }
        }