Asp.net 基于viewstate在Page_PreRender中创建动态控件会导致button OnClick事件不起作用
我意识到应该在Page_Load和Page_Init中创建动态控件,以便在控件树中注册它们 我创建了一个自定义控件,该控件需要在button OnClick事件中使用ViewState。然后使用此ViewState动态创建控件 因为生命周期将继续:页面加载->按钮单击->页面预渲染。视图状态在“单击按钮”之前不会更新,因此我正在页面预渲染中创建动态控件。但是,在Page_PreRender中创建按钮并以编程方式指定OnClick EventHandler不起作用 有人知道我怎样才能让它工作吗 btn_DeleteTableRow_单击将不会触发。这是在CreatePartRows()中设置的 以下是我的例子:Asp.net 基于viewstate在Page_PreRender中创建动态控件会导致button OnClick事件不起作用,asp.net,Asp.net,我意识到应该在Page_Load和Page_Init中创建动态控件,以便在控件树中注册它们 我创建了一个自定义控件,该控件需要在button OnClick事件中使用ViewState。然后使用此ViewState动态创建控件 因为生命周期将继续:页面加载->按钮单击->页面预渲染。视图状态在“单击按钮”之前不会更新,因此我正在页面预渲染中创建动态控件。但是,在Page_PreRender中创建按钮并以编程方式指定OnClick EventHandler不起作用 有人知道我怎样才能让它工作吗 b
<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的答案是正确的,但需要更清楚地了解他所说的页面加载。这里有三个页面请求
<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);
}
}
}