Pregunta

Quiero eliminar las casillas de verificación donde el nodo. Type es 5 o 6. Utilizo este código:

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;
    }
}

El problema es que la imagen y la línea al nodo raíz no están allí. ¿Cómo puede eliminar la casilla de verificación y dejar que la imagen y la línea allí?

¡Esto está mal!

¿Fue útil?

Solución

En el código que ha mostrado, está manejando el dibujo usted mismo para todos los nodos cuyo tipo es 5 o 6. Para el resto de los tipos, simplemente está permitiendo que el sistema dibuje los nodos de la manera predeterminada. Es por eso que todos tienen las líneas como se esperaba, pero las que no tienen el drogadicto no: ¡olvidó trazar las líneas! Ya ves, cuando dices e.DrawDefault = false; Se supone que realmente lo dices en serio. Ninguno de los dibujos regulares se realiza, incluidas las líneas estándar.

Tendrá que dibujar en esas líneas usted mismo o descubrir cómo sobrevivir sin que el propietario drogue en absoluto.

Desde el código que tiene ahora, parece que está tratando de simular el estilo de dibujo nativo del sistema tanto como sea posible en su código de drogadio de propietario, por lo que no está claro para mí qué logra exactamente por el presentación de dibujo en primer lugar. . Si solo está tratando de evitar que las casillas de verificación aparezcan para los nodos tipo 5 y 6 (que, como las líneas, simplemente no se están dibujando porque no las está dibujando!), ¡Hay una forma más sencilla de hacerlo sin involucrar al propietario dibujo.


Entonces, preguntas, ¿cuál es esa forma más simple de ocultar las casillas de verificación para nodos individuales? Bueno, resulta que el TreeView El control en sí mismo realmente admite esto, pero esa funcionalidad no está expuesta en el marco .NET. Debe P/Invok y llamar a la API de Windows para hacerlo. Agregue el siguiente código a su clase de formulario (asegúrese de agregar un using declaración de 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);
}

Todas las cosas desordenadas en la parte superior son sus declaraciones P/Invoke. Necesitas un puñado de constantes, la TVITEM estructura que describe los atributos de un elemento de revisión de árboles y el SendMessage función. En la parte inferior está la función que realmente llamará para hacer la escritura (HideCheckBox). Simplemente pasas en el TreeView control y el particular TreeNode Elemento del que desea eliminar la marca de verificación.

Por lo tanto, puede eliminar las marcas de verificación de cada uno de los nodos infantiles para obtener algo que se vea así:

   TreeView with checkmarks hidden for child nodes

Otros consejos

Uso de TreeViewExtensions.

Muestra de uso:

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;
}

Aquí está el código de la respuesta como un método de extensión, usando esto que puede hacer:

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);
    }
}

¡Esto es muy bueno! La única modificación que haría es pasar solo el TreeNode Y no el TreeView hacia HideCheckBox método. los TreeView se puede recuperar del TreeNode sí mismo:

TreeView tvw = node.TreeView;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top