web-dev-qa-db-ja.com

TreeView一部のノードでCheckBoxを削除

Node.Typeが5または6のCheckBoxesを削除したいのですが、次のコードを使用します。

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

問題は、画像とルートへの線Nodeがそこにないことです。チェックボックスを削除して画像と線をそこに配置するにはどうすればよいですか?

これは間違っています!

27
Werewolve

上記のコードでは、タイプが5または6のすべてのノードの描画を自分で処理しています。残りのタイプについては、システムがデフォルトの方法でノードを描画できるようにしているだけです。そのため、すべての線に期待どおりの線が表示されますが、所有者が描画している線には線がありません。線を描画するのを忘れました!ほら、あなたがe.DrawDefault = false;と言うとき、あなたは本当にそれを意味していると想定されています。標準線を含め、通常の描画は行われません。

あなたはそれらの線を自分で描くか、所有者がまったく描かずに何とかやっていく方法を見つける必要があります。

あなたが現在持っているコードから、あなたはオーナー描画コードでシステムのネイティブの描画スタイルをできるだけシミュレートしようとしているように見えるので、最初にオーナー描画によってあなたが正確に何を達成するのか私には明確ではありません。タイプ5と6のノードのチェックボックスが表示されないようにするだけの場合(線のように、それらを描画していないため、描画されません!)お絵かき。


では、個々のノードのチェックボックスを非表示にする最も簡単な方法は何でしょうか。まあ、TreeViewコントロール自体が実際にこれをサポートしていることがわかりましたが、その機能は.NET Frameworkでは公開されていません。取得するには、Windows APIをP/Invokeして呼び出してください。次のコードをフォームクラスに追加します(System.Runtime.InteropServicesusing宣言が追加されていることを確認してください)。

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

上部の乱雑なものはすべてP/Invoke宣言です。少数の定数、ツリービューアイテムの属性を説明する TVITEM structure 、および SendMessage function が必要です。一番下は、行為を行うために実際に呼び出す関数です(HideCheckBox)。 TreeViewコントロールと、チェックマークを削除する特定のTreeNodeアイテムを渡すだけです。

したがって、各子ノードからチェックマークを削除して、次のようなものを取得できます。

TreeView with checkmarks hidden for child nodes

70
Cody Gray

TreeViewExtensionsの使用。

使用例:

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

これは、拡張メソッドとしての回答のコードです。これを使用すると、次のことができます。

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

これはとても良いです!私が行う唯一の変更は、TreeNodeではなくTreeViewだけをHideCheckBoxメソッドに渡すことです。 TreeViewTreeNode自体から取得できます。

TreeView tvw = node.TreeView;
5
user1680739