【问题标题】:Dynamically added controls in Asp.Net在 Asp.Net 中动态添加控件
【发布时间】:2008-09-22 06:07:53
【问题描述】:

我正试图围绕asp.net。我有一个长期 php 开发人员的背景,但我现在面临学习 asp.net 的任务,我遇到了一些麻烦。这很可能是因为我试图将框架强加于它不打算用于的东西 - 所以我想学习如何“以正确的方式”去做。 :-)

我的问题是如何在运行时以编程方式将控件添加到页面。据我所知,您需要在 page_init 创建控件,否则它们会在下一次 PostBack 时消失。但是很多时候我面临的问题是我不知道在 page_init 中添加哪些控件,因为它依赖于以前 PostBack 中的值。

一个简单的场景可能是在设计器中添加了一个下拉控件的表单。下拉菜单设置为 AutoPostBack。当 PostBack 发生时,我需要根据下拉控件中的选定值呈现一个或多个控件,并且最好让这些控件的行为就像它们是由设计添加的一样(如“在回发时,行为“正确”)。

我是不是走错了路?

【问题讨论】:

  • 我想这里的很多人都在引导你走错路;虽然他们所有的答案在技术上都是正确的,但我真的不会这样做。与 MultiView 之类的更优雅的解决方案相比,太复杂了。

标签: asp.net web-user-controls


【解决方案1】:

我同意这里提出的其他观点“如果您可以摆脱动态创建控件,那么就这样做......”(@Jesper Blad Jenson aka)但这是我在过去。

问题变成了先有鸡还是先有蛋。您需要您的 ViewState 来创建控件树,并且您需要创建您的控件树来获取您的 ViewState。嗯,这几乎是正确的。 就在树的其余部分被填充之前,有一种方法可以获取您的 ViewState 值。那是通过覆盖LoadViewState(...)SaveViewState(...)

在 SaveViewState 中存储您要创建的控件:

protected override object SaveViewState()
{
    object[] myState = new object[2];
    myState[0] = base.SaveViewState();
    myState[1] = controlPickerDropDown.SelectedValue;

    return myState
}

当框架调用您的“LoadViewState”覆盖时,您将取回您从“SaveViewState”返回的确切对象:

protected override void LoadViewState(object savedState) 
{
    object[] myState = (object[])savedState;

    // Here is the trick, use the value you saved here to create your control tree.
    CreateControlBasedOnDropDownValue(myState[1]);

    // Call the base method to ensure everything works correctly.
    base.LoadViewState(myState[0]);
}

我已经成功地使用它来创建 ASP.Net 页面,其中 DataSet 被序列化为 ViewState 以存储对整个数据网格的更改,从而允许用户使用 PostBacks 进行多次编辑,并最终在单个文件中提交所有更改“保存”操作。

【讨论】:

  • 这似乎是个好主意。我会考虑一段时间,看看我是否能把它融入我的心态,或者反过来。 :-)
【解决方案2】:

您必须在 OnInit 事件中添加您的控件,并且视图状态将被保留。不要使用if(ispostback),因为每次都必须添加控件,事件在postback中!
(De)视图状态的序列化发生在 OnInit 之后和 OnLoad 之前,因此如果在 OnInit 中添加它们,您的视图状态持久性提供程序将看到动态添加的控件。

但在您描述的场景中,多视图或简单的隐藏/显示(可见属性)可能是更好的解决方案。
这是因为在 OnInit 事件中,当您必须阅读下拉菜单并添加新控件时,尚未读取(反序列化)视图状态并且您不知道用户选择了什么! (你可以做 request.form(),但感觉有点不对)

