Laurent Nicot - 2009-08-04

Thanks for this great control.

Since the version  1.7.0.0, when I send the StructureChanged event in a model with TreePath.Empty :
1) the tree is collapsed
2) the selection is lost

The first problem is describe in a previous thread (https://sourceforge.net/forum/forum.php?thread_id=3328697&forum_id=568369). The Root node have null Tag, SaveExpandedNodes and RestoreExpandedNodes do nothing. Here are my changes :

in TreeviewAdv.cs
private void RestoreExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
{
   if ((node == _root) || (node.Tag != null && list.ContainsKey(node.Tag)))
   {
      node.IsExpanded = true;
      foreach (var child in node.Children)
         RestoreExpandedNodes(child, list);
   }
}

private void SaveExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
{
   if ((node == _root) || (node.IsExpanded && node.Tag != null))
   {
      if (node != _root)
         list.Add(node.Tag, null);
      foreach (var child in node.Children)
         SaveExpandedNodes(child, list);
   }
}

After resolving the first problem, the second problem appears : all selected nodes (in the structure changed path) are unselected.
Here is the method call by the StructureChanged event :

in TreeviewAdv.cs
private void _model_StructureChanged(object sender, TreePathEventArgs e)
{
   if (e.Path == null)
      throw new ArgumentNullException();

   TreeNodeAdv node = FindNode(e.Path);
   if (node != null)
   {
      if (node != Root)
         node.IsLeaf = Model.IsLeaf(GetPath(node));

      var list = new Dictionary<object, object>();
      SaveExpandedNodes(node, list);
      ReadChilds(node);
      RestoreExpandedNodes(node, list);

      UpdateSelection();
      SmartFullUpdate();
   }
}

The ReadChilds method clears child nodes in the tree and creates new nodes. So, when UpdateSelection is called, old nodes are not owned by the tree, the selection is lost. To correct this problem, I replace the call of method UpdateSelection by a new methode RestoreSelection :

private void _model_StructureChanged(object sender, TreePathEventArgs e)
{
   ...
   RestoreExpandedNodes(node, list);

   RestoreSelection();
   SmartFullUpdate();
   ...
}

Here is the code of RestoreSelection (based on UpdateSelection) :
        private void RestoreSelection()
        {
            bool flag = false;

            if (!IsMyNode(CurrentNode) && (CurrentNode != null))
                CurrentNode = FindNode(GetPath(CurrentNode));
            if (!IsMyNode(_selectionStart) && (_selectionStart != null))
                _selectionStart = FindNode(GetPath(_selectionStart));

            for (int i = Selection.Count - 1; i >= 0; i--)
            {
                if (!IsMyNode(Selection[i]))
                {
                    if (Selection[i] != null)
                        Selection[i] = FindNode(GetPath(Selection[i]));
                    if (Selection[i] != null)
                        Selection[i]._isSelected = true;
                    else
                    {
                        flag = true;
                        Selection.RemoveAt(i);
                    }
                }
            }

            if (flag)
                OnSelectionChanged();
        }

I retrieve the new node using the path of the old node : FindNode(GetPath(...)).
The _isSelected field in TreeNodeAdv must be declared as internal.
I don't used IsSelected property because it calls UpdateView() and OnSelectionChanged().