Raymond
Raymond

Reputation: 77

Scrollbar resetting to the top of the treeView after sorting?

I have a fairly large tree structure, and whenever a user adds or removes a child node, the tree is re-sorted. This all works very well, but my issue is this: After the sorting, the scrollbar is automatically reset to the top of the tree. I'd like to make it so the scrollbar holds (or returns to) the position where the node was just added or deleted so the user doesn't have to scroll down and find the parent node every single time they want to add or delete something.

I've been trying to find some way to do this for some time now, but haven't had any luck. Does anyone have any tips?

Here's the method I'm using for removing a child node, if it helps:

private void RemoveFromCategoryEvent(object sender, EventArgs e)
{
  SuspendLayout();

  if (treeViewCategories.SelectedNode != null)
  {
    TreeNode treeNode = treeViewCategories.SelectedNode;
    TreeNode parentNode = treeNode.Parent;
    if ((settingGroup != null) && (settingGroup.GroupRootCategory != null)
        && (settingGroup.GroupRootCategory.Settings != null) && (treeNode.Tag is ISetting)
        && (parentNode.Tag is IDeviceSettingCategory))
    {
      ISetting currentSetting = treeNode.Tag as ISetting;
      (parentNode.Tag as IDeviceSettingCategory).Settings.Remove(currentSetting);
      treeNode.Remove();

      settingGroup.GroupRootCategory.Settings.Add(currentSetting);
      TreeNode settingNode = rootCategoryNode.Nodes.Add(currentSetting.ShortName);
      settingNode.Tag = currentSetting;

      settingNode.ImageIndex = Utilities.SettingCategoryChildImage;
      settingNode.SelectedImageIndex = Utilities.SettingCategoryChildImage;

      treeViewCategories.Sort(); //scrollbar reset happens here
    }
  }

  ResumeLayout();
}

Upvotes: 3

Views: 1008

Answers (1)

Bradley Uffner
Bradley Uffner

Reputation: 16991

You can use P/Invoke to get the current scroll position, save it, and then restore it after sorting.

You will need the following API Calls:

[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern int GetScrollPos(int hWnd, int nBar);

[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

private const int SB_HORZ = 0x0;
private const int SB_VERT = 0x1;

Getting the current position:

private Point GetTreeViewScrollPos(TreeView treeView)
{
    return new Point(
        GetScrollPos((int)treeView.Handle, SB_HORZ), 
        GetScrollPos((int)treeView.Handle, SB_VERT));
}

Setting the position:

private void SetTreeViewScrollPos(TreeView treeView, Point scrollPosition)
{
    SetScrollPos((IntPtr)treeView.Handle, SB_HORZ, scrollPosition.X, true);
    SetScrollPos((IntPtr)treeView.Handle, SB_VERT, scrollPosition.Y, true); 
}

Upvotes: 3

Related Questions