Extend Dynamic TextBox Control View State To Store

原创 2004年08月20日 14:33:00
download.gif  Download C# Source Code
Only a developer would know the absolute joy of moving a heavily database centric desktop application to a web environment.  Can you smell the sarcasm?  Aside from storing data in cache, session, or static objects there is no storage place in memory for us to put data for fast access and hold onto it until the user closes the application the same way a desktop application can.  Thus, we end up having to run expensive queries to retrieve meta data (information stored in our database that helps describe our data) each time the page loads as well as when it posts back to itself.  Wouldn't it be nice to store this information somewhere so we don't have to run the same query again on page post back?
This nice to have feature has really become a bit of a necessity for a rather complex project our team has been working on that is a little bit out of the norm.  Let me briefly summarize the requirements of our data entry pages.  The entire data entry page is database driven and in many cases this includes user specific settings for each data entry point.  A typical page might have 40 or so dynamically generated data entry points.  A wide variety of settings or meta data exists for each data entry point that range from display oriented settings, server side calculation settings, relational settings to combinations of data entry points, and settings determining how and when to save the data.  As you can see, this can get rather complicated.
Let's also review the application environment.  A typical user analysis model would consist of around a 100 of these data entry pages.  The Web site itself supports an unlimited number of analysis models.  Thus, the database is quite large and the process of obtaining the meta data is quite complex.  Running more queries than absolutely necessary can be a real drag on performance.  Also keep in mind that a typical user will spend anywhere from 15 - 45 minutes on a single data entry page completing that section of the analysis model.
Before trying to implement the ViewState solution described below, I looked into utilizing session, static objects, and the application cache.  Each of these had their pros and cons as it applied to our specific situation.  I opted for this solution but it is important to note that if your requirements aren't quite as complex and particularly if the meta data is fairly static, then I'd look towards loading it up in a static object or use the cache.  The ViewState solution I've come up with is strictly for those times when you need to attach additional properties to controls and maintain the state of the control and the state of the extended properties together.  In other words, I've opted to show you that this can be done.  It doesn't mean that you always should.  The performance impact of having larger than normal ViewState and the process of managing ViewState isn't necessarily prohibitive but if you are trying to squeeze out every once of performance, doing this without it being necessary could hurt your cause.

buycontent.gif
New Message Board Posts
the question of full-text index
How to compare 2 timings?
DTS - Execute SQL Task
authenticate using ADSI and give access to files
Display a graph in a tooltip
<SCRIPT type=text/javascript><!-- google_ad_client = "pub-8682474657542641"; google_alternate_ad_url = "http://www.eggheadcafe.com/alternateads.asp"; google_ad_width = 300; google_ad_height = 250; google_ad_format = "300x250_as"; google_ad_channel ="0679176943"; google_color_border = "FFFFFF"; google_color_bg = "FFFFFF"; google_color_link = "6D99CA"; google_color_url = "008000"; google_color_text = "000000"; //--></SCRIPT> <SCRIPT src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript> </SCRIPT> <IFRAME name=google_ads_frame marginWidth=0 marginHeight=0 src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-8682474657542641&amp;random=1092983545734&amp;lmt=1092983545&amp;alternate_ad_url=http%3A%2F%2Fwww.eggheadcafe.com%2Falternateads.asp&amp;format=300x250_as&amp;output=html&amp;channel=0679176943&amp;url=http%3A%2F%2Fwww.eggheadcafe.com%2Farticles%2Fextendtextboxviewstate.asp&amp;color_bg=FFFFFF&amp;color_text=000000&amp;color_link=6D99CA&amp;color_url=008000&amp;color_border=FFFFFF&amp;ref=http%3A%2F%2Fwww.asp.net%2FDefault.aspx%3Ftabindex%3D0%26tabid%3D1" frameBorder=0 width=300 scrolling=no height=250 allowTransparency><img height="1" width="1" border="0" src="http://pagead2.googlesyndication.com/pagead/imp.gif?client=ca-pub-8682474657542641&random=1092983545734&lmt=1092983545&alternate_ad_url=http%3A%2F%2Fwww.eggheadcafe.com%2Falternateads.asp&format=300x250_as&output=html&channel=0679176943&url=http%3A%2F%2Fwww.eggheadcafe.com%2Farticles%2Fextendtextboxviewstate.asp&color_bg=FFFFFF&color_text=000000&color_link=6D99CA&color_url=008000&color_border=FFFFFF&ref=http%3A%2F%2Fwww.asp.net%2FDefault.aspx%3Ftabindex%3D0%26tabid%3D1&event=noiframe" /></IFRAME>

