2009-03-13 15 views
2

ASP.NETページのViewStateは動的に削除されたコントロールとその値に追いつくのに苦労しているようです。ViewStateと動的に削除されたコントロール

のは、一例として、次のコードを見てみましょう:

ASPX:

<form id="form1" runat="server"> 
<div> 
    <asp:Panel runat="server" ID="controls" /> 
</div> 
</form> 

CS:

protected void Page_Init(object sender, EventArgs e) { 
    Button b = new Button(); 
    b.Text = "Add"; 
    b.Click +=new EventHandler(buttonOnClick); 
    form1.Controls.Add(b); 
    Button postback = new Button(); 
    postback.Text = "Postback"; 
    form1.Controls.Add(postback); 
} 

protected void Page_Load(object sender, EventArgs e) { 
    if (ViewState["controls"] != null) { 
     for (int i = 0; i < int.Parse(ViewState["controls"].ToString()); i++) { 
      controls.Controls.Add(new TextBox()); 
      Button remove = new Button(); 
      remove.Text = "Remove"; 
      remove.Click +=new EventHandler(removeOnClick); 
      controls.Controls.Add(remove); 
      controls.Controls.Add(new LiteralControl("<br />")); 
     } 
    } 
} 

protected void removeOnClick(object sender, EventArgs e) { 
    Control s = sender as Control; 
    //A hacky way to remove the components around the button and the button itself 
    s.Parent.Controls.Remove(s.Parent.Controls[s.Parent.Controls.IndexOf(s) + 1]); 
    s.Parent.Controls.Remove(s.Parent.Controls[s.Parent.Controls.IndexOf(s) - 1]); 
    s.Parent.Controls.Remove(s.Parent.Controls[s.Parent.Controls.IndexOf(s)]); 
    ViewState["controls"] = (int.Parse(ViewState["controls"].ToString()) - 1).ToString(); 
} 

protected void buttonOnClick(object sender, EventArgs e) { 
    if (ViewState["controls"] == null) 
     ViewState["controls"] = "1"; 
    else 
     ViewState["controls"] = (int.Parse(ViewState["controls"].ToString()) + 1).ToString(); 
    controls.Controls.Add(new TextBox()); 
} 

その後、あなたは4つのコントロールを作成し、挿入しましょう以下の値:

[ 1 ] [ 2 ] [ 3 ] [ 4 ] 

2番目のコントロールを削除します。第2の制御を取り除いた後に、

[ 1 ] [ 3 ] [ 4 ] 

が出力されます。残念ながら、その後のポストバックで、リスト は次のようになります。

[ 1 ] [ ] [ 3 ] 

だから、私の質問は、なぜこの出来事はありますか?私が読んだ限り、ViewStateは、実際のコントロールではなく、インデックスに関連してコントロールのプロパティを保存する必要があります。

答えて

6

カップルのもの。コントロールがIDまたはインデックスによってロードされるかどうかは、ViewStateModeById属性によって決まります。デフォルトではfalse(インデックスによるロードを意味します)です。

ただし、テキストボックスの処理方法は異なります。それらのビューステートは、無効または不可視でない限り、入力値を含みません。テキストプロパティは、IDを使用して転記された値によって上書きされます。テキストボックスIDを管理していないので、これが起こります。

4つのコントロールを追加すると、4つのテキストボックス(ctrl0、ctrl1、ctrl2、ctrl3)に値1、2、3、4がそれぞれ表示されます。

次に、ctrl1ボックスを削除し、クライアントは3つのボックスctrl0、ctrl2、およびctrl3を取得します。これらの3つの値は、ポストバックを行うと、ctrl0 = 1 & ctrl2 = 3 & ctrl3 = 4の形式で送信されます。

次に、Page_Loadでは、3つのコントロールを作成します。今回は、値なしのctrl0、ctrl1、ctrl2です。

