void DoTest(string tree1, string tree2, string expected) { var edits = TreeEdit.GetTreeEdits(new TestNode(tree1), new TestNode(tree2)); var actual = string.Join("; ", edits); Assert.AreEqual(expected, actual); }
void UpdateStructure(ITreeNode newRoot) { void Rebind(NSNodeItem item, ITreeNode newNode) { nodeToItem.Remove(item.Node); item.Node = newNode; nodeToItem[newNode] = item; } void DeleteDescendantsFromMap(NSNodeItem item) { item.Children.ForEach(c => { Debug.Assert(nodeToItem.Remove(c.Node)); DeleteDescendantsFromMap(c); }); } var edits = TreeEdit.GetTreeEdits(rootItem.Node, newRoot); Rebind(rootItem, newRoot); foreach (var e in edits) { var node = nodeToItem[e.Node]; switch (e.Type) { case TreeEdit.EditType.Insert: var insertedNode = CreateItem(e.NewChild); node.Children.Insert(e.ChildIndex, insertedNode); treeView.InsertItems(new NSIndexSet(e.ChildIndex), ToObject(node), NSTableViewAnimation.None); break; case TreeEdit.EditType.Delete: var deletedNode = node.Children[e.ChildIndex]; node.Children.RemoveAt(e.ChildIndex); Debug.Assert(deletedNode == nodeToItem[e.OldChild]); nodeToItem.Remove(e.OldChild); treeView.RemoveItems(new NSIndexSet(e.ChildIndex), ToObject(node), NSTableViewAnimation.None); DeleteDescendantsFromMap(deletedNode); break; case TreeEdit.EditType.Reuse: treeView.ReloadItem(ToObject(node)); Rebind(nodeToItem[e.OldChild], e.NewChild); break; case TreeEdit.EditType.Expand: treeView.ExpandItem(ToObject(node), expandChildren: false); break; case TreeEdit.EditType.Collapse: treeView.CollapseItem(ToObject(node), collapseChildren: false); break; } } }
void UpdateStructure(ITreeNode newRoot) { void Rebind(NSNodeItem item, ITreeNode newNode) { nodeToItem.Remove(item.Node); item.Node = newNode; nodeToItem[newNode] = item; } void DeleteDescendantsFromMap(NSNodeItem item) { item.Children.ForEach(c => { Debug.Assert(nodeToItem.Remove(c.Node)); DeleteDescendantsFromMap(c); }); } var edits = TreeEdit.GetTreeEdits(rootItem.Node, newRoot, new TreeEdit.Options { TemporariltyExpandParentToInitChildren = true }); Rebind(rootItem, newRoot); foreach (var e in edits) { var node = nodeToItem[e.Node]; switch (e.Type) { case TreeEdit.EditType.Insert: var insertedNode = CreateItem(e.NewChild); node.Children.Insert(e.ChildIndex, insertedNode); using (var set = new NSIndexSet(e.ChildIndex)) treeView.InsertItems(set, ToObject(node), NSTableViewAnimation.None); break; case TreeEdit.EditType.Delete: var deletedNode = node.Children[e.ChildIndex]; node.Children.RemoveAt(e.ChildIndex); Debug.Assert(deletedNode == nodeToItem[e.OldChild]); nodeToItem.Remove(e.OldChild); using (var set = new NSIndexSet(e.ChildIndex)) treeView.RemoveItems(set, ToObject(node), NSTableViewAnimation.None); DeleteDescendantsFromMap(deletedNode); break; case TreeEdit.EditType.Reuse: var viewItem = nodeToItem [e.OldChild]; Rebind(viewItem, e.NewChild); treeView.ReloadItem(ToObject(viewItem), reloadChildren: false); if (owner.OnUpdateRowView != null) { var rowIdx = treeView.RowForItem(ToObject(viewItem)); var rowView = rowIdx >= 0 ? treeView.GetRowView(rowIdx, makeIfNecessary: false) : null; if (rowView != null) { owner.OnUpdateRowView(rowView, (Node)e.NewChild); } } break; case TreeEdit.EditType.Expand: treeView.ExpandItem(ToObject(node), expandChildren: false); break; case TreeEdit.EditType.Collapse: treeView.CollapseItem(ToObject(node), collapseChildren: false); break; } } }
public void Update(Node newRoot) { var finalizeActions = new List <Action>(); bool updateBegun = false; Action beginUpdate = () => { if (!updateBegun) { // Call ListView's BeginUpdate/EndUpdate only when needed // tree structure changed to avoid flickering when only selection changes. treeView.BeginUpdate(); updateBegun = true; } }; updating = true; try { var edits = TreeEdit.GetTreeEdits(currentRoot, newRoot); currentRoot = newRoot; foreach (var e in edits) { TreeNode node = e.Node == newRoot ? null : nodeToViewNodes[e.Node]; TreeNodeCollection nodeChildren = e.Node == newRoot ? treeView.Nodes : node.Nodes; switch (e.Type) { case TreeEdit.EditType.Insert: beginUpdate(); var insertedNode = CreateViewNode((Node)e.NewChild); nodeChildren.Insert(e.ChildIndex, insertedNode); break; case TreeEdit.EditType.Delete: beginUpdate(); var deletedNode = nodeChildren[e.ChildIndex]; nodeChildren.RemoveAt(e.ChildIndex); Debug.Assert(deletedNode == nodeToViewNodes[e.OldChild]); nodeToViewNodes.Remove(e.OldChild); DeleteDescendantsFromMap(deletedNode); break; case TreeEdit.EditType.Reuse: var nodeToReuse = nodeToViewNodes[e.OldChild]; Rebind(nodeToReuse, (Node)e.NewChild); UpdateViewNode(nodeToReuse, (Node)e.NewChild, (Node)e.OldChild, beginUpdate); break; case TreeEdit.EditType.Expand: finalizeActions.Add(node.Expand); break; case TreeEdit.EditType.Collapse: finalizeActions.Add(() => node.Collapse(ignoreChildren: true)); break; case TreeEdit.EditType.Select: treeView.SelectNode(node); break; case TreeEdit.EditType.Deselect: treeView.DeselectNode(node); break; } } } finally { if (updateBegun) { treeView.EndUpdate(); } finalizeActions.ForEach(a => a()); if (treeView.SelectedNode is ViewNode selected && !selected.Node.IsSelected) { // When no nodes are explicitly selected, the OS selects one for us, // and we have to undo that. // Another scenario is that a node that was optimistically allowed to be selected in BeforeSelect // turned out not be selected. treeView.SelectedNode = null; } updating = false; } }