3

コントロール ツリーに動的コントロールを登録するには、Page_Load および Page_Init 内に動的コントロールを作成する必要があることを認識しています。

ボタンの OnClick イベントで ViewState を使用する必要があるカスタム コントロールを作成しました。この ViewState は、コントロールを動的に作成するために使用されます。

ライフサイクルは次のようになります: ページの読み込み -> ボタンのクリック -> ページのプリレンダー。ビューステートは「ボタン クリック」まで更新されないため、Page PreRender で動的コントロールを作成しています。ただし、ボタンを作成し、Page_PreRender で OnClick EventHandler をプログラムで割り当てることは機能しません。

これを機能させる方法を知っている人はいますか?

btn_DeleteTableRow_Click は起動しません。これは 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);
    }        
}
4

4 に答える 4

1

Load イベントの直後にコントロール イベントが呼び出されるため、ボタン クリックは発生しません。ボタンは、asp.net ライフサイクルがイベントを呼び出そうとする時点でコントロール階層にないため、削除されています。これはラウンド トリップであり、イベント ハンドラーが呼び出されるには、LoadComplete イベントが発生する前にコントロールがポストバックに存在する必要があることに注意してください。

PreLoad または Load イベントで動的コントロールを作成すれば問題ありません (その時点で完全なビューステートにアクセスして、その行の削除ボタンを動的に作成する必要があるかどうかを決定できます)。

ASP.net ページ ライフサイクル ドキュメント: http://msdn.microsoft.com/en-us/library/ms178472(v=vs.100).aspx

于 2013-07-19T23:33:49.857 に答える
0

ロバートとビルに同意します。

ただし、ここに追加すると、私の意見では、これを達成する唯一の方法は、メソッドとメソッドをオーバーライドするカスタム コントロール/Web サーバー コントロール (継承WebControlクラス)を作成することです。これは、あなたのコメントの 1 つで、グリッド ビュー バージョンをコード化するつもりであると言ったときの意味だと思います。CreateChildControlsRenderContents

于 2013-07-24T13:56:33.560 に答える
0

Robert は正しい答えを持っていると思いますが、彼が話している Page.Load についてもっと明確にする必要があります。ここには 3 つのページ要求があります。

  1. 最初のページ リクエストで、最初のボタンはまだクリックされていません。
  2. ボタンクリックでポストバック。Page Load での処理はありません。PreRender 呼び出しは、新しいテーブル行と新しいボタンを作成し、ボタン クリック イベントを新しいボタンにリンクします。
  3. クライアントが新しいボタンをクリックした後のポストバック。動的ボタンの Click イベントがドロップされないように、Page Load で動的ボタンを再作成する必要があります。
于 2013-07-22T16:06:46.700 に答える