フレームワークはLoadRecursiveを呼び出してビューステートを呼び出し、次にProcessPostDataを呼び出して入力値を割り当てます。送信されたctrl0とctrl2を見て、同じIDのコントロールを見つけ、値1と3を割り当てます。ctrl3が見つからないため、スキップします。残りのctrl1は単純にw/oの値を持ちます。一例として、

、このソリューション(最高ではない)を検討:

protected void Page_Init(object sender, EventArgs e) 
{ 
    Button b = new Button(); 
    b.Text = "Add"; 
    b.Click += new EventHandler(buttonOnClick); 
    form1.Controls.Add(b); 

    Button postback = new Button(); 
    postback.Text = "Postback"; 
    form1.Controls.Add(postback); 
} 

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (ViewState["controls"] != null) 
    { 
     List<string> ids = (List<string>)ViewState["controls"]; 

     for (int i = 0; i < ids.Count; i++) 
     { 
      TextBox textbox = new TextBox(); 
      textbox.ID = string.Format("txt_{0}", ids[i]); 
      textbox.Text = textbox.ID; 
      controls.Controls.Add(textbox); 

      Button remove = new Button(); 
      remove.Text = "Remove"; 
      remove.Click += new EventHandler(removeOnClick); 
      remove.ID = ids[i]; 
      controls.Controls.Add(remove); 

      controls.Controls.Add(new LiteralControl("<br />")); 
     } 
    } 
} 

protected void removeOnClick(object sender, EventArgs e) 
{ 
    Control btn = sender as Control; 

    List<string> ids = (List<string>)ViewState["controls"]; 
    ids.Remove(btn.ID); 

    //A hacky way to remove the components around the button and the button itself 
    btn.Parent.Controls.Remove(btn.Parent.Controls[btn.Parent.Controls.IndexOf(btn) + 1]); 
    btn.Parent.Controls.Remove(btn.Parent.Controls[btn.Parent.Controls.IndexOf(btn) - 1]); 
    btn.Parent.Controls.Remove(btn); 

    ViewState["controls"] = ids; 
} 

protected void buttonOnClick(object sender, EventArgs e) 
{ 
    List<string> ids; 

    if (ViewState["controls"] == null) 
     ids = new List<string>(); 
    else 
     ids = (List<string>)ViewState["controls"]; 

    string id = Guid.NewGuid().ToString(); 
    TextBox textbox = new TextBox(); 
    textbox.ID = string.Format("txt_{0}", id); 
    textbox.Text = textbox.ID; 
    controls.Controls.Add(textbox); 

    Button remove = new Button(); 
    remove.Text = "Remove"; 
    remove.Click += new EventHandler(removeOnClick); 
    remove.ID = id; 
    controls.Controls.Add(remove); 

    controls.Controls.Add(new LiteralControl("<br />")); 

    ids.Add(id); 

    ViewState["controls"] = ids; 
} 
+0

を私は、関連する問題を持っている - 私は、コンボポストバックに依存するGridViewを持っています。コンボを変更すると、新しいコンボ値のデータでグリッドがリフレッシュされます。しかしリフレッシュするとグリッドはコンボの最初のアイテムのデフォルトデータに戻りますが、コンボはリフレッシュ時に選択されたアイテムにリセットされます。グリッドとコンボは同期していません。私はバインドし、コンボを 'Page_Load if!postback'の最初の項目に設定しようとしましたが、htmlは' selected = "selected" 'に装飾されていることをhtmlが示していますが、項目!これは関連していますか? – Chris

0

Page_Loadでコードの半分、ポストバックイベントでコードの半分を実行しています。この混乱のどこかで、あなたは葛藤に遭っています。 2回目のポストバックまで表示されないという事実は、あなたのロジックにいくつかの実行があることを私に伝えます。

問題の発生場所は正確にはわかりませんが、カスタムViewState crudを実行しているときは、ViewStateの処理は世界で最も楽しいものではありません。私は、アプリケーションを再構築し、何が起こっているかを見るための監視条件を設定する必要がありますが、私はかなりあなたのPage_Loadコードとイベントハンドラ間のインピーダンスの不一致であると確信しています。

関連する問題