【问题标题】:ASP.NET Adding Controls Dynamically and the Page Life CycleASP.NET 动态添加控件和页面生命周期
【发布时间】:2023-03-18 22:56:02
【问题描述】:

我是 ASP.NET 的新手,请耐心等待。

这是我的场景的简化解释。我在页面上有一个按钮。当我单击该按钮时,我将从数据库中检索字符串列表并动态生成一系列链接按钮,并将检索到的字符串作为链接按钮的文本。

我已经明白我不能在按钮的单击事件处理程序中执行此操作有几个原因。我也知道需要在 Page_Init 或 Page_Load 事件处理程序中生成动态控件,以便可以连接链接按钮的点击事件。

所以,这是我考虑的过程:

  1. 点击按钮
  2. 在单击事件处理程序中,检索字符串并将它们存储在 ViewState 变量中
  3. 在 Page_Load 事件处理程序中,遍历 ViewState 变量中的字符串并生成链接按钮

问题在于:由于页面的生命周期,按钮的点击事件直到 Page_Load 事件之后才会被处理。因此,在 Page_Load 事件(我希望在其中创建链接按钮)之后,我不会检索用于生成链接按钮的字符串并将其分配给 ViewState 变量。

因此,链接按钮不会在第二次单击按钮时生成,此时已分配 ViewState 变量。显然,这是一个问题。

我设计的解决方案可行,但我不知道它是否是最佳解决方案。这是我正在使用的方法:

  1. 点击按钮
  2. Page_Load 事件触发
  3. 在 Page_Load 事件处理程序中,如果是 PostBack,请检查 ViewState 变量是否为 null 以及哪个控件触发了 PostBack
  4. 如果 ViewState 变量为 null 并且单击了按钮,则检索字符串,将它们保存到 ViewState 变量中,并根据 ViewState 变量生成链接按钮
  5. 如果ViewState变量不为null,则根据ViewState变量生成链接按钮

现在,这个解决方案确实有效。但是,如果我刷新页面,我会弹出确认表单重新提交(我不喜欢,但我可以接受)。

我在这里向编码员提出的问题是——你们会如何处理我的情况?

更新:

这是一个似乎可行的解决方案。我可能对可以在哪里连接事件处理程序感到困惑,但请看一下这段代码并告诉我它是否有意义或者它只是一个 hack:

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (IsPostBack)
        {
            if(ViewState["ControlsArray"] != null)
            {
                ArrayList controlsList = (ArrayList)ViewState["ControlsArray"];
                GenerateLinkButtons(controlsList);
            }
        }
    }

    //The event handler for the dynamically generated linkbuttons
    void linkButton_Click(object sender, EventArgs e)
    {
        LinkButton btn = (LinkButton)sender;
        string btnName = btn.Text;

        Response.Write(btnName);
    }

    //The click event handler for the Generate Controls button
    protected void Button1_Click(object sender, EventArgs e)
    {
        ArrayList PageArrayList = new ArrayList();

        PageArrayList = new ArrayList();
        PageArrayList.Add("Text 1");
        PageArrayList.Add("Text 2");
        PageArrayList.Add("Text 3");
        PageArrayList.Add("Text 4");
        PageArrayList.Add("Text 5");

        GenerateLinkButtons(PageArrayList);

        ViewState["ControlsArray"] = PageArrayList;
    }

    void GenerateLinkButtons(ArrayList controlsList)
    {
        int i = 1;

        foreach (string s in controlsList)
        {
            LinkButton lnkButton = new LinkButton();
            lnkButton.ID = "btn" + i;
            lnkButton.Text = s;
            this.form1.Controls.Add(lnkButton);
            this.form1.Controls.Add(new LiteralControl("<br />"));
            lnkButton.Click += new EventHandler(linkButton_Click);
            i++;
        }
    }
}

【问题讨论】:

  • 你为什么不直接在按钮点击的事件处理程序中生成链接按钮,你不应该有代码从数据库中检索字符串以分离关注点,但是 UI 交互像生成按钮是正确的。
  • 当然,但我的理解是您无法为该单击事件处理程序中新添加的控件连接事件处理程序。这必须在 Page_Init 或 Page_Load 事件处理程序中完成。
  • 正如 Mt.Scheniders 在回复中所说,我也不这么认为。

标签: asp.net web-controls


【解决方案1】:

需要在 Page_Init 或 Page_Load 事件处理程序中生成动态控件,以便可以连接链接按钮的点击事件。

其实,你可以在Button Click事件上创建控件。但是您必须确保在以下 PostBacks 中重新创建这些控件。

假设您有一个名为Data 的属性,它指向一个ViewState 变量。我们还假设您使用Repeater 创建链接按钮。

然后你可以这样做:

private List<string> Data
{
    get { return (List<string>)ViewState["Data"]; }
    set { ViewState["Data"] = value; }
}

protected void Button_Click(object sender, EventArgs e)
{
    Data = GetData();
    LoadRepeater();
}

protected void Page_Load(object sender, EventArgs e)
{
    if(Data != null)
    {
        LoadRepeater();
    }
}

private void LoadRepeater()
{
    repeater.DataSource = Data;
    repeater.DataBind();
}

中继器:

<asp:Repeater id="repeater" runat="server">
    <ItemTemplate>
        <asp:LinkButton id="link" runat="server" OnClick="link_Click" />
    </ItemTemplate>
</asp:Repeater>

protected void link_Click(object sender, EventArgs e)
{
    //Do Stuff
}

此外,如果您想避免 Confirm Form Resubmission,请使用 ASP.NET UpdatePanel 控件。 示例:

<asp:UpdatePanel id="upp" runat="server" >
    <ContentTemplate>
        <!-- Button-->
        <!-- Repeater-->
        <!-- Other Stuff-->
    </ContentTemplate>
</asp:UpdatePanel>

另一种方法(不确定是否有效):

尝试在标签定义上设置转发器数据源:

<asp:Repeater id="repeater" runat="server" DataSource='<%# Data %>' >
    <ItemTemplate>
        <asp:LinkButton id="link" runat="server" OnClick="link_Click" />
    </ItemTemplate>
</asp:Repeater>

protected void Button_Click(object sender, EventArgs e)
{
    Data = GetData();
    LoadRepeater();
}

protected void Page_Load(object sender, EventArgs e)
{
}

private void LoadRepeater()
{
    repeater.DataBind();
}

【讨论】:

  • 感谢您的回复!我的印象是您可以在 click 事件处理程序中创建控件,但您只能在 Page_Init 或 Page_Init 事件处理程序中为这些控件添加事件处理程序。我的理解有误吗?
  • @Jeremy Choate,我不这么认为。你有这方面的资料吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多