EXE文件方便大家测试 源码下载
TreeView控件非常的好用,在我的公文系统中,使用TreeView控件选择接收公文的人员,支持单选,可多选
现提取出来,方便大家使用
涉及到的知识点
1:从Xml文件中加载内容显示到TreeView控件中
<?xml version="1.0" encoding="utf-8"?> <根目录> <组 名称="校长" 用户ID="1000"> <成员 名称="某某校长" 用户ID="9001" /> </组> <组 名称="副校长" 用户ID="1000"> <成员 名称="副校长甲" 用户ID="9002" /> <成员 名称="副校长乙" 用户ID="9003" /> </组> <组 名称="主任" 用户ID="1000"> <成员 名称="主任甲" 用户ID="9004" /> <成员 名称="主任乙" 用户ID="9005" /> <成员 名称="主任丙" 用户ID="9006" /> </组> <组 名称="教师" 用户ID="1000"> <成员 名称="教师甲" 用户ID="9007" /> <成员 名称="教师乙" 用户ID="9008" /> <成员 名称="教师丙" 用户ID="9009" /> <成员 名称="教师丁" 用户ID="9010" /> <成员 名称="教师戊" 用户ID="9011" /> <成员 名称="教师己" 用户ID="9012" /> </组> <组 名称="班主任" 用户ID="1000"> <成员 名称="教师甲" 用户ID="9007" /> <成员 名称="教师乙" 用户ID="9008" /> </组> <组 名称="学科" 用户ID="1000"> <组 名称="语文教师" 用户ID="1000"> <成员 名称="教师甲" 用户ID="9007" /> <成员 名称="教师丁" 用户ID="9010" /> </组> <组 名称="数学教师" 用户ID="1000"> <成员 名称="教师丙" 用户ID="9009" /> <成员 名称="教师己" 用户ID="9012" /> </组> </组> </根目录>
加载Xml配置文件到TreeView中
class="code_img_closed" src="/Upload/Images/2015030202/0015B68B3C38AA5B.gif" alt="" />logs_code_hide('63fe2a5a-ae61-495a-a5e9-81c5d00d6f90',event)" src="/Upload/Images/2015030202/2B1B950FA3DF188F.gif" alt="" />private void LoadMixedTreeView() { mixedCheckBoxesTreeView1.Nodes.Clear(); // Clear any existing items mixedCheckBoxesTreeView1.BeginUpdate(); // Begin updating the treeview HiddenCheckBoxTreeNode rootNode = new HiddenCheckBoxTreeNode("某某单位"); mixedCheckBoxesTreeView1.Nodes.Add(rootNode); HiddenCheckBoxTreeNode treenode; XmlNodeList baseNodeList = docXML.SelectNodes("根目录/组"); // Get all first level <folder> nodes foreach (XmlNode xmlnode in baseNodeList) // loop through all base <folder> nodes { string title = xmlnode.Attributes["名称"].Value; string id = xmlnode.Attributes["用户ID"].Value; treenode = new HiddenCheckBoxTreeNode(title); // add it to the tree treenode.Name = id; rootNode.Nodes.Add(treenode); populateChildNodes(xmlnode, treenode); // Get the children } mixedCheckBoxesTreeView1.EndUpdate(); // Stop updating the tree mixedCheckBoxesTreeView1.Refresh(); this.mixedCheckBoxesTreeView1.Nodes[0].Expand(); }绑定xml数据到左侧单选TreeView
//level的作用主要是为了防止触发子节点的AfterCheck方法。 private int level = 1; //遍历 获取选中的节点的值 //(二) 1、 多选树形控件 AfterCheck private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { if (level == 1) { level = 2; //遍历选择所有相关子栏目 TreeViewCheck.CheckControl(e); listBox1.Items.Clear(); //遍历所有子栏目并添加到listBox中 foreach (TreeNode node in treeView1.Nodes) { SetMulTreeViewList(node); } label3.Text = "接收对象" + listBox1.Items.Count.ToString() + "人"; } } //(二) 2、 设置多个树形控件列表 public void SetMulTreeViewList(TreeNode nodes) { level = 1; //防止节点没有子节点被忽略 if (nodes.Checked && nodes.Nodes.Count == 0) { selectUser = new SelectUser(nodes.Text, nodes.Name); if (!hasExist(selectUser)) { listBox1.Items.Add(selectUser); listBox1.DisplayMember = "Name"; listBox1.ValueMember = "UserID"; } } //有子节点 foreach (TreeNode newNode in nodes.Nodes) { if (newNode.Nodes.Count > 0) { SetMulTreeViewList(newNode); } //判断孩子节点 else { if (newNode.Checked && newNode.Nodes.Count == 0) { selectUser = new SelectUser(newNode.Text, newNode.Name); if (!hasExist(selectUser)) { listBox1.Items.Add(selectUser); listBox1.DisplayMember = "Name"; listBox1.ValueMember = "UserID"; } } } } } //(二) 3. 添加的项目是否已经存在 private bool hasExist(SelectUser selectUser) { bool flag = false; foreach (SelectUser _Row in listBox1.Items) { if (_Row.Name == selectUser.Name && _Row.UserID == selectUser.UserID) flag = true; } return flag; }绑定Xml数据到上例中右侧多选TreeView
2:扩展TreeView控件,默认的TreeView 控件只能设置显示选中框,或者不显示选中框
如图:
如果要实现如下图的效果,就要对TreeView控件做一些扩展
扩展的方法来自国外的一个网站,感谢原作者
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Runtime.Serialization; using System.Runtime.InteropServices; namespace CnTreeView { public class HiddenCheckBoxTreeNode : TreeNode { internal bool CheckboxHidden { set; get; } public HiddenCheckBoxTreeNode() { } public HiddenCheckBoxTreeNode(string text) : base(text) { } public HiddenCheckBoxTreeNode(string text, TreeNode[] children) : base(text, children) { } public HiddenCheckBoxTreeNode(string text, int imageIndex, int selectedImageIndex) : base(text, imageIndex, selectedImageIndex) { } public HiddenCheckBoxTreeNode(string text, int imageIndex, int selectedImageIndex, TreeNode[] children) : base(text, imageIndex, selectedImageIndex, children) { } protected HiddenCheckBoxTreeNode(SerializationInfo serializationInfo, StreamingContext context) : base(serializationInfo, context) { } } }HiddenCheckBoxTreeNode
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Runtime.Serialization; using System.Runtime.InteropServices; namespace CnTreeView { public class MixedCheckBoxesTreeView : TreeView { /// <summary> /// Specifies or receives attributes of a node /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct TV_ITEM { public int Mask; public IntPtr ItemHandle; public int State; public int StateMask; public IntPtr TextPtr; public int TextMax; public int Image; public int SelectedImage; public int Children; public IntPtr LParam; } public const int TVIF_STATE = 0x8; public const int TVIS_STATEIMAGEMASK = 0xF000; public const int TVM_SETITEMA = 0x110d; public const int TVM_SETITEM = 0x110d; public const int TVM_SETITEMW = 0x113f; [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, ref TV_ITEM lParam); protected override void WndProc(ref Message m) { base.WndProc(ref m); // trap TVM_SETITEM message if (m.Msg == TVM_SETITEM || m.Msg == TVM_SETITEMA || m.Msg == TVM_SETITEMW) // check if CheckBoxes are turned on if (CheckBoxes) { // get information about the node TV_ITEM tv_item = (TV_ITEM)m.GetLParam(typeof(TV_ITEM)); HideCheckBox(tv_item); } } protected void HideCheckBox(TV_ITEM tv_item) { if (tv_item.ItemHandle != IntPtr.Zero) { // get TreeNode-object, that corresponds to TV_ITEM-object TreeNode currentTN = TreeNode.FromHandle(this, tv_item.ItemHandle); HiddenCheckBoxTreeNode hiddenCheckBoxTreeNode = currentTN as HiddenCheckBoxTreeNode; // check if it's HiddenCheckBoxTreeNode and // if its checkbox already has been hidden if (hiddenCheckBoxTreeNode != null && !hiddenCheckBoxTreeNode.CheckboxHidden) { // to evade repeat hiding, we set CheckboxHidden to true hiddenCheckBoxTreeNode.CheckboxHidden = true; // specify attributes to update TV_ITEM updatedTvItem = new TV_ITEM(); updatedTvItem.ItemHandle = tv_item.ItemHandle; updatedTvItem.Mask = TVIF_STATE; updatedTvItem.StateMask = TVIS_STATEIMAGEMASK; updatedTvItem.State = 0; // send TVM_SETITEM message SendMessage(new HandleRef(this, Handle), TVM_SETITEM, 0, ref updatedTvItem); } } } protected override void OnBeforeCheck(TreeViewCancelEventArgs e) { base.OnBeforeCheck(e); // prevent checking/unchecking of HiddenCheckBoxTreeNode, // otherwise, we will have to repeat checkbox hiding if (e.Node is HiddenCheckBoxTreeNode) e.Cancel = true; } } }MixedCheckBoxesTreeView
其他相关类
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; namespace CnTreeView { public static class TreeViewCheck { /// <summary> /// 系列节点 Checked 属性控制 /// </summary> /// <param name="e"></param> public static void CheckControl(TreeViewEventArgs e) { if (e.Action != TreeViewAction.Unknown) { if (e.Node != null) { CheckParentNode(e.Node, e.Node.Checked); } if (e.Node.Nodes.Count > 0) { CheckAllChildNodes(e.Node, e.Node.Checked); } } } #region 私有方法 //改变所有子节点的状态 private static void CheckAllChildNodes(TreeNode pn, bool IsChecked) { foreach (TreeNode tn in pn.Nodes) { tn.Checked = IsChecked; if (tn.Nodes.Count > 0) { CheckAllChildNodes(tn, IsChecked); } } } //改变父节点的选中状态 private static void CheckParentNode(TreeNode curNode, bool IsChecked) { bool bChecked = true; if (curNode.Parent != null) { foreach (TreeNode node in curNode.Parent.Nodes) { if (node.Checked == false) { bChecked = false; break; } } if (bChecked) { curNode.Parent.Checked = true; CheckParentNode(curNode.Parent, true); } else { curNode.Parent.Checked = false; CheckParentNode(curNode.Parent, false); } } } #endregion } }TreeViewCheck
SelectUser类,您可以根据使用情况进行替换
using System; using System.Collections.Generic; using System.Text; namespace CnTreeView { public class SelectUser { private string name; public string Name { get { return name; } set { name = value; } } private string userID; public string UserID { get { return userID; } set { userID = value; } } public SelectUser(string name, string userID) { this.name = name; this.userID = userID; } } }SelectUser
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnostics; using System.Xml; using System.IO; using System.Threading; namespace CnTreeView { public partial class TreeViewDemo : Form { private XmlDocument docXML = new XmlDocument(); public TreeViewDemo() { InitializeComponent(); this.mixedCheckBoxesTreeView1.BeforeCheck += new System.Windows.Forms.TreeViewCancelEventHandler(this.myTreeView1_BeforeCheck); this.mixedCheckBoxesTreeView1.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.myTreeView1_AfterCheck); this.treeView1.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterCheck); } private SelectUser selectUser; #region 树形控件 单选 // (一)1、 单选树形控件 BeforeCheck private void myTreeView1_BeforeCheck(object sender, TreeViewCancelEventArgs e) { if (e.Action != TreeViewAction.Unknown) { TreeNode oldNode = this.mixedCheckBoxesTreeView1.Tag as TreeNode; if (oldNode != null && oldNode != e.Node) { oldNode.Checked = false; } TreeNodeCollection nodes = this.mixedCheckBoxesTreeView1.Nodes; if (e.Node.Parent != null) { nodes = e.Node.Parent.Nodes; } foreach (TreeNode node in nodes) { if (node != e.Node) { node.Checked = false; } } this.mixedCheckBoxesTreeView1.Tag = e.Node; } } // (一)2、 单选树形控件 AfterCheck //遍历 获取选中的节点的值 private void myTreeView1_AfterCheck(object sender, TreeViewEventArgs e) { foreach (TreeNode node in mixedCheckBoxesTreeView1.Nodes) { SetTreeViewList(node); } label3.Text = "接收对象" + listBox1.Items.Count.ToString() + "人"; } //(一)、3 SetTreeViewList 遍历TreeView 设置ListBox中的内容 public void SetTreeViewList(TreeNode nodes) { //防止节点没有子节点被忽略 if (nodes.Checked && nodes.Nodes.Count == 0) { listBox1.Items.Clear(); selectUser = new SelectUser(nodes.Text, nodes.Name); listBox1.Items.Add(selectUser); listBox1.DisplayMember = "Name"; listBox1.ValueMember = "UserID"; } //有子节点 foreach (TreeNode newNode in nodes.Nodes) { if (newNode.Nodes.Count > 0) { SetTreeViewList(newNode); } //判断孩子节点 else { if (newNode.Checked && newNode.Nodes.Count == 0) { listBox1.Items.Clear(); selectUser = new SelectUser(newNode.Text, newNode.Name); listBox1.Items.Add(selectUser); listBox1.DisplayMember = "Name"; listBox1.ValueMember = "UserID"; } } } } #endregion #region 树形控件 多选 //level的作用主要是为了防止触发子节点的AfterCheck方法。 private int level = 1; //遍历 获取选中的节点的值 //(二) 1、 多选树形控件 AfterCheck private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { if (level == 1) { level = 2; //遍历选择所有相关子栏目 TreeViewCheck.CheckControl(e); listBox1.Items.Clear(); //遍历所有子栏目并添加到listBox中 foreach (TreeNode node in treeView1.Nodes) { SetMulTreeViewList(node); } label3.Text = "接收对象" + listBox1.Items.Count.ToString() + "人"; } } //(二) 2、 设置多个树形控件列表 public void SetMulTreeViewList(TreeNode nodes) { level = 1; //防止节点没有子节点被忽略 if (nodes.Checked && nodes.Nodes.Count == 0) { selectUser = new SelectUser(nodes.Text, nodes.Name); if (!hasExist(selectUser)) { listBox1.Items.Add(selectUser); listBox1.DisplayMember = "Name"; listBox1.ValueMember = "UserID"; } } //有子节点 foreach (TreeNode newNode in nodes.Nodes) { if (newNode.Nodes.Count > 0) { SetMulTreeViewList(newNode); } //判断孩子节点 else { if (newNode.Checked && newNode.Nodes.Count == 0) { selectUser = new SelectUser(newNode.Text, newNode.Name); if (!hasExist(selectUser)) { listBox1.Items.Add(selectUser); listBox1.DisplayMember = "Name"; listBox1.ValueMember = "UserID"; } } } } } //(二) 3. 添加的项目是否已经存在 private bool hasExist(SelectUser selectUser) { bool flag = false; foreach (SelectUser _Row in listBox1.Items) { if (_Row.Name == selectUser.Name && _Row.UserID == selectUser.UserID) flag = true; } return flag; } #endregion #region 树形控件 private void radioButton2_Click(object sender, EventArgs e) { mixedCheckBoxesTreeView1.Visible = false; treeView1.Visible = true; listBox1.Items.Clear(); label3.Text = "接收对象0人"; level = 2; CheckTreeview(treeView1, false); level = 1; } private void radioButton1_Click(object sender, EventArgs e) { mixedCheckBoxesTreeView1.Visible = true; treeView1.Visible = false; listBox1.Items.Clear(); label3.Text = "接收对象0人"; CheckTreeview(mixedCheckBoxesTreeView1, false); } //遍历TreeView 全部取消 或全部选中 private void checkSubNodes(TreeNode treeNode, bool flag) { treeNode.Checked = flag; foreach (TreeNode tn in treeNode.Nodes) { checkSubNodes(tn, flag); } } private void CheckTreeview(TreeView treeView, bool flag) { TreeNodeCollection nodes = treeView.Nodes; foreach (TreeNode n in nodes) { checkSubNodes(n, flag); } } #endregion #region 加载xml菜单 private void LoadMixedTreeView() { mixedCheckBoxesTreeView1.Nodes.Clear(); // Clear any existing items mixedCheckBoxesTreeView1.BeginUpdate(); // Begin updating the treeview HiddenCheckBoxTreeNode rootNode = new HiddenCheckBoxTreeNode("某某单位"); mixedCheckBoxesTreeView1.Nodes.Add(rootNode); HiddenCheckBoxTreeNode treenode; XmlNodeList baseNodeList = docXML.SelectNodes("根目录/组"); // Get all first level <folder> nodes foreach (XmlNode xmlnode in baseNodeList) // loop through all base <folder> nodes { string title = xmlnode.Attributes["名称"].Value; string id = xmlnode.Attributes["用户ID"].Value; treenode = new HiddenCheckBoxTreeNode(title); // add it to the tree treenode.Name = id; rootNode.Nodes.Add(treenode); populateChildNodes(xmlnode, treenode); // Get the children } mixedCheckBoxesTreeView1.EndUpdate(); // Stop updating the tree mixedCheckBoxesTreeView1.Refresh(); this.mixedCheckBoxesTreeView1.Nodes[0].Expand(); } private void LoadTreeView() { treeView1.Nodes.Clear(); // Clear any existing items treeView1.BeginUpdate(); // Begin updating the treeview TreeNode rootNode = new TreeNode("某某单位"); treeView1.Nodes.Add(rootNode); TreeNode treenode; XmlNodeList baseNodeList = docXML.SelectNodes("根目录/组"); // Get all first level <folder> nodes foreach (XmlNode xmlnode in baseNodeList) // loop through all base <folder> nodes { string title = xmlnode.Attributes["名称"].Value; string id = xmlnode.Attributes["用户ID"].Value; treenode = new TreeNode(title); // add it to the tree treenode.Name = id; rootNode.Nodes.Add(treenode); populateChildNodes(xmlnode, treenode); // Get the children } treeView1.EndUpdate(); // Stop updating the tree treeView1.Refresh(); this.treeView1.Nodes[0].Expand(); } private void populateChildNodes(XmlNode oldXmlnode, TreeNode oldTreenode) { //TreeNode treenode = null; XmlNodeList childNodeList = oldXmlnode.ChildNodes; // Get all children for the past node (parent) foreach (XmlNode xmlnode in childNodeList) // loop through all children { string title = xmlnode.Attributes["名称"].Value; string id = xmlnode.Attributes["用户ID"].Value; TreeNode tnode = new TreeNode(title); tnode.Name = id; oldTreenode.Nodes.Add(tnode); //treenode = oldTreenode.Nodes.Add(title); // add it to the parent node tree populateChildNodes(xmlnode, tnode); // get any children for this node } } #endregion private void TreeViewDemo_Load(object sender, EventArgs e) { docXML.Load(AppDomain.CurrentDomain.BaseDirectory + "\\menu.xml"); LoadMixedTreeView(); LoadTreeView(); } } }TreeViewDemo