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