让客户端javascript修改的内容在服务端也能记忆的一个简单例子
在asp.net中,由于微软使用了WebControl控件,利用一种叫做ViewState方式,将服务端设置的内容记录在ViewState中,这样,当每次数据重新提交到客户端后,自动从ViewState中恢复前一次设置的内容。无状态的网页具有了部分记忆功能。
但在用的过程中,为了避免与服务端过多的交互,有时候会直接在客户端使用javascript脚本修改一些网页元素的内容,例如label的text,但在提交到服务端后,系统并不知道客户端的改变,会自动从ViewState中恢复原有内容,造成数据丢失。类似的问题还表现在服务端控件DropDownList, ListBox在客户端增加项后,回到服务端同样会从ViewState中恢复到原来的内容。
目前asp.net中的服务端控件和对应产生的客户端网页元素的关联很弱,几乎是完全割裂的,仅仅依靠原有html的form机制和__doPostBack方法,产生了服务端的事件处理机制。
微软的asp.net还有很大的改善空间,既然利用了ViewState将服务端控件的属性内容存储在客户端页面中,就应该可以改进为它的服务端控件产生客户端对象,允许在客户端直接操作部分属性。
下面介绍一个简单例子,处理label的text在客户端的修改,让服务端"记忆"客户端的改变:
1. 建立一个保持客户端、服务端联系的类
public class WebControlClientClass
{
private System.Collections.ArrayList m_list = new System.Collections.ArrayList();
public WebControlClientClass()
{
}
public void Add(System.Web.UI.WebControls.WebControl obj)
{
if( obj == null )
{
}
if( m_list.IndexOf(obj) < 0 )
{
m_list.Add(obj);
}
}
public void Make(System.Web.UI.Page page)
{
System.Type t;
object obj;
string s;
for(int i=0; i<m_list.Count; i++)
{
obj = m_list[i];
t = obj.GetType();
s = t.ToString();
switch( s )
{
case "System.Web.UI.WebControls.Label":
{
make_LabelClientClass(page, obj as System.Web.UI.WebControls.Label);
break;
}
default:
{
break;
}
}
}
}
public void Restore(System.Web.UI.Page page)
{
if( page == null )
{
return;
}
if( page.IsPostBack == false )
{
return;
}
System.Type t;
object obj;
for(int i=0; i<m_list.Count; i++)
{
obj = m_list[i];
t = obj.GetType();
switch( t.ToString() )
{
case "System.Web.UI.WebControls.Label":
{
restore_LabelClientClass(obj as System.Web.UI.WebControls.Label);
break;
}
default:
{
break;
}
}
}
}
private void restore_LabelClientClass(System.Web.UI.WebControls.Label label)
{
string hiddenID = "hidden"+label.ClientID;
string v = System.Web.HttpContext.Current.Request.Form[hiddenID];
label.Text = v;
}
private void make_LabelClientClass(System.Web.UI.Page page, System.Web.UI.WebControls.Label label)
{
string sClass="<script>/n"+
"function LabelClientClass(id)/n"+
"{/n"+
" this.id = id;/n"+
" this.hiddenID = 'hidden'+id;/n"+
" this.getText = function()/n"+
" {/n"+
" return document.getElementById(this.id).innerText;/n"+
" }/n"+
" this.setText = function(s)/n"+
" {/n"+
" document.getElementById(this.id).innerText=s;/n"+
" document.getElementById(this.hiddenID).value = s;/n"+
" }/n"+
"}/n"+
"</script>";
string keyClass = "LabelClientClass";
if( page.IsClientScriptBlockRegistered(keyClass) == false )
{
page.RegisterClientScriptBlock(keyClass, sClass);
}
string sLabel, keyLabel;
sLabel = string.Format("<script>var obj{0}=new LabelClientClass('{0}');</script>", label.ClientID);
keyLabel = "LabelClientObject"+label.ClientID;
if( page.IsStartupScriptRegistered(keyLabel) == false)
{
page.RegisterHiddenField("hidden"+label.ClientID, label.Text);
page.RegisterStartupScript(keyLabel, sLabel);
}
}
}
2. 在网页的程序部分申明 WebControlClientClass 类的对象 client;
WebControlClientClass client= new WebControlClientClass();
3. 在Page_Load中,将label控件加入client中,并执行 client.Restore方法。
//加入使用客户端的控件列表
client.Add(this.Label1);
client.Restore(this);
4. 在Page的 PreRender 事件中,利用client对象,生成对应的客户端对象。
//必须在服务端修改label内容之后,所以 PreRender 事件最合适。
client.Make(this);
5. 在客户端,用label对应的客户端对象的方法 setText 修改label的text
objLabel1.setText("test");
客户端对象名称与服务端对象名称有关,如果服务端的id= Label1, 则客户端的对象名称为 objLabel1
这里仅仅是简单以Label为例子,大家可以修改、扩展 WebControlClientClass,让它能够处理ListBox, DropDownList, RadioGroup等,产生对应的客户端对象,这样就可以像在服务端一样处理部分属性的方法,甚至事件包装。
在asp.net中,由于微软使用了WebControl控件,利用一种叫做ViewState方式,将服务端设置的内容记录在ViewState中,这样,当每次数据重新提交到客户端后,自动从ViewState中恢复前一次设置的内容。无状态的网页具有了部分记忆功能。
但在用的过程中,为了避免与服务端过多的交互,有时候会直接在客户端使用javascript脚本修改一些网页元素的内容,例如label的text,但在提交到服务端后,系统并不知道客户端的改变,会自动从ViewState中恢复原有内容,造成数据丢失。类似的问题还表现在服务端控件DropDownList, ListBox在客户端增加项后,回到服务端同样会从ViewState中恢复到原来的内容。
目前asp.net中的服务端控件和对应产生的客户端网页元素的关联很弱,几乎是完全割裂的,仅仅依靠原有html的form机制和__doPostBack方法,产生了服务端的事件处理机制。
微软的asp.net还有很大的改善空间,既然利用了ViewState将服务端控件的属性内容存储在客户端页面中,就应该可以改进为它的服务端控件产生客户端对象,允许在客户端直接操作部分属性。
下面介绍一个简单例子,处理label的text在客户端的修改,让服务端"记忆"客户端的改变:
1. 建立一个保持客户端、服务端联系的类
public class WebControlClientClass
{
private System.Collections.ArrayList m_list = new System.Collections.ArrayList();
public WebControlClientClass()
{
}
public void Add(System.Web.UI.WebControls.WebControl obj)
{
if( obj == null )
{
}
if( m_list.IndexOf(obj) < 0 )
{
m_list.Add(obj);
}
}
public void Make(System.Web.UI.Page page)
{
System.Type t;
object obj;
string s;
for(int i=0; i<m_list.Count; i++)
{
obj = m_list[i];
t = obj.GetType();
s = t.ToString();
switch( s )
{
case "System.Web.UI.WebControls.Label":
{
make_LabelClientClass(page, obj as System.Web.UI.WebControls.Label);
break;
}
default:
{
break;
}
}
}
}
public void Restore(System.Web.UI.Page page)
{
if( page == null )
{
return;
}
if( page.IsPostBack == false )
{
return;
}
System.Type t;
object obj;
for(int i=0; i<m_list.Count; i++)
{
obj = m_list[i];
t = obj.GetType();
switch( t.ToString() )
{
case "System.Web.UI.WebControls.Label":
{
restore_LabelClientClass(obj as System.Web.UI.WebControls.Label);
break;
}
default:
{
break;
}
}
}
}
private void restore_LabelClientClass(System.Web.UI.WebControls.Label label)
{
string hiddenID = "hidden"+label.ClientID;
string v = System.Web.HttpContext.Current.Request.Form[hiddenID];
label.Text = v;
}
private void make_LabelClientClass(System.Web.UI.Page page, System.Web.UI.WebControls.Label label)
{
string sClass="<script>/n"+
"function LabelClientClass(id)/n"+
"{/n"+
" this.id = id;/n"+
" this.hiddenID = 'hidden'+id;/n"+
" this.getText = function()/n"+
" {/n"+
" return document.getElementById(this.id).innerText;/n"+
" }/n"+
" this.setText = function(s)/n"+
" {/n"+
" document.getElementById(this.id).innerText=s;/n"+
" document.getElementById(this.hiddenID).value = s;/n"+
" }/n"+
"}/n"+
"</script>";
string keyClass = "LabelClientClass";
if( page.IsClientScriptBlockRegistered(keyClass) == false )
{
page.RegisterClientScriptBlock(keyClass, sClass);
}
string sLabel, keyLabel;
sLabel = string.Format("<script>var obj{0}=new LabelClientClass('{0}');</script>", label.ClientID);
keyLabel = "LabelClientObject"+label.ClientID;
if( page.IsStartupScriptRegistered(keyLabel) == false)
{
page.RegisterHiddenField("hidden"+label.ClientID, label.Text);
page.RegisterStartupScript(keyLabel, sLabel);
}
}
}
2. 在网页的程序部分申明 WebControlClientClass 类的对象 client;
WebControlClientClass client= new WebControlClientClass();
3. 在Page_Load中,将label控件加入client中,并执行 client.Restore方法。
//加入使用客户端的控件列表
client.Add(this.Label1);
client.Restore(this);
4. 在Page的 PreRender 事件中,利用client对象,生成对应的客户端对象。
//必须在服务端修改label内容之后,所以 PreRender 事件最合适。
client.Make(this);
5. 在客户端,用label对应的客户端对象的方法 setText 修改label的text
objLabel1.setText("test");
客户端对象名称与服务端对象名称有关,如果服务端的id= Label1, 则客户端的对象名称为 objLabel1
这里仅仅是简单以Label为例子,大家可以修改、扩展 WebControlClientClass,让它能够处理ListBox, DropDownList, RadioGroup等,产生对应的客户端对象,这样就可以像在服务端一样处理部分属性的方法,甚至事件包装。