动态加载用户控件的组件

来源:互联网 发布:仿淘宝首页下拉刷新 编辑:程序博客网 时间:2024/06/10 22:11
让我们来做个页面模版吧!有了模版是不是就可以统一了呢!Sure
比如:模版页Template.ascx中我们留出中间一个部分,或者你想要留出的一个空间,让以后放入你想要的内容。
好了!那么在我们的页面index.aspx上我们就可以引用这个Template.ascx,然后在空出的部分放入我们特别的东西,当然最好是在空的地方我们插入另外一个页面如:List.ascx
当然我们在做个页面MyArchive.aspx.同样的我们引用这个Template.ascx,然后再在空出大那个地方我们插入了另外一个页面Archive.ascx.
非常好。我们要的两个index.aspx.MyArchive.aspx页面是不是一样的呢?就只有我们留空的那一个地方不一样而已。
当然这样的应用可以是各种各样,可以不用框架集而达到更完美的效果。而你的页面完全可以没有重复的东西。因为我们的页面完全是组装而成的!
那么有了这个美妙的想法之后我们就开始去实现。
 
技术点:1、怎么留出一个空间出来,然后还要让引用页找到这个空间。
        2、怎么引用模版而且还要找出留出的空间。
        3、怎么引用另外一页插入我们在模版页中留出的空间。
 
其实所有这些就需要用到三个组件,一个是用来保留的空间,一个是用来引用页面放入到我们保留出来的空间,这两个组件其实只是起到标记的作用而已。另一个也是主要的一个就是引用模版,然后处理引用页面并插入到模版中去。
 
1、我们来解决的一个技术问题,留个空间很容易的就是PlaceHolder那么我们还要考虑到ID的问题,因为我们还要找到这个地方,当然我们可能要留几个不同的地方,这样就很有必要处理一下ID的问题。那么扩展PlaceHolder同时继承INamingContainer
我们取名为:PlugArea
那么这个主要做的事情有两件事,把本身保存起来,然后在第三个组件用到的时候取出来。
public class PlugArea : PlaceHolder, INamingContainer {       
       public override string ID {
           get {
              return base.ID;
           }
           set {
              base.ID = value;
              AddToContext();
           }
       }
       private static readonly String contextKey = "Region.MasterPages.Region";
       private void AddToContext() {
           if ( HttpContext.Current != null ) {
              String myKey = contextKey + this.ID;
              if ( HttpContext.Current.Items.Contains(myKey) ) {
                  throw new InvalidOperationException("这个ID'" + this.ID + "'已经用了啦!.");
              } else {
                  HttpContext.Current.Items[myKey] = this;
              }
           }
       }
       internal static PlugArea FindPlugArea( String ID ) {
           if ( HttpContext.Current == null ) {
              return null;
           }
           return HttpContext.Current.Items[contextKey + ID] as PlugArea;
       }  
    }
 
那么我们的Template.ascx可以写成这样
<%@ Control %>
<%@ Register TagPrefix="Region" Namespace="Region.Controls" Assembly="Region.Controls" %>
<HTML>
    <HEAD>    
       <title>信息管理系统</title>      
    </HEAD>
    <bodyleftmargin="0"topmargin="0"marginwidth="0"marginheight="0">       <formrunat="server"id="Form1">      
       <tablewidth = 800align=center border=0cellpadding=0cellspacing=0><tr><td>     
       相同的第一部分
       </td></tr><tr><td>      
       <Region:PlugAreaid="part1"runat="server"/>     </td></tr><tr><td>
        相同的第二部分
        </td></tr><tr><td>
       <Region:PlugAreaid="part2"runat="server"/>
       </td></tr><tr><td>
       相同的第三部分
       </td></tr></table>
       </form>
    </body>
</HTML>
 
2、引用模版页的时候,在里面标记以下我们保留的空间应该插入哪个页面,标记以下就可以了!具体的事情由引用模版页的组建来搞定。继承PlaceHolder
组建起名:SignArea
两件事情:一、只需把ID设成我们要插入那个空间组件的ID.
          二、在后面把这个插入我们留出的空间的时候,把组建的路径设成一样的,避免路径不一样引起异常发生。