In the code sample below (and the downloadable zip file above), we'll see how this can be accomplished.  In a nutshell, I've extended the existing ASP.NET TextBox server control by adding a custom made namevaluecollection class and overrode how ViewState is handled.  The custom namevaluecollection class inherits the base namevaluecollection class and adds two methods for loading the collection from a string and converting the collection to a string.  Our own Peter Bromberg contributed the loading method and I took care of the rest.  These methods were needed because serializing the entire namevaluecollection will cause our ViewState to grow enormously and take up bandwidth unnecessarily.  All we really want to do is store a few strings and ints for each data point in ViewState.  So, we'll store a string representation of the namevaluepair, similar to what you would see on a querystring, in ViewState.  Then, when we load and save view state, we'll move the data in and out of the NameValueCollection to make it easier for our user interface developers to work with the control.
For your convenience, I've hard coded in all of the base properties of the textbox control that can be stored in ViewState.  These properties are not stored in ViewState by ASP.NET controls.  In your implementation, you will probably want to exclude any of those properties you don't need.  You'll also want to note that controls created at runtime via the Page_Init event will not have their ViewState contents loaded until the Page_Load or OnLoad event fire (assuming you aren't overriding the Page.LoadViewState event).
The Webform1.aspx page has a method called BuildDynamicControls and the OnLoad event.  Put breakpoints in these two and watch the Output section of the IDE.  By stepping through the code, you can watch the controls get created and populated the first time the page is accessed.  Then, watch what happens to the values held in ViewState after you've changed a few textbox values in the browser and clicked the button to submit.
When you review the source code for this extended server control, keep in mind that this is just a proof of concept and not necessarily 100% ready for your production use.  I also didn't bother to wire up any of the normal textbox events but this is certainly still available just like it always has been.  If you need assistance with this, EggHeadCafe.com has another article Extending a TextBox Control in ASP.NET that does a good job of explaining the whole process including setting up the the control so that it shows up in the Visual Studio .NET IDE.
Please take a moment to rate this article (opens new browser window).  Rate Article
WebForm1.aspx
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Diagnostics; 

namespace TextBoxSample
{
 
  public class WebForm1 : System.Web.UI.Page
  {
    protected System.Web.UI.WebControls.Button Button1;
    protected CustomControls.TxtBox TextBox2;
    protected System.Web.UI.WebControls.PlaceHolder ph1;
      
   private void Page_Init(object sender, System.EventArgs e)
   {
     BuildDynamicControls();
   }
 
   protected override void OnLoad( EventArgs e )
   {
      CustomControls.TxtBox oTextBox = null;
 
      for(int i=1;i<ph1.Controls.Count;i++)
      {
        if (ph1.Controls[i].ID.StartsWith("TextBox") != true) { continue;}
        oTextBox = (CustomControls.TxtBox)ph1.Controls[i];
        Debug.Write(oTextBox.ID + " ");
        Debug.Write(oTextBox.Text + " ");
        Debug.Write(oTextBox.NameValuePairs["test1"].ToString() + " ");
        Debug.WriteLine(oTextBox.NameValuePairs["test2"].ToString());
      }
		 
   }
	 
      
   private void BuildDynamicControls()
   {
      try
      {
		 
        for(int i=0;i<10;i++)
        {
          CustomControls.TxtBox TextBox1 = new CustomControls.TxtBox();

          TextBox1.ID = "TextBox" + i.ToString();
          TextBox1.EnableViewState = true;
                 
          if (!Page.IsPostBack) 
          {
            TextBox1.Text = "eggheadcafe " + i.ToString();
            TextBox1.ForeColor = System.Drawing.Color.Orchid;
 
            if (i%2==0)
            {
              TextBox1.ForeColor = System.Drawing.Color.Red; 
            }
				
            TextBox1.NameValuePairs.Add("test1",i.ToString());
            TextBox1.NameValuePairs.Add("test2","10" + i.ToString());
          }

          ph1.Controls.Add(TextBox1);  
 
         }
       }
       catch (Exception e) { Debug.WriteLine("Build Controls: " + e.Message); }
       
 
     }
 
  // Web Designer Code Goes Here
 }
}

CustomControls.TxtBox
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.Diagnostics; 
 

namespace CustomControls
{
 
    [DefaultProperty("Text"),
    ToolboxItem(true),
    ToolboxData("<{0}:TxtBox runat=server></{0}:TxtBox>")]
    public class TxtBox : System.Web.UI.WebControls.TextBox 
    {
  
      private NameValueCollectionEx colNameValuePairs = new NameValueCollectionEx();
 
      
      [Bindable(false),Category("Design")]
      public NameValueCollectionEx NameValuePairs
      {
        get  { return this.colNameValuePairs; }
        set  { this.colNameValuePairs=value; }
      }
 
  
 
      protected override void Render(System.Web.UI.HtmlTextWriter writer) 
      {
         base.Render(writer);
      }
 

