2011-01-28 7 views
19

quiero quitar CheckBoxes donde el Node.Type es 5 o 6. Uso este código:TreeView Eliminar CheckBox por algunos nodos

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 entonces la imagen y la línea hacia el nodo raíz es no ahí. ¿Cómo se puede quitar la casilla de verificación y dejar allí la imagen y la línea?

This is wrong!

+0

posible duplicado de [Busco a un buen recurso en treeviews ownerdrawn ] (http://stackoverflow.com/questions/4179522/i-am-looking-for-a-good-resource-on-ownerdrawn-treeviews) –

+0

Estoy de acuerdo con Hans; el sorteo del propietario generalmente es prohibitivamente difícil. Si insistes, encontré una muestra más completa de una vista de árbol dibujada por el propietario como respuesta a [esta pregunta] (http://stackoverflow.com/questions/1003459/c-treeview-owner-drawing-with-ownerdrawtext- and-the-weird-black-highlighting-wh/1004087), completo con las líneas de nodo. –

Respuesta

63

En el código que has demostrado, que están manejando el dibujo mismo para todos los nodos cuyo tipo es 5 ó 6. Para el resto de los tipos, usted es simplemente permitiendo que el sistema dibujar los nodos de la manera predeterminada. Es por eso que todos tienen las líneas como se esperaba, pero las que usted es dueña del dibujo no: ¡olvidó dibujar en las líneas! Cuando dices e.DrawDefault = false;, se supone que realmente lo dices en serio. Ninguno de los dibujos regulares está hecho, incluidas las líneas estándar.

Tendrá que dibujar en esas líneas usted mismo, o averiguar cómo hacerlo sin el dibujo del propietario en absoluto.

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


Entonces, usted pregunta, ¿cuál es la forma más sencilla de ocultar las casillas de verificación de los nodos individuales? Bueno, resulta que el control TreeView en realidad es compatible con esto, pero esa funcionalidad no está expuesta en .NET Framework. Necesitas P/Invocar y llamar a la API de Windows para obtenerlo. Agregue el código siguiente a su clase de formulario (asegúrese de que ha añadido una declaración using para 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 desordenado en la parte superior son sus declaraciones P/Invoke. Necesita un puñado de constantes, el TVITEM structure que describe los atributos de un elemento treeview y el SendMessage function. En la parte inferior está la función que realmente llamará para hacer la escritura (HideCheckBox). Simplemente pase el control TreeView y el elemento TreeNode particular desde el que desea eliminar la marca de verificación.

para que pueda quitar las marcas de verificación de cada uno de los nodos secundarios para conseguir algo que se parece a esto:

      TreeView with checkmarks hidden for child nodes

+0

@Werewolve: Bueno, quizás me haya equivocado al decir que es "más simple". Personalmente, creo que es más sencillo porque estoy más familiarizado con él y porque el dibujo del propietario es tan difícil de hacer bien. Básicamente, el control 'TreeView' en sí mismo permite ocultar las casillas de verificación para nodos individuales, pero esa funcionalidad no está expuesta en .NET Framework. Necesitas P/Invocar para obtenerlo. Actualizaré mi respuesta con el codez, si quieres. –

+0

@Charith: Sí, más allá del dibujo del propietario (que definitivamente no desea hacer, tanto por el trabajo involucrado como porque nunca se verá/se comportará exactamente como el control TreeView nativo), esta es la única forma de hazlo. Parece un tanto extraño y complicado porque estás usando P/Invoke para llamar a funciones de la API Win32 nativa, pero esa es la única parte extraña al respecto. Es exactamente como lo haría un programador C o C++, simplemente no necesitarían las extrañas convenciones .NET para que las cosas sucedan. Pero no debe preocuparse por usar P/Invoke, está integrado en el marco por alguna razón. –

+5

Verifique esta respuesta para encontrar una solución a un modo de falla de este código: http://stackoverflow.com/questions/7308238/treeview-problem-with-treenode-handle-not-returning/7308950#7308950 –

4

Esto es muy bueno! La única modificación que haré es pasar solo el TreeNode y no el TreeView al método HideCheckBox. El TreeView se puede recuperar de la misma TreeNode:

TreeView tvw = node.TreeView; 
13

Usando TreeViewExtensions.

Ejemplo 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, el uso de este 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); 
    } 
} 
Cuestiones relacionadas