在ASP.NET的上面,TextBox是表单设计时最常用的控件之一。很多时候为了页面的紧凑和美观,我们需要适当的限制TextBox的显示宽度,但是如果TextBox过于窄了之后,又会给用户的填写带了不便,而且更麻烦的是很多时候我们并不知道用户到底会往那个TextBox里填多少内容。为了解决这些问题,下面给大家推荐一个可自动适应输入内容的宽度的TextBox控件。 

    本控件是从TextBox控件继承,设计原理是使用一个agent input(type=text)来做为实际的用户录入的TextBox,在焦点切换的过程中完成background input和agent input的属性同步。  

    下面的代码完成两个input之间的样式和属性同步: 

function ATB_SwitchToInputAgent(input)#region function ATB_SwitchToInputAgent(input) 
function ATB_SwitchToInputAgent(input) 

    var spanWrapper = input.parentElement; 
    var agentInput = spanWrapper.lastChild; 
    var userOffsetTop, userOffsetLeft; 
    with(input.style) 
    { 
        var userMarginTop = parseInt(marginTop); 
        var userMarginLeft = parseInt(marginLeft); 
        var userBorderTop = parseInt(borderTopWidth); 
        var userBorderLeft = parseInt(borderLeftWidth); 
        userMarginTop = isNaN(userMarginTop) ? 0 : userMarginTop; 
        userMarginLeft = isNaN(userMarginLeft) ? 0 : userMarginLeft; 
        userBorderTop = isNaN(userBorderTop) ? 0 : userBorderTop; 
        userBorderLeft = isNaN(userBorderLeft) ? 0 : userBorderLeft; 
        userOffsetTop = userBorderTop + userMarginTop; 
        userOffsetLeft = userBorderLeft + userMarginLeft; 
    } 
    var retouch = 0; 
    agentInput.style.top = userOffsetTop; 
    agentInput.style.left = userOffsetLeft-1; 
    spanWrapper.style.zIndex = 2; 
    agentInput.style.display = 'inline'; 
    agentInput.value = input.value; 
    agentInput.style.borderWdith = input.style.borderWdith; 
    agentInput.style.borderColor = input.style.borderColor; 
    agentInput.style.backgroundColor = input.style.backgroundColor; 
    agentInput.style.color = input.style.color; 
    agentInput.style.fontFamily = input.style.fontFamily; 
    agentInput.style.fontWegith = input.style.fontWeight; 
    agentInput.style.fontSize = input.style.fontSize; 
    agentInput.style.height = input.style.height; 
    agentInput.style.fontStyle = input.style.fontStyle; 
    try { agentInput.style.font = input.style.font } catch(exp){}; 
    agentInput.style.fontVariant = input.style.fontVariant; 
    agentInput.style.zoom = input.style.zoom; 
    agentInput.focus(); 
    agentInput.select(); 

  #endregion      注意:不能使用style=style或for( attribute in style)的方式来赋值,否这引起onpropertychange的死循环递归。 

    第二个问题是使用onpropertychange属性来同步agent input的宽度和其内容宽度相等,代码如下:  
function ATB_AutoIncreaseWidth(input)  
{  
    if ( input.style.display == 'none' ) return;  
    var spanWrapper = input.parentElement;  
    var userInput = spanWrapper.firstChild;  
    userInput.value = input.value;  
    var absOffsetWidth = GetAbsoluteOffsetLeft(input);  
    var docClientWidth = window.document.body.clientWidth;  
    if ( input.scrollWidth < userInput.clientWidth )  
    {  
        if ( absOffsetWidth + styleWidth >= docClientWidth )   
        {  
            input.style.width = docClientWidth - absOffsetWidth;  
        }  
        else  
        {  
            input.style.width = userInput.clientWidth+2;  
        }  
        return;  
    }  
    var styleWidth = parseInt(input.style.width);  
    if ( styleWidth != input.scrollWidth+2 )  
    {  
        if ( absOffsetWidth + styleWidth >= docClientWidth )   
        {  
            input.style.width = docClientWidth - absOffsetWidth;  
        }  
        else  
        {  
            input.style.width = input.scrollWidth+2;  
        }  
    }  
}      这里需要注意的是当增长的agent input的最右端超出了IE的body区域时,需要停止其增长,否则用户看不见输入的东西了。  

    演示效果如下:       

