【问题标题】:TreeView Remove CheckBox by some NodesTreeView 删除某些节点的复选框
【发布时间】:2011-06-17 03:04:03
【问题描述】:

我想删除 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;
    }
}

问题是图像和根节点的线不存在。 怎样才能去掉Checkbox,让Image和Line出现呢?

This is wrong!

【问题讨论】:

标签: c# winforms checkbox treeview ownerdrawn


【解决方案1】:

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

您要么需要自己画出这些线条,要么想办法在没有所有者绘图的情况下过日子。

从您现在拥有的代码来看,您似乎正在尝试在您的自绘代码中尽可能多地模拟系统的本机绘图样式,所以我不清楚您通过自绘完成了什么第一名。如果您只是想阻止显示类型 5 和 6 节点的复选框(就像线条一样,根本没有被绘制,因为您没有绘制它们!),有一种更简单的方法可以做到这一点而无需涉及所有者绘图。


那么,您问,隐藏单个节点复选框的更简单方法是什么?好吧,事实证明TreeView 控件本身实际上支持这一点,但该功能并未在 .NET Framework 中公开。您需要 P/Invoke 并调用 Windows API 来获取它。将以下代码添加到您的表单类(确保您已为 System.Runtime.InteropServices 添加了 using 声明):

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 structureSendMessage function。底部是您实际调用的函数 (HideCheckBox)。您只需传入 TreeView 控件和要从中删除复选标记的特定 TreeNode 项目。

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

   

【讨论】:

  • @Werewolve:好吧,也许我误会了它“更简单”。我个人认为它更简单,因为我更熟悉它并且因为所有者绘图很难正确。基本上,TreeView 控件本身支持隐藏单个节点的复选框,但该功能并未在 .NET Framework 中公开。你需要 P/Invoke 才能得到它。如果你愿意,我会用 codez 更新我的答案。
  • @Charith:是的,除了所有者绘制之外(你肯定不想这样做,既因为涉及的工作,也因为它永远不会看起来/行为与原生 TreeView 控件完全一样) ,这是唯一的方法。它看起来有点奇怪和复杂,因为您使用 P/Invoke 从本机 Win32 API 调用函数,但这是唯一奇怪的部分。这正是 C 或 C++ 程序员的工作方式,他们只是不需要奇怪的 .NET 约定来使事情发生。但是您不必担心使用 P/Invoke——它内置在框架中是有原因的。
  • 检查此答案以获取此代码故障模式的解决方案:stackoverflow.com/questions/7308238/…
  • @George 您传递给HideCheckBox 函数的Node 对象必须为空。该函数没有做任何特别的事情,它只是使用它。如果你给它传递一个无效的节点,它就会爆炸。 Related reading
  • @NathanMcKaskle:虽然几年过去了:TreeNode.ShowCheckBox 不相关的原因是因为它是System.Web.UI.WebControls 元素,而不是System.Windows.Forms 元素(OP 的问题是关于System.Windows.Forms
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    这很好!我要做的唯一修改是只将TreeNode 而不是TreeView 传递给HideCheckBox 方法。 TreeView 可以从 TreeNode 本身检索:

    TreeView tvw = node.TreeView;
    

    【讨论】:

    • 你在和谁说话??
    • aaaa ?什么 ?这是什么?
    猜你喜欢
    • 2015-06-18
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 2010-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多