创建ASP.NETWEB自定义控件——例程3
创建ASP.NET WEB自定义控件——例程3(标准化越来越近了):namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
作者:大毛
本系列文章中“例程1”和“例程2”讲述了利用Visual Studio.NET2003中已有的WEB自定义控件,通过继承或复合一些简单控件生成自己需要的自定义控件。这样的控件制作比较简单,但是它的执行效率相对要低一些,所以如果我们不继承已有的控件那么这个控件该怎么做呢?
下面作者通过实例向大家讲述这种自写控件的编程方法。
(例程使用C#)
本例程实现一个TextBox,该TextBox对于输入的字符串进行检验,将半角单引号替换为全角单引号(半角单引号导致数据库错误)。
       控件首先要继承所有控件的基类:System.Web.UI.Control,实现两个接口:IStateManager(实现ViewState),IPostBackDataHandler(处理回发数据),然后可以仿照System.Web.UI.WebControls.TextBox编写一些常用的属性和方法。因篇幅限制,本例只实现Text属性。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
namespace Demo
{
    /// <summary>
    /// WebCustomControl1 的摘要说明。
    /// </summary>
像前两个例子一样,先处理一下控件设计时属性。
    [DefaultProperty("Text"),
    Designer("Demo.DemoDesigner"),
        ToolboxData("<{0}:DemoTextBox runat=server></{0}:DemoTextBox>")]
public class DemoTextBox : System.Web.UI.Control,IStateManager,IPostBackDataHandler
    {
        private StateBag _state;
        private bool _marked;
下面就是我们要实现的属性:Text
        [Bindable(true),
        Category("Appearance"),
            DefaultValue("")]
        public string Text
        {
            get
            {
                string _text = (string) ViewState["Text"];
                return _text==null?"":_text;
            }
            set
            {
                string text = "";
                text = value;
                text = text.Replace("'","’");
                ViewState["Text"] = text;
            }
        }
为了能实现视图状态就必须实现IStateManager接口
        object IStateManager.SaveViewState()
        {
            object _stateState = null;
            if( _state != null ) 
                _stateState = ((IStateManager)_state).SaveViewState();
            if ( _stateState == null ) 
                return null;
            return _stateState;
        }
        void IStateManager.TrackViewState()
        {
            _marked = true;
            if( _state != null )
                ((IStateManager)_state).TrackViewState();
        }
        void IStateManager.LoadViewState( object state )
        {
            if( state != null )
            {
                object _newState = (object)state;
                
                 ((IStateManager)ViewState).LoadViewState( _newState );
            }
        }
        bool IStateManager.IsTrackingViewState 
        {
            get 
            {
                return _marked;
            }
        }
        internal new StateBag ViewState //注意,这里覆盖基类的ViewState属性
        {
            get 
            {
                if( _state == null ) 
                {
                    _state = new StateBag( true );
                    if( ((IStateManager)this).IsTrackingViewState )
                        ((IStateManager)_state).TrackViewState();
                }
                return _state;
            }
        }
        下面把控件的表现输出到页面,其实System.Web.UI.WebControls.TextBox也是重新包装了Input而已。
        protected override void Render(HtmlTextWriter output)
        {
            string strOutput = "<Input name=\""+this.ClientID+"\" type=\"text\" value=\""+this.Text+"\">";
            output.Write(strOutput);
        }
        #region IPostBackDataHandler 成员
        public void RaisePostDataChangedEvent()
        {
            // TODO:  添加 DemoTextBox.RaisePostDataChangedEvent 实现
        }
下面的方法很重要,把回发的数据保存。
        public bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
        {
            // TODO:  添加 DemoTextBox.LoadPostData 实现
            string presentValue = this.Text;
            string postedValue = postCollection[postDataKey];
    
            if (!presentValue.Equals(postedValue))//如果回发数据不等于原有数据
            {
                this.Text = postedValue;
                return true;
            }
            return false;
        }
        #endregion
    }
}
好了,一个自己写的TextBox控件完成了。如果读者觉得自己实现ViewState麻烦,那么可以把继承的基类由System.Web.UI.Control改为System.Web.UI.WebControls.WebControl,这样只需要实现IPostBackDataHandler就可以了,ViewState的问题控件自己就解决了。
