VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > C#教程 >
  • c#发现之旅—高情能ASP.net树状列表控件中

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  第一段HTML代码块

  若控件的“DynamicLoadChildNodes”属性值为true,也就是控件运行在客户端动态加载子节点,则输出支持客户端动态加载子节点的HTML代码,首先输出一个名为“SkyTreeViewControlTempXML”的XML数据岛标签,并将它的 “onreadystatechange“事件绑定到”SkyTreeViewControlDynamicLoadChildNodes”的 javascript函数上。这里还定义了一个名称为“SkyTreeViewControlDyanmicRootNodeID”的全局变量,用于指明是哪个节点正在加载在节点。这里输出的HTML代码内容为

<!-- 

    定义一个XML数据岛标签
    
    当动态加载子节点时使用该XML数据岛来加载定义子节点的XML文档,

    XML数据岛是IE特有技术,其他浏览器可能不支持。

-->
<xml id='SkyTreeViewControlTempXML'
     onreadystatechange='SkyTreeViewControlDynamicLoadChildNodes()' ></xml>
<script language=javascript>

//--------- 开始定义动态加载子节点使用的javascript 代码---------------------

// 当前动态加载子节点的根节点对象编号
var SkyTreeViewControlDyanmicRootNodeID ;

// 动态加载子节点
function SkyTreeViewControlDynamicLoadChildNodes()
{
    // 获得加载子节点定义数据的XML数据岛对象
    var xml = document.getElementById( 'SkyTreeViewControlTempXML' );
    if( xml == null )
    {
        return ;
    }
    if( xml.readyState != 'complete' )
    {    // 此时说明XML数据岛正处于工作状态,取消当前操作
        return ;
    }
    // 获得当前正在处理的树状列表节点对象
    var RootNode = document.getElementById( SkyTreeViewControlDyanmicRootNodeID + '_text' );
    if( RootNode == null)
        return ;
    var html = '';
    var errorflag = false;

    // 获得包含XSLT代码的XML数据岛对象
    var xsl = document.getElementById( 'SkyTreeViewControlXSLT');
    if( xsl == null )
    {
        // 未找到XSLT文档则设置错误信息
        html = '缺失XSLT数据';
        errorflag = true ;
    }
    else if( xml.XMLDocument.parseError.errorCode != 0)
    {
        // 若加载定义子节点的XML文档错误则设置错误信息
        html = '错误:' + xml.XMLDocument.parseError.reason
                + '[' + xml.XMLDocument.parseError.url + ']' ;
        errorflag = true ;
    }
    else
    {
        if( xml.XMLDocument.documentElement == null )
        {
            html = '未找到根节点';
            errorflag = true ;
        }
        else
        {
            // 将当前节点的HTML标签的编号保存到XML文档中。
            xml.XMLDocument.documentElement.setAttribute(
                'RootID' , 
                SkyTreeViewControlDyanmicRootNodeID );

            // 执行XSLT转换,生成用于显示子列表的HTML字符串
            html = xml.XMLDocument.transformNode( xsl.XMLDocument );
        }
    }
    // 将当前节点的“正在加载C#发现之旅 - 高性能ASP.NET树状列表控件(中)”的字样删掉
    var lbl = document.getElementById( SkyTreeViewControlDyanmicRootNodeID +'_Loading');
    if( lbl != null )
    {
        if( errorflag )
        {
            lbl.innerHTML = '<br />' + html ;
            return ;
        }
        // 将动态生成的HTML代码输出到HTML页面中
        lbl.insertAdjacentHTML('afterEnd', html );
        lbl.parentNode.removeChild( lbl );
    }
    else
    {
        // 将动态生成的HTML代码输出到HTML页面中
        RootNode.insertAdjacentHTML('afterEnd', html );
    }

    // 获得节点的展开点图片对象
    var myExpend    = document.getElementById( SkyTreeViewControlDyanmicRootNodeID + '_expend');
    // 获得节点的图标图片对象
    var myIcon        = document.getElementById( SkyTreeViewControlDyanmicRootNodeID + '_icon');
    // 获得节点的文本对象
    var myText        = document.getElementById( SkyTreeViewControlDyanmicRootNodeID + '_text');
    // 获得子节点表格    
    var myTable        = document.getElementById( SkyTreeViewControlDyanmicRootNodeID + '_table');

    if( myExpend != null 
        && myIcon != null
        && myText != null 
        && myTable != null )
    {
        // 将当前节点的控制图标从收缩状态改变为展开状态
        var SrcBack = myIcon.src ;
        myIcon.src = myIcon.getAttribute('SrcBack');
        myIcon.setAttribute( 'SrcBack' , SrcBack );
        
        SrcBack = myExpend.src ;
        myExpend.src = myExpend.getAttribute('SrcBack');
        myExpend.setAttribute( 'SrcBack' , SrcBack );

        //myTable.scrollIntoView( false );
    }

    SkyTreeViewControlDyanmicRootNodeID = null;

}//function SkyTreeViewControlDynamicLoadChildNodes()