【讨论】:

    【解决方案3】:

    在与这个问题斗争了一段时间之后,我想出了这些似乎可行的基本规则,但是 YMMV。

    • 尽可能使用声明性控件
    • 尽可能使用数据绑定
    • 了解 ViewState 的工作原理
    • Visibilty 属性可以发挥很大作用
    • 如果您必须在事件处理程序中使用添加控件,请使用 Aydsman 的提示并在覆盖的 LoadViewState 中重新创建控件。

    TRULY Understanding ViewState 是必读的。

    Understanding Dynamic Controls By Example 展示了一些关于如何使用数据绑定而不是动态控件的技术。

    TRULY Understanding Dynamic Controls 还阐明了可用于避免动态控制的技术。

    希望这可以帮助其他有同样问题的人。

    【讨论】:

    • +1 尤其是“Visibilty 属性可以走很长一段路”,让我意识到我可以让我的问题变得更简单。
    【解决方案4】:

    如果你真的需要使用动态控件,以下应该可以工作:

    • 在 OnInit 中,重新创建与满足前一个请求时页面上完全相同的控制层次结构。 (如果这不是最初的请求,当然)
    • 在 OnInit 之后,框架将从上一个请求中加载视图状态,并且您的所有控件现在应该处于稳定状态。
    • 在 OnLoad 中,删除不需要的控件并添加必要的控件。此时您还必须以某种方式保存当前的控制树,以便在以下请求的第一步中使用。您可以使用一个会话变量来指示如何创建动态控制树。我什至将整个 Controls 集合存储在会话中一次(放下你的干草叉,这只是为了演示)。

    重新添加您将不需要并且无论如何将在 OnLoad 中删除的“陈旧”控件似乎有点古怪,但 Asp.Net 的设计并没有真正考虑到动态控件的创建。如果在视图状态加载期间没有保留完全相同的控件层次结构,则各种难以发现的错误开始潜伏在页面中,因为旧控件的状态被加载到新添加的控件中。

    阅读 Asp.Net 页面生命周期,尤其是视图状态的工作原理,它会变得清晰。

    编辑:这是一篇非常好的文章,介绍了视图状态的行为方式以及在处理动态控件时应考虑的事项:http://geekswithblogs.net/FrostRed/archive/2007/02/17/106547.aspx

    【讨论】:

      【解决方案5】:

      嗯。如果您可以摆脱动态创建控件,那么就这样做 - 否则,我应该做的是使用 Page_Load 而不是 Page_Init,而不是在 If Not IsPostBack 中放置东西,然后直接在方法中设置 i。

      【讨论】:

        【解决方案6】:

        啊,这就是 ASP.NET Web 表单的泄漏抽象问题。

        也许您有兴趣查看用于创建此 stackoverflow.com 网站的 ASP.NET MVC?这应该更适合您,来自 PHP(因此,当涉及到 HTML 和 Javascript 时,踏板到金属)背景。

        【讨论】:

        • 是的,ASP.NET MVC 看起来很有前途,而且更接近我习惯的工作方式。不幸的是,我的同事有 WinForms 开发背景,我不确定我能否说服他们相信 ASP.NET MVC 才是正确的选择。
        【解决方案7】:

        我认为这里的答案在MultiView 控件中,因此例如下拉菜单在多视图中的不同视图之间切换。

        您甚至可以将多视图的当前视图属性数据绑定到下拉列表的值!

        【讨论】:

          【解决方案8】:

          Aydsman 给出了唯一正确的答案。 LoadViewState 是添加动态控件的唯一位置,在该位置重新创建时将恢复其视图状态值,并且您可以访问视图状态以确定要添加的控件。

          【讨论】:

            【解决方案9】:

            我在“Pro ASP.NET 3.5 in C# 2008”一书中的动态控件创建部分下遇到了这个问题:

            如果您需要多次重新创建控件,您应该在 Page.Load 事件处理程序中执行控件创建。这还有一个额外的好处,就是允许您在动态控件中使用视图状态。即使视图状态通常在 Page.Load 事件之前恢复,如果您在 Page.Load 事件的处理程序中创建一个控件,ASP.NET 将应用它在 Page.Load 事件处理程序结束后拥有的任何视图状态信息。这个过程是自动的。

            我没有对此进行测试,但您可以研究一下。

            【讨论】:

              猜你喜欢
              • 2013-09-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-02-11
              • 1970-01-01
              • 2011-03-06
              • 1970-01-01
              相关资源
              最近更新 更多