我需要能够禁用 WinForms 应用程序控件中的某些复选框,但标准控件TreeView
中没有内置此类功能。TreeView
我已经在使用该TreeView.BeforeCheck
事件并在节点被禁用并且工作正常时取消它。
我还将ForeColor
禁用节点的 更改为GrayText
.
有没有人有一个简单而强大的解决方案?
由于在 C++ 中有支持,我们可以使用 p/invoke 解决它。
这是 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);
在您的 tree_DrawNode 函数中确定正在绘制的节点是否应该有一个复选框,并在适当时将其隐藏。然后将 Default 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
}
}
树视图:
$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)
}
}
TreeView.BeforeCheck - 注册此事件,检查节点是否是允许选中复选框的节点,如果无法选中,则可以通过设置 TreeViewCancelEventArgs 上的 Cancel 属性来取消事件。这应该有望阻止用户选中这些框,但不会带来最佳的用户体验。
要删除不可选中项的复选框,您可以使用 owner-draw 在复选框上绘制一个实心矩形以将其删除。
没有内置的东西可以做到这一点。您可以使用 BeforeCheck 事件并为所需节点取消它。如果复选框的外观很重要,那么您需要在此处放置图像以显示复选框已禁用。
此链接可能会引起您的兴趣。