//-------- 本段javascript 定义结束--------------------------

</script>

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  当用户展开一个节点而导致动态加载子节点时,其他的JavaSciprt代码会设置节点的XMLSource属性值到这个名为 “SkyTreeViewControlTempXML”的XML数据岛的src属性上。这会导致IE浏览器立即开始异步的加载XML文档,并根据其文档加载状态而多次触发“onreadystatechange”事件,从而调用javascript函数 “SkyTreeViewControlDynamicLoadChildNodes”,在这个javascript函数中,首先获得XML数据岛对象,然后判断其状态,若状态值不等于“complete”时,则文档还没有完成加载,从而退出等待下一次调用。

  若XML数据岛完成加载后,获得父节点的文本元素,然后获得嵌入在HTML文档中另外一个名为“SkyTreeViewControlXSLT”的 XML数据岛,这个XML数据岛包含了XSLT文档。然后使用刚刚加载的XML文档,调用它的“transfromNode”函数执行XSLT转换,则转换结果就是显示子节点的HTML字符串。然后使用HTML元素的“insertAdjacentHTML”函数将生成的HTML字符串输出到HTML页面上。

  成功的动态加载子节点后,javascript脚本还更新父节点的图标,使其表示为展开状态。

  第二段HTML代码块

  WEB控件输出完第一段HTML代码后,会根据需要输出第二段代码,第二段代码包含在客户端执行XSLT转换所需的XSLT模板代码以及初始化生成树状列表的HTML代码的javascript代码,其C#代码为

if( this.GenerateAtServer == false || this.DynamicLoadChildNodes )
{
    // 若允许动态加载子节点而且不是在服务器段生成HTML代码
    // 则输出动态加载子节点使用的javascript代码
    if (!base.Page.ClientScript.IsStartupScriptRegistered( 
         this.GetType() ,
         "SkyTreeViewControlXSLT"))
        {
        // 输出第二段HTML代码块
        base.Page.ClientScript.RegisterStartupScript( 
            this.GetType() ,
            "SkyTreeViewControlXSLT" , 
            @"
<!-- 使用一个XML数据岛保存客户端动态生成HTML代码时使用的XSLT代码-->
<xml id='SkyTreeViewControlXSLT'>" 
            + ReadXSLTString() // 此处从资源文件SkyTreeViewControl.xslt中获得XSLT代码
            + @"</xml>

<script language=javascript>

//--------------- 生成树状列表--------------------------------------
// 参数id 就是树状列表控件的编号
function RefreshSkyTreeViewControl( id )
{
    var xml = document.getElementById( id + '_xml');
    var xsl = document.getElementById( 'SkyTreeViewControlXSLT');
    var container = document.getElementById( id + '_container'  );
    if( container == null )
    {
        alert('未找到目标');
        return ;
    }
    if( container != null )
    {
        if( xml == null )
        {
            container.innerText = '缺失XML数据';
            return ;
        }
        if( xsl == null )
        {
            container.innerText = '缺失XSLT数据';
            return ;
        }
        var html = xml.XMLDocument.transformNode( xsl.XMLDocument );
        container.innerHTML = html ;
    }
}//function RefreshSkyTreeViewControl( id )

</script>"
        );
    }
}

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  在这里程序会判断控件的GenerateAtServer和DynamicLoadChildNodes 的属性值,若WEB控件不是在服务器端生成HTML代码或者允许在客户端动态加载子列表就会输出第二段HTML代码。

  在输出第二段HTML代码时,首先会输出一个名为“SkyTreeViewControlXSLT”的XML数据岛元素,该数据岛内容来自函数 “ReadXSLTString”,该函数就是简单的从一个名为“SkyTreeViewControl.xslt”的嵌入式程序集资源中读取所有的文本内容。

  此处还输出一个为“RefreshSkyTreeViewControl”的javascript函数,用于初始化一个树状列表,其参数就是树状列表的编号。也就是“myTreeView”,“myTreeView2”之类的控件客户端编号。在javascript函数中,首先获得第三个XML数据岛,获得树状节点定义信息XML文档,然后和“SkyTreeViewControlXSLT”数据岛中的XSLT文档执行XSLT转换,生成HTML字符串,然后调用HTML元素的“innerHTML”属性向HTML文档填充刚刚生成的HTML代码,从而展现出一个树状结构。

  本过程配套使用的“ReadXSLTString”函数的代码为

