如果直接在页面上使用 DataGrid、Repeater 等控件,
在第一次访问页面的时候绑定数据数据后,如果在回发的时候,不对其进行处理(再次绑定),那么它也可以利用ViewState自动保持它的状态。现在的问题是,我继承Repeater写了一个服务器控件,绑定之后,可以显示数据,但是在回发的时候如果不对它进行处理(再次绑定),那么就什么都显示不出来 。继承了Repeater那么为什么没有把保存状态也继承下来呢?难道还要手动处理一下保存状态的地方吗?上次问了一回这个问题,没有很好的方法。时间紧迫我先用了一个很笨的方法,控件写好了之后,在局域网运行还可以;但是如果拿到广域网上,速度就有一点慢了。我的方法是:
我是把数据源(DataTable)记录到ViewSatate里面,回发的时候再取出来绑定一遍。这个方法倒是可行。但是ViewState就变得很大了。
大家有没有什么好的方法呢?代码很长,贴在这里速度很慢,也不好看,我把它放在了这里:
http://www.52life.cn/jyk/articles/259.life另外这是演示网址:http://www.zhengdaic.com/offer/jy/test/showdata.aspx
控件的简介
目的:管理页面中使用,代替DataGrid。用途:显示数据列表,附带触发修改、删除、审核、打印等事件。只是触发时间并不实现功能。组成:继承Repeater控件,需要实现ItemTemplate模版列的接口。优点:不是很多,主要是方便,封装了一些常用的功能,比如1.点删除的时候,先弹出确认对话框;2.支持多行表头;3.移动鼠标的时候,tr背景色随之改变;4.支持DataKey,可以设置多个字段。5.修改页面样式(颜色、风格)的时候,只需要修改一个控件就可以了,不用每一个页都改一遍。6.可以像DataList那样多行多列显示。缺点:这个就很多了。1.不支持行内修改,不支持模版列,比如文本框。2.ViewState占用很多的空间。主要是在回发的时候不知道怎么利用ViewState来保持状态,所以用了一个很笨的方法来实现的 —— 把DataTable 放到了ViewState里面,回发的时候再取出来绑定控件 —— 所以造成了ViewState的“巨大”的体积。当然这里是要改进的,只是目前还没有找到好的方法。

