解决方案可以考虑:
1. 在客户端手动通过 js 捕获 checkbox 的 click 事件,然后显示的执行 __doPostBack 方法
对于如何捕获事件,获取目标节点,与 类似 TreeView几个小技巧 提到的 父子节点CheckBox的级联选择 类似
2. 扩展 TreeNode(继承 System.Web.UI.WebControls.TreeNode)
然而 TreeNode 并未继承自 System.Web.UI.Control,故而无法访问 checkbox 自控件,其无 Render 之类的方法。虽然它对控件开发者提供了 RenderPreText 和 RenderPostText 方法,分别在节点前、后添加自定义信息,但还是无法访问 CheckBox。
看来此路暂时不通
3. 扩展 TreeView,重写 Render,通过 HtmlTextWriter 获取呈现的 html 代码,并想办法遍历其中的 <input type=checkbox /> 为其添加 οnclick=_doPostBack
XTreeView.cs
Code
using System;
using System.Data;
using System.Configuration;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
namespace Digdotnet.Test
{
/**//// <summary>
/// XTreeView 的摘要说明
/// </summary>
public class XTreeView : TreeView
{
/**//// <summary>
/// 为 checkbox 添加客户端事件 click 处理程序。
/// <remarks>
///
/// 默认 TreeView 节点呈现为
/// <input type="checkbox" name="TreeView1n2CheckBox" id="TreeView1n2CheckBox" title="1.1.1" />
/// <a class="TreeView1_0" href="javascript:__doPostBack('TreeView1','s1\\1.1\\1.1.1')" οnclick="TreeView_SelectNode(TreeView1_Data, this,'TreeView1t2');" id="TreeView1t2">1.1.1</a>
///
/// 重写 Render 方法之后呈现为
/// <input type="checkbox" name="TreeView1n2CheckBox" id="TreeView1n2CheckBox" οnclick="TreeView_SelectNode(TreeView1_Data, this.nextSibling,'TreeView1t2');__doPostBack('TreeView1','s1\\1.1\\1.1.1')" title="1.1.1" />
/// <a class="TreeView1_0" href="javascript:__doPostBack('TreeView1','s1\\1.1\\1.1.1')" οnclick="TreeView_SelectNode(TreeView1_Data, this,'TreeView1t2');" id="TreeView1t2">1.1.1</a>
///
/// </remarks>
/// </summary>
/// <param name="writer"></param>
protected override void Render(HtmlTextWriter writer)
{
if (DesignMode) { // 设计时,不做处理
base.Render(writer);
return;
}
//
StringWriter sw = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(sw);
// 输出 TreeView 的 html 源码
base.Render(htmlWriter);
//
sw.Flush();
string treeHtml = sw.ToString();
// 从节点的 <a/> 标记中分析 href 和 onclick 属性中的两个 js 函数,
// 并插入 checkbox 的 onclick 事件
string pattern = @"<input.* (id=.*) title=.*/>[\n\r\s]*<a.* href=.*(__doPostBack.*)"".* οnclick=.*(TreeView_SelectNode.*);"".* id=.*"">";
Match match = Regex.Match(treeHtml, pattern);
// 正则替换
treeHtml = Regex.Replace(treeHtml, pattern, new MatchEvaluator(ReplaceTextCallback));
// 呈现经过处理的 TreeView
writer = new HtmlTextWriter(Context.Response.Output);
writer.Write(treeHtml);
}
/**//// <summary>
/// 正则替换回调方法。
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
private static string ReplaceTextCallback(Match match)
{
int pos = match.Value.IndexOf(match.Groups[1].Value) + match.Groups[1].Value.Length + 1;
return match.Value.Insert(pos, String.Format(@"οnclick=""{0};{1}"" ", match.Groups[3].Value.Replace("this", "this.nextSibling"), match.Groups[2].Value));
}
}
}
测试页面
测试效果
using System;
using System.Data;
using System.Configuration;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
namespace Digdotnet.Test
{
/**//// <summary>
/// XTreeView 的摘要说明
/// </summary>
public class XTreeView : TreeView
{
/**//// <summary>
/// 为 checkbox 添加客户端事件 click 处理程序。
/// <remarks>
///
/// 默认 TreeView 节点呈现为
/// <input type="checkbox" name="TreeView1n2CheckBox" id="TreeView1n2CheckBox" title="1.1.1" />
/// <a class="TreeView1_0" href="javascript:__doPostBack('TreeView1','s1\\1.1\\1.1.1')" οnclick="TreeView_SelectNode(TreeView1_Data, this,'TreeView1t2');" id="TreeView1t2">1.1.1</a>
///
/// 重写 Render 方法之后呈现为
/// <input type="checkbox" name="TreeView1n2CheckBox" id="TreeView1n2CheckBox" οnclick="TreeView_SelectNode(TreeView1_Data, this.nextSibling,'TreeView1t2');__doPostBack('TreeView1','s1\\1.1\\1.1.1')" title="1.1.1" />
/// <a class="TreeView1_0" href="javascript:__doPostBack('TreeView1','s1\\1.1\\1.1.1')" οnclick="TreeView_SelectNode(TreeView1_Data, this,'TreeView1t2');" id="TreeView1t2">1.1.1</a>
///
/// </remarks>
/// </summary>
/// <param name="writer"></param>
protected override void Render(HtmlTextWriter writer)
{
if (DesignMode) { // 设计时,不做处理
base.Render(writer);
return;
}
//
StringWriter sw = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(sw);
// 输出 TreeView 的 html 源码
base.Render(htmlWriter);
//
sw.Flush();
string treeHtml = sw.ToString();
// 从节点的 <a/> 标记中分析 href 和 onclick 属性中的两个 js 函数,
// 并插入 checkbox 的 onclick 事件
string pattern = @"<input.* (id=.*) title=.*/>[\n\r\s]*<a.* href=.*(__doPostBack.*)"".* οnclick=.*(TreeView_SelectNode.*);"".* id=.*"">";
Match match = Regex.Match(treeHtml, pattern);
// 正则替换
treeHtml = Regex.Replace(treeHtml, pattern, new MatchEvaluator(ReplaceTextCallback));
// 呈现经过处理的 TreeView
writer = new HtmlTextWriter(Context.Response.Output);
writer.Write(treeHtml);
}
/**//// <summary>
/// 正则替换回调方法。
/// </summary>
/// <param name="match"></param>
/// <returns></returns>
private static string ReplaceTextCallback(Match match)
{
int pos = match.Value.IndexOf(match.Groups[1].Value) + match.Groups[1].Value.Length + 1;
return match.Value.Insert(pos, String.Format(@"οnclick=""{0};{1}"" ", match.Groups[3].Value.Replace("this", "this.nextSibling"), match.Groups[2].Value));
}
}
}
测试页面
Code
<%@ Page Language="C#" %>
<%@ Register TagPrefix="ddntest" Namespace="Digdotnet.Test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void TreeView1_TreeNodeCheckChanged(object sender, TreeNodeEventArgs e)
{
Label1.Text = String.Format("You check the node whose <font color='red'>Text={0} and ValuePath={1}</font>", e.Node.Text, e.Node.ValuePath);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>扩展 TreeView 实现选择 CheckBox 自动回发</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>扩展 TreeView 实现选择 CheckBox 自动回发</h1>
<input type="button" value="Refresh" onclick="location.href=location.href" />
<ddntest:XTreeView id="TreeView1" runat="server" ShowCheckBoxes="All" OnTreeNodeCheckChanged="TreeView1_TreeNodeCheckChanged">
<Nodes>
<asp:TreeNode Text="1">
<asp:TreeNode Text="1.1" >
<asp:TreeNode Text="1.1.1" ></asp:TreeNode>
</asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="2">
<asp:TreeNode Text="2.1" >
<asp:TreeNode Text="2.2.1" ></asp:TreeNode>
</asp:TreeNode>
</asp:TreeNode>
</Nodes>
</ddntest:XTreeView>
<asp:Label ID="Label1" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
<%@ Page Language="C#" %>
<%@ Register TagPrefix="ddntest" Namespace="Digdotnet.Test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
protected void TreeView1_TreeNodeCheckChanged(object sender, TreeNodeEventArgs e)
{
Label1.Text = String.Format("You check the node whose <font color='red'>Text={0} and ValuePath={1}</font>", e.Node.Text, e.Node.ValuePath);
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>扩展 TreeView 实现选择 CheckBox 自动回发</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>扩展 TreeView 实现选择 CheckBox 自动回发</h1>
<input type="button" value="Refresh" onclick="location.href=location.href" />
<ddntest:XTreeView id="TreeView1" runat="server" ShowCheckBoxes="All" OnTreeNodeCheckChanged="TreeView1_TreeNodeCheckChanged">
<Nodes>
<asp:TreeNode Text="1">
<asp:TreeNode Text="1.1" >
<asp:TreeNode Text="1.1.1" ></asp:TreeNode>
</asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="2">
<asp:TreeNode Text="2.1" >
<asp:TreeNode Text="2.2.1" ></asp:TreeNode>
</asp:TreeNode>
</asp:TreeNode>
</Nodes>
</ddntest:XTreeView>
<asp:Label ID="Label1" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
测试效果