web-dev-qa-db-fra.com

TreeView Supprimer CheckBox par certains nœuds

Je veux supprimer les CheckBoxes où le Node.Type est 5 ou 6. J'utilise ce code:

private void TvOne_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
    int type = (e.Node as Node).typ;
    if (type == 5 || type == 6)
    {
        Color backColor, foreColor;
        if ((e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected)
        {
            backColor = SystemColors.Highlight;
            foreColor = SystemColors.HighlightText;
        }
        else if ((e.State & TreeNodeStates.Hot) == TreeNodeStates.Hot)
        {
            backColor = SystemColors.HotTrack;
            foreColor = SystemColors.HighlightText;
        }
        else
        {
            backColor = e.Node.BackColor;
            foreColor = e.Node.ForeColor;
        }
        using (SolidBrush brush = new SolidBrush(backColor))
        {
            e.Graphics.FillRectangle(brush, e.Node.Bounds);
        }
        TextRenderer.DrawText(e.Graphics, e.Node.Text, this.TvOne.Font,
            e.Node.Bounds, foreColor, backColor);

        if ((e.State & TreeNodeStates.Focused) == TreeNodeStates.Focused)
        {
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Node.Bounds,
                foreColor, backColor);
        }
        e.DrawDefault = false;
    }
    else
    {
        e.DrawDefault = true;
    }
}

Le problème est qu'alors l'image et la ligne vers la racine Node n'est pas là. Comment supprimer la case à cocher et laisser l'image et la ligne là-bas?

C'est faux!

27
Werewolve

Dans le code que vous avez montré, vous gérez vous-même le dessin pour tous les nœuds dont le type est 5 ou 6. Pour le reste des types, vous autorisez simplement le système à dessiner les nœuds de la manière par défaut. C'est pourquoi ils ont tous les lignes comme prévu, mais pas celles que vous dessinez par le propriétaire: vous avez oublié de dessiner les lignes! Vous voyez, quand vous dites e.DrawDefault = false; on suppose que vous le pensez vraiment. Aucun dessin régulier n'est effectué, y compris les lignes standard.

Vous devrez soit dessiner ces lignes vous-même, soit trouver comment vous en sortir sans dessin du propriétaire.

D'après le code que vous avez maintenant, il semble que vous essayez de simuler autant que possible le style de dessin natif du système dans votre code de dessin du propriétaire, donc je ne sais pas exactement ce que vous accomplissez exactement en dessinant par le propriétaire en premier lieu . Si vous essayez simplement d'empêcher les cases à cocher de s'afficher pour les nœuds de type 5 et 6 (qui, comme les lignes, ne sont tout simplement pas dessinées parce que vous ne les dessinez pas!), Il existe un moyen plus simple de le faire sans impliquer le propriétaire. dessin.


Alors, demandez-vous, quelle est cette façon plus simple de masquer les cases à cocher pour les nœuds individuels? Eh bien, il s'avère que le contrôle TreeView lui-même prend en charge cela, mais cette fonctionnalité n'est pas exposée dans le .NET Framework. Vous devez P/Invoke et appeler l'API Windows pour y accéder. Ajoutez le code suivant à votre classe de formulaire (assurez-vous d'avoir ajouté une déclaration using pour System.Runtime.InteropServices):

private const int TVIF_STATE = 0x8;
private const int TVIS_STATEIMAGEMASK = 0xF000;
private const int TV_FIRST = 0x1100;
private const int TVM_SETITEM = TV_FIRST + 63;

[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
private struct TVITEM
{
    public int mask;
    public IntPtr hItem;
    public int state;
    public int stateMask;
    [MarshalAs(UnmanagedType.LPTStr)]
    public string lpszText;
    public int cchTextMax;
    public int iImage;
    public int iSelectedImage;
    public int cChildren;
    public IntPtr lParam;
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
                                         ref TVITEM lParam);

/// <summary>
/// Hides the checkbox for the specified node on a TreeView control.
/// </summary>
private void HideCheckBox(TreeView tvw, TreeNode node)
{
    TVITEM tvi = new TVITEM();
    tvi.hItem = node.Handle;
    tvi.mask = TVIF_STATE;
    tvi.stateMask = TVIS_STATEIMAGEMASK;
    tvi.state = 0;
    SendMessage(tvw.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
}

Toutes les choses désordonnées en haut sont vos déclarations P/Invoke. Vous avez besoin d'une poignée de constantes, la TVITEM structure qui décrit les attributs d'un élément de l'arborescence, et la SendMessage fonction . En bas se trouve la fonction que vous appellerez réellement pour faire l'acte (HideCheckBox). Vous passez simplement le contrôle TreeView et l'élément TreeNode particulier dont vous souhaitez supprimer la coche.

Vous pouvez donc supprimer les coches de chacun des nœuds enfants pour obtenir quelque chose qui ressemble à ceci:

TreeView with checkmarks hidden for child nodes

70
Cody Gray

Utilisation de TreeViewExtensions.

Échantillon d'utilisation:

private void MyForm_Load(object sender, EventArgs e)
{
     this.treeview1.DrawMode = TreeViewDrawMode.OwnerDrawText;
     this.treeview1.DrawNode += new DrawTreeNodeEventHandler(arbolDependencias_DrawNode);
}

void treeview1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
    if (e.Node.Level == 1) e.Node.HideCheckBox();
    e.DrawDefault = true;
}

Voici le code de la réponse en tant que méthode d'extension, en utilisant ceci, vous pouvez faire:

public static class TreeViewExtensions
{
    private const int TVIF_STATE = 0x8;
    private const int TVIS_STATEIMAGEMASK = 0xF000;
    private const int TV_FIRST = 0x1100;
    private const int TVM_SETITEM = TV_FIRST + 63;

    [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
    private struct TVITEM
    {
        public int mask;
        public IntPtr hItem;
        public int state;
        public int stateMask;
        [MarshalAs(UnmanagedType.LPTStr)]
        public string lpszText;
        public int cchTextMax;
        public int iImage;
        public int iSelectedImage;
        public int cChildren;
        public IntPtr lParam;
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
                                             ref TVITEM lParam);

    /// <summary>
    /// Hides the checkbox for the specified node on a TreeView control.
    /// </summary>
    public static void HideCheckBox(this TreeNode node)
    {
        TVITEM tvi = new TVITEM();
        tvi.hItem = node.Handle;
        tvi.mask = TVIF_STATE;
        tvi.stateMask = TVIS_STATEIMAGEMASK;
        tvi.state = 0;
        SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
    }
}
17
user1404096

C'est très bien! La seule modification que je ferais est de ne passer que la TreeNode et non la TreeView à la méthode HideCheckBox. Le TreeView peut être récupéré depuis le TreeNode lui-même:

TreeView tvw = node.TreeView;
5
user1680739