从主页上注册的回调中检索ascx控件值。在OnItemCreated期间,控件添加到Repeater的PlaceHolder

时间:2013-07-03 03:57:55

标签: c# asp.net postback dynamic-controls

这是我最好的简化代码以便很好地提出问题的尝试。希望它有所帮助。

简短:我需要获取动态创建的Control的值,其路径从数据库加载并添加到包含Repeater的{​​{1}}。需要从从母版页调用的子页面上的函数中检索该值。

长: 我有一个母版页,其上有很多设置,以及一个子页面可以添加自己的配置选项的区域。假设母版页如下:

PlaceHolder

在代码隐藏中,我需要将设置保留到数据库,包括用户页面中的自定义设置。子页面需要从母版页创建的一些数据才能保留其数据。为了实现这一点,我有一个事件,在子页面加载时填充并在重定向之前调用。它看起来像这样:

<%@ Master Language="C#" MasterPageFile="~/MainTemplate.master" CodeBehind="ConfigureChoices.master.cs" Inherits="Demo.ConfigureChoices"
AutoEventWireup="true"  %>


<asp:Content ID="Content1" ContentPlaceHolderID="RenderArea" runat="Server">

    <asp:Panel runat="server" ID="PanelConfiguration">
        <asp:TextBox ID="TextBoxForSomething" runat="Server"/>
        <asp:DropDownList ID="AnotherConfigurableThing" runat="server" OnSelectedIndexChanged="DropDownConfiguration_Click" AutoPostBack="true">
            <asp:ListItem Text="Option 1" Selected="True" Value="1"></asp:ListItem>
            <asp:ListItem Text="Option 2"  Value="2"></asp:ListItem>
            <asp:ListItem Text="Option 3"  Value="3"></asp:ListItem>
        </asp:DropDownList>
        <!--etc-->

        <asp:ContentPlaceHolder ID="CustomSettings" runat="server">
        </asp:ContentPlaceHolder>

        <asp:Button ID="ButtonSubmit" runat="Server" Text="Submit" OnClick="ButtonSubmit_Click" />
    </asp:Panel>

</asp:Content>

用户页面的自定义部分包含public delegate void BeforeSubmitEventHandler(int configInfoID); public event BeforeSubmitEventHandler BeforeSubmit; protected void ButtonSubmit_Click(object sender, EventArgs e) { ConfigInfo config = new ConfigInfo; config.EnteredText = TextBoxForSomething.Text; config.SelectedValue = AnotherConfigurableThing.SelectedValue; int configID = AddToDatabase(config); if (BeforeSubmit != null) BeforeSubmit(configID); Response.Redirect("RedirectURL.aspx"); } Repeater和“添加”DropDownListButton具有选项的名称,简短描述,删除图像和用于从数据库加载自定义控件的Repeater。更多关于代码后的内容:

PlaceHolder

在代码隐藏中,<%@ Page Title="" Language="C#" MasterPageFile="~/ConfigureChoices.master" ValidateRequest="false" AutoEventWireup="true" Inherits="Demo.CustomChoicePage1" Codebehind="CustomChoicePage1.aspx.cs" MaintainScrollPositionOnPostback="true" %> <asp:Content ID="MyContent" ContentPlaceHolderID="CustomSettings" runat="server"> <asp:Repeater ID="RepeaterSelectedOptions" OnItemCreated="OnOptionAdded" runat="server"> <HeaderTemplate> <table id="SelectedOptionsTable"> <thead> <tr> <th>Name</th> <th>Description</th> <th>Remove</th> </tr> </thead> <tbody> </HeaderTemplate> <ItemTemplate> <tr> <td> <%# Server.HtmlEncode(Eval("Name").ToString()) %> </td> <td> <%# Server.HtmlEncode(Eval("Description").ToString()) %> </td> <td> <asp:ImageButton ImageUrl="delete.png" ID="ImgDeleteOption" runat="server" OnCommand="DeleteOption_Click" CommandArgument='<%# Eval("OptionID") %>' /> </td> </tr> <asp:PlaceHolder runat="server" ID="optionConfiguration" /> </ItemTemplate> <FooterTemplate> </tbody> </table> </FooterTemplate> </asp:Repeater> <br /> <asp:DropDownList ID="DropDownListAvailableOptions" runat="server" /> <asp:Button ID="ButtonAddOption" runat="server" Text="Add Option" OnCommand="AddOption_Click" /> </asp:Content> 首次在Repeater上使用以下代码填充(C#和伪代码的组合缩短了这个已久的问题):

Page_Load

如果单击添加或删除按钮,则使用以下方法:

protected void Page_Load(object sender, EventArgs e)
{
    ((ConfigureChoices)Master).BeforeSubmit += OnSubmit;
    if (!Page.IsPostBack)
    {
        RefreshOptions();
    }
}

protected void RefreshOptions()
{
    List<Option> fullList = GetOptionsFromDB();
    List<Option> availableList = new List<Option>();
    List<Option> selectedList = new List<Option>();
    List<int> selectedOptions = GetSelectedOptions();

    // Logic here to set the available/selected Lists

    DropDownListAvailableOptions.DataSource = availableList;
    DropDownListAvailableOptions.DataBind();

    RepeaterSelectedOptions.DataSource = selectedList;
    RepeaterSelectedOptions.DataBind();
}

public List<short> GetSelectedOptions()
{
    List<int> selectedOptions = this.ViewState["SelectedOptions"];
    if (selectedOptions == null)
    {
        selectedOptions = new List<int>();
        foreach (Option option in GetOptionsFromDB())
        {
            selectedOptions.Add(option.OptionID);
        }
    }
    return selectedOptions;
}

最后,我认为这个问题可能存在的问题,以及我尝试过的一些解释。将一个选项添加到控件时,将查询另一个表以查看是否还有一个必须加载到占位符中的其他ascx。这种情况发生在public void AddOption_Click(object sender, CommandEventArgs e) { List<int> selectedOptions = GetSelectedOptions(); selectedOptions.Add(Convert.ToInt32(DropDownListAvailableOptions.SelectedValue)); this.ViewState["SelectedOptions"] = selectedTests; RefreshOptions(); } public void DeleteOption_Click(object sender, CommandEventArgs e) { List<int> selectedOptions = GetSelectedOptions(); selectedOptions.Remove(Convert.ToInt32(e.CommandArgument)); this.ViewState["SelectedOptions"] = selectedOptions; RefreshOptions(); }

OnItemCreated指向的方法中
Repeater

所以上面的所有“工作”,我看到页面上的控件,列表正常工作,以及类似的东西。当我单击“提交”按钮时,我在Request表单变量中看到配置(为了这个例子,我们只是说它是一个复选框)。但是,在子页面上的回调方法中设置断点,protected void OnOptionAdded(Object sender, RepeaterItemEventArgs e) { if (e.Item == null || e.Item.DataItem == null) return; short optionID = ((Option)e.Item.DataItem).OptionID; OptionControl optionControl = GetControlForOptionFromDB(optionID); if (optionControl == null) return; CustomOptionControl control = (CustomOptionControl)this.LoadControl(optionControl.Path); control.ID = "CustomControl" + optionID.ToString(); TableRow tableRow = new TableRow(); tableRow.ID = "CustomControlTR" + optionID.ToString(); tableRow.CssClass = "TestConfiguration"; TableCell tableCell = new TableCell(); tableCell.ID = "CustomControlTC" + optionID.ToString(); tableCell.ColumnSpan = 3; e.Item.FindControl("optionConfiguration").Controls.Add(tableRow); tableRow.Cells.Add(tableCell); tableCell.Controls.Add(control); } 似乎不在CustomOptionControl中。只有RepeaterSelectedOptions存在。

我至少尝试过以下等等(但老实说,我不记得我尝试过的每一步):

  • Option的来电添加到被覆盖的RefreshOptions 在调用加载基础
  • 之后
  • 做我最初的LoadViewState绑定 在Repeater而不是Page_Init
  • 将表格行,单元格和自定义控件相互添加和主要的不同顺序 页

我应该如何构建此页面及其必要的数据绑定事件,以便我可以在下面的代码中创建类似于注释行的内容?当我在方法开始时突破并查看Page_Load时,RepeaterOptions.Controls已消失。

CustomOptionControl

1 个答案:

答案 0 :(得分:0)

我不确定发生了什么变化,也许是使用以上所有内容进行橡皮鸭调试。我已经回过头来尝试调整我以前的一些事情(插入顺序,使用它们等等)以确定它们是否有所作为,但无论哪种方式,Control现在都被保留在ViewState正确使用上面的代码。只要添加以下内容,就可以在母版页调用的回发中使用它(我之前尝试过的内容#1):

    protected override void LoadViewState(object savedState)
    {
        base.LoadViewState(savedState);
        RefreshOptions();
    }

之前,savedState仅显示添加List<int>以维护所选选项。在调整和调试的某些时候,我看到我创建的控件现在在viewstate中,并且添加了RefreshOptions调用。这意味着在回发添加/删除时,有两次调用RefreshOptions,但我可以解决这个问题或忽略它,因为行为仍然是正确的。谢谢你的期待!