2011-01-28 8 views
19

voglio togliere CheckBoxes dove il Node.Type è di 5 o 6. Io uso questo codice:TreeView Rimuovere CheckBox da alcuni nodi

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

Il problema è che poi l'immagine e la linea al nodo radice è non là. Come rimuovere la casella di controllo e lasciare lì l'immagine e la linea?

This is wrong!

+0

possibile duplicato del [Sto cercando una buona risorsa su treeviews ownerdrawn ] (http://stackoverflow.com/questions/4179522/i-am-looking-for-a-good-resource-on-ownerdrawn-treeviews) –

+0

Sono d'accordo con Hans; il tiraggio del proprietario è generalmente proibitivo. Se insisti, ho trovato un esempio più completo di una vista ad albero disegnata dal proprietario data come risposta a [questa domanda] (http://stackoverflow.com/questions/1003459/c-treeview-owner-drawing-with-ownerdrawtext- e-the-weird-black-highlighting-wh/1004087), completo con le linee del nodo. –

risposta

63

Nel codice che avete mostrato, si gestisce il te stesso disegno per tutti i nodi il cui tipo è o 5 o 6. Per il resto dei tipi, si sta semplicemente permettendo al sistema disegnare i nodi nel modo predefinito. Ecco perché hanno tutte le linee come previsto, ma quelle che stai disegnando dal proprietario non lo fanno: ti sei dimenticato di tracciare le linee! Vedete, quando si dice e.DrawDefault = false; si presume che lo si intenda davvero. Nessuno dei disegni regolari è finito, comprese le linee standard.

O dovrete disegnare in quelle linee da soli, o capire come cavarsela senza il disegno del proprietario.

Dal codice che hai ora, sembra che tu stia cercando di simulare il più possibile lo stile di disegno nativo del sistema nel tuo codice di disegno proprietario, quindi non mi è chiaro che cosa realizzi esattamente dal disegno del proprietario innanzitutto. Se stai solo cercando di non mostrare le caselle di controllo per i nodi di tipo 5 e 6 (che, come le linee, semplicemente non vengono disegnate perché non le stai disegnando!), C'è un modo più semplice per farlo senza coinvolgere il proprietario disegno.


Quindi, chiedi, qual è il modo più semplice per nascondere le caselle di controllo per i singoli nodi? Bene, si scopre che il controllo TreeView in realtà supporta questo, ma quella funzionalità non è esposta in .NET Framework. È necessario P/Invoke e chiamare l'API di Windows per ottenere a esso. Aggiungere il seguente codice alla classe form (assicurati di aver aggiunto una dichiarazione using per 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); 
} 

tutte le cose disordinato in alto sono i vostri P/Invoke dichiarazioni. Sono necessarie una manciata di costanti, lo TVITEM structure che descrive gli attributi di un elemento di visualizzazione struttura e lo SendMessage function. In basso c'è la funzione che chiamerai per fare l'atto (HideCheckBox). È sufficiente passare il controllo TreeView e il particolare elemento TreeNode da cui si desidera rimuovere il segno di spunta.

modo da poter rimuovere i segni di spunta da ciascuno dei nodi figlio per ottenere qualcosa che assomiglia a questo:

      TreeView with checkmarks hidden for child nodes

+0

@Werewolve: Beh, forse ho misspoke su di esso essere "più semplice". Personalmente ritengo che sia più semplice perché mi è più familiare e perché il disegno del proprietario è così difficile da correggere. Fondamentalmente, il controllo 'TreeView' stesso supporta nascondere le checkbox per i singoli nodi, ma quella funzionalità non è esposta in .NET Framework. Hai bisogno di P/Invoke per arrivarci. Aggiornerò la mia risposta con il codez, se vuoi. –

+0

@Charith: Sì, al di là del proprietario-draw (che sicuramente non vuoi fare, sia per il lavoro in questione che perché non sarà mai simile/si comporterà esattamente come il controllo TreeView nativo), questo è l'unico modo per fallo. Sembra strano e complicato perché stai usando P/Invoke per chiamare le funzioni dall'API Win32 nativa, ma questa è l'unica parte strana a riguardo. È esattamente come lo farebbe un programmatore C o C++, semplicemente non avrebbero bisogno delle strane convenzioni .NET per far accadere le cose. Ma non dovresti preoccuparti di usare P/Invoke: è incorporato nel framework per una ragione. –

+5

Controllare questa risposta per una soluzione a una modalità di errore di questo codice: http://stackoverflow.com/questions/7308238/treeview-problem-with-treenode-handle-not-returning/7308950#7308950 –

4

Questo è molto buono! L'unica modifica che apporterei è di passare solo lo TreeNode e non lo TreeView al metodo HideCheckBox. Il TreeView può essere recuperato dal TreeNode stesso:

TreeView tvw = node.TreeView; 
13

Utilizzando TreeViewExtensions.

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

Ecco il codice del risposta come un metodo di estensione, utilizzando questo si può fare:

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