附 AdjustableTextBox 控件源码#region 附 AdjustableTextBox 控件源码 
using System; 
using System.IO; 
using System.Drawing; 
using System.Text; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.ComponentModel; 
 
namespace WebExcel.UI.WebControls 

    /**//// <summary> 
    /// Summary description for AdjustableTextBox. 
    /// </summary> 
    [DefaultProperty("Text")] 
    [ToolboxData("<{0}:AdjustableTextBox runat=server></{0}:AdjustableTextBox>")] 
    public class AdjustableTextBox : TextBox 
    { 
        public Color AgentBorderColor 
        { 
            get 
            { 
                object obj = ViewState["AgentBorderColor"]; 
                return obj == null ? Color.Gray : (Color)obj; 
            } 
            set 
            { 
                ViewState["AgentBorderColor"] = value; 
            } 
        } 
 
        public bool AutoIncrease 
        { 
            get 
            { 
                object obj = ViewState["AutoIncrease"]; 
                return obj == null ? true : (bool)obj; 
            } 
            set 
            { 
                ViewState["AutoIncrease"] = value; 
            } 
        } 
 
        // the property is always TextBoxMode.SingleLine. 
        public override TextBoxMode TextMode 
        { 
            get 
            { 
                return base.TextMode; 
            } 
            set 
            { 
                base.TextMode = value; 
                if ( value != TextBoxMode.SingleLine ) 
                { 
                    this.AutoIncrease = false; 
                } 
                else 
                { 
                    this.AutoIncrease = true; 
                } 
            } 
        } 
 
        public new Unit BorderWidth 
        { 
            get 
            { 
                if ( base.BorderWidth == Unit.Empty ) 
                { 
                    base.BorderWidth = 1; 
                } 
                return base.BorderWidth; 
            } 
            set 
            { 
                if ( value != Unit.Empty ) 
                { 
                    base.BorderWidth = value; 
                } 
            } 
        } 
 
        /**//// <summary>  
        /// Render this control to the output parameter specified. 
        /// </summary> 
        /// <param name="output"> The HTML writer to write out to </param> 
        protected override void Render(HtmlTextWriter output) 
        { 
            if ( this.AutoIncrease ) 
            { 
                this.RegisterClientScript(); 
                base.Attributes["onfocus"] = "ATB_SwitchToInputAgent(this)"; 
                base.Attributes.CssStyle["position"] = "relative"; 
                if ( base.BorderWidth == Unit.Empty ) 
                { 
                    base.BorderWidth = 1; 
                } 
                string spanWrapper = @"<span style='z-index: 1; position: relative; border: solid 0px black;'>{0}<input type='text' onblur='ATB_GetAgentValue(this)' onpropertychange='ATB_AutoIncreaseWidth(this)' style='border: solid 1px gray; position: absolute; display:none;' /></span>"; 
                StringBuilder sb = new StringBuilder(); 
                StringWriter sw = new StringWriter(sb); 
                HtmlTextWriter htw = new HtmlTextWriter(sw); 
                base.Render(htw); 
                output.Write(string.Format(spanWrapper, sb.ToString(), ColorTranslator.ToHtml(this.AgentBorderColor))); 
            } 
            else 
            { 
                // base.Attributes["onfocus"] = "this.height='100%'"; 
                base.Render(output); 
            } 
        } 
 
        private void RegisterClientScript() 
        { 
            const string COMMON_SCRIPT_KEY = "__CommonJavaScript__"; 
            string strCommon = @"<script language='javascript'> 
            function GetAbsoluteOffsetLeft(element) 
            { 
                if ( element == null || arguments.length != 1 ) 
                { 
                    return; 
                } 
                var offsetLeft = element.offsetLeft; 
                while( element = element.offsetParent ) 
                { 
                    offsetLeft += element.offsetLeft; 
                } 
                return offsetLeft; 
            } 
            </script>"; 
            if ( !this.Page.IsStartupScriptRegistered(COMMON_SCRIPT_KEY) ) 
            { 
                this.Page.RegisterStartupScript(COMMON_SCRIPT_KEY, strCommon); 
            } 
 
            const string SCRIPT_KEY = "__AdjustableTextBoxKey__"; 
            string strScript = @" 
                <script language='javascript'> 
                function ATB_SwitchToInputAgent(input) 
                { 
                    if ( input.disabled ) return; 
                    var spanWrapper = input.parentElement; 
                    var agentInput = spanWrapper.lastChild; 
                    var userOffsetTop, userOffsetLeft; 
                    with(input.style) 
                    { 
                        var userMarginTop = parseInt(marginTop); 
                        var userMarginLeft = parseInt(marginLeft); 
                        var userBorderTop = parseInt(borderTopWidth); 
                        var userBorderLeft = parseInt(borderLeftWidth); 
                        userMarginTop = isNaN(userMarginTop) ? 0 : userMarginTop; 
                        userMarginLeft = isNaN(userMarginLeft) ? 0 : userMarginLeft; 
                        userBorderTop = isNaN(userBorderTop) ? 0 : userBorderTop; 
                        userBorderLeft = isNaN(userBorderLeft) ? 0 : userBorderLeft; 
                        userOffsetTop = userBorderTop + userMarginTop; 
                        userOffsetLeft = userBorderLeft + userMarginLeft; 
                    } 
                    var retouch = 0; 
                    agentInput.value = input.value; // must be mdified at first 
                    agentInput.style.top = userOffsetTop; 
                    agentInput.style.left = userOffsetLeft-1; 
                    spanWrapper.style.zIndex = 10; 
                    agentInput.style.display = 'inline'; 
                    agentInput.style.borderWdith = input.style.borderWdith; 
                    agentInput.style.borderColor = input.style.borderColor; 
                    agentInput.style.backgroundColor = input.style.backgroundColor; 
                    agentInput.style.color = input.style.color; 
                    agentInput.style.fontFamily = input.style.fontFamily; 
                    agentInput.style.fontWegith = input.style.fontWeight; 
                    agentInput.style.fontSize = input.style.fontSize; 
                    agentInput.style.height = input.style.height; 
                    var absOffsetWidth = GetAbsoluteOffsetLeft(input); 
                    var docClientWidth = window.document.body.clientWidth; 
                    var styleWidth = parseInt(agentInput.style.width); 
                    if ( absOffsetWidth + styleWidth >= docClientWidth )  
                    { 
                        agentInput.style.width = docClientWidth - absOffsetWidth; 
                    } 
                    else 
                    { 
                        agentInput.style.width = input.clientWidth+2; 
                    } 
                    agentInput.style.fontStyle = input.style.fontStyle; 
                    try { agentInput.style.font = input.style.font } catch(exp){}; 
                    agentInput.style.fontVariant = input.style.fontVariant; 
                    agentInput.style.zoom = input.style.zoom; 
                    agentInput.readOnly = input.readOnly; 
                    //agentInput.focus(); must remove!!! 
                    if ( !agentInput.readOnly ) 
                    {         
                        agentInput.select(); 
                    } 
                } 
 
                function ATB_GetAgentValue(input) 
                { 
                    var spanWrapper = input.parentElement; 
                    var userInput = spanWrapper.firstChild; 
                    input.style.width = userInput.clientWidth+2; 
                    spanWrapper.style.zIndex = 1; 
                    userInput.value = input.value; 
                    input.style.display = 'none'; 
                } 
                 
                function ATB_AutoIncreaseWidth(input) 
                { 
                    if ( input.style.display == 'none' ) return; 
                    var spanWrapper = input.parentElement; 
                    var userInput = spanWrapper.firstChild; 
                    userInput.value = input.value; 
                    var absOffsetWidth = GetAbsoluteOffsetLeft(input); 
                    var docClientWidth = window.document.body.clientWidth; 
                    if ( input.scrollWidth < userInput.clientWidth ) 
                    { 
                        if ( absOffsetWidth + styleWidth >= docClientWidth )  
                        { 
                            input.style.width = docClientWidth - absOffsetWidth; 
                        } 
                        else 
                        { 
                            input.style.width = userInput.clientWidth+2; 
                        } 
                        return; 
                    } 
                    var styleWidth = parseInt(input.style.width); 
                    if ( styleWidth != input.scrollWidth+2 ) 
                    { 
                        if ( absOffsetWidth + styleWidth >= docClientWidth )  
                        { 
                            input.style.width = docClientWidth - absOffsetWidth; 
                        } 
                        else 
                        { 
                            input.style.width = input.scrollWidth+2; 
                        } 
                    } 
                } 
                </script>"; 
            if ( !this.Page.IsStartupScriptRegistered(SCRIPT_KEY) ) 
            { 
                this.Page.RegisterStartupScript(SCRIPT_KEY, strScript); 
            } 
        } 
    } 

#endregion