      protected override object SaveViewState() 
      {          
        object[] newstate = new object[23];
        try
        {
          newstate[0]=(object)this.NameValuePairs.ConvertPairsToString();  
          newstate[1] = (object)this.AutoPostBack;  
          newstate[2] = (object)this.Columns;                              
          newstate[3] = (object)this.MaxLength;   
          newstate[4] = (object)this.TextMode;  
          newstate[5] = (object)this.ReadOnly;   
          newstate[6] = (object)this.Rows;  
          newstate[7] = (object)this.Text;   
          newstate[8] = (object)this.Wrap;   
          newstate[9] = (object)this.AccessKey;  
          newstate[10] = (object)this.BackColor;  
          newstate[11] = (object)this.BorderColor;  
          newstate[12] = (object)this.BorderWidth;  
          newstate[13] = (object)this.BorderStyle;  
          newstate[14] = (object)this.CssClass;  
          newstate[15] = (object)this.Enabled;  
          newstate[16] = (object)this.ForeColor;  
          newstate[17] = (object)this.Height;  
          newstate[18] = (object)this.TabIndex;  
          newstate[19] = (object)this.ToolTip;  
          newstate[20] = (object)this.Width;  
          newstate[21] = (object)this.Site;  
          newstate[22] = (object)this.Visible;  
        }
       catch { }
        return newstate;
      }
      


      protected override void LoadViewState(object savedState)
      {
        try
        {
          object[] newstate = (object[])savedState;
          this.colNameValuePairs.FillFromString((string)newstate[0]);  
          this.AutoPostBack = (System.Boolean)newstate[1]; 
          this.Columns = (System.Int32)newstate[2];                      
          this.MaxLength = (System.Int32)newstate[3]; 
          this.TextMode = (System.Web.UI.WebControls.TextBoxMode)newstate[4];
          this.ReadOnly = (System.Boolean)newstate[5];
          this.Rows = (System.Int32)newstate[6];
          this.Text = (System.String)newstate[7];
          this.Wrap = (System.Boolean)newstate[8];
          this.AccessKey = (System.String)newstate[9];
          this.BackColor = (System.Drawing.Color)newstate[10];
          this.BorderColor = (System.Drawing.Color)newstate[11];
          this.BorderWidth = (System.Web.UI.WebControls.Unit)newstate[12];
          this.BorderStyle = (System.Web.UI.WebControls.BorderStyle)newstate[13];
          this.CssClass =  (System.String)newstate[14];
          this.Enabled = (System.Boolean)newstate[15];
          this.ForeColor = (System.Drawing.Color)newstate[16];
          this.Height = (System.Web.UI.WebControls.Unit)newstate[17];
          this.TabIndex =  (System.Int16)newstate[18];
          this.ToolTip =  (System.String)newstate[19];
          this.Width = (System.Web.UI.WebControls.Unit)newstate[20];
          this.Site = (System.ComponentModel.ISite)newstate[21];
          this.Visible = (System.Boolean)newstate[22];
      }
      catch { }
   }


  }
}

CustomControls.NameValueCollectionEx
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Runtime;
using System.Runtime.Serialization;
using System.Text;
using System.Web;

namespace CustomControls
{
 
  [SerializableAttribute()]
  public class NameValueCollectionEx:NameValueCollection
  {
		 
    internal string ConvertPairsToString()
    {

       StringBuilder sb = new StringBuilder();
       string Ret="";

       try
       {
         for(int i=0;i<this.Count;i++)
         {
           sb.Append(this.Keys[i].ToString() + "=");
           sb.Append(this.Get(this.Keys[i].ToString()));
           sb.Append("&");
         }

         if (this.Count>0)
         {
           Ret = sb.ToString();
           Ret = Ret.Substring(0,Ret.Length - 1);
         }
       }
       catch { }

       return Ret;

    }
 


    internal void FillFromString(string s)
    {
      char chNameValueDelim=Convert.ToChar(" ");
      char chPairDelim=Convert.ToChar(" ");
      /*
       You may choose to implement the next three variables
       as parameters to this method and the ConvertPairsToString
       so I've left in certain logic to support this.
      */
      bool urlencoded = false;
      char nameValueDelim = Convert.ToChar(" ");
      char pairDelim = Convert.ToChar(" ");
      Encoding encoding = System.Text.Encoding.ASCII;
 
      if(nameValueDelim==Convert.ToChar(" "))
      {
        chNameValueDelim ='=';
        chPairDelim='&';
      }
      else
      {
       chNameValueDelim =nameValueDelim;
       chPairDelim=pairDelim;
      }

      int i1 = (s == null) ? 0 : s.Length;
      for (int j = 0; j < i1; j++)
      {
        int k = j;
        int i2 = -1;
        for (; j < i1; j++)
        {
          char ch = s[j];
          if (ch == chNameValueDelim)
          {
            if (i2 < 0)
            {
              i2 = j;
            }
          }
          else if (ch == chPairDelim)
          {
            break;
          }
        }
        string strName = null;
        string strValue = null;
        if (i2 >= 0)
        {
          strName = s.Substring(k, i2 - k);
          strValue = s.Substring(i2 + 1, j - i2 - 1);
        }
        else
        {
          strValue = s.Substring(k, j - k);
        }
        if (urlencoded)
        {
          Add(HttpUtility.UrlDecode(strName, encoding), HttpUtility.UrlDecode(strValue, encoding));
        }
        else
        {
          Add(strName, strValue);
        }
        if (j == i1 - 1 && s[j] == chPairDelim)
        {
          Add(null, "");
        }
       }
    }


  }
}


