TreeView elimina CheckBox por algunos nodos

Quiero eliminar CheckBoxes donde el Node.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 entonces la imagen y la línea al nodo raíz no están allí. ¿Cómo se puede eliminar la checkbox y dejar allí la imagen y la línea?

¡Esto está mal!

En el código que ha mostrado, está manejando el dibujo usted mismo para todos los nodos cuyo tipo sea 5 o 6. Para el rest 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 usted es dueña del dibujo no: ¡olvidó dibujar en las líneas! Ya ves, 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.

Necesitarás dibujar en esas líneas tú mismo o descubrir cómo salir adelante sin el dibujo del propietario.

Desde el código que tienes ahora, parece que intentas simular el estilo de dibujo nativo del sistema tanto como sea posible en tu código de dibujo del propietario, por lo que no me queda claro qué es lo que logras con 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, pregunta, ¿cuál es la forma más simple de ocultar las casillas de verificación para nodos individuales? Bueno, resulta que el control TreeView sí mismo 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 siguiente código a su clase de formulario (asegúrese de haber agregado una statement de 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); ///  /// Hides the checkbox for the specified node on a TreeView control. ///  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 de P / Invoke. Necesita un puñado de constantes, la estructura TVITEM que describe los atributos de un elemento treeview y la función SendMessage . En la parte inferior está la función que realmente llamará para hacer la escritura ( HideCheckBox ). Simplemente TreeNode el control TreeView y el elemento TreeNode particular desde el que desea eliminar la marca de verificación.

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

TreeView con marcas de verificación ocultas para nodos secundarios

Usando 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, con esto 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); ///  /// Hides the checkbox for the specified node on a TreeView control. ///  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é es pasar solo TreeNode y no TreeView al método HideCheckBox . TreeView se puede recuperar desde TreeNode mismo:

 TreeView tvw = node.TreeView;