C# 允许在 .NET TreeView 中进行多选
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/206096/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Allow multi-select in a .NET TreeView
提问by Darcy Casselman
I'm stuck in .NET 2.0 Windows Forms.
我被困在 .NET 2.0 Windows 窗体中。
It doesn't look like the ability to select multiple nodes exists in the standard TreeView
control.
标准TreeView
控件中似乎不存在选择多个节点的能力。
I'm trying to do this for a context menu selection. So check boxes aren't an acceptable UI paradigm here.
我正在尝试为上下文菜单选择执行此操作。因此,复选框在这里不是可接受的 UI 范例。
What's the best way to provide that very necessary functionality?
提供这种非常必要的功能的最佳方式是什么?
采纳答案by Jeff Yates
We did this in a WTL project once, but the basic work needed is the same for .NET. To achieve a multiple selection tree control, you will need to draw the tree items yourself and override the keyboard and mouse handling. You will also need to maintain your own list of items that are selected.
我们曾经在一个 WTL 项目中这样做过,但所需的基本工作对于 .NET 是相同的。要实现多选树控件,您需要自己绘制树项并覆盖键盘和鼠标处理。您还需要维护自己的所选项目列表。
Don't forget to consider selection rules (are parents and children allowed, for example), and don't forget to implement the keyboard shortcuts including selection using Ctrl, Shift, and Ctrl+Shift, as well as the Spacebar for selecting/deselecting.
不要忘记考虑选择规则(例如,父母和孩子是否允许),不要忘记实现键盘快捷键,包括使用 Ctrl、Shift 和 Ctrl+Shift 进行选择,以及用于选择/取消选择的空格键.
回答by Darcy Casselman
回答by Jay Mooney
Are check-boxes an option? or do you want the select like you get in a list box?
复选框是一个选项吗?或者你想要像你在列表框中得到的选择?
- checkboxes are built in
- select like you get in a list box requires a custom tree control
- 复选框是内置的
- 像在列表框中一样选择需要自定义树控件
There is a multi-select tree control available on CodeProject:Multi-Select Tree View
CodeProject 上有一个多选树控件:Multi-Select Tree View
回答by Jon B
You might look at a 3rd party solution. The Infragisticstree does this. Not free, but the time spent trying to find a solution isn't really free, either.
您可能会查看 3rd 方解决方案。该Infragistics的树做到这一点。不是免费的,但是花在寻找解决方案上的时间也不是免费的。
回答by timpeck
The simplest solution would be to extend the existing TreeView control shipped with the framework and override the OnBeforeSelect and OnAfterSelect methods with logic to capture multiple selections.
最简单的解决方案是扩展框架附带的现有 TreeView 控件,并使用捕获多个选择的逻辑覆盖 OnBeforeSelect 和 OnAfterSelect 方法。
An example can be found here: http://www.arstdesign.com/articles/treeviewms.html
一个例子可以在这里找到:http: //www.arstdesign.com/articles/treeviewms.html
回答by Oliver Bock
The below code will allow you to adjust the background colour you use, to ensure that all selected nodes are highlighted.
下面的代码将允许您调整您使用的背景颜色,以确保所有选定的节点都突出显示。
protected override void WndProc(ref Message m)
{
switch (m.Msg) {
// WM_REFLECT is added because WM_NOTIFY is normally sent just
// to the parent window, but Windows.Form will reflect it back
// to us, MFC-style.
case Win32.WM_REFLECT + Win32.WM_NOTIFY: {
Win32.NMHDR nmhdr = (Win32.NMHDR)m.GetLParam(typeof(Win32.NMHDR));
switch((int)nmhdr.code) {
case Win32.NM_CUSTOMDRAW:
base.WndProc(ref m);
Win32.NMTVCUSTOMDRAW nmTvDraw = (Win32.NMTVCUSTOMDRAW)m.GetLParam(typeof(Win32.NMTVCUSTOMDRAW));
switch (nmTvDraw.nmcd.dwDrawStage) {
case Win32.CDDS_ITEMPREPAINT:
// Find the node being painted.
TreeNode n = TreeNode.FromHandle(this, nmTvDraw.nmcd.lItemlParam);
if (allSelected.Contains(n))
// Override its background colour.
nmTvDraw.clrTextBk = ColorTranslator.ToWin32(SystemColors.Highlight);
m.Result = (IntPtr)Win32.CDRF_DODEFAULT; // Continue rest of painting as normal
break;
}
Marshal.StructureToPtr(nmTvDraw, m.LParam, false); // copy changes back
return;
}
break;
}
}
base.WndProc(ref m);
}
// WM_NOTIFY notification message header.
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
public class NMHDR
{
private IntPtr hwndFrom;
public IntPtr idFrom;
public uint code;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMCUSTOMDRAW
{
public NMHDR hdr;
public int dwDrawStage;
public IntPtr hdc;
public RECT rc;
public IntPtr dwItemSpec;
public int uItemState;
public IntPtr lItemlParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct NMTVCUSTOMDRAW
{
public NMCUSTOMDRAW nmcd;
public int clrText;
public int clrTextBk;
public int iLevel;
}
public const int CDIS_SELECTED = 0x0001;
public const int CDIS_FOCUS = 0x0010;
public const int CDDS_PREPAINT = 0x00000001;
public const int CDDS_POSTPAINT = 0x00000002;
public const int CDDS_PREERASE = 0x00000003;
public const int CDDS_POSTERASE = 0x00000004;
public const int CDDS_ITEM = 0x00010000; // item specific
public const int CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT);
public const int CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT);
public const int CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE);
public const int CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE);
public const int CDDS_SUBITEM = 0x00020000;
public const int CDRF_DODEFAULT = 0x00000000;
public const int CDRF_NOTIFYITEMDRAW = 0x00000020;
public const int CDRF_NOTIFYSUBITEMDRAW = 0x00000020; // flags are the same, we can distinguish by context
public const int WM_USER = 0x0400;
public const int WM_NOTIFY = 0x4E;
public const int WM_REFLECT = WM_USER + 0x1C00;