private static string strXSLString = null;
/// <summary>
/// 从程序集资源文件SkyTreeViewControl.xslt中加载XSLT代码。
/// </summary>
/// <returns>加载的XSLT代码字符串</returns>
private string ReadXSLTString()
{
    if (strXSLString == null)
    {
        foreach (string name in this.GetType().Assembly.GetManifestResourceNames())
        {
            // 查询程序集中所有的嵌入的资源的名称,找到以"SkyTreeViewControl.xslt"
            // 结尾的程序集资源并以UTF8的文本编码格式加载其中的文本内容。
            // 程序集资源的全名为“程序集默认名称空间.保存文件的各级目录.文件名”
            // 其中文件名中不能出现下划线。
            if (name.EndsWith(".SkyTreeViewControl.xslt"))
            {
                using (System.IO.Stream stream =
                    this.GetType().Assembly.GetManifestResourceStream(name))
                {
                    System.IO.StreamReader reader = new System.IO.StreamReader(
                        stream,
                        System.Text.Encoding.UTF8);
                    strXSLString = reader.ReadToEnd();
                }
                return strXSLString;
            }
        }
        throw new Exception("未找到程序集资源SkyTreeViewControl.xslt");
    }
    return strXSLString;
}

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  本函数中,程序会遍历程序集中所有的嵌入式的资源名称,若该名称以“.SkyTreeViewControl.xslt”结尾则以UTF8的编码格式读取该资源的文本内容。

  第三段HTML代码块

  WEB控件还会输出一个名为“SkyTreeViewControlExpendNodebyID”的javascript函数,该函数用于展开或收缩节点,而与之配套的定义了一个名为SkyTreeViewControlCurrentTreeNode的全局变量,用于保存当前高亮度显示的节点的编号。这段javascript代码为

// 定义树状列表的当前节点对象
var SkyTreeViewContrlCurrentTreeNode ;

