Pages

Thursday, November 29, 2012

Multiselect tree view

Recently I needed to implement multiselect tree view. Knowing that there is nothing new under the sun I googled for solution and found this article. At first glance it worked as expected, however later I had to improve it.
  • it does not support editing of text nodes;
  • added property for turning off multiselect;
  • removed built-in tooltips;
  • enabled node selection with clicks in a row, not only on text and icon.
So here are my changes:

// Disable built-in tooltips
protected override CreateParams CreateParams 
{
    get
    {
        CreateParams parms = base.CreateParams;
        parms.Style |= 0x80;  // Turn on TVS_NOTOOLTIPS 
        return parms;
    }
}

// Switch to enable or disable multiselect
private bool _multiSelectEnabled;
public bool MultiSelectEnabled 
{ 
    get { return _multiSelectEnabled; }
    set
    {
        _multiSelectEnabled = value;
        //reset selection
        if (!_multiSelectEnabled && SelectedNodes.Count > 0) 
        SelectedNode = SelectedNodes[0];
    }
}

private List m_SelectedNodes;
public List SelectedNodes
{
    get { return m_SelectedNodes; }
    set
    {
        ClearSelectedNodes();
        if (MultiSelectEnabled)
        {
            if (value != null)
            {
                foreach (TreeNode node in value)
                {
                    ToggleNode(node, true);
                }
            }
        }
        else
        {
            if (value.Count > 0)
            {
                m_SelectedNodes.Clear();
                ToggleNode(value[0], true);
            }
        }
    }
}

// if user clicks on node, we will check if we need to edit nodes text
private TreeNode _clickedNode;
protected override void OnMouseDown(MouseEventArgs e)
{
    // If the user clicks on a node that was not previously selected, select it now.
    try
    {
        base.SelectedNode = null;

        TreeNode node = this.GetNodeAt(e.Location);
        if (node != null)
        {
            if (ModifierKeys == Keys.None && (m_SelectedNodes.Contains(node)))
            {
                _clickedNode = node;
            }
            else
            {
                if (MultiSelectEnabled) //if multiselect enabled - SelectNode
                {
                    SelectNode(node);
                }
                else //else select single node
                {
                    SelectSingleNode(node);
                }
            }
        }

        base.OnMouseDown(e);
    }
    catch (Exception ex)
    {
        HandleException(ex);
    }
}

protected override void OnMouseUp(MouseEventArgs e)
{
    try
    {
        var node = this.GetNodeAt(e.Location);
        if (node != null &&
            ModifierKeys == Keys.None && m_SelectedNodes.Contains(node))
        {
            if (MultiSelectEnabled)
            {
                SelectNode(node);
            }
            else
            {
                SelectSingleNode(node);
            }

            int leftBound = node.Bounds.X;
            int rightBound = node.Bounds.Right;
            if (_clickedNode == node && e.Location.X > leftBound && e.Location.X < rightBound)
            {
                _clickedNode.BeginEdit(); // single click on node - we can rename it
            }
        }

        _clickedNode = null; //clear clicked node

        base.OnMouseUp(e);
    }
    catch (Exception ex)
    {
        HandleException(ex);
    }
}

No comments:

Post a Comment