解决方案 »

  1.   

    近期我们公司的站台做了个大修改,就是把所有的ViewState存储数据源方式改掉.ViewState是存储在客户端的,它不能存储DataView,只有存储DataSet。我们的站台
    本来是想用ViewState存储dataSet实现翻页后继续排序功能, 后来发现数据大了,翻
    页速度极慢,甚至”当“掉服务器几次。  检查一下发现客户端内存用了占70M,仅
    不到十页数据. 所以说,用ViewState最好不要存储DataSet.  
      

  2.   

    实现IPostBackDataHandler接口..实现bool LoadPostData(string s,NameValueCollection ke)方法就好了...public void RaisePostDataChangedEvent(){}这个方法可以根据是否触发autoback而修改,如果不触发就不用写了/public bool LoadPostData(string s,NameValueCollection ke){

    //string tem = (string)ViewState["Text"];
    ViewState["Text"] = ke[s];
    return false;
    }
    private string text;

    public string Text{

    get {
    text = (string)ViewState["var"];
    return (text == null) ? "" : text;
    }

    set { ViewState["var"] = value;}

    }
      

  3.   

    用Reflector仔细看一下,Repeater是怎么重载CreateChildControls()和OnDataBinding()的
      

  4.   

    注意是Reapeter控件 ,而不是文本框
      

  5.   

    to:eyis感谢测试。再点一下就可以了。这个只是演示用,有一点“延迟”实际应用中,都是在第一次访问的时候设置好的,而不会在回发的时候再改变状态的。这是代码执行顺序造成的。
      

  6.   

    如果你仔细看的话, protected virtual void CreateControlHierarchy(bool useDataSource)
    {
      //....
    }
     protected override void CreateChildControls()
    {
          this.Controls.Clear();
          if (this.ViewState["_!ItemCount"] != null)
          {
                this.CreateControlHierarchy(false); <===这里是false
          }
          else
          {
                this.itemsArray = new ArrayList();
          }
          base.ClearChildViewState();
    }
     protected override void OnDataBinding(EventArgs e)
    {
          base.OnDataBinding(e);
          this.Controls.Clear();
          base.ClearChildViewState();
          this.CreateControlHierarchy(true); <===这里是true
          base.ChildControlsCreated = true;
    }
     
    ViewState是在CreateControlHierarchy(false);里恢复的建议你先写个小的控件,从Repeater继承来,确认你照顾到基类的这2个函数了,工作后,再一步步加你的逻辑,别一口想吃成胖子
      

  7.   

    写了一个简单的例子,还是不行,好像差了一个步骤。在页面里适用Repeater是很简单的。.aspx页面:<asp:Repeater id="Rpt2" runat="server">
    <ItemTemplate>
    <%# DataBinder.Eval(Container, "DataItem.au_id")%>
    <br>
    </ItemTemplate>
    </asp:Repeater>.aspx.cs 页面
    if (!Page.IsPostBack)
    {
    DataTable dt =  ....  //取一个记录集
    Rpt2.DataSource = dt;
    Rpt2.DataBind();
    }只要这样写就可以了,在回发事件里不处理Repeater,他也会保留上一次的状态。
    但是写成了控件就不行了。Imports System.ComponentModel
    Imports System.Web.UI
    Imports System
    Imports System.Web.UI.WebControls
    '数据列的信息。设置标题、字段名、对齐方式、宽度
    <DefaultProperty("Text"), ToolboxData("<{0}:testRpt runat=server></{0}:testRpt>")> _
     Public Class testRpt
        Inherits System.Web.UI.WebControls.Repeater
        #Region " 创建子控件,添加模版列 "
        Protected Overrides Sub CreateChildControls()        Dim tmp = New JYK.Controls.ITemplate.TemplateTestRpt
            Me.ItemTemplate = tmp    End Sub
    #End RegionEnd Class#Region "测试用"
        Public Class TemplateTestRpt : Implements System.Web.UI.ITemplate#Region "实现接口"
            Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn
               
                Dim lcLTR As New System.Web.UI.LiteralControl("a<br>")
                lcLTR.ID = "lc_LTR"
                container.Controls.Add(lcLTR)        End Sub
    #End Region
        End Class
    #End Region
    第一次访问的时候可以显示一列 a ,但是回发(点击按钮触发的事件)后就没有显示了。就好像没有DataBind()一样。
      

  8.   

    Protected Overrides Sub CreateChildControls()     Dim tmp = New JYK.Controls.ITemplate.TemplateTestRpt
         Me.ItemTemplate = tmp
         MyBase.CreateChildControls() End Sub刚刚找到了一个问题:忘记了这一句: MyBase.CreateChildControls() 在测试控件里加上这一句就可以了,
    但是在显示数据的控件里加上这一句,只解决了一般的问题。功能列(添加、修改等),可以保留住状态,但是数据列就没有了。看来我还要研究一下 OnDataBinding事件。
      

  9.   

    多谢多谢。昨天晚上一连回了三回,今天没机会了,多写楼上的老兄。我的控件是先bind出一个table,然后在往里填数据 
    现在是table可以保留状态,但是数据就保持不住了 在页面里面直接使用的时候
    可以用这种方法来取出字段里的内容
    <ItemTemplate>
    <%# DataBinder.Eval(Container, "DataItem.au_id")%>
    <br/>
    </ItemTemplate>那么在控件里面呢?我只会用这种方法来加“固定”的内容,可是怎么来指定字段呢?
    #Region "实现接口"
    Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateInDim lcLTR As New System.Web.UI.LiteralControl("a<br/>")
    lcLTR.ID = "lc_LTR"
    container.Controls.Add(lcLTR)End Sub
    #End Region
    End Class
    #End Region