//
//---------------- 展开指定编号的树状列表的节点---------------
// 参数strID 指明节点的ID号
// 参数bolSelect 指明是否高亮度显示这个树状列表节点
//
function SkyTreeViewContrlExpendNodeByID(strID , bolSelect )
{
    // 获得节点的展开点图片对象
    var myExpend    = document.getElementById(strID + '_expend');
    // 获得节点的图标图片对象
    var myIcon        = document.getElementById(strID + '_icon');     
    // 获得节点的文本对象
    var myText        = document.getElementById(strID + '_text');     
    // 获得子节点表格
    var myTable        = document.getElementById(strID + '_table'); 
    if( myText == null )
        return ;
    if( bolSelect )
    {
        // 设置树状列表节点高亮度显示
        if( SkyTreeViewContrlCurrentTreeNode != myText
            && SkyTreeViewContrlCurrentTreeNode != null)
        {
            SkyTreeViewContrlCurrentTreeNode.className = 'SkyTreeViewControl_TreeNode';
        }

        SkyTreeViewContrlCurrentTreeNode = myText;
        SkyTreeViewContrlCurrentTreeNode.className = 'SkyTreeViewControl_SelectedNode';
    }

    
    // 展开或收缩子节点
    if( myExpend != null 
        && myIcon != null
        && myTable != null )
    {
        // 切换节点前面的展开或收缩样式的图标
        var SrcBack = myIcon.src ;
        myIcon.src = myIcon.getAttribute('SrcBack');
        myIcon.setAttribute( 'SrcBack' , SrcBack );

        // 切换节点前面的+ 或者- 样式的图标
        SrcBack = myExpend.src ;
        myExpend.src = myExpend.getAttribute('SrcBack');
        myExpend.setAttribute( 'SrcBack' , SrcBack );
        
        // 显示或隐藏包含子节点的表格对象
        if( myTable.style.display != 'none' )
        {
            myTable.style.display='none';
        }
        else
        {
            myTable.style.display='';
        }
    }

    var dyload = false;
    if( myTable == null )
    {
        // 若不存在包含子节点的表格对象则尝试动态加载子节点
        // 此时节点的XMLSource扩展属性就保存着定义子节点的XML文档URL地址。
        var XMLSource = myText.getAttribute('XMLSource');
        if( XMLSource != null && XMLSource.length > 0 )
        {
            // 若设置了该XML文档地址则删除XMLSource 扩展属性并
            myText.removeAttribute('XMLSource');
            var xml = document.getElementById( 'SkyTreeViewControlTempXML');
            if( xml != null )
            {
                // 设置“正在加载C#发现之旅 - 高性能ASP.NET树状列表控件(中)”字样为显示状态
                SkyTreeViewControlDyanmicRootNodeID = strID ;
                var lbl = document.getElementById( SkyTreeViewControlDyanmicRootNodeID +'_Loading');
                if( lbl != null )
                {
                    lbl.style.display = '';
                }
                // 调用编号为SkyTreeViewControlTempXML 的XML数据岛来异步加载XML文档
                xml.src = XMLSource ;
                dyload = true ;
            }
        }
    }
    if( dyload == false )
    {
        //myText.scrollIntoView( false );
    }

}//function SkyTreeViewContrlExpendNodeByID(strID)

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  这个javascript函数有两个参数,第一个参数是节点编号,第二个参数是是否设置该节点为当前节点,也就是是否设置高亮度显示(一般的就是蓝底白字)。

  在这个javascript函数里面,首先根据节点编号获得节点的图标,文本和包含子节点列表的表格对象。并根据需要设置当前高亮度显示的节点对象。

  若子节点列表存在则需要展开和收缩子节点列表,此时将节点图标的src属性和它们的扩展属性SrcBack值进行互换,从而切换了图标,还对包含子节点列表的表格对象在可见状态和不可见状态间进行切换。

  若子节点列表不存在而且节点的XMLSource属性有效则开始动态加载子节点。首先获得名为 “SkyTreeViewControlTempXML”的XML数据岛对象,本控件输出的第一段HTML代码中已经包含了该XML数据岛。设置 javascript全局变量“SkyTreeViewControlDyanmicRootNodeID”的值为当前节点的编号,然后设置这个XML数据岛的src属性值为节点的XMLSource属性值。之后IE浏览器就异步的加载XML文档,转而执行第一段HTML代码块中的javascript脚本了。

  上面的代码都是使用RegisterStartupScript函数输出了三段HTML代码块。接下来就是输出控件的HTML代码内容了。

  输出控件HTML代码

  C#代码首先在内存中创建一个XML文档书写器,创建一个System.Xml.Serialization.XmlSerializer类型的对象,使用XML序列化技术将控件Nodes属性中的树状节点保存到一个XML文档中,实现这个功能的代码为

