主题:  一点一滴学做.NET服务控件

蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
#12006/6/17 11:16:43
最近学习.NET,除了开发之余,学习一下服务器控件的编程。可能各位都知道,ASP.NET控件分用户控件和服务器控件。用户控件编程相对简单些,一般用得比较多。服务器控件在学习上就相对难一点,但通过一定学习也不难掌握。服务器控件比用户控件要灵活,如果掌握这一点,在开发上会有很大帮助的。

在这里,没有什么必要象教科书一样把知识都列出来,出这一帖,只是想把一些经验和收获写出来。因此,以代码和讨论为主。有什么问题都这里讨论解决。

声明一点,本帖不为教材,各位可随便发,与服务控件有关的都可加到本帖下。


非常大鱼

蓝鲸

职务:版主
等级:5
金币:42.1
发贴:2614
注册:2001/12/20 15:57:57
#22006/6/17 11:38:07
先发个自己做的文章显示控件,用于显示文章的标题列
主要功能:
  • 显示文章,并可以按一定长度显示
  • 控制显示发布日期的关,并可控制日期显示是否换行
  • 控制显示是否显示NEW图标
  • 设定文章显示样式,标题样式及日期样式等


    服务器控件的建立方法与建立普通的类差不多,但服务器控件的继承处Control类或WebControl类,这些要写很长的基础知识就不多说,可以找一些教材或资料。
    本例子的控件是继承自WebControl类,因为可以继承一些更多的如EnableViewState、Width、Height、ForeColor等属性。

    protected override void Render(System.Web.UI.HtmlTextWriter writer)
    说明:该类是继承自WebControl类

    在开发服务器控件中,会用到一最常见的方法Render,该方法作用是在网页中呈现html代码,该方法是WebControl类中原有的,因此在开发时,应重写该方法。在服务器控件开发中,还会用到一些其它的Render方法,在以后介绍
    protected override void Render(System.Web.UI.HtmlTextWriter writer)

  • 非常大鱼

    蓝鲸

    职务:版主
    等级:5
    金币:42.1
    发贴:2614
    注册:2001/12/20 15:57:57
    #32006/6/17 12:15:58
    另外从以上代码中,我们已经接触到了HtmlTextWriter这个类,该类是向WEB页中写出HTML代码。看下面代码:

    writer.AddAttribute(HtmlTextWriterAttribute.Target, "_blank");
    writer.AddAttribute(HtmlTextWriterAttribute.Href , "http://www.hellosea.com")
    writer.RenderBeginTag(HtmlTextWriterTag.A);
    writer.Write("东海龙宫");
    writer.RenderEndTag();

    该代码在网页上呈现:
    <a href="http://www.hellosea.com" target="_blank">东海龙宫</a>

    为什么要使用HtmlTextWriter?
  • 使用该类,使HTML写法很清晰,代码容易管理
  • 可以检查出错,如没有关闭标签,在页面显示时会报出错
  • 执行速度快,比StringBuilder要快很多。如果使用StringBuilder,可能会引起显示速度缓慢

    注意:
    在使用时,必须先使AddAttribute(添加属性),AddStyleAttribute(添加样式)先写,然后再写RenderBeginTag,不能搞错顺序。

  • 非常大鱼

    蓝鲸

    职务:版主
    等级:5
    金币:42.1
    发贴:2614
    注册:2001/12/20 15:57:57
    #42006/6/17 12:19:27
    先帖上控件的全部代码,在下文中解析

    // *******************************************************************
    // 控件名:ArticleTitleList
    // 用 途:用于呈现文章标题的显示方法
    // 设计者:蓝鲸
    // 最后修改日期:2006-6-15
    // *******************************************************************
    using System;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.ComponentModel;
    using System.Data;
    using Hellosea.WebModule;
    using Hellosea.WebModule.Article.Data;
    using Hellosea.WebModule.Article.Business;
    using Hellosea.Object.Tree;

    namespace Hellosea.Control.Article
    {
        // ArticleTitleList的呈现方法
        [
        DefaultProperty("Text"),
        ToolboxData("<{0}:ArticleTitleList Runat=\"server\"></{0}:ArticleTitleList>")
        ]
        public class ArticleTitleList : System.Web.UI.WebControls.WebControl
        {
            private int mArticleCategoryID;
            private int mPageSize = 5;
            private int mPageNum = 1;
            private int mMaxTitleLength = -1;
            private string mHref = "ShowArticle.aspx";
            private string mTarget = "_blank";

            private string mTitleCss;
            private string mPubDateCss;
            private string mPubDateFormateString = "[yyyy-MM-dd]";

            private bool mPubDateChangeLine = false;
            private bool mShowPubDate = false;

            private int mNewIconLenth = 2;
            private bool mShowNewIcon = false;
            private string mNewIconString = @"<font style=""color:red; font-family:arial; font-size:11px;"">New!</font>";

            #region 定义属性
            [
            Description("该属性为文章的分类号"),
            Bindable(true),
            Category("文章属性"),
            Defaultvalue(0)
            ]
            public int ArticleCategoryID
            {
                get
                {
                    return mArticleCategoryID;
                }
                set
                {
                    mArticleCategoryID = value;
                }
            }

            [
            Description("该属性为文章每页显示条数"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(5)
            ]
            public int PageSize
            {
                get
                {
                    return mPageSize;
                }
                set
                {
                    mPageSize = value;
                }
            }

            [
            Description("该文章显示页号"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(1)
            ]
            public int PageNum
            {
                get
                {
                    return mPageNum;
                }
                set
                {
                    mPageNum = value;
                }
            }

            [
            Description("文章每记录显示字符最大长度"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(-1)
            ]
            public int MaxTitleLength
            {
                get
                {
                    return mMaxTitleLength;
                }
                set
                {
                    mMaxTitleLength = value;
                }
            }

            [
            Description("文章链接路径,相对于网站目录"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue("ShowArticle.aspx")
            ]
            public string Href
            {
                get
                {
                    return mHref;
                }
                set
                {
                    mHref = value;
                }
            }

            [
            Description("目标窗口"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue("_blank")
            ]
            public string Target
            {
                get
                {
                    return mTarget;
                }
                set
                {
                    mTarget = value;
                }
            }

            [
            Description("标题样式"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue("")
            ]
            public string TitleCss
            {
                get
                {
                    return mTitleCss;
                }
                set
                {
                    mTitleCss = value;
                }
            }

            [
            Description("日期样式"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue("")
            ]
            public string PubDateCss
            {
                get
                {
                    return mPubDateCss;
                }
                set
                {
                    mPubDateCss = value;
                }
            }


            [
            Description("日期显示格式"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue("[yyyy-MM-dd]")
            ]
            public string PubDateFormateString
            {
                get
                {
                    return mPubDateFormateString;
                }
                set
                {
                    mPubDateFormateString = value;
                }
            }

            [
            Description("显示发布日期是,是否换行"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(false)
            ]
            public bool PubDateChangeLine
            {
                get
                {
                    return mPubDateChangeLine;
                }
                set
                {
                    mPubDateChangeLine = value;
                }
            }

            [
            Description("是否显示发布日期"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(false)
            ]
            public bool ShowPubDate
            {
                get
                {
                    return mShowPubDate;
                }
                set
                {
                    mShowPubDate = value;
                }
            }

            
            [
            Description("New图标相对字符长度"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(2)
            ]
            public int NewIconLenth
            {
                get
                {
                    return mNewIconLenth;
                }
                set
                {
                    mNewIconLenth = value;
                }
            }

            [
            Description("是否显示New图标"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue(false)
            ]
            public bool ShowNewIcon
            {
                get
                {
                    return mShowNewIcon;
                }
                set
                {
                    mShowNewIcon = value;
                }
            }

            [
            Description("New图标的显示代码"),
            Bindable(false),
            Category("文章属性"),
            Defaultvalue("")
            ]
            public string NewIconString
            {
                get
                {
                    return mNewIconString;
                }
                set
                {
                    mNewIconString = value;
                }
            }
            #endregion

            public ArticleTitleList() : base(HtmlTextWriterTag.Div)
            {}

            protected override void Render(System.Web.UI.HtmlTextWriter writer)
            {
                ShowTitle(writer);
                base.Render(writer);
            }

            private void ShowTitle(HtmlTextWriter writer)
            {
                // 要目录相对路径
                WebPageInfo pinfo = WebCode.GetCurrentPathInfo();
                string cPath = pinfo.HomeRelativeSite;

                // 取得文章的DataSet
                TreeList categoryTree = ArticleCategoryTool.GetCategoryTree();
                String arrIDs = categoryTree.GetAllChildsIDString(mArticleCategoryID, ",", false);
                if (arrIDs == "")
                {
                    arrIDs = "(" + mArticleCategoryID.ToString() + ")";
                }
                else
                {
                    arrIDs = "(" + arrIDs + "," + mArticleCategoryID.ToString() + ")";
                }
                DataSet ds = ArticleTool.GetArticles(arrIDs, false, mPageSize, mPageNum);

                writer.RenderBeginTag(HtmlTextWriterTag.Ul);
                foreach(DataRow row in ds.Tables[0].Rows)
                {
                    // 标题最大显示字数
                    int maxLength = mMaxTitleLength;
                    if (mShowPubDate && !mPubDateChangeLine)
                    {
                        int dateLen = WebCode.StringRealLength((Convert.ToDateTime(row["PubDate"])).ToString(mPubDateFormateString));
                        int titleLen = WebCode.StringRealLength(row["Title"].ToString());
                        if (dateLen % 2 != 0)
                        {
                            maxLength -= (dateLen + 1) / 2;

                            if ( WebCode.StringRealLength( WebCode.CutString( row["Title"].ToString(), maxLength)
                                + (Convert.ToDateTime(row["PubDate"])).ToString(mPubDateFormateString ) ) <= (mMaxTitleLength - 1)*2 )
                                maxLength += 1;
                        }
                        else
                        {
                            maxLength =- dateLen / 2;
                        }
                    }

                    // 判断是否显示New Icon
                    bool showNewIcon = false;
                    if (mShowNewIcon)
                    {
                        int newDateDiff = WebSiteConfig.GetSettings().Article_NewDateDiff;
                        TimeSpan ts = DateTime.Now.Subtract(Convert.ToDateTime(row["PubDate"]));
                        if (ts.Days < newDateDiff) showNewIcon = true;
                    }

                    if (showNewIcon) maxLength -= mNewIconLenth;

                    writer.AddAttribute(HtmlTextWriterAttribute.Class, mTitleCss);
                    writer.RenderBeginTag(HtmlTextWriterTag.Li);

                    // 显示文章标题
                    writer.AddAttribute(HtmlTextWriterAttribute.Title, row["Title"].ToString());
                    writer.AddAttribute(HtmlTextWriterAttribute.Target, Target);
                    writer.AddAttribute(HtmlTextWriterAttribute.Href
                        ,cPath + mHref + "?ArticleID=" + row["ArticleID"].ToString());
                    writer.RenderBeginTag(HtmlTextWriterTag.A);
                    if (MaxTitleLength < 0)
                        writer.Write(row["Title"].ToString());
                    else
                        writer.Write(WebCode.CutString(row["Title"].ToString(), maxLength));
                    writer.RenderEndTag();

                    // 显示NewIcon
                    if (showNewIcon) writer.Write(mNewIconString);

                    // 显示日期
                    if (mShowPubDate)
                    {
                        // 是否日期换行显示
                        if (mPubDateChangeLine)
                        {
                            writer.RenderEndTag();
                            writer.AddAttribute(HtmlTextWriterAttribute.Class, mPubDateCss);
                            writer.RenderBeginTag(HtmlTextWriterTag.Li);
                            writer.Write( (Convert.ToDateTime(row["PubDate"])).ToString(mPubDateFormateString) );
                        }
                        else
                        {
                            writer.Write(" ");
                            writer.Write( (Convert.ToDateTime(row["PubDate"])).ToString(mPubDateFormateString) );
                        }
                    }

                    writer.RenderEndTag();
                }
                writer.RenderEndTag();
            }

        }
    }


    非常大鱼

    蓝鲸

    职务:版主
    等级:5
    金币:42.1
    发贴:2614
    注册:2001/12/20 15:57:57
    #52006/6/17 12:42:35
    [
    DefaultProperty("Text"),
    ToolboxData("<{0}:ArticleTitleList Runat=\"server\"></{0}:ArticleTitleList>")
    ]


    该代码是用于在控件在aspx页面中呈现方式,如
    <cc1:ArticleTitleList RunatRunat="Server" id="ArticleTitleList1"></cc1:ArticleTitleList>


    [
    Description("该属性为文章的分类号"),
    Bindable(true),
    Category("文章属性"),
    Defaultvalue(0)
    ]


    Description:在属性中显示的提示信息
    Bindable:是否可以绑定
    Category:在属性栏中的分类,该分类可以自己添加,也可以添加在一些固有分类中,使属性摆放大某分类下
    Defaultvalue:默认值
    其它还有一些,以后再介绍,现在不要说太多了

    protected override void Render(System.Web.UI.HtmlTextWriter writer) {
    ShowTitle(writer);
    base.Render(writer);
    }

    Render,前面介绍过的重要方法,用于呈现控件
    base.Render(writer);调用基类Render方法,呈现基类的属性
    ShowTitle方法,是自定义方法,用一从数据库读取文章,并写html代码

    // 要目录相对路径
    WebPageInfo pinfo = WebCode.GetCurrentPathInfo();
    string cPath = pinfo.HomeRelativeSite;

    是自定义类的方法,是自己函数库中的一些函数库,用于取得本页面的一些重要值,本代码取得本页相对根目录的相对路径,表现形式为如“../../”。本类在以前贴子中介绍过,现在暂不讨论

    // 取得文章的DataSet
    TreeList categoryTree = ArticleCategoryTool.GetCategoryTree();
    String arrIDs = categoryTree.GetAllChildsIDString(mArticleCategoryID, ",", false);
    if (arrIDs == "")
    {
    arrIDs = "(" + mArticleCategoryID.ToString() + ")";
    }
    else
    {
    arrIDs = "(" + arrIDs + "," + mArticleCategoryID.ToString() + ")";
    }
    DataSet ds = ArticleTool.GetArticles(arrIDs, false, mPageSize, mPageNum);

    // 该方法的树形类介绍在本论坛有过粗略介绍,已经经过改进,该方法的用途是从数据库中取得分类,并整理成树形。
    GetAllChildsIDString,是取得某一ID号节点下所有了节点的ID,表现形式为“(1,12,18)”,因某一分类下的文章,可能还是子类的文章,均显示出来。
    注:本代码已经经过几次包装,如果看不懂,可以略去,与控件制作方法并不很相关。

    DataSet ds = ArticleTool.GetArticles(arrIDs, false, mPageSize, mPageNum);
    取得文章内容的类库,为数据层和业务层的类,作用是取得文章内容的DataSet。只了解作用,看时可以略去。

    WebCode.CutString
    如果文章太长,截取某一段长度,大家可以用自己的函数截取


    非常大鱼

    缺缺

    职务:管理员
    等级:8
    金币:41.0
    发贴:9620
    注册:2004/1/14 19:14:47
    #62006/6/22 15:28:51
    呵呵
    刚看到.写的不错.



    蓝鲸

    职务:版主
    等级:5
    金币:42.1
    发贴:2614
    注册:2001/12/20 15:57:57
    #72006/6/23 10:29:09
    allinhands在上个帖子中说
    引用:
    呵呵
    刚看到.写的不错.



    哈哈
    可能有点烦,来个简单的热热身

    using System;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.ComponentModel;
    using System.Data;

    namespace Hellosea.Control.MyTest
    {
        public class TestControl : System.Web.UI.WebControls.WebControl
        {
            protected override void Render(System.Web.UI.HtmlTextWriter writer)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Target, "_blank");
                writer.AddAttribute(HtmlTextWriterAttribute.Href , "http://www.hellosea.com")
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write("东海龙宫");
                writer.RenderEndTag();

                base.Render(writer);
            }
        }
    }


    非常大鱼

    追梦人

    职务:普通成员
    等级:1
    金币:0.0
    发贴:3
    注册:2006/3/9 8:25:52
    #82006/8/7 21:42:09
    这个帖子真好。前一阵子刚写完了一个多功能分页控件



    蓝鲸

    职务:版主
    等级:5
    金币:42.1
    发贴:2614
    注册:2001/12/20 15:57:57
    #92006/8/8 8:50:37
    aniusky在上个帖子中说
    引用:
    这个帖子真好。前一阵子刚写完了一个多功能分页控件


    能把代码发上来吗,学习一下


    非常大鱼

    xzzhangg

    职务:普通成员
    等级:1
    金币:0.0
    发贴:1
    注册:2005/6/5 9:11:10
    #102006/8/10 0:20:40
    好象这段时间流行学这个呀,刚好我也在学这个.
    楼主这个长长的例子怎么没发自定义命名控件的类代码呀



    蓝鲸

    职务:版主
    等级:5
    金币:42.1
    发贴:2614
    注册:2001/12/20 15:57:57
    #112006/8/10 7:57:18
    xzzhangg在上个帖子中说
    引用:
    好象这段时间流行学这个呀,刚好我也在学这个.
    楼主这个长长的例子怎么没发自定义命名控件的类代码呀


    因为类都比较长,并且用到几个类,代码太长了。这里只说明一个方法


    非常大鱼

    呵呵

    职务:普通成员
    等级:1
    金币:0.0
    发贴:26
    注册:2007/7/27 11:06:08
    #122007/7/27 13:23:21
    敲开IT财富的大门,你准备好了吗?
    伴随着互联网的发展,社会对IT人才的需求越来越大。除北京、上海外,绝大部分的需求集中在华南、华东地区的大中型城市。而国内目前IT教育主要是高等学校的计算机、电子、电信、信息技术等相关专业的学历教育,每年培养的大学毕业生不到10万人,远远不能满足市场的需求。为了能适应市场对IT人才的需求,作为我们个人来说,应该赶快行动起来,积极加入到IT培训中来,以使自己能适应社会的需要。
    一、    选择合适的培训方向
    对非计算机科系的人来说,要半路出家进入IT业,既然你选择了软件开发作为自己的奋斗方向,就必须从基础课程学起,注意学习方法,循序渐进,掌握好它们之间的关联性。学习软件开发,如果先把C++学好,再学诸如Java、SQL Server、Oracle、VB、ASP等其他语言时,在程序设计的语法上就十分好理解了;C++学好的同时,如果掌握好计算机操作系统知识,熟悉了Windows的操作与应用,再学习Win32API的程序设计也就有基础了;Win32API的程序设计学好了,几乎所有计算机专业人员都认为十分困难的Visual C++程序设计的学习也就成了一件水到渠成的事情了。掌握好了一两种语言,以后再学习新的语言来就不会太困难,因为不同的语言只是语法上有区别,逻辑结构大部分相似。其他技能也是一样,只要牢固掌握一门技术,就能融会贯通、举一反三。
    二、    认真执行培训计划
    不论任何技术都有被淘汰的一天,即使我们已经熟悉IT业的许多知识了,但在目前的情况下,还必须不断的培训以便不断地补充和完善自己。IT界的技术服务和支持领域的工作,在当前的经济萧条时期遭受到了一定冲击。而开发和担负重点工程系统体系设计的人,由于其紧跟重点工程的发展而没有受到影响。如果当前你的专业知识仅仅限于一个领域,那么,你就面临着在当前的就业市场变得越来越没有个人价值的危险。
    如果你想正式开始学习IT知识时,应该首先扪心自问一下:这一学习计划或IT技术论证能否使自己得到进一步提升,能否在IT行业的价值链中获益?制定的学习计划应该为了进一步提高自己现有的专业才能,而不是为自己填补一些可以充当部门负责人的新才能。一旦确定现在有必要学习的新东西,该如何着手呢?首先需要注意的一点是,不要只是死抱着一两种技术或平台,或只掌握一两种开发语言。现在,用人单位越来越希望招聘到万事通式的人才。所以,你不能满足于只精通Windows或者Linux,或者只会JAVA。要赶快学习其他有关技术,即使不在你的工作范围内。
    在现代社会,许多人面临的并不是知识危机,因为很多人都拥有大专以上的学历,知识不再是危机。现代人越来越多的体验到的是本领和技能的危机。他们个人需要培训的愿望很强烈,愿意出钱培训,所以针对本领和技能方面的培训市场会越来越大。另外,现代人生活质量提高了,面对个人兴趣方面的培训市场会多起来,在工作之后,人们根据自己的兴趣爱好来选择一些培训,充实和丰富自己的生活。只有自己时刻保持危机感,敢于让自己跳出舒适的位置,继续拓宽和充实你在IT行业的技能,才能在当今就业市场上保持先机。
    您的腾飞,需要一个踏脚的平台,而我们愿意成为您走向成功的平台—让我们共同努力,成就您的IT职业生涯!
    北大青鸟中山大学科苑中心结合培训中心的自身优势,携手"广州近千家企业"开设IT企业定向培养就业班,现正热招中,欢迎您的报读。
    请相信:教育改变生活~~!
    详情了解:QQ:457411385
    电话:13450489218/020-84111371 肖老师
    当面咨询地址:广州市海珠区(中山大学西门)海珠科技园七楼

    中心网址:www.gz-accp.com