0

After removing one TreeNode I want the View to be at the node after the one I deleted (the same functionality should later also be implemented for editing a node), but currently it always shows the top of the list again and I need to scroll down manually, which can be quite irritating for the user.

I'm using the EnsureVisible() method but unfortunately it doesn't work (I'm testing it with a TreeView which contains about 30 nodes that don't have sub-nodes).

The code of the function (Only the first line and the last 4/5 lines are relevant, I think):

public override void Remove()
    {
        TreeNode moveToThisNode = treeControl1.SelectedNodes.Last().NextVisibleNode;

        // first, group them by whether they are ObjectGroups or ObjectTypes
        var grouping = from node in treeControl1.SelectedNodes
                       where !node.IsUngroupedNode()
                       let isGroup = node.IsGroupNode()
                       group node by isGroup into g
                       select new { IsGroupNode = g.Key, Items = g };

        foreach (var grp in grouping)
        {
            foreach (var selectedNode in grp.Items)
            {
                // Only allow removal FIRSTLY of ObjectGroups and SECONDLY that are NOT the "ungrouped" group.
                if (grp.IsGroupNode)
                {
                    // Removes the Group
                    var cmd = (Commands.DataCommand<string>)mApplicationData.CommandFactory.Create(string.Concat(CommandPrefix, "Remove"));
                    cmd.Data = selectedNode.Text;
                    cmd.Execute();
                }
                else // ObjectType node --> just move to ungrouped
                {
                    var t = (ObjectType)selectedNode.Tag;
                    var parentNode = selectedNode.Parent;
                    if (parentNode?.IsGroupNode() == true &&
                        parentNode?.IsUngroupedNode() == false) // No removal of ObjectTypes from within "ungrouped"
                    {
                        var group = (ObjectGroup)parentNode.Tag;
                        // Remove the ObjectType from the ObjectGroup but does not delete it -> becomes "ungrouped".
                        var cmd = (Commands.IGroupTypeCommand)mApplicationData.CommandFactory.Create(string.Concat(CommandPrefix, "TypeRemove"));
                        cmd.ObjectClass = t.Class;
                        cmd.ObjectTypeName = t.Name;
                        cmd.Data = group.Name;
                        cmd.Execute();
                    }
                }
            }
        }
        UpdateData();

        if (moveToThisNode!=null)
        {
            moveToThisNode.EnsureVisible();
            MessageBox.Show("Dummy test if moveToThisNode isn't null");
        }
    }
  • [See here](https://stackoverflow.com/questions/457932/scroll-selected-treeview-node-into-view), referring esp. to [TopNode](https://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.topnode(v=vs.110).aspx) - Or is moveToThisNode null ?? – TaW Jul 17 '18 at 09:40
  • @TaW I also found this post and it's basically what I do, except for the second answer with setting the BindingIndex… My node doesn't have such a member. Also I don't quite understand how TopNode can help me. And, no moveToThisNode is not null, it shows the TextBox message. – Markus Rechberger Jul 17 '18 at 09:47
  • TopNode would move a certain node to the top of the visible range, whereas EnsureVisible would only ensure that it is visible (by scrolling and expanding) but not necessarily at the top. If it actually doesn't do even that for you then you have other things going on in your code.. - Try to add moveToThisNode.Text to the message you display..! – TaW Jul 17 '18 at 10:14
  • @TaW I added moveToThisNode.Text to the message and it displays the node I want to be at after removing (=the node after the one deleted). So if my nodes would be: A B C D and I delete B the MessageBox shows "C" but the visible part is at the beginning again and I'd have to scroll down again (Imagine that the list is very long) – Markus Rechberger Jul 17 '18 at 10:23
  • Hm, that is strange. No time to recreate atm; can you try to inset a tv.Refresh() before the ensurevisible? (Maybe the layout is not finished directly after the deletion..? – TaW Jul 17 '18 at 10:28
  • @TaW Tried this, but unfortunately it doesn't work. I just had the concern that maybe after Remove() another function is called which makes my EnsureVisible() useless, but I set a breakpoint on the line where the MessageBox is displayed (so right after EnsureVisible) but at this point I'm already at the beginning of the list again meaning that EnsureVisible probably didn't do anything. – Markus Rechberger Jul 17 '18 at 10:37
  • Hm, NextVisibleNode may bring any type of node, previous level, subnode or same level or null. Shouldn't you always try to go to NextNode (or node.Parent.NextNode) instead? – TaW Jul 17 '18 at 11:51
  • @TaW Okay, you're probably right with that but it also worked the way I did it (at least in this context) with showing the correct name of the next node but it just doesn't move there…. I also tried to go to treeControl1.Nodes[treeControl1.Nodes.Count()-1] just to make sure that EnsureVisible is my problem :D – Markus Rechberger Jul 17 '18 at 12:01
  • Hm, I test only with a normal treeview and it works as expected. It jumo to the top only when I remove the last brqnch. - Your multiselect version may behave differently. – TaW Jul 17 '18 at 12:08
  • 1
    @TaW This could be but thanks for spending your time on trying to help me with the roblem, I really appreciate that. Now I just have to hope that someone out there has an answer :D Schönen Nachmittag noch! – Markus Rechberger Jul 17 '18 at 12:23

1 Answers1

0

I figured it out!

The problem was that after the Remove() function my UpdateData() function is called which redraws all nodes. So calling EnsureVisible() before that is total nonsense.

So what I did was that in the Remove() I stored the name of the node I want to jump to in a member variable and at the end of UpdateData() I get the node with that name out of the TreeNodeCollection and (FINALLY) call EnsureVisible() for it.

  • I was experiencing something similar in one of my programs. My code was calling TreeView.ExpandAll at a point after EnsureVisible is called, and this was rendering the node no longer in view. Lesson learned: Make sure calling EnsureVisible is the very last thing your code does with the TreeView before returning control to the user! – Stewart Feb 26 '20 at 16:45