Asp.net 基于viewstate在Page_PreRender中创建动态控件会导致button OnClick事件不起作用

Asp.net 基于viewstate在Page_PreRender中创建动态控件会导致button OnClick事件不起作用,asp.net,Asp.net,我意识到应该在Page_Load和Page_Init中创建动态控件,以便在控件树中注册它们 我创建了一个自定义控件,该控件需要在button OnClick事件中使用ViewState。然后使用此ViewState动态创建控件 因为生命周期将继续:页面加载->按钮单击->页面预渲染。视图状态在“单击按钮”之前不会更新,因此我正在页面预渲染中创建动态控件。但是,在Page_PreRender中创建按钮并以编程方式指定OnClick EventHandler不起作用 有人知道我怎样才能让它工作吗 b

我意识到应该在Page_Load和Page_Init中创建动态控件,以便在控件树中注册它们

我创建了一个自定义控件,该控件需要在button OnClick事件中使用ViewState。然后使用此ViewState动态创建控件

因为生命周期将继续:页面加载->按钮单击->页面预渲染。视图状态在“单击按钮”之前不会更新,因此我正在页面预渲染中创建动态控件。但是,在Page_PreRender中创建按钮并以编程方式指定OnClick EventHandler不起作用

有人知道我怎样才能让它工作吗

btn_DeleteTableRow_单击将不会触发。这是在CreatePartRows()中设置的

以下是我的例子:

<asp:UpdatePanel ID="up_RMAPart" runat="server" UpdateMode="Conditional" EnableViewState="true" ChildrenAsTriggers="true">
<ContentTemplate>
    <div class="button" style="width: 54px; margin: 0px; float: right;">
        <asp:Button ID="btn_AddPart" runat="server" Text="Add" OnClick="btn_AddPart_Click" />
    </div>
    <asp:Table ID="Table_Parts" runat="server" CssClass="hor-zebra">
    </asp:Table>
    <div class="clear"></div>
</ContentTemplate>
<Triggers>
    <asp:AsyncPostBackTrigger ControlID="btn_AddPart" EventName="Click" />
</Triggers>

代码隐藏:

[Serializable]
public struct Part
{
    public string PartName;
    public int Quantity;
    public int PartID;

    public Part(string sPartName, int iQuantity, int iPartID)
    {
        PartName = sPartName;
        Quantity = iQuantity;
        PartID = iPartID;
    }
}

public partial class RMAPart : System.Web.UI.UserControl
{
    private Dictionary<string,Part> m_RMAParts;
    private int m_RowNumber = 0;

    public Dictionary<string, Part> RMAParts
    {
        get
        {
            if (ViewState["m_RMAParts"] != null)
                return (Dictionary<string, Part>)ViewState["m_RMAParts"];
            else
                return null;
        }
        set
        {
            ViewState["m_RMAParts"] = value;
        }
    }

