【问题标题】:Odd behavior with dynamically created usercontrols on postback回发时动态创建的用户控件的奇怪行为
【发布时间】:2017-08-16 20:33:36
【问题描述】:

我在动态生成的用户控件保留其所选值时遇到了一些困难。我创建了一个包含多个表单字段的用户控件。在主页上,我有一个按钮,可以将我的用户控件放在占位符中。用户可以根据需要创建任意数量的这些。我在控件本身也有一个按钮,允许用户删除任何给定的控件。此功能似乎运行良好。

但是,在以下情况下会出现奇怪的情况:

  1. 单击按钮在页面上创建用户控件。填写表格 字段。
  2. 再次单击按钮以创建第二个 UC 并填写表格 字段。在这一点上一切都很好。 UC#1 中的值保留了它的 价值观。
  3. 单击按钮创建第三个 UC,所有选定的值都是 被 UC #1 和 #2 淘汰。
  4. 如果我重新填写所有 UC 中的字段,然后单击按钮以创建第 4 个 UC,则 UC#1 和 UC#3 将保留其值,但 UC#2 会丢失其值。

任何帮助将不胜感激。我正在努力解决这个问题。这是我第一次涉足动态用户控件,到目前为止它让我很兴奋。而且我仍然必须弄清楚如何使用数据库中的值填充这些 UC,以便用户可以回来编辑表单,但一次只做一件事。

aspx:

    <asp:PlaceHolder ID="placeholderOffenseCodes"  runat="server">  </asp:PlaceHolder>
    <asp:Button ID="btnAddOffense" runat="server" Text="Add an Offense" CausesValidation="false" OnClick="btnAddOffense_Click" />
<!--The text value determines how many items are initially displayed on the page-->
    <asp:Literal ID="ltlCount" runat="server" Text="0" Visible="false" />
    <asp:Literal ID="ltlRemoved" runat="server" Visible="false" /> 

aspx.cs:

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

private void AddAndRemoveDynamicOffenseControls()
{
    //Determine which control fired the postback event. 
    Control c = GetPostBackOffenseControl(Page);

    if ((c != null))
    {
        //If the add button was clicked, increase 
        //the count to let the page know we want
        //to display an additional user control
        if (c.ID.ToString() == "btnAddOffense")
        {
            ltlCount.Text = Convert.ToString(Convert.ToInt16(ltlCount.Text) + 1);
        }
    }

    //Be sure everything in the placeholder control is cleared out
    placeholderOffenseCodes.Controls.Clear();

    int ControlID = 0;

    //Re-add controls every time the page loads.
    for (int i = 0; i <= (Convert.ToInt16(ltlCount.Text) - 1); i++)
    {
        IncidentGroupA_Offenses uc = (IncidentGroupA_Offenses)LoadControl("IncidentGroupA_Offenses.ascx");

        //If this particular control id has been deleted 
        //from the page, DO NOT use it again. If we do, it will
        //pick up the viewstate data from the old item that 
        //had this control id, instead of generating
        //a completely new control. Instead, increment 
        //the control ID so we're guaranteed to get a "new"
        //control that doesn't have any lingering information in the viewstate.
        while (InDeletedOffenseList("offense" + ControlID) == true)
        {
            ControlID += 1;
        }

        //Note that if the item has not been deleted from the page, 
        //we DO want it to use the same control id
        //as it used before, so it will automatically maintain 
        //the viewstate information of the user control
        //for us.
        uc.ID = "offense" + ControlID;

        //Add an event handler to this control to raise 
        //an event when the delete button is clicked
        //on the user control
        uc.RemoveOffenseUC += this.HandleRemoveOffenseUserControl;

        //Add the user control to the panel
        placeholderOffenseCodes.Controls.Add(uc);

        //Add Offense number to label on usercontrol
        int OffenseNum = i + 1;
        uc.OffenseNumber = "Offense " + OffenseNum;

        //Increment the control id for the next round through the loop
        ControlID += 1;
    }
}

protected void btnAddOffense_Click(object sender, EventArgs e)
{
    //handled in page_load
}

private bool InDeletedOffenseList(string ControlID)
{
    //Determine if the passed in user control ID 
    //has been stored in the list of controls that
    //were previously deleted off the page
    string listvalues = ltlRemoved.Text;
    string[] stringSeparators = new string[] { "|" };
    string[] DeletedList = listvalues.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries);
    for (int i = 0; i <= DeletedList.GetLength(0) - 1; i++)
    {
        if (ControlID == DeletedList[i])
        {
            return true;
        }
    }
    return false;
}

public void HandleRemoveOffenseUserControl(object sender, EventArgs e)
{
    //This handles delete event fired from the user control

    //Get the user control that fired this event, and remove it
    LinkButton linkBtn = sender as LinkButton;
    IncidentGroupA_Offenses uc = (IncidentGroupA_Offenses)linkBtn.Parent;

    if (uc != null)
    {
        placeholderOffenseCodes.Controls.Remove(uc);
    }

    //Keep a pipe delimited list of which user controls were removed.  This will increase the 
    //viewstate size if the user keeps removing dynamic controls, but under normal use
    //this is such a small increase in size that it shouldn't be an issue.
    ltlRemoved.Text += uc.ID.ToString() + "|";

    //Also, now that we've removed a user control decrement the count of total user controls on the page
    ltlCount.Text = Convert.ToString(Convert.ToInt16(ltlCount.Text) - 1);
}

public Control GetPostBackOffenseControl(Page page)
{
    Control control = null;

    string ctrlname = page.Request.Params.Get("__EVENTTARGET");
    if ((ctrlname != null) & ctrlname != string.Empty)
    {
        control = page.FindControl(ctrlname);
    }
    else
    {
        foreach (string ctl in page.Request.Form)
        {
            Control c = page.FindControl(ctl);
            if (c is System.Web.UI.WebControls.Button)
            {
                control = c;
                break; 
            }
        }
    }
    return control;
} 

.ascx.cs:

public event EventHandler RemoveOffenseUC;

protected void btnRemoveOffense_Click(object sender, EventArgs e)
{
    //Raise this event so the parent page can handle it
    if (RemoveOffenseUC != null)
    {
        RemoveOffenseUC(sender, e);
    }
}

public string OffenseNumber
{
    get { return lblOffenseNumber.Text; }
    set { lblOffenseNumber.Text = value; }
}

【问题讨论】:

    标签: c# asp.net webforms user-controls viewstate


    【解决方案1】:

    我一直认为您必须在 Page_Init 添加动态控件以确保正确加载 ViewState。也许这个简单的改变就能解决你的问题?

    否则,我过去很幸运能够完全避免使用中继器进行动态控制。与其添加动态控件(Webforms 绝对不是很擅长),不如将数据添加到 List 或 ADO DataTable 之类的数据结构中,然后将其绑定到带有所需控件的 asp:Repeater。无需为动态控件而大惊小怪。

    祝你好运!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 2010-12-13
      相关资源
      最近更新 更多