从母版页上注册的回调中检索 ascx 控件值.控件在 OnItemCreate 期间添加到中继器的占位符

本文关键字:控件 OnItemCreate 添加 占位符 中继器 回调 母版页 注册 检索 ascx | 更新日期: 2023-09-27 18:20:51

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

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

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

<%@ 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、一个DropDownList和一个"添加"ButtonRepeater具有选项的名称、简短说明、删除图像和用于从数据库加载自定义控件的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>

在代码隐藏中,RepeaterPage_Load上首次使用以下代码填充(结合 C# 和伪代码以缩短这个已经很长的问题(:

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;
}

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

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();
}

最后,我认为问题可能在哪里,以及对我尝试过的一些解释。将选项添加到控件时,将查询其他表,以查看是否有必须加载到占位符中的其他 ascx。这发生在RepeaterOnItemCreated指出的方法中:

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

至少尝试了以下方法,甚至更多(但老实说,我不记得我尝试过的每一步(:

  • 将呼叫添加到被覆盖LoadViewState RefreshOptions调用后加载底座
  • 执行初始Repeater绑定在Page_Init而不是Page_Load
  • 将表行、单元格和自定义控件相互添加和主控件的不同顺序页

我应该如何构建此页面及其必要的数据绑定事件,以便我可以使以下代码中的注释行之类的内容起作用?当我在方法开始时中断并查看RepeaterOptions.Controls时,CustomOptionControl消失了。

protected void OnSubmit(int configID)
{
    //List<CustomOptionControl> optionsToInsert = find CustomOptionControls in RepeaterOptions (probably an iterative search through the Controls);
    //foreach (CustomOptionControl control in optionsToInsert)
    //{
    //    control.AddOptionToDatabase(configID);
    //}
}

从母版页上注册的回调中检索 ascx 控件值.控件在 OnItemCreate 期间添加到中继器的占位符

我不确定发生了什么变化,也许是使用上述所有内容进行橡皮鸭调试。我已经回去尝试调整我之前的一些东西(插入顺序、调用使用等(,看看它们是否有区别,但无论哪种方式,Control现在都使用上面的代码正确地保留在ViewState中。只要添加以下内容(我之前尝试过的项目符号 #1(,它就可以从母版页调用回发

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

早些时候,savedState仅显示添加到其中以维护所选选项的List<int>。在调整和调试的某个时刻,我发现我创建的控件现在处于视图状态中,并且添加RefreshOptions调用有效。这意味着在添加/删除的回发中有两个调用RefreshOptions,但我可以解决这个问题或忽略它,因为行为仍然是正确的。感谢您的观看!