冬眠
“如果你觉得自己在为傻瓜设计产品,那么很可能不仅无法设计出优秀的产品,而且连傻瓜也不喜欢你的设计。”--Paul Graham

导航

 

  VS中使用TreeView,当需要用到Checked属性,并需要同步子节点和父节点的Checked属性时,若使用AfterCheck事件会导致死循环,这里我使用的是NodeMouseClick事件。代码如下:

private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if (e.Node == null)
        return;
    switch (e.Button)
    {
        case MouseButtons.Left: //左键
          //改变子节点的状态
          this.CheckChildNode(e.Node);
        //改变父节点的状态
          this.CheckParentNode(e.Node);
            break;
        default:
            break;
    }
}

private void CheckChildNode(TreeNode node)
{
    if (node.Nodes.Count < 1)
    {
        return;
    }
    foreach (TreeNode childNode in node.Nodes)
    {
        if (childNode.Checked != node.Checked)
        {
            childNode.Checked = node.Checked;
            CheckChildNode(childNode);
        }
    }
}

private void CheckParentNode(TreeNode node)
{
    if (node.Parent == null)
    {
        return;
    }
    TreeNode parentNode = node.Parent;
    for (int i = 0; i < parentNode.Nodes.Count; i++)
    {
        if (!parentNode.Nodes[i].Checked)
        {
            parentNode.Checked = false;
            CheckParentNode(parentNode);
            return;
        }
    }
    parentNode.Checked = true;
    CheckParentNode(parentNode);
}

  但是,在如下图的情况下:若单击“节点1”的非Checkbox位置(即只是单击节点,并不改变Checked属性),会导致子节点的Checked属性全部被置为false。

                   

  因为,在单击节点的时候,触发了NodeMouseClick事件,而此时无法判断是否是在改变其Checked属性。笔者尝试在NodeMouseClick和AfterCheck事件中记录并判断当前是否是在改变点击节点的Checked属性,结果由于无法确定点击时先触发的是哪个事件,导致这个方法失败了。

  最后,笔者通过判断点击的位置来确定是否是在改变点击节点的Checked属性,解决了这一缺陷。修改后的代码如下:


/// <summary>
/// 0级树节点Checkbox有效范围的X的最小值
/// </summary>
private int TreeNodeZeroLevelCheckboxLocationXMin = 3;

/// <summary>
/// 0级树节点Checkbox有效范围的X的最大值
/// </summary>
private int TreeNodeZeroLevelCheckboxLocationXMax = 15;

/// <summary>
/// 相邻等级树节点Checkbox有效范围的X的差值
/// </summary>
private int TreeNodeNextLevelCheckboxDiffX = 0;

private void Form1_Load(object sender, EventArgs e)
{
    TreeNodeNextLevelCheckboxDiffX = this.treeView.Indent;
    TreeNodeZeroLevelCheckboxLocationXMin += TreeNodeNextLevelCheckboxDiffX;
    TreeNodeZeroLevelCheckboxLocationXMax += TreeNodeNextLevelCheckboxDiffX;
}

private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    if (e.Node == null)
       
return;
   
switch (e.Button)
    {
       
case MouseButtons.Left: //左键
           
//判断点击位置是否为Checkbox的有效范围
            if (e.X <= TreeNodeZeroLevelCheckboxLocationXMax + e.Node.Level * TreeNodeNextLevelCheckboxDiffX
               
&& e.X >= TreeNodeZeroLevelCheckboxLocationXMin + e.Node.Level * TreeNodeNextLevelCheckboxDiffX)
            {
               
//改变子节点的状态
                this.CheckChildNode(e.Node);
               
//改变父节点的状态
                this.CheckParentNode(e.Node);
            }
           
break;
       
default:
           
break;
    }
}

   代码中的三个常量是笔者测试出来的,其中this.treeView.Indent是指每个子树节点级别的缩进距离。测试发现只要在X的范围内点击节点就会改变Checked属性,Y的取值没有影响。

posted on 2014-01-03 11:44  无尽的冬眠  阅读(1107)  评论(0编辑  收藏  举报