【问题标题】:Strange auto-collapse behaviour in a treeview when SelectedImageIndex is set?设置 SelectedImageIndex 时树视图中奇怪的自动折叠行为?
【发布时间】:2020-07-09 09:42:01
【问题描述】:

在树形视图控件中,我默认的所需键盘行为是使用左/右箭头键折叠/展开,使用上/下箭头键遍历可见节点不使用 折叠或展开它们。

但由于某些奇怪的原因,以下代码在使用向上/向下箭头键选择节点时会自动折叠/展开节点:

private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
    // This line produces strange auto-collapse/expand behaviour,
    // but is needed in order to correctly set the image of the selected node.
    // If I comment this line out, then keyboard input produces the desired behaviour.
    treeView1.SelectedImageIndex = e.Node.ImageIndex;
}
  1. 为什么会这样?
  2. 如何预防?

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    其实这是设计的。

    TreeView.SelectedImageIndex 属性的文档末尾:

    在运行时设置 SelectedImageIndex 属性时,TreeView 重新创建句柄(请参阅 Control.RecreateHandle)以更新 控件的外观。这会导致所有树节点折叠, 除了选定的 TreeNode。

    我重现了这个问题,并意识到只有在树视图的 SelectedImageIndex 更改时才会发生这种情况(不是在分配时,而是在分配给不同的值时)。如果您选择一个具有ImageIndex 8 的节点,然后选择另一个具有相同图像索引的节点,则不会发生这种不良行为。

    但是;无论如何有一个解决方案。它并不完美,但可以改进。

    解决方案包括将展开的节点保留在自定义集合中,并在 .SelectedImageIndex 分配后展开它们,并且仅当 SelectedImageIndex 更改时。

    下面的代码中有很多解决方法。有时间我会在评论里解释,但也许你可以同时试试。

        private List<TreeNode> expandedNodes = new List<TreeNode>();
        private TreeNode nodeAboutToCollapse;
    
        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // skip system calls
            if(e.Action == TreeViewAction.Unknown)
            {
                return;
            }
    
            if (treeView1.SelectedImageIndex == e.Node.ImageIndex)
            {
                nodeAboutToCollapse = null;
                return;
            }
    
            treeView1.SelectedImageIndex = e.Node.ImageIndex;
    
            for (int i = 0; i < expandedNodes.Count; i++)
            {
                if (expandedNodes[i] != nodeAboutToCollapse)
                {
                    expandedNodes[i].Expand();
                }
            }
            nodeAboutToCollapse = null;
        }
    
        private void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
        {
            if (!expandedNodes.Contains(e.Node))
            {
                expandedNodes.Add(e.Node);
            }
        }
    
        private void treeView1_AfterCollapse(object sender, TreeViewEventArgs e)
        {
            expandedNodes.Remove(e.Node);
            nodeAboutToCollapse = null;
        }
    
        private void treeView1_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
        {
            nodeAboutToCollapse = e.Node;
        }
    

    【讨论】:

    • 这样解决了问题,但也引入了其他问题。例如,填充一个大的嵌套树,但使窗口控件的大小足够小,因此需要滚动才能看到所有内容。然后使用键盘遍历树......即使使用BeginUpdate()EndUpdate(),它也会导致大量闪烁,并跳转视图。作为一种更有效的解决方法,我只是在创建节点并设置node.ImageIndex 之后直接设置node.SelectedImageIndex = node.ImageIndex。对我有用,但在使用 TreeViews 时可能不是每个场景的解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    • 2011-08-22
    • 2016-02-10
    • 1970-01-01
    • 2011-01-07
    相关资源
    最近更新 更多