// 在内存中创建一个XML文档书写器
System.IO.StringWriter myStrWriter = new System.IO.StringWriter();
System.Xml.XmlTextWriter myXMLWriter = new System.Xml.XmlTextWriter( myStrWriter );
if( this.IndentXML && this.GenerateAtServer == false )
{
    myXMLWriter.Indentation = 3 ;
    myXMLWriter.IndentChar = ' ';
    myXMLWriter.Formatting = System.Xml.Formatting.Indented ;
}
// 使用XML序列化将控件的树状节点全部保存到一个XML文档中并输出到XML文档书写器中
System.Xml.Serialization.XmlSerializer xser = 
    new System.Xml.Serialization.XmlSerializer( typeof( SkyTreeNodeList ));
xser.Serialize( myXMLWriter , this.Nodes );
myXMLWriter.Close();
// 获得定义控件树状节点的XML字符串
string xml = myStrWriter.ToString();

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  若控件的“GenerateAtServer”属性值为true,也就是在服务器端生成HTML代码,实现该功能的代码为

// 若在服务器端生成HTML代码则使用服务器端的XSLT转换

// 这里从资源文件SkyTreeViewControl.xslt中获得XSLT代码
string xslt = ReadXSLTString();
System.Xml.XmlDocument xsltDocument = new System.Xml.XmlDocument();
xsltDocument.LoadXml( xslt );

// 获得树状节点的数据XML文档
System.Xml.XmlDocument NodeXmlDocument = new System.Xml.XmlDocument();
NodeXmlDocument.LoadXml( xml );
// 创建一个字符串书写器,XSLT转换结果将输出到这个字符串书写器中
myStrWriter = new System.IO.StringWriter();
// 创建XSLT转换引擎
System.Xml.Xsl.XslCompiledTransform transform = 
    new System.Xml.Xsl.XslCompiledTransform();
// 引擎加载XSLT模板
transform.Load(xsltDocument);
// 执行XSLT转换
transform.Transform( NodeXmlDocument  , null , myStrWriter );
// 直接向ASPX页面输出转换结果
writer.Write( myStrWriter.ToString());

  这段代码中,首先调用函数ReadXSLTString从资源文件“SkyTreeViewControl.xslt”加载一个XML文档,然后创建一个NodeXmlDocument变量,调用它的LoadXml函数对根节点进行XML序列化所得的XML字符串来生成XML文档,然后创建一个 System.Xml.Xsl.XslCompiledTransform类型的XSLT转换引擎,调用它的Load方法加载XSLT模板,调用它的 Transform方法来执行XSLT转换,转换结果输出到myStrWriter的字符串书写器中,这个字符串书写器中的内容就是用于显示树状结构的 HTML代码。然后程序使用RenderContent函数的writer参数将这个HTML代码输出到页面中。

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  若不是在服务器端生成HTML代码,那就是在客户端生成代码了,于是程序输出一个XML数据岛的HTML代码,该数据岛的内容就是节点XML文档的内容。实现这个功能的C#代码为

