TreeView通过某些节点删除CheckBox

Wer*_*lve 26 c# checkbox treeview ownerdrawn winforms

我想删除CheckBoxes,其中Node.Type是5或6.我使用此代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是那时图像和到根节点的线不存在.如何删除复选框并让图像和线路在那里?

这是错的!

Cod*_*ray 72

在您显示的代码中,您自己为所有类型为5或6的节点处理绘图.对于其他类型,您只是允许系统以默认方式绘制节点.这就是为什么他们都有预期的线条,但你所有者绘制的线条没有:你忘了画线!你看,当你说它e.DrawDefault = false;被认为你真正的意思.没有完成常规绘图,包括标准线.

您可能需要自己绘制这些线条,或者根本没有所有者绘图来弄清楚如何使用.

从您现在的代码中,看起来您正试图在您的所有者绘制代码中尽可能地模拟系统的原生绘图样式,因此我不清楚您最初通过所有者绘图完成了什么.如果你只是试图保持复选框不显示类型5和6节点(就像线条一样,因为你没有绘制它们而根本没有被绘制!),有一种更简单的方法可以在不涉及所有者的情况下完成画画.


那么,你问,隐藏单个节点的复选框的简单方法是什么?好吧,事实证明TreeView控件本身实际上支持这一点,但该功能未在.NET Framework中公开.您需要P/Invoke并调用Windows API才能获得它.将以下代码添加到表单类(确保已添加using声明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);
}
Run Code Online (Sandbox Code Playgroud)

顶部的所有杂乱的东西都是你的P/Invoke声明.您需要一些常量,描述树视图项的属性的TVITEM结构SendMessage函数.在底部是您实际调用deed(HideCheckBox)的函数.您只需传入TreeView控件以及TreeNode要从中删除复选标记的特定项目.

因此,您可以从每个子节点中删除复选标记,以获得如下所示的内容:

   具有为子节点隐藏的复选标记的TreeView

  • 请查看此答案以获取此代码的故障模式的解决方案:http://stackoverflow.com/questions/7308238/treeview-problem-with-treenode-handle-not-returning/7308950#7308950 (5认同)

小智 17

使用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;
}
Run Code Online (Sandbox Code Playgroud)

以下是作为Extension方法的答案代码,使用此方法可以:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 6

这是非常好的!我唯一要进行的修改是仅将TreeNode和不传递TreeViewHideCheckBox方法。该TreeView可从检索TreeNode本身:

TreeView tvw = node.TreeView;
Run Code Online (Sandbox Code Playgroud)