treeview插件的官方demo地址:http://jquery.bassistance.de/treeview/demo/
实现步骤:
一、新建一JQueryTreeviewController,其默认的Index View内容如下:
<link rel="stylesheet" href="/Content/jquery.treeview.css" />
<script src="/Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.treeview.js" type="text/javascript"></script>
<script src="/Scripts/jquery.treeview.async.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#black").treeview({
url: '<%=Url.Action("GetMenuTree","JQueryTreeview") %>'
});
});
</script>
<h2>TreeViewIndex</h2>
<ul id="black" class="navigateFiletree">
</ul>
从以上代码中可以看出,获取此视图后,当页面就绪时将调用GetMenuTree action方法来获取treeview插件所需要的json字符串,并且自动生成树形。
注:代码中引用的js和css文件,在下载的treeview插件包中可以找到。
二、实现GetMenuTree action方法,代码如下:
public JsonStringResult GetMenuTree()
{
string sql = "SELECT [ModuleID],[SuperModuleID] FROM [SysModules]";
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
{
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
DataTable dt = new DataTable();
SqlDataReader reader = cmd.ExecuteReader();
dt.Load(reader);
reader.Close();
conn.Close();
return this.JsonString(JQTreeHelper.GetJsonString(dt, "ModuleID", "ModuleID", "SuperModuleID", ""));
}
}
其作用就是从数据库中读取出需要显示成树形的数据,并且调用JQTreeHelper来生成相应的json字符串,其返回结果中的JsonStringResult 是自定义的一个result类,其作用基本与系统自带的JsonResult相同,只是输出文本时不再进行json序列化而已。
三、实现JQTreeHelper类,代码如下:
/// <summary>
/// jquery插件中的treeview控件的帮助类,用于生成treeview控件所需要的html代码结构
/// </summary>
public static class JQTreeHelper
{
public static List<JQTreeNode> GetJsonData(DataTable dtAllNodes,string idColumnName,string textColumnName,string parentIdColumnName,string rootNodeParentIdValue)
{
List<JQTreeNode> rootNodes = new List<JQTreeNode>();
DataView dvRootNodes = new DataView(dtAllNodes);
dvRootNodes.RowFilter = parentIdColumnName + "='" + rootNodeParentIdValue + "'";
foreach (DataRowView dv in dvRootNodes)
{
JQTreeNode node = new JQTreeNode();
if (dv[idColumnName] != DBNull.Value)
{
node.id = dv[idColumnName].ToString();
}
node.text = dv[textColumnName].ToString();
node.children = GetJsonData(dtAllNodes, idColumnName, textColumnName, parentIdColumnName, dv[idColumnName].ToString());
rootNodes.Add(node);
}
return rootNodes;
}
public static string GetJsonString(DataTable dtAllNodes, string idColumnName, string textColumnName, string parentIdColumnName, string rootNodeParentIdValue)
{
List<JQTreeNode> actual;
actual = GetJsonData(dtAllNodes, idColumnName, textColumnName, parentIdColumnName, rootNodeParentIdValue);
//序列化后,由于默认将所有字段都序列化输出,所以需要将没有赋值取默认值的字段替换为空,以此来减少输出的字符数
StringBuilder result = new StringBuilder();
new JavaScriptSerializer().Serialize(actual, result);
result.Replace("\"id\":null,", "");
result.Replace(",\"expanded\":false", "");
result.Replace(",\"hasChildren\":false", "");
result.Replace(",\"classes\":null", "");
result.Replace(",\"children\":null", "");
return result.ToString();
}
}
/// <summary>
/// jquery插件中的treeview控件进行ajax请求时返回的json数据对象
/// </summary>
public class JQTreeNode
{
/// <summary>
/// 树节点id
/// </summary>
public string id { get; set; }
/// <summary>
/// 树节点文本
/// </summary>
public string text { get; set; }
/// <summary>
/// 是否展开
/// </summary>
public bool expanded { get; set; }
/// <summary>
/// 是否有子节点
/// </summary>
public bool hasChildren { get; set; }
/// <summary>
/// cssclass类名称
/// </summary>
public string classes { get; set; }
/// <summary>
/// 子节点集合
/// </summary>
public List<JQTreeNode> children { get; set; }
}
到此代码就全部结束。
最近在做酒店的网上会员自助服务项目,其中有一项是介绍会员手册的。由于此项目需要做成产品,而每家酒店的会员手册又不相同,如何做到既能通用又能由用户进行个性化修改而不修改程序呢?
最后采取了用xml的方法,将会员手册的数据保存到xml文件中,由于会员手册有可能会包含图片,表格等html数据,如果我的xml文件考虑得太细则不能通用,于是我将xml文件设置成以下格式:
<?xml version="1.0" encoding="utf-8" ?>
<handbook>
<title>如何成为会员</title>
<content>
<![CDATA[
<table>
<tr>
<td>1</td>
<td>网上直接注册</td>
</tr>
<tr>
<td>2</td>
<td>前台直接办理</td>
</tr>
<tr>
<td>3</td>
<td>传真办理</td>
</tr>
</table>
]]>
</content>
</handbook>
只保留了一个标题和一个内容项,而内容项里需要注意的是包含有:<![CDATA[]]>标签,将需要包含的html代码直接放在其中即可。
在输出的时候进行xsl转换,转换时由于包含有html代码,所以需要将输出项的“禁止输出编码转换”设置为yes,这样在输出的时候就会将html代码直接输出,ie解析的时候就能正常显示相应的结果了。
xslt文件如下:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<table>
<tr>
<td align="center">
<xsl:value-of select="handbook/title"/>
</td>
</tr>
<tr>
<td align="left">
<xsl:value-of disable-output-escaping="yes" select="handbook/content"/>
</td>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>
在会员手册的详细页面中,放置一个XML的控件,设置其DocumentSource,TransformSource属性后调用databind方法即可。当用户想要更改会员手册内容的时候,只需要更改xml文件即可。程序无需再修改和编译。
通过调试检查代码,并没有发现错误,并且页面的响应也完全正常,但就是事件会执行两次。百思不得其解,于是就上网寻找答案,结果发现网上介绍此乃是.Net的一个bug(详细请参考:http://www.cnblogs.com/bluewater/archive/2006/11/21/567871.html),ImageButton会导致传递IE向IIS服务器POST两次数据,其中第一次传回服务器的数据缺少鼠标指针位置数据,第二次传回服务器的数据是正确的。(注:经测试发现,只有将ImageButton放在其他容器控件的内部时才会发生这样的事情,如果单独使用并不会),导致控件中的事件也响应了两次。既然如此又想要ImageButton的美观,又要能完成事件,于是就将ImageButton更改成了HyperLink,设置其图片地址,并且将其客户端OnClick事件连接上回发脚本即可实现事件。
在此提醒大家一下,使用ImageButton作为其他控件的子控件时需要注意,为了避免出现莫名错误,建议还是在其他控件内部不要使用ImageButton,直到微软有补丁推出。
在内容页中如何调用母版页上的内容大家想必都已经知道,这里我也不再啰嗦。我想介绍给大家的方法是如何在母版页中如何调用内容页的方法。
母版页给我们带来了很多方便性,但也带来了一个问题:在设计母版页的时候,总会碰到需要在母版页中调用内容页的方法,但此时内容页尚未设计,如何调用呢?下面就让我用一个实例给大家讲解一下:
母版页:MasterPage.master的页面代码如下:
<body>
<form id="form1" runat="server">
<table>
<tr>
<td>
<asp:Button ID="CallContentMethod" runat="server" OnClick="CallContentMethod_Click"
Text="调用内容页方法" />
<asp:Label ID="welcomeMessage" runat="server" Text="这里将显示内容页的欢迎信息"></asp:Label></td>
</tr>
<tr>
<td>
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
</td>
</tr>
</table>
</form>
</body>
其中有一个按钮和一个文本,其中的文本用来显示内容页的欢迎信息,按钮用来调用内容页的方法,但此时内容页并不存在,那么按钮的单击事件代码如何写呢?
这里我们需要引入一个页面基类的概念,想必大家都清楚;aspx页面只要求后台类是继承此Page类即可。所以我们先添加一个继承自Page的页面基类BasePage,然后让页面继承自我们BasePage并重写相关方法,利用运行时的动态性来解决此问题。相关代码如下:
BasePage.cs:
public class BasePage :Page
{
/// <summary>
/// 输出每个内容页的欢迎信息,内容页继承此类并重写此方法即可。此方法会由母版页自动调用
/// </summary>
public virtual string SayHello()
{
return "这是页面基类返回的欢迎信息!";
}
}
母版页的后台代码如下:
BasePage currentPage = null;
protected void Page_Load(object sender, EventArgs e)
{
currentPage = Page as BasePage;
}
protected void CallContentMethod_Click(object sender, EventArgs e)
{
if (currentPage != null)
{
welcomeMessage.Text = currentPage.SayHello();
}
}
此处母版页中定义一个成员变量指向BasePage,在PageLoad中将实际运行的页面进行转型,这样在按钮的单击事件中就可以调用BasePage定义的SayHello方法了。又由于此方法是虚方法,在运行时绑定具体方法,即可实现我们的要求。
下面是内容页的代码:
Default.aspx.cs:
//注意类一定要继承自自定义的基类,否则母版页中转型会失败
public partial class Template_Default : BasePage
//重写欢迎信息方法
public override string SayHello()
{
return "这是来自内容页的欢迎信息!";
}
。
通过以上的步骤,我们就可以轻松实现在母版页中调用内容页的方法。如果想自动调用,只需要在母版页的Page_Load方法中转型后直接调用相关方法即可。
如果大家有更好的方法欢迎一起讨论!!!
