问题
C#的TreeView能够实现大部分功能,
但是1)类似Shift键进行批量选择,Ctrl进行选择性选择功能没有实现。
2)不存在级联选择。父节点选择了,子节点没有根据父节点的状态进行状态设置(某些应用)
解决方案
向 注册事件,在KeyDown中记录是否存在Shift或者Ctrl键的按下。在KeyUp完成选择。在NodeMouseClick事件中把中间选择的点高亮。
通过注册AfterCheck事件实现级联选择。
完整代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
namespace WorldWind.Aide
{
/// <summary>
/// 这个类提供树形视图的另类操作
/// </summary>
[CodeDescription("2013.07.24","封装多选的功能")]
public class TreeViewAssist
{
#region 属性
/// <summary>
/// 批量选择的节点
/// </summary>
private List<TreeNode> m_selectedNodes = new List<TreeNode>();
private bool m_controlKeyDown = false;
private bool m_shiftKeyDown = false;
private TreeView m_treeView;
private Color m_defaultForeColor = Color.Black;
private Color m_defaultBackColor = Color.White;
private Color m_highlightBackColor = SystemColors.Highlight;
private Color m_highlightForeColor = Color.White;
private bool m_enableMultiSelect = true;
private bool m_enebleCascadeSelect = true;
private bool m_allowParentSingleCheck = true;
#endregion
#region 对外属性
/// <summary>
/// 获得批量选择的节点
/// <para>注意,这个是通过Shift键或者Control键得到的节点,键没用按下去就没有</para>
/// </summary>
public List<TreeNode> SelectedNodes
{
get { return m_selectedNodes; }
}
public Color DefaultForeColor
{
get { return m_defaultForeColor; }
set { m_defaultForeColor = value; }
}
public Color DefaultBackColor
{
get { return m_defaultBackColor; }
set { m_defaultBackColor = value; }
}
public Color HighlightBackColor
{
get { return m_highlightBackColor; }
set { m_highlightBackColor = value; }
}
public Color HighlightForeColor
{
get { return m_highlightForeColor; }
set { m_highlightForeColor = value; }
}
/// <summary>
/// 是否允许多选
/// </summary>
public bool EnableMultiSelect
{
get { return m_enableMultiSelect; }
set {
if (m_enableMultiSelect != value)
{
m_enableMultiSelect = value;
SetEvent();
}
}
}
/// <summary>
/// 是否允许级联选择
/// </summary>
public bool EnebleCascadeSelect
{
get { return m_enebleCascadeSelect; }
set {
if (m_enebleCascadeSelect != value)
{
m_enebleCascadeSelect = value;
SetEvent();
}
}
}
/// <summary>
/// 是否允许父节点单独进行选择,默认true,即子类没有选择那么父类也没得选择
/// </summary>
public bool AllowParentSingleCheck
{
get { return m_allowParentSingleCheck; }
set { m_allowParentSingleCheck = value; }
}
#endregion
#region 构造函数
/// <summary>
/// 根据一个树来构建一个辅助
/// </summary>
/// <param name="treeView"></param>
public TreeViewAssist(TreeView treeView)
: this(treeView, true, true)
{
}
/// <summary>
/// 建立图层节点的帮助
/// </summary>
/// <param name="treeView"></param>
/// <param name="enableMultiSelect">是否允许多点选择</param>
/// <param name="enableCascadeSelect">是否允许级联选择</param>
public TreeViewAssist(TreeView treeView, bool enableMultiSelect,bool enableCascadeSelect)
{
m_enableMultiSelect = enableMultiSelect;
m_enebleCascadeSelect = enableCascadeSelect;
m_treeView = treeView;
m_defaultForeColor = treeView.ForeColor;
m_defaultBackColor = treeView.BackColor;
SetEvent();
}
#endregion
#region TreeView事件
/// <summary>
/// 根据设置配置事件
/// </summary>
private void SetEvent()
{
if (m_enableMultiSelect)
{
m_treeView.KeyDown += new KeyEventHandler(m_treeView_KeyDown);
m_treeView.KeyUp += new KeyEventHandler(m_treeView_KeyUp);
m_treeView.NodeMouseClick += new TreeNodeMouseClickEventHandler(m_treeView_NodeMouseClick);
}
else
{
m_treeView.KeyDown -= new KeyEventHandler(m_treeView_KeyDown);
m_treeView.KeyUp -= new KeyEventHandler(m_treeView_KeyUp);
m_treeView.NodeMouseClick -= new TreeNodeMouseClickEventHandler(m_treeView_NodeMouseClick);
}
if (m_enebleCascadeSelect)
{
m_treeView.AfterCheck += new TreeViewEventHandler(m_treeView_AfterCheck);
}
else
{
m_treeView.AfterCheck -= new TreeViewEventHandler(m_treeView_AfterCheck);
}
}
void m_treeView_AfterCheck(object sender, TreeViewEventArgs e)
{
if (e.Action != TreeViewAction.ByMouse)
return;
TriggerParentCheck(e.Node, e.Node.Checked);
TriggerChildCheck(e.Node, e.Node.Checked);
}
void m_treeView_KeyDown(object sender, KeyEventArgs e)
{
m_controlKeyDown = e.Control;
m_shiftKeyDown = e.Shift;
}
void m_treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
OnSelectingNodes(e.Node);
}
}
void m_treeView_KeyUp(object sender, KeyEventArgs e)
{
m_controlKeyDown = false;
m_shiftKeyDown = false;
}
#endregion
#region 批量选择的代码
/// <summary>
/// 清除选择的节点
/// </summary>
public void ClearSelectedNodes()
{
if (m_selectedNodes.Count == 0)
return;
foreach (TreeNode tn in m_selectedNodes)
{
tn.ForeColor = DefaultForeColor;
tn.BackColor = DefaultBackColor;
}
m_selectedNodes.Clear();
}
/// <summary>
/// 清除选择的节点
/// </summary>
/// <param name="tn"></param>
private void ClearSelectedNode(TreeNode tn)
{
tn.ForeColor = DefaultForeColor;
tn.BackColor = DefaultBackColor;
m_selectedNodes.Remove(tn);
}
/// <summary>
/// 添加一个节点作为选择节点的一个
/// </summary>
/// <param name="tn"></param>
/// <param name="checkExist"></param>
private void SetNodeAsSelectedNodes(TreeNode tn, bool checkExist)
{
if (checkExist)
{
if (m_selectedNodes.Contains(tn))
return;
}
m_selectedNodes.Add(tn);
tn.BackColor = HighlightBackColor;
tn.ForeColor = HighlightForeColor;
}
/// <summary>
/// 正在通过Shift或者Control的节点
/// </summary>
/// <param name="selectedNode"></param>
private void OnSelectingNodes(TreeNode selectedNode)
{
if (m_controlKeyDown == false && m_shiftKeyDown == false)
{
ClearSelectedNodes();
return;
}
if (m_controlKeyDown)
{
if (m_selectedNodes.Count == 0)
{
if (this.m_treeView.SelectedNode != null)
{
SetNodeAsSelectedNodes(this.m_treeView.SelectedNode, true);
}
}
SetNodeAsSelectedNodes(selectedNode, true);
}
if (m_shiftKeyDown)
{
TreeNode firstTn = this.m_treeView.SelectedNode;
if (m_selectedNodes.Count > 0)
firstTn = m_selectedNodes[0];
TreeNode secondTn = selectedNode;
AddShiftNodes(firstTn, secondTn);
}
}
/// <summary>
/// 添加经过Shift控制的节点
/// </summary>
/// <param name="firstTn"></param>
/// <param name="secondTn"></param>
private void AddShiftNodes(TreeNode firstTn, TreeNode secondTn)
{
TreeNode nextVisibleNode = firstTn;
bool find = false;
while (nextVisibleNode != null)
{
if (nextVisibleNode == secondTn)
{
find = true;
break;
}
nextVisibleNode = nextVisibleNode.NextVisibleNode;
}
//清除原来的数据
ClearSelectedNodes();
if (firstTn != null && secondTn != null)
{
TravelShiftSelectedNodes(firstTn, secondTn, find);
}
}
/// <summary>
/// 添加Shift控制选择的节点
/// </summary>
/// <param name="currentNode"></param>
/// <param name="secondNode"></param>
/// <param name="findNext"></param>
private void TravelShiftSelectedNodes(TreeNode currentNode, TreeNode secondNode, bool findNext)
{
SetNodeAsSelectedNodes(currentNode, false);
if (currentNode == secondNode)
return;
TreeNode nextNode;
if (findNext)
nextNode = currentNode.NextVisibleNode;
else
nextNode = currentNode.PrevVisibleNode;
if (nextNode != null)
{
TravelShiftSelectedNodes(nextNode, secondNode, findNext);
}
}
/// <summary>
/// 组织选择的节点,包括
/// <para>判断一个节点的选择了,但它的子节点只选择了一部分</para>
/// <para>一个节点和它的子节点都选择了,那么只选择这个节点,子节点不作为选择</para>
/// </summary>
/// <returns></returns>
public bool OrganizeSelectedNodes()
{
bool[] toBeRemove = new bool[m_selectedNodes.Count];
for (int i = m_selectedNodes.Count - 1; i > -1; i--)
{
//存在一个组,这个组内的数据只有部分被选择
if (m_selectedNodes[i].Nodes.Count > 0)
{
int childSelCount = 0;
foreach (TreeNode tn in m_selectedNodes[i].Nodes)
{
if (m_selectedNodes.Contains(tn))
{
childSelCount++;
}
}
if (childSelCount != 0 && childSelCount < m_selectedNodes[i].Nodes.Count)
{
MessageBox.Show("【" + m_selectedNodes[i].Text + "】只选择了部分的数据,不能进行下一步操作!");
return false;
}
}
}
for (int i = m_selectedNodes.Count - 1; i > -1; i--)
{
for (int j = i - 1; j > -1; j--)
{
if (m_selectedNodes[j].Parent == m_selectedNodes[i])
{
toBeRemove[j] = true;
}
}
}
for (int i = m_selectedNodes.Count - 1; i > -1; i--)
{
if (toBeRemove[i])
m_selectedNodes.RemoveAt(i);
}
return true;
}
#endregion
#region 级联选择
/// <summary>
/// 级联到父类的选择
/// </summary>
/// <param name="tn"></param>
/// <param name="tnChecked"></param>
public void TriggerParentCheck(TreeNode tn, bool tnChecked)
{
if (tnChecked)
{
TreeNode parentTN = tn.Parent;
//传递上层
while (parentTN != null && parentTN.Checked == false)
{
parentTN.Checked = true;
parentTN = parentTN.Parent;
}
}
else
{
TreeNode parentTN = tn.Parent;
if (parentTN == null)
return;
bool childHasChecked = false;
for (int i = 0; i < parentTN.Nodes.Count; i++)
{
if (parentTN.Nodes[i].Checked)
{
childHasChecked = true;
break;
}
}
if (childHasChecked)
{
TriggerParentCheck(tn, true);
}
else if (m_allowParentSingleCheck == false)
{
if (parentTN.Checked == true)
{
parentTN.Checked = false;
TriggerParentCheck(parentTN, false);
}
}
}
}
/// <summary>
/// 级联到子类的选择
/// </summary>
/// <param name="tn"></param>
/// <param name="tnChecked"></param>
public void TriggerChildCheck(TreeNode tn, bool tnChecked)
{
TriggerChildCheck(tn, tnChecked, true);
}
/// <summary>
/// 级联到子类的选择
/// </summary>
/// <param name="tn"></param>
/// <param name="tnChecked"></param>
/// <param name="checkNodeCount"></param>
private void TriggerChildCheck(TreeNode tn, bool tnChecked, bool checkNodeCount)
{
if (checkNodeCount)
{
if (tn.Nodes == null && tn.Nodes.Count == 0)
{
return;
}
}
foreach (TreeNode childTN in tn.Nodes)
{
if (childTN.Checked != tnChecked)
{
childTN.Checked = tnChecked;
if (childTN.Nodes != null && childTN.Nodes.Count != 0)
{
TriggerChildCheck(childTN, tnChecked, false);
}
}
}
}
#endregion
#region 卸载
/// <summary>
/// 卸载
/// </summary>
public void Dispose()
{
EnableMultiSelect = false;
this.EnebleCascadeSelect = false;
}
#endregion
}
}