如何禁用WinForms TreeView节点复选框?

如何禁用WinForms TreeView节点复选框?,winforms,treeview,treenode,Winforms,Treeview,Treenode,我需要能够禁用WinForms应用程序的TreeView控件中的一些复选框,但标准TreeView控件中没有内置此类功能 我已经在使用TreeView.BeforeCheck事件,如果节点被禁用,则取消该事件,并且该操作非常正常 我还将禁用节点的ForeColor更改为GrayText 有人有简单而健壮的解决方案吗?TreeView.BeforeCheck--注册此事件之前,请检查该节点是否是允许选中复选框的节点,如果无法选中,则可以通过在TreeViewCancelEventArgs上设置ca

我需要能够禁用WinForms应用程序的
TreeView
控件中的一些复选框,但标准
TreeView
控件中没有内置此类功能

我已经在使用
TreeView.BeforeCheck
事件,如果节点被禁用,则取消该事件,并且该操作非常正常

我还将禁用节点的
ForeColor
更改为
GrayText

有人有简单而健壮的解决方案吗?

TreeView.BeforeCheck--注册此事件之前,请检查该节点是否是允许选中复选框的节点,如果无法选中,则可以通过在TreeViewCancelEventArgs上设置cancel属性来取消该事件。这将有望防止用户选中这些框,但不会带来最佳的用户体验


要删除不可检查项的复选框,您可以使用owner draw在复选框上方绘制一个实心矩形以将其删除。

没有内置的功能。您可以使用BeforeCheck事件并对所需节点取消它。如果复选框的外观很重要,则需要在其中放置一个图像以显示已禁用的复选框


这可能对你有兴趣。

因为C++中有支持,我们可以用p/javk./p>解决它。 这里是p/invoke部分的设置,只需让调用类可以使用它

    // constants used to hide a checkbox
    public const int TVIF_STATE = 0x8;
    public const int TVIS_STATEIMAGEMASK = 0xF000;
    public const int TV_FIRST = 0x1100;
    public const int TVM_SETITEM = TV_FIRST + 63;

    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam,
    IntPtr lParam); 

    // struct used to set node properties
    public 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;

    } 
我们希望在一个节点一个节点的基础上确定。最简单的方法是使用“绘制节点”事件。为了这个事件,我们必须将树设置为所有者绘制,所以一定要将其设置为默认设置以外的其他设置

this.tree.DrawMode = TreeViewDrawMode.OwnerDrawText;
this.tree.DrawNode += new DrawTreeNodeEventHandler(tree_DrawNode);
在树中_DrawNode函数确定正在绘制的节点是否应该有复选框,并在适当时将其隐藏。然后将默认的Draw属性设置为true,因为我们不想担心绘制所有其他细节

void tree_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
    if (e.Node.Level == 1)
    {
        HideCheckBox(e.Node);
        e.DrawDefault = true;
    }
    else 
    {
        e.Graphics.DrawString(e.Node.Text, e.Node.TreeView.Font,
           Brushes.Black, e.Node.Bounds.X, e.Node.Bounds.Y);
    }
}
最后,我们定义的函数的实际调用:

private void HideCheckBox(TreeNode node)
{
    TVITEM tvi = new TVITEM();
    tvi.hItem = node.Handle;
    tvi.mask = TVIF_STATE;
    tvi.stateMask = TVIS_STATEIMAGEMASK;
    tvi.state = 0;
    IntPtr lparam = Marshal.AllocHGlobal(Marshal.SizeOf(tvi));
    Marshal.StructureToPtr(tvi, lparam, false);
    SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, lparam);
}

这是PowerShell版本,非常感谢@sam trost的救世主代码

p/调用:

$TypeDefinition = @'
using System;
using System.Runtime.InteropServices;
namespace Win32Functions {
    public class Win32TreeView {
        // constants used to hide a checkbox
        public const int TVIF_STATE = 0x8;
        public const int TVIS_STATEIMAGEMASK = 0xF000;
        public const int TV_FIRST = 0x1100;
        public const int TVM_SETITEM = TV_FIRST + 63;

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        // struct used to set node properties
        public 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;
        }
    }
}
'@

Add-Type -TypeDefinition $TypeDefinition -PassThru
事件处理程序:

$TreeView1_DrawNode = [System.Windows.Forms.DrawTreeNodeEventHandler]{
    #Event Argument: $_ = [System.Windows.Forms.DrawTreeNodeEventArgs]
    if ($null -ne $_.Node) {

        # P/invoke hack to hide Node CheckBox
        if ($_.Node.Level -eq 0) {
            Hide-NodeCheckBox($_.Node)
        }

        $_.DrawDefault = $true
    }
}
TreeView:

$TreeView1.DrawMode = [TreeViewDrawMode]::OwnerDrawText
$TreeView1.add_DrawNode($TreeView1_DrawNode)
功能:

function Hide-NodeCheckBox([TreeNode]$node) {
    # P/invoke hack to hide Node CheckBox
    if ($node.TreeView.CheckBoxes) {
        $tvi = [Win32Functions.Win32TreeView+TVITEM]::new()
        $tvi.hItem = $node.Handle
        $tvi.mask = [Win32Functions.Win32TreeView]::TVIF_STATE
        $tvi.stateMask = [Win32Functions.Win32TreeView]::TVIS_STATEIMAGEMASK
        $tvi.state = 0
        [IntPtr]$lparam = [Marshal]::AllocHGlobal([Marshal]::SizeOf($tvi))
        [Marshal]::StructureToPtr($tvi, $lparam, $false)
        [Win32Functions.Win32TreeView]::SendMessage($node.TreeView.Handle, [Win32Functions.Win32TreeView]::TVM_SETITEM, [IntPtr]::Zero, $lparam)
    }
}

在HideCheckBox函数中,将tvi.state=0更改为tvi.state=1。当我尝试此操作时,复选框最终会在实际具有复选框的节点上被切断。是否使用树视图的默认显示属性?如果您使用的是自己的复选框图像,它可能太大……您可以通过自己绘制节点文本,将其稍微向右移动来解决此问题。我被答案中的第一句话弄糊涂了,没有再看下去。我不知道为什么TreeNode.ShowCheckBox在ASP.NET中运行良好,但在Windows窗体中不起作用。真烦人。我不喜欢在我的应用程序中添加我几乎不懂的代码,我主要是一名基础架构架构师,而不是开发人员。我不了解所有的十六进制数以及这些值的来源。对于未来的读者:我刚刚找到了第二个问题的答案,正如Shane Courtrille在2011年发现的那样,如果您将e.DrawDefault设置为true,出于某种原因,Windows在绘制文本时会删除部分复选框。事实上,我发现总是调用DrawString()更容易(从不将e.DrawDefault设置为true)。唯一的问题是,如果用户双击复选框,它仍然会进入选中状态。因此,如果他想使用这种方法,他必须进行额外的检查,以防止这种情况发生。:)