    public int RowNumber
    {
        get
        {
            if (ViewState["m_RowNumber"] != null)
                return Convert.ToInt32(ViewState["m_RowNumber"]);
            else
                return 0;
        }
        set
        {
            ViewState["m_RowNumber"] = value;
        }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            RMAParts = new Dictionary<string, Part>();
            RowNumber = 0;
            RMAParts.Add("PartRow_" + RowNumber.ToString(), new Part());
            RowNumber = 1;
            CreatePartRows();
        }
    }



    protected void Page_PreRender(object sender, EventArgs e)
    {
        CreatePartRows();
    }

    private void CreatePartRows()
    {
        Table_Parts.Controls.Clear();

        TableHeaderRow thr = new TableHeaderRow();

        TableHeaderCell thc1 = new TableHeaderCell();
        thc1.Controls.Add(new LiteralControl("Part"));
        thr.Cells.Add(thc1);

        TableHeaderCell thc2 = new TableHeaderCell();
        thc2.Controls.Add(new LiteralControl("Quantity"));
        thr.Cells.Add(thc2);

        TableHeaderCell thc3 = new TableHeaderCell();
        thc3.Controls.Add(new LiteralControl(""));
        thr.Cells.Add(thc3);

        Table_Parts.Rows.Add(thr);

        foreach (KeyValuePair<string, Part> kvp in RMAParts)
        {
            string[] sKey = kvp.Key.Split('_');

            TableRow tr = new TableRow();
            tr.ID = kvp.Key;

            TableCell tc1 = new TableCell();
            TextBox tb_Part = new TextBox();
            tb_Part.ID = "tb_Part_" + sKey[1];
            tb_Part.CssClass = "textbox1";
            tc1.Controls.Add(tb_Part);
            tr.Cells.Add(tc1);

            TableCell tc2 = new TableCell();
            TextBox tb_Quantity = new TextBox();
            tb_Quantity.ID = "tb_Quanitty_" + sKey[1];
            tb_Quantity.CssClass = "textbox1";
            tc2.Controls.Add(tb_Quantity);
            tr.Cells.Add(tc2);

            TableCell tc3 = new TableCell();
            Button btn_Delete = new Button();
            btn_Delete.ID = "btn_Delete_" + sKey[1];
            btn_Delete.CommandArgument = tr.ID;
            btn_Delete.Click += new EventHandler(btn_DeleteTableRow_Click);                
            btn_Delete.Text = "Remove";
            tc3.Controls.Add(btn_Delete);
            tr.Cells.Add(tc3);

            Table_Parts.Rows.Add(tr);               
        }

    }

    public void Reset()
    {
        Table_Parts.Controls.Clear();
        RMAParts.Clear();
        RowNumber = 0;
        RMAParts.Add("PartRow_" + RowNumber.ToString(), new Part());
        RowNumber = 1;
        CreatePartRows();
    }

    protected void btn_AddPart_Click(object sender, EventArgs e)
    {
        RMAParts.Add("PartRow_" + RowNumber.ToString(), new Part());
        RowNumber++;
    }

    protected void btn_DeleteTableRow_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        TableRow tr = (TableRow)Table_Parts.FindControl(btn.CommandArgument);
        Table_Parts.Rows.Remove(tr);
        RMAParts.Remove(btn.CommandArgument);
    }        
}
[可序列化]
公共结构部分
{
公共字符串部分名;
公共整数;
公众参与;
公共部分(字符串sPartName、int IQUANTY、int iPartID)
{
PartName=sPartName;
数量=质量;
PartID=iPartID;
}
}
公共部分类RMAPart:System.Web.UI.UserControl
{
私家词典;
私有整数m_行数=0;
公共词典
{
得到
{
如果(ViewState[“m_rParts”!=null)
返回(字典)视图状态[“m_RMAParts”];
其他的
返回null;
}
设置
{
ViewState[“m_零件”]=值;
}
}
公共整数行数
{
得到
{
如果(ViewState[“m_RowNumber”]!=null)
返回Convert.ToInt32(ViewState[“m_RowNumber]”);
其他的
返回0;
}
设置
{
ViewState[“m_行编号”]=值;
}
}
受保护的无效页面加载(对象发送方、事件参数e)
{
如果(!Page.IsPostBack)
{
RMAParts=新字典();
行数=0;
RMAParts.Add(“PartRow_u3;”+RowNumber.ToString(),new Part());
行数=1;
CreatePartRows();
}
}
受保护的无效页面\u预呈现(对象发送方,事件参数e)
{
CreatePartRows();
}
私有void CreatePartRows()
{
表_零件.控件.清除();
TableHeaderRow thr=新的TableHeaderRow();
TableHeaderCell thc1=新的TableHeaderCell();
thc1.控件。添加(新的文字控件(“部分”);
thr.Cells.Add(thc1);
TableHeaderCell thc2=新的TableHeaderCell();
thc2.控件。添加(新的文字控件(“数量”);
thr.Cells.Add(thc2);
TableHeaderCell thc3=新的TableHeaderCell();
thc3.Controls.Add(新的LiteralControl(“”);
thr.Cells.Add(thc3);
表_部分行添加(thr);
foreach(零件中的KeyValuePair kvp)
{
字符串[]sKey=kvp.Key.Split(“”“);
TableRow tr=新的TableRow();
tr.ID=kvp.Key;
TableCell tc1=新的TableCell();
TextBox tb_Part=new TextBox();
tb_Part.ID=“tb_Part_”+sKey[1];
tb_Part.CssClass=“textbox1”;
tc1.控制。添加(tb_部分);
tr.Cells.Add(tc1);
TableCell tc2=新的TableCell();
TextBox tb_数量=新建TextBox();
tb_Quantity.ID=“tb_Quanitty”+sKey[1];
tb_Quantity.CssClass=“textbox1”;
tc2.控件.添加(tb_数量);
tr.Cells.Add(tc2);
TableCell tc3=新的TableCell();
按钮btn_Delete=新建按钮();
btn_Delete.ID=“btn_Delete”+sKey[1];
btn_Delete.CommandArgument=tr.ID;
btn_Delete.Click+=新的事件处理程序(btn_Delete tableRow_Click);
btn_Delete.Text=“删除”;
tc3.控件.添加(btn_删除);
tr.Cells.Add(tc3);
表_部分行添加(tr);
}
}
公共无效重置()
{
表_零件.控件.清除();
r.Clear();
行数=0;
RMAParts.Add(“PartRow_u3;”+RowNumber.ToString(),new Part());
行数=1;
CreatePartRows();
}
受保护的无效btn\u添加部分\u单击(对象发送者,事件参数e)
{
RMAParts.Add(“PartRow_u3;”+RowNumber.ToString(),new Part());
行数++;
}
受保护的无效btn\u DeleteTableRow\u单击(对象发送方,事件参数e)
{
按钮btn=(按钮)发送器;
TableRow tr=(TableRow)Table_Parts.FindControl(btn.CommandArgument);
表_零件行移除(tr);
RMAParts.Remove(btn.CommandArgument);
}        
}

由于在加载事件之后立即调用控制事件,因此没有触发按钮单击。在asp.net生命周期尝试调用事件时,您的按钮不在控件层次结构中,因此它将被删除。记住,这是一个往返过程,在LoadComplete事件触发之前,控件必须存在于回发中,以便调用其事件处理程序

在“预加载”或“加载”事件中创建动态控件,您应该可以(此时您将有权访问full viewstate,以决定是否需要为该行动态创建删除按钮)


ASP.net页面生命周期文档:

我认为Robert的答案是正确的,但需要更清楚地了解他所说的页面加载。这里有三个页面请求

  • 初始页面请求,尚未单击初始按钮
  • 点击按钮返回。页面加载中没有处理。PreRender调用创建新表行和新按钮,并将按钮单击事件链接到新按钮
  • 客户端单击“新建”按钮后回发。您需要重新创建dyna
    <asp:Table ID="Table_Parts" runat="server" CssClass="hor-zebra">
        <asp:TableRow>
            <asp:TableHeaderCell Text="Part" />
            <asp:TableHeaderCell Text="Quantity" />
            <asp:TableHeaderCell />
        </asp:TableRow>
    </asp:Table>
    
    public partial class RMAPart : System.Web.UI.UserControl
    {
        private List<string> RowIDs
        {
            get { return (List<string>)ViewState["m_RowIDs"]; }
            set { ViewState["m_RowIDs"] = value; }
        }
    
        protected void btn_AddPart_Click(object sender, EventArgs e)
        {
            string id = GenerateRowID();
            RowIDs.Add(id);
            CreatePartRow(id);
        }
    
        private string GenerateRowID()
        {
            int id = (int)ViewState["m_NextRowID"];
            ViewState["m_NextRowID"] = id + 1;
            return id.ToString();
        }
    
        private void CreatePartRow(string id)
        {
            TableRow tr = new TableRow();
            tr.ID = id;
    
            TableCell tc1 = new TableCell();
            TextBox tb_Part = new TextBox();
            tb_Part.ID = "tb_Part_" + id;
            tb_Part.CssClass = "textbox1";
            tc1.Controls.Add(tb_Part);
            tr.Cells.Add(tc1);
    
            TableCell tc2 = new TableCell();
            TextBox tb_Quantity = new TextBox();
            tb_Quantity.ID = "tb_Quantity_" + id;
            tb_Quantity.CssClass = "textbox1";
            tc2.Controls.Add(tb_Quantity);
            tr.Cells.Add(tc2);
    
            TableCell tc3 = new TableCell();
            Button btn_Delete = new Button();
            btn_Delete.ID = "btn_Delete_" + id;
            btn_Delete.CommandArgument = id;
            btn_Delete.Click += btn_DeleteTableRow_Click;
            btn_Delete.Text = "Remove";
            tc3.Controls.Add(btn_Delete);
            tr.Cells.Add(tc3);
    
            Table_Parts.Rows.Add(tr);
        }
    
        protected void btn_DeleteTableRow_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            TableRow tr = (TableRow)Table_Parts.FindControl(btn.CommandArgument);
            Table_Parts.Rows.Remove(tr);
            RowIDs.Remove(btn.CommandArgument);
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                Reset();
            }
        }
    
        public void Reset()
        {
            while (Table_Parts.Rows.Count > 1)
                Table_Parts.Rows.RemoveAt(Table_Parts.Rows.Count - 1);
    
            ViewState["m_NextRowID"] = 0;
            string id = GenerateRowID();
            RowIDs = new List<string> { id };
            CreatePartRow(id);
        }
    
        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
    
            foreach (string id in RowIDs)
            {
                CreatePartRow(id);
            }
        }
    }