当然,我们要在这个SignArea内应用我们的页面。
public class SignArea: PlaceHolder {
      internal string Directory;
       public override string TemplateSourceDirectory {
           get {
              return Directory;
           }
       }
    }
 
我们可以这样用:
<Region: SignArea id=" part1"runat="server">
    这里可以用我前面的文章讲LoadSky来来引用用户页面,或直接写内容放这里。
</Region: SignArea>
<Region: SignArea id=" part2"runat="server">
    同上第一部分。
</Region: SignArea>
 
3、应用我们的模版页并处理其中的模块插入。
继承PlaceHolder
命名:LoadTemplate
做事情:一、重载AddParsedSubObject事件,在记录PlaceHolder中的SignArea
二、加载Template页。
        三、根据SignAreaid找到PlugArea(用PlugArea内的FindPlugArea,也就是为什么要用静态方法的原因),然后把SignArea插入到PlugArea中去。
这三件事做完事情也就做完了
看一下代码:
public class LoadTemplate : PlaceHolder {    
        private ArrayList signarealist = new ArrayList();
        protected override void AddParsedSubObject(object obj)
        {
            if (obj is SignArea) {
              signarealist.Add(obj);
           }         
       }       
       protected override void OnInit(EventArgs e) {
           this.GetTemplate();
           base.OnInit(e);
       }
       private void GetTemplate() {
           if (TemplateFilePath == null) {
              throw new Exception("ûÓÐÄ£°åÒ³£¡");
           }
           Controls.Add(Page.LoadControl(TemplateFilePath));
           SignAreaInsertIntoPlugArea();
       }
       private void SignAreaInsertIntoPlugArea() {
           foreach (SignArea signarea in signarealist) {
              PlugArea plugarea = PlugArea.FindPlugArea(signarea.ID);
              if (plugarea == null ) {
                  throw new Exception("ÕÒ²»µ½²åÈëµÄ¿Õ¼ä'" + signarea.ID + "'");
              }
              SignArea.Directory = TemplateSourceDirectory;
              plugarea.Controls.Clear();
              plugarea.Controls.Add(signarea);
           }
       }
       public string TemplateFilePath{
           get {
              return (string)ViewState["TemplateFilePath"];
           }
           set {
              ViewState["TemplateFilePath"] = value;
              ChildControlsCreated = false;
           }
       }
    }
 
 
好我们来看看怎样引用模版页!index.aspx 页面:
<%@ Page %>
<%@ Register TagPrefix="Region" Namespace="Region.Controls" Assembly="Region.Controls" %>
<Region: LoadTemplate runat="server"id="LoadTemplate "TemplateFilePath ="~/Template.ascx"> 
    <Region:SignArea id="part1"runat="server">
    <Region:LoadSky id="Sky1" skinPath="~/List.ascx "runat="server"/>
</Region:SignArea>  
<Region:SignArea id="part2"runat="server">
    <Region:LoadSky id="Sky2" skinPath="~/MyArchive.ascx "runat="server"/>
</Region:SignArea>
</Region:LoadTemplate>
 
那么运行一下完整的一个页面就出现在我们面前了。当然可以这样生成所有想要的一样风格的页面。
 
从一开始写到现在,最后这里就变成了传说中的那个Masterpages的技术。
就如同天下武学都源自少林一样
上一篇文章写到了动态加载用户组件的组件。
但是怎样灵活的在项目中运用呢?怎样做到面向组件的开发呢?就像是积木式开发,我们的叶面可以有不同的组件来完成,而整个叶面就是一个容器,我们只不过是往容器里添加不同的元素而已,因此只要我们的元素能够做到通用,一般化,那么元素积累到了一定的程度,元素足够的丰富就可以经而一举构造出我们想要得叶面。
更多地运用到下一篇文章再详细到来。下面我们先来看看怎么样加载组合我们的用户组件:
1、让我们来先做两个元素,这里我就把用户组件ascx的文件称之为元素了。Head.ascxFooter.ascx.
 
