[原创]FineUI秘密花园(二十三) — 树控件概述
树控件用来展示具有层次结构的数据。前面在介绍下拉列表和表格控件时,我们已经接触到模拟树的下拉列表和模拟树的表格,今天我们就来讲解真正的树控件。
标签创建的树控件
我们可以直接在ASPX页面中创建树控件,非常直观,比如:
1: <ext:Tree ID="Tree1" Width="500px" ShowHeader="true" Title="树控件(内联)" runat="server">
2: <Nodes>
3: <ext:TreeNode Text="中国" Expanded="true">
4: <ext:TreeNode Text="河南省" Expanded="true">
5: <ext:TreeNode Text="驻马店市" NodeID="zhumadian">
6: <ext:TreeNode Text="遂平县" Leaf="false" NodeID="suiping">
7: <ext:TreeNode Text="槐树乡" Leaf="false" NodeID="huaishu">
8: <ext:TreeNode Text="陈庄村" Leaf="true" NodeID="chenzhuang">
9: </ext:TreeNode>
10: </ext:TreeNode>
11: </ext:TreeNode>
12: </ext:TreeNode>
13: <ext:TreeNode Text="漯河市" Leaf="true" NodeID="luohe" />
14: </ext:TreeNode>
15: // 省略其他节点...
16: </ext:TreeNode>
17: </Nodes>
18: </ext:Tree>
显示效果如下图所示:
由此可见,一棵树是由TreeNode节点嵌套而来的,下面就来看下TreeNode有哪些属性:
树节点的常用属性
- Text:树节点文本
- NodeID:树节点ID
- Leaf:是否叶子节点
- Enabled:是否可用
- Expanded:是否展开
- NavigateUrl:链接地址
- Target:链接目标
- Icon:预定义图标
- IconUrl:图标地址
- ToolTip:提示文本
- SingleClickExpand:单击可切换节点的折叠展开状态
由此可见,树节点可以禁用、可以渲染为超链接、可以定义图标、可以设置提示文本。
可以回发的树节点
- EnablePostBack:是否可以回发(单击树节点)
- OnClientClick:点击按钮时需要执行的客户端脚本
- CommandName:命令名称
- CommandArgument:命令参数
可见,树节点也可以作为一个按钮来触发后台事件,只不过这个事件定义是在树控件上。而CommandName和CommandArgument则类似于表格控件中LinkButtonField定义的同名属性。
带复选框的树节点
- Checked:是否选中
- EnableCheckBox:是否启用复选框
- AutoPostBack:是否自动回发(改变复选框状态)
可见,树节点也可以作为一个复选框来触发后台事件。这里AutoPostBack属性就类似于表格控件中CheckBoxField定义的同名属性。
可以回发的树节点
通过一个简单示例来讲解其用法:
1: <ext:Tree ID="Tree1" Width="500px" OnNodeCommand="Tree1_NodeCommand" ShowHeader="true"
2: Title="树控件" runat="server">
3: <Nodes>
4: <ext:TreeNode Text="中国" Expanded="true">
5: <ext:TreeNode Text="河南省" Expanded="true">
6: <ext:TreeNode Text="驻马店市(点击回发)" EnablePostBack="true" Expanded="true" NodeID="Zhumadian">
7: <ext:TreeNode Text="遂平县(点击回发)" EnablePostBack="true" NodeID="Suiping">
8: </ext:TreeNode>
9: <ext:TreeNode Text="西平县(点击回发)" EnablePostBack="true" NodeID="Xiping">
10: </ext:TreeNode>
11: </ext:TreeNode>
12: <ext:TreeNode Text="漯河市" Enabled="true" NodeID="Luohe" />
13: </ext:TreeNode>
14: // 省略其他节点...
15: </ext:TreeNode>
16: </Nodes>
17: </ext:Tree>
这里有几个关键点:
- 为树控件注册节点命令处理函数;
- 在需要点击回发的树节点上启用EnablePostBack;
- 还可以指定CommandName或者CommandArgument(本例中未用到)。
来看下后台处理函数:
1: protected void Tree1_NodeCommand(object sender, FineUI.TreeCommandEventArgs e)
2: {
3: labResult.Text = "你点击了树节点:" + e.Node.Text;
4: }
运行截图:
带复选框的树节点
带复选框的树节点只需要启用EnableCheckBox即可,下面的例子我们会更进一步,使用自动回发的复选框树节点来全选/反选所有的子节点,运行效果如下图所示:
当选中河南省前面的复选框时,会回发页面并选中河南省下面所有子节点的复选框,这是怎么做到的呢?
先看一下页面标签:
1: <ext:Tree ID="Tree1" OnNodeCheck="Tree1_NodeCheck" Width="500px" ShowHeader="true"
2: Title="树控件" runat="server">
3: <Nodes>
4: <ext:TreeNode Text="中国" EnableCheckBox="true" AutoPostBack="true" Expanded="true">
5: <ext:TreeNode AutoPostBack="true" Text="河南省" EnableCheckBox="true" Expanded="true">
6: <ext:TreeNode Text="驻马店市" AutoPostBack="true" EnableCheckBox="true" NodeID="zhumadian">
7: <ext:TreeNode Text="遂平县" AutoPostBack="true" EnableCheckBox="true" NodeID="Suiping">
8: </ext:TreeNode>
9: <ext:TreeNode Text="西平县" AutoPostBack="true" EnableCheckBox="true" NodeID="Xiping">
10: </ext:TreeNode>
11: </ext:TreeNode>
12: <ext:TreeNode Text="漯河市" AutoPostBack="true" EnableCheckBox="true" NodeID="luohe" />
13: </ext:TreeNode>
14: // 省略其他节点...
15: </ext:TreeNode>
16: </Nodes>
17: </ext:Tree>
这里有几个关键点:
- 为树控件注册节点选中处理函数;
- 在需要显示复选框的节点上启用EnableCheckBox;
- 在需要自动回发复选框的树节点上启用AutoPostBack;
再来看下选中节点复选框的处理函数:
1: protected void Tree1_NodeCheck(object sender, FineUI.TreeCheckEventArgs e)
2: {
3: if (e.Checked)
4: {
5: Tree1.CheckAllNodes(e.Node.Nodes);
6: }
7: else
8: {
9: Tree1.UncheckAllNodes(e.Node.Nodes);
10: }
11: }
这里调用了CheckAllNodes函数来选中所有的子节点,当然我们也可以手工递归所有的子节点来完成此操作。
下面是使用递归的方式来完成此操作的参考代码:
1: protected void Tree1_NodeCheck(object sender, FineUI.TreeCheckEventArgs e)
2: {
3: if (!e.Node.Leaf)
4: {
5: CheckTreeNode(e.Node.Nodes, e.Checked);
6: }
7: }
8:
9: private void CheckTreeNode(TreeNodeCollection nodes, bool isChecked)
10: {
11: foreach (TreeNode node in nodes)
12: {
13: node.Checked = isChecked;
14: if (!node.Leaf)
15: {
16: CheckTreeNode(node.Nodes, isChecked);
17: }
18: }
19: }
延迟加载的树节点
在上面这些例子中,不知道你有没有发现一个细节,有时我们为子节点设置了Leaf=true,有时又没有设置,不过似乎都能正常运行,这是怎么回事?
其实,是否为树节点设置Leaf属性都可以,因为FineUI内部会重新递归所有的子节点,将拥有子节点的节点Leaf属性设为false,反之设为true。控制这一行为的属性就是AutoLeafIdentification(默认值为true)。
如果将树控件的AutoLeafIdentification设为false,则我们就需要为每一个子节点设置Leaf=true(默认为false),如果没有为一个理应成为子节点的节点设置Leaf=true,则此节点就会被渲染为一个可折叠展开的父节点,展开此节点时就会触发树控件的NodeExpand事件。
正好,我们可以利用这一特性来完成延迟加载的树节点,是不是很巧妙。下面通过一个示例来演示。
先看页面的标签:
1: <ext:Tree ID="Tree1" EnableArrows="true" OnNodeExpand="Tree1_NodeExpand" Width="500px"
2: ShowHeader="true" Title="延迟加载的树控件" AutoLeafIdentification="false" runat="server">
3: <Nodes>
4: <ext:TreeNode Text="中国" Expanded="true">
5: <ext:TreeNode Text="河南省" Expanded="true">
6: <ext:TreeNode Text="驻马店市(此节点延迟加载)" NodeID="zhumadian">
7: </ext:TreeNode>
8: <ext:TreeNode Text="漯河" NodeID="luohe" Leaf="true" />
9: </ext:TreeNode>
10: // 省略其他节点...
11: </ext:TreeNode>
12: </Nodes>
13: </ext:Tree>
这里有几个关键点:
- 为树控件注册节点展开处理函数;
- 为树控件设置AutoLeafIdentification=false;
- 为真正的子节点设置Leaf=true;
- 需要延迟加载的树节点不要设置Leaf属性(即默认为false)。
先来看下页面第一次打开的截图:
此时“驻马店市”下面并没有子节点,因此展开此节点时会触发树控件的节点展开事件。
下面来看下节点展开事件的处理函数:
1: protected void Tree1_NodeExpand(object sender, FineUI.TreeExpandEventArgs e)
2: {
3: DynamicAppendNode(e.Node);
4: }
5:
6: private void DynamicAppendNode(TreeNode parentNode)
7: {
8: parentNode.Expanded = true;
9:
10: TreeNode node = null;
11: switch (parentNode.NodeID)
12: {
13: case "zhumadian":
14: node = new TreeNode();
15: node.Text = "遂平县";
16: node.Leaf = false;
17: node.NodeID = "suiping";
18: parentNode.Nodes.Add(node);
19:
20: node = new TreeNode();
21: node.Text = "西平县";
22: node.Leaf = true;
23: node.NodeID = "xiping";
24: parentNode.Nodes.Add(node);
25: break;
26: case "suiping":
27: node = new TreeNode();
28: node.Text = "槐树乡";
29: node.Leaf = false;
30: node.NodeID = "huaishu";
31: parentNode.Nodes.Add(node);
32: break;
33: case "huaishu":
34: node = new TreeNode();
35: node.Text = "陈庄村";
36: node.Leaf = true;
37: node.NodeID = "chenzhuang";
38: parentNode.Nodes.Add(node);
39: break;
40: }
41: }
这段代码不仅处理展开“驻马店市”的情况,而且处理下面的层次结构,通过NodeID进行关联,大家可以认真分析下这段代码。
下面是运行截图:
注:第一次展开“驻马店市”之后,就向其中添加了子节点,所以折叠后再次展开此节点就不会触发节点展开事件了。
小结
本章我们介绍了树控件的各种用法,树节点不仅可以被渲染为普通文本、超链接、可回发的文本,而且可以渲染为带自动回发复选框的文本,同时我们还讲解了延迟树节点的用法。
下一篇文章我们会介绍如何将各种不同的数据源绑定到将树控件。