// 若在客户端动态生成HTML代码则将数据XML字符串输出到ASPX页面中
writer.Write("<span id='" + this.ClientID + "_container' >正在加载,请稍候C#发现之旅 - 高性能ASP.NET树状列表控件(中)</span>");
// 将数据XML字符串输出到ASPX页面中的一个XML数据岛中
writer.Write("<xml id='" + this.ClientID + "_xml'>" + xml + "</xml>");
// 输出将要初始化树状列表的javascript函数
this.Page.ClientScript.RegisterStartupScript(
    this.GetType() ,
    "SkyTreeViewControL_Init_" + this.ClientID , @"
<script language=javascript>
RefreshSkyTreeViewControl( '" + this.ClientID + @"' );
</script>
");

  这里调用了RegisterStartupScript函数,使得HTML页面加载时立即调用名为 RefreshSkeyTreeViewControl 的javascript函数来初始化这个树状列表,本控件输出的第二段HTML代码就包含了该javascript函数。

  操作数据视图

  本WEB控件还在数据视图中保存数据,其功能代码为

/// <summary>
/// 保存数据视图状态
/// </summary>
/// <returns>操作结果</returns>
protected override object SaveViewState()
{
    this.ViewState["nodes"] = this.myNodes ;
    return base.SaveViewState ();
}
/// <summary>
/// 加载数据视图状态
/// </summary>
/// <param name="savedState">操作结果</param>
protected override void LoadViewState(object savedState)
{
    myNodes = this.ViewState["nodes"] as SkyTreeNodeList ;
    base.LoadViewState (savedState);
}

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  当ASP.NET框架要求WEB控件保存数据到视图中,系统会自动调用控件的SaveViewState函数,当ASP.NET框架要求WEB控件从数据视图中加载数据时,系统会自动调用WEB控件的LoasViewState函数。能保存在数据视图中的对象必须能进行二进制序列化。这就是在 SkyTreeNode和SkyTreeNodeList类型前面都附加声明类型能进行二进制序列化的 “[System.Serializable()]”的原因。

  分析SkyTreeViewControl的源代码,读者可以看到这个WEB控件还是比较复杂的,它需要了解ASP.NET自定义控件的一些知识,此外还需要掌握javascript和IE浏览器XML数据岛的知识。

  XML数据岛是IE浏览器特有的功能,是微软对HTML标准的扩展,其他浏览器是不支持XML数据岛的,实际上我们可以使用 XMLHttpRequest 的ActiveX组件来从服务器上下载XML文档,而FireFox是支持XMLHttpRequest的,这样可以做到对FireFox的兼容。在这里我特地演示使用了XML数据岛的功能,而且使用XML数据岛的功能能将XML文档嵌入到HTML文档中,减少WEB系统的文件数,从而降低系统复杂度,而且方便部署。若规定客户端浏览器限制为IE浏览器时,则可以采用XML数据岛的功能。

  SkyTreeViewControl.xslt

  这个WEB控件中有一个很重要的文档就是XSLT模板文档。它保存在文件SkyTreeViewControl.xslt中,并作为嵌入的资源参与程序的编译。这个XSLT模板文档的主体结构为

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   <!-- 

  和 SkyTreeViewControl 树状列表控件配合使用的XSLT文档,本文档的生成操作必须为“嵌入的资源”。

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  编制 袁永福 2008-1-29

 -->
   <xsl:output method="html" indent="no" />
   <!-- ***************** 主模板,为XSLT转换的入口点 ******************** -->
   <xsl:template match="/*">
      ------------- 主模板的内容 -----------------------
   </xsl:template>
   <!-- *******************  输出一个树状列表节点 *************************** -->
   <xsl:template name="TreeNode">
      -------------- 子模板的内容 ----------------------
   </xsl:template>
</xsl:stylesheet>

  这里使用了xsl:output指令

  <xsl:output method="html" indent="no" />

  表明此XSLT转换生成是HTML代码,而且不进行缩进处理。

  该XSLT模板文档定义了两个XSLT模板,一个是默认模板,还有一个名为“TreeNode”的子模板。默认模板内容为

<!-- ***************** 主模板,为XSLT转换的入口点 ******************** -->
<xsl:template match="/*">
  <!-- 定义一个NodeID变量,表示当前节点的编号 -->
  <xsl:variable name="NodeID">
     <xsl:choose>
        <xsl:when test="string-length( @RootID ) > 0 ">
           <xsl:value-of select="@RootID" />
        </xsl:when>
        <xsl:when test="string-length(ID) > 0">
           <xsl:value-of select="ID" />
        </xsl:when>
        <xsl:otherwise>
           <xsl:value-of select="generate-id( . ) " />
        </xsl:otherwise>
     </xsl:choose>
  </xsl:variable>
  <!-- 若有子节点则显示子节点 -->
  <table border="0" cellspacing="0" cellpadding="0">
     <xsl:attribute name="id">
        <xsl:value-of select="concat( $NodeID , '_table' ) " />
     </xsl:attribute>
     <xsl:for-each select="Node">
        <xsl:call-template name="TreeNode">
           <xsl:with-param name="Level">1</xsl:with-param>
        </xsl:call-template>
     </xsl:for-each>
  </table>
</xsl:template>

 

  主模板是XSLT转换的入口处,在主模板中,首先创建了一个名为NodeID的XSLT参数,若定义了树状列表的根节点则创建table元素,然后循环遍历所有的根节点,并对每一个列表节点元素调用TreeNode模板,并传递了一个名为Level的值为1的参数,表示生成的节点层次数。这样就开始了递归创建HTML元素的过程。

 

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发
 

  当用户展开一个节点而导致动态加载子节点时,其他的JavaSciprt代码会设置节点的XMLSource属性值到这个名为 “SkyTreeViewControlTempXML”的XML数据岛的src属性上。这会导致IE浏览器立即开始异步的加载XML文档,并根据其文档加载状态而多次触发“onreadystatechange”事件,从而调用javascript函数 “SkyTreeViewControlDynamicLoadChildNodes”,在这个javascript函数中,首先获得XML数据岛对象,然后判断其状态,若状态值不等于“complete”时,则文档还没有完成加载,从而退出等待下一次调用。

  若XML数据岛完成加载后,获得父节点的文本元素,然后获得嵌入在HTML文档中另外一个名为“SkyTreeViewControlXSLT”的 XML数据岛,这个XML数据岛包含了XSLT文档。然后使用刚刚加载的XML文档,调用它的“transfromNode”函数执行XSLT转换,则转换结果就是显示子节点的HTML字符串。然后使用HTML元素的“insertAdjacentHTML”函数将生成的HTML字符串输出到HTML页面上。

  成功的动态加载子节点后,javascript脚本还更新父节点的图标,使其表示为展开状态。

  第二段HTML代码块

  WEB控件输出完第一段HTML代码后,会根据需要输出第二段代码,第二段代码包含在客户端执行XSLT转换所需的XSLT模板代码以及初始化生成树状列表的HTML代码的javascript代码,其C#代码为

if( this.GenerateAtServer == false || this.DynamicLoadChildNodes )
{
    // 若允许动态加载子节点而且不是在服务器段生成HTML代码
    // 则输出动态加载子节点使用的javascript代码
    if (!base.Page.ClientScript.IsStartupScriptRegistered( 
         this.GetType() ,
         "SkyTreeViewControlXSLT"))
        {
        // 输出第二段HTML代码块
        base.Page.ClientScript.RegisterStartupScript( 
            this.GetType() ,
            "SkyTreeViewControlXSLT" , 
            @"
<!-- 使用一个XML数据岛保存客户端动态生成HTML代码时使用的XSLT代码-->
<xml id='SkyTreeViewControlXSLT'>" 
            + ReadXSLTString() // 此处从资源文件SkyTreeViewControl.xslt中获得XSLT代码
            + @"</xml>

<script language=javascript>

//--------------- 生成树状列表--------------------------------------
// 参数id 就是树状列表控件的编号
function RefreshSkyTreeViewControl( id )
{
    var xml = document.getElementById( id + '_xml');
    var xsl = document.getElementById( 'SkyTreeViewControlXSLT');
    var container = document.getElementById( id + '_container'  );
    if( container == null )
    {
        alert('未找到目标');
        return ;
    }
    if( container != null )
    {
        if( xml == null )
        {
            container.innerText = '缺失XML数据';
            return ;
        }
        if( xsl == null )
        {
            container.innerText = '缺失XSLT数据';
            return ;
        }
        var html = xml.XMLDocument.transformNode( xsl.XMLDocument );
        container.innerHTML = html ;
    }
}//function RefreshSkyTreeViewControl( id )

</script>"
        );
    }
}

编缉推荐阅读以下文章

  • C#发现之旅 - 高性能ASP.NET树状列表控件(下)
  • C#发现之旅 - 高性能ASP.NET树状列表控件(上)
  • C#发现之旅:C#开发Windows Service程序(下)
  • C#发现之旅:C#开发Windows Service程序(上)
  • C#发现之旅之终结篇第十讲 文档对象模型
  • C#发现之旅第九讲 ASP.NET验证码技术
  • C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
  • C#发现之旅第七讲 C#图形开发高级篇
  • C#发现之旅第一讲 C#-XML开发
  • C#发现之旅第二讲 C#-XSLT开发


相关教程