2、作个aspx叶面来加载着两个元素。
3、运行的效果如下:
 
哈哈!是不是很激动人心呢?
 
好让我们来动态加载,让头脚换一下位置怎么样!我们在aspx叶面上加一个按钮,在按钮的相应事件里改变加载不同的用户组件。事件的代码这样写:
运行之后:
赶快按下鼠标试试看
哈啊!是不是头脚换了位置了呢?
 
好!动态加载用户组件搞定。可以 Release 一下了。
 
那么这只是一个简单的应用,让我们期待下一篇文章再来领略动态加载组建的真正的应用。
坐着沙发等吧...
 
未完(持续)
    上一篇文章写到动态加载用户控件的简单应用
    页面是用来浏览信息的!但是更重要的是和用户交互,根据不同的需求提供不同的内容服务,这是一种服务或是一种更贴近用户的人性化。(又在胡言乱语了!^_^
动态加载叶面,根据不同的用户权限加载不懂的内容服务。根据用户的相应加载相应的内容服务。
还有另外一个应用就是做到页面与代码的分离。在vs2003里,一般ascxaspx文件,在刚建立的时候都直接跟一个cs文件关联。那么我们在写程序的时候就不能分开来做。作叶面和写后台代码的不能分开。为了能够做到作业面与作后台代码的能完全分开来,我们可以把后台的所有代码当作一个组件来做就可以了!这样一个不用跟cs文件关联的aspx叶面文件直接引用一个组件就可以了!那么组件可以加载不同的ascx文件最后组成一个完整的叶面。就这样一个项目的开发就像个机车制造厂一样组装不同的零件就有辆车出来了。软件也可以拿来组装,零件我们也可以订制,最后整体就可以出来了!(常常看别人的文章的时候怎么就觉得废话那么多,原来发现我废话也不少!^_^
好!让我们step by step ,就从不需要关联cs文件的aspx叶面开始吧!(在vs2005里,我新建aspx叶面的时候就直接没有cs文件关联。但是直接有个不完整类型隐藏起来了。怎么用基类就成为问题了!隐藏部分应该是继承了Page了!那么根据单继承的原则我们是不能在继承别的类型的了。这个问题有待研究。)
根据aspx叶面运行原理。叶面要跟服务端交互必须通过一个run at server的form标签才能行得通。因此我不要先来写个form组件,那么form就应该是个容器的形势来承载叶面所有要与服务端交互的元素,(容器太重要了,namespace也可以看作容器,只不过是不能放东西而已,是虚拟的容器)
1、做form容器组建:继承继承他就行了,注意一点就是唯一ID的问题。自己继承的可能该改变了ID,那么回传的时候就找不到了啊。切记!当然render叶面的时候是通过遍历所有form容器内所有的组件来一个个render出来。所以要改UniqueID。
示例一下:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
 
namespace Region.Controls {
   
    public class MyForm : System.Web.UI.HtmlControls.HtmlForm {
 
            public override string UniqueID {
            get {
                if (this.NoNameContainer && this.NamingContainer != this.Page ) {
                    return base.UniqueID.Substring(base.UniqueID.LastIndexOf(":")+1);
                } else {
                    return base.UniqueID;
                }
            }
        }
 
        protected override void RenderAttributes(HtmlTextWriter writer) {
            this. NoNameContainer = true;
            base.RenderAttributes (writer);
            this. NoNameContainer = false;
        }
       
        protected override void RenderChildren(HtmlTextWriter writer) {
            this. NoNameContainer = true;
            base.RenderChildren (writer);
            this. NoNameContainer = false;
        }
 
        private Boolean NoNameContainer = false;
    }
}
 

 
 
未完(持续)

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=78758
[点击此处收藏本文]   发表于 2004年08月19日 10:03 AM


 
空心菜 发表于2004-08-22 6:26 PM  IP: 220.173.7.*
不知所云

 
Region 发表于2004-09-07 10:09 PM  IP:
TrackBack来自《动态加载用户控件的组件!(终结MasterPages技术)》:

Ping Back来自:blog.csdn.net

 
开拓者 发表于2004-09-23 10:06 AM  IP: 61.144.226.*
请作者认真一点好吗?!看看你的东西!

 
region 发表于2004-09-25 11:08 AM  IP: 222.94.39.*
我也不知道是为什么?
我用word写的!放到这里就成这个样子了,也是没有办法

 
遇見鵬 发表于2004-09-29 3:35 PM  IP: 218.87.234.*
就是就是

 
ithanku 发表于2005-01-08 4:15 PM  IP: 221.219.56.*
先拷贝到UltraEdit 或 EditPlus,再拷贝到页面上,应该显示效果会好一些。:)
 (实在很懒,关于动态加载用户控件的内容实在写也写不完,说也说不完。关系到asp.net的一切!)
       我们要做没有关联cs文件的aspx叶面。其实叶面的东西并不在aspx上,而是在ascx上。Aspx所起的作用只是一个入口。对组件的引用而已,而组件就可以管理很多的ascx页面,所谓的叶面ascx叶面也应该是没有关联cs的叶面。
       所以整个系统所有的东西都是在组件里面,aspx是单纯的访问入口,ascx是纯页面的东西。Aspx入口调用组件,组件调用ascx页面以及相应客户的交互。
       只有这样才能做到每工与后台的很好的分开。
       完全可以有一个团队来开发页面(纯页面不需要任何的cs代码,全都是ascx),而有另一个团队来开发组件。最后组装成整个系统,由aspx调用组件就可以了。
       让我们来作个无代码关联的ascx叶面,叶面上有个按钮,然后写个组件加载这个ascx叶面,以及如何响应这个按钮的事件!
       (废话一下,写文章有时候不废话真是很痛苦的一件事情啊!)ascx叶面与处理叶面的后台代码分开是一件非常好的事情,不知你有没有发现一个叶面有只能与一个后台代码文件关联,不可能有两个类来关联这个叶面。而用组件来加载ascx以及相应事件,那么你就可以用同一个叶面ascx而有很多种不同的组件调用。可重用就大大的。不仅在同一个项目内重用,而是想用就用。
       实例一下:
       作个无关联cs文件的ascx页面。上面有个button. Id为 mybutton. 当然是run at server我们才能在组件中找到他了!ascx叶面也可以是文本文件。把后缀名改为ascx就行了。
       用我前面写的loadskin来加载吧!然后在里面处理button 的onclick事件就可以了。
然后在aspx中引用这个组件就行了。当然也可以在ascx中引用,都是一个效果。
       Ascx起名为a.ascx. 上面只有一个button
       也是继承SkinnedControl
namespace Region.Controls {
   
    ///<summary>
    /// 加载用户组件,加载不同的组件
    ///</summary>
    public class Abutton : SkinnedControl {
         Button bt;
        public Abutton() : base()
         {
base.SkinPath = "a.ascx";
         }
 
        ///<summary>
        /// 初始化组建摸板,进行必要的动态设置或更新
        ///</summary>
        override protected void InitializeSkin(Control skin) {
              bt = (Button)skin.FindControl("myButton");
              bt.Click +=new EventHandler(bt_Click);
              skin.DataBind();
        }
       
        ///<summary>
        /// 获取组件
        ///</summary>
        public override ControlCollection Controls {
              get {
                   EnsureChildControls();
                   return base.Controls;
              }
         }
 
         private void bt_Click(object sender, EventArgs e)
         {
              bt.Text = "心雨楼";
         }
     }
}
我么在写个同样的组件叫ebutton 根Abutton一样。
把事件改为bt.Text = "心雨楼!!!!!!!!";
让我们来看看无代码的aspx是什么样子的!
 
运行之后就这个样子:
分别点击之后就这样:
 
 
相同的页面做不同的事情。
原创粉丝点击