【问题标题】:asp.net dynamically added user control saving values after postbackasp.net 在回发后动态添加用户控件保存值
【发布时间】:2010-10-15 19:11:40
【问题描述】:

这是我的问题。我有一个用户控件,我希望允许用户使用按钮单击添加尽可能多的实例(每次单击按钮时,我想将我的用户控件的另一个实例添加到面板)。它第一次运行良好,但每次额外的回帖都会删除所有添加的控件。我可以跟踪用户添加的用户控件的数量,但我如何确保它们保持在回发之前的相同状态?我已经阅读了一些关于人们使用 SaveViewState 和 LoadViewState 的帖子,但我找不到任何示例。

我最大的问题是确保每个用户控件的所有文本框和下拉列表在每次回发后都填充相同的文本/选定值/数据

提前致谢, 本

【问题讨论】:

    标签: c# asp.net user-controls dynamically-generated


    【解决方案1】:

    由于您以编程方式向页面添加控件,因此您需要在每次回发时重新创建它们。

    此外,您还必须在页面的PreInitInit 事件上重新创建以编程方式添加的控件。这是为了正确的视图状态恢复事件管理。

    如果您不这样做,回发时控制将消失,并且它们不会处理任何事件。

    编辑

    虽然建议在PreInitInit 上添加动态控件,但确实(正如Dustin Hodges 所说)如果您在page_load 上添加它们可能会起作用。我会说你应该避免它,除非你别无选择。

    您也许可以将控件加载到 Page_Load 事件处理程序并正确维护视图状态。
    这完全取决于您是否以编程方式设置动态加载的控件的任何属性,如果是,那么当您相对于 Controls.Add(动态控制) 线。
    对此进行彻底的讨论有点超出本文的范围,但它可能起作用的原因是因为 控件属性的 Add() 方法递归地将父视图状态加载到其子视图中,即使加载视图状态阶段已经过去。

    来源MSDN

    【讨论】:

    • 这并不完全正确。您可以在 Load 中添加控件,但仍然可以让它们恢复其视图状态并生成事件,因为添加到控件集合时会播放赶上控件
    • 越早添加越好
    • +1 确保在重新创建控件时为控件分配相同的 ID。另外,请注意 ViewState 对象在 Page_Init 中对您不可用,因此如果您需要在加载之间读取一些值,请使用 Session。有关 ASP.NET 页面生命周期的更多信息,请参阅这篇文章:msdn.microsoft.com/en-us/library/ms178472.aspx
    • 我一直在寻找关于这个主题的清晰解释,谢谢!
    • +1 表示“当您相对于 Controls.Add(dynamicControl) 行执行此操作时”。只是将一些属性设置逻辑移动了几行并修复了我的(v.令人沮丧的)问题......
    【解决方案2】:
    【解决方案3】:

    如果您要跟踪用户添加的控件数量,则需要重新创建用户之前添加的控件,最好在 Page_Init 或 Page_Load 中。向该处理程序添加类似的内容:

    for(int i=0; i<NumberOfControlsUserHasAdded; i++)
    {
        //todo:  change this to the appropriate user control
        TextBox tb = new TextBox();
        tb.ID = "tb" + i.ToString();
        //todo:  add to appropriate control collection
        this.Controls.Add(tb);
    }
    

    如果您这样做,控件的状态应该保持,因为当您将 tb 控件添加到控件集合时,它会赶上事件并应该自动恢复其视图状态。

    您不必在会话中跟踪它们的状态,因为在大多数情况下它将为您存储在视图状态中

    【讨论】:

      【解决方案4】:

      我曾有过一段噩梦,试图在一个旧项目上实现这一目标。在中间的时间里,我发现我对 Web 开发的了解比我想象的要少得多(阅读这个网站是每天(如果不是每小时)谦逊自己的好方法)。在那个项目中,Page.IsPostBack 对我来说完全没用,因为我已经动态地实例化了控件。

      话虽如此,我能建议的最好的办法是考虑使用 Session 变量。如果您有一个代表您从页面捕获的数据的类(或一个类的集合),那么将值存储在该类/集合中以提高代码可读性,然后将其写入会话。

      【讨论】:

      • 谦虚的道具,但我不确定在这种情况下我会使用会话。您应该能够利用页面的 ViewState 或对其进行一些控制。
      • @Brad,我在上面提到的项目上试过这个,但始终无法正常工作,但在阅读了 Claudio Redi 发布的文章后,我同意你的看法。
      【解决方案5】:

      查看您的PageLoad 并在您清除面板的行之前添加if(!this.IsPostBack)

      这当然只是一个猜测,但我看到很多问题都与此有关

      【讨论】:

      • 除非我理解错了,否则 OP 并没有说 he 正在清除面板,而是说它正在 清除。
      【解决方案6】:

      我认为可能发生的情况是,当您单击添加按钮时,Page_Load 会触发,从而为您创建一个全新的页面。然后,按钮单击方法添加控件,页面完成渲染。当您第二次单击它时,Page_Load 将创建您的页面,并且按钮单击方法再次创建一个控件并将其添加到页面中。很遗憾,您之前添加的那个已经不在了。

      如果您将控件添加到中继器会怎样? Repeater 的视图状态可能会跟踪您添加的每个控件,以便在回发时不会被吹走。

      【讨论】:

        【解决方案7】:

        如果您有大量用户,这是一个丑陋的解决方案,但您可以将用户控件自己粘贴到会话中。 我使用页脚控件执行此操作,因为我不想每次页面更改以重新创建页脚时都点击数据库。

        如果您有很多用户并且他们经常使用此功能,则此解决方案可以在服务器上完成任务。至少我认为会……

        但是您可以在 page_load 上重新填充包含用户控件的占位符。我可以很快举一个例子。

        我所做的示例:

        if (Session["footer"] == null)
        {
         Session["footer"] = new Footer(LinksRules.BuildFooterLinks((int)WebSiteSections.Main));// where Footer is my control
        }
        footerPH.Controls.Add((Footer)Session["footer"]);
        

        类似于单例模式...

        所以在我看来,您可以对任何会导致回发的事情执行此操作

        Session["DynamicControls"] = PlaceHolder.Controls;

        在 page-Load 方法中你可以:

        foreach(var control in (List<Controls>)Session["DynamicControls"])
        {
          yourPlaceHolder.Controls.Add(control);
        }
        

        如果会话对象为空,只需添加一个它们从未出现过的对象..

        我相信这会像你想要的那样挂在控件内的数据上。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-02-15
          • 1970-01-01
          • 2011-06-01
          • 2017-04-14
          • 2011-06-09
          • 2012-02-11
          • 1970-01-01
          相关资源
          最近更新 更多