Robbe Morris is a 2004 Microsoft MVP (Visual C#) and Senior Software Engineer (Decision Tools, TCO Schools, CIO Exp, and TVO) at Gartner in Maitland, FL.  He is a co-developer of EggHeadCafe.com which is hosted by his web site development and hosting company RobbeMorris.com Inc.  In his spare time, he also contributes political commentary and satire to GOP MessageBoard.com.

MVC view与control数据传递

MVC是一种常用的web应用程序的设计模式,其优点在于分离复杂的逻辑,我们可以在不关注复杂逻辑的情况下专注于视图设计,同时让代码是也变得方便了很多。view与control之间的数据传递与接收需要我们...
  • u012466304
  • u012466304
  • 2015年12月27日 20:13
  • 2004

redux的所有state都需要放到store里吗?

在项目前期的时候我们的技术经理提出了所有的state都放进去store,这样的好处是可以统一维护,格式化所有代码,但是我个人对此持有保留意见,在一段时间的书写代码后,今天我和技术经理重新讨论了这个问题...
  • a986597353
  • a986597353
  • 2017年11月27日 16:57
  • 80

自定义view (二<ImageView>)

转载自:http://blog.csdn.net/lmj623565791/article/details/24300125 继续自定义View之旅,前面已经介绍过一个自定义View的基础的例子,A...
  • u014141035
  • u014141035
  • 2016年08月01日 14:29
  • 353

动态范围规划(调整)Dynamic Range Control的一些心得(二)

上次基本上提到的动态范围调整的一些基本概念,模块图等,这次继续说它的原理。 如果简单的说一个DRC,应该很快就可以说完,但随着分析的深入,如果考虑 soft knee,attack time,rele...
  • book_bbyuan
  • book_bbyuan
  • 2017年05月18日 10:46
  • 1013

android程序开发——自定义View(一)

1. Android中内置的UI控件和布局无法满足需求的时候,就需要进行外观、操作都是自定义的一些控件,这个时候就要进行自定义View 2.自定义View的方式: 1)继承现有的UI控件:实现特定功能...
  • treasureqian
  • treasureqian
  • 2016年09月28日 21:29
  • 333

Android ViewGroup 子布局Layout id重名导致某些设备出现中断问题

最近看了一下友盟的异常日志,发现很多类型转换异常导致程序中断,看了代码,感觉这些错误也挺莫名其妙的,看不到直接引起异常的代码,唯一可疑的是最近在某一子Layout调整了@+id/loadingLayo...
  • huanghr_1
  • huanghr_1
  • 2013年01月11日 20:04
  • 3477

ElasticSearch常用插件整理

说明 1)    素材来自互联网,针对部分插件,已通过实际操作验证,进而整理、总结形成。 (感谢度娘、感谢互联网、感谢开源世界里的大牛) 2)    如有谬误,请及时指出。 (...
  • ZYC88888
  • ZYC88888
  • 2018年01月10日 09:42
  • 32

NetworkStateView:界面多状态加载

NetworkStateView:界面多状态加载在项目中经常需要进行不同状态的加载,例如在网络请求时的加载中状态,加载失败状态,没有网络状态和没有数据的状态等,之前在项目中的做法是把几个不同的状态布局...
  • AlarmZ
  • AlarmZ
  • 2017年04月17日 09:22
  • 323

MVVM模式--Model,View,ViewModel三者平衡

MVC的概念已经逐渐被大家所熟悉——Model,View,Controllor。但是在最近的开发过程中,特别与WPF相关的开发中,发现MVVM这个模式相当好用,而且还可以很方便的通过UnitTest了...
  • liuyongkun1003
  • liuyongkun1003
  • 2015年09月14日 17:05
  • 1682

easyui-datagrid 编辑模式详解

一,建立编辑器          从api得知,扩展一种新的编辑器类型,需要提供以上几个方法。项目中正好需要一个checkbox 类型编辑器,但在easyui中并没提供这样的编辑器,那我们可以通过...
  • andyliulin
  • andyliulin
  • 2016年07月21日 08:55
  • 3248
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Extend Dynamic TextBox Control View State To Store
举报原因:
原因补充:

(最多只允许输入30个字)