在回发时动态创建用户控件的奇怪行为

时间:2017-03-24 02:35:09

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

我在动态生成的用户控件中保留其选定值时遇到了一些困难。我创建了一个包含多个表单字段的usercontrol。在主页面上,我有一个按钮,可以将我的usercontrol放在占位符中。用户可以根据需要创建尽可能多的这些内容。我在控件本身也有一个按钮,允许用户删除任何给定的控件。这个功能似乎工作正常。

但是,在以下情况中出现了奇怪的现象:

  1. 单击按钮在页面上创建用户控件。填写表格 领域。
  2. 再次单击按钮以创建第二个UC并填写表单 领域。一切都很顺利。 UC#1中的值保留了它 值。
  3. 点击按钮创建第三个UC,所有选定的值都是 从UC#1和#2中消失。
  4. 如果我重新填写所有UC的字段,然后单击按钮创建第4个UC,然后UC#1和UC#3保留其值,但UC#2会丢失它的值。
  5. 任何帮助都会受到大力赞赏。我正试图弄清楚这一点。这是我第一次涉足动态用户控制,到目前为止,它正在踢我的屁股。而且我仍然需要弄清楚如何使用db中的值来填充这些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; }
    }
    

1 个答案:

答案 0 :(得分:0)

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

否则,我过去很幸运,完全避免使用转发器进行动态控制。而不是添加动态控件,哪些webforms绝对不擅长,将数据添加到数据结构(如List或ADO DataTable),然后将其绑定到具有所需控件的asp:Repeater。没有乱七八糟的动态控制。

祝你好运!