15

動的制御の問題

こんにちは皆さん、

いくつかの動的コントロールを作成し、ページの読み込み全体でビューステートを保持させたいと考えています。簡単ですよね?私がしなければならないのは、同じIDを使用して、ページの読み込みごとにコントロールを再作成することだけです。ただし、ここに問題があります。PreRenderイベントで、コントロールコレクションをクリアしてから、新しい値で動的コントロールを再作成したいと考えています。その理由は複雑で、なぜそれをやりたいのかを説明するのに1ページほどかかるでしょう。したがって、簡潔にするために、私が絶対にこれを行わなければならず、他の方法はないと仮定しましょう。

PreRenderイベントでコントロールを再作成した後、問題が発生します。再作成されたコントロールはビューステートにバインドされることはなく、それらの値はページの読み込みを超えて保持されません。なぜこれが起こるのかわかりません。OnLoadイベントですでにコントロールを再作成しています。これを行うと、毎回同じIDを使用する場合、新しく作成されたコントロールはViewStateに正常にバインドされます。ただし、PreRenderイベントで同じことを実行しようとすると、失敗します。

いずれにせよ、ここに私のサンプルコードがあります:

名前空間TestFramework.WebControls{

public class ValueLinkButton : LinkButton
{
    public string Value
    {
        get
        {
            return (string)ViewState[ID + "vlbValue"];
        }

        set
        {
            ViewState[ID + "vlbValue"] = value;
        }
    }
}

public class TestControl : WebControl
{
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        Controls.Clear();

        ValueLinkButton tempLink = null;

        tempLink = new ValueLinkButton();
        tempLink.ID = "valueLinkButton";
        tempLink.Click += new EventHandler(Value_Click);

        if (!Page.IsPostBack)
        {
            tempLink.Value = "old value";
        }

        Controls.Add(tempLink);
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        ValueLinkButton tempLink = ((ValueLinkButton)FindControl("valueLinkButton"));  //[CASE 1]

        //ValueLinkButton tempLink = new ValueLinkButton();  [CASE 2]

        tempLink.ID = "valueLinkButton";
        tempLink.Value = "new value";
        tempLink.Text = "Click";            

        Controls.Clear();
        Controls.Add(tempLink);
    }

    void Value_Click(object sender, EventArgs e)
    {
        Page.Response.Write("[" + ((ValueLinkButton)sender).Value + "]");
    }
}

}

それでは、[CASE 1]の隣の行はコメントアウトされていないが、[CASE2]の隣の行はコメントアウトされているケース1を調べてみましょう。ここでは、すべてが正常に機能します。このコントロールをページに配置してページをロードすると、「クリック」というリンクが表示されます。リンクをクリックすると、ページに「[新しい値]」というテキストが出力され、次の行に、おなじみの「クリック」リンクが表示されます。その後、「クリック」リンクをクリックするたびに、同じことが表示されます。ここまでは順調ですね。

しかし、ここで、[CASE 1]の隣の行がコメント化されているが、[CASE2]の隣の行がコメント化されていないケース2を調べてみましょう。ここで問題が発生します。ページをロードすると、「クリック」リンクが表示されます。ただし、リンクをクリックすると、ページに「[newvalue]」ではなく「[]」というテキストが出力されます。クリックイベントは正常に発生しています。ただし、コントロールのValue属性に割り当てた「新しい値」のテキストは保持されません。繰り返しになりますが、これは私には少し謎です。OnLoadでコントロールを再作成すると、すべてが正常でダンディになりますが、PreRenderでコントロールを再作成すると、値が保持されないのはなぜですか?

これを行う方法がなければならないような気がします。PreRenderでコントロールを再作成するときに、新しく作成したコントロールをViewStateにバインドする方法はありますか?

私はこれに何日も苦労してきました。あなたが私に与えることができるどんな助けでもありがたいです。

ありがとう。

4

9 に答える 9

19

コントロールが現在 ViewState を追跡している場合、ViewState でサポートされるプロパティは ViewState にのみ永続化されます。これは、ViewState をできるだけ小さく保つための設計によるものです。真に動的なデータのみを含める必要があります。これの結果は次のとおりです。

Init イベント中に設定された ViewState プロパティは、ViewState に戻されません (ページがまだViewState の追跡を開始していないため)。したがって、Init は、コントロールを追加し、(a) ポストバック間で変更されないプロパティ (ID、CssClass...) と動的プロパティの初期値 (残りのコードで変更できる) を設定するのに適した場所です。ページのライフサイクル - ロード、イベント ハンドラー、PreRender)。

Load または PreRender でコントロールを動的に追加すると、ViewState が追跡されます。開発者は、動的に追加されたコントロールに対して保持されるプロパティを次のように制御できます。

  • コントロールがページのコントロール ツリーに追加される前に設定されたプロパティは、ViewState に保持されません。通常、コントロール ツリーにコントロールを追加する前に、動的ではないプロパティ (ID など) を設定します。

  • コントロールがページのコントロール ツリーに追加された後に設定されたプロパティは、ViewState に永続化されます (ViewState の追跡は、Load イベントの前から PreRender イベントの後まで有効になります)。

あなたの場合、PreRender ハンドラーは、コントロールをページのコントロール ツリーに追加する前にプロパティを設定しています。必要な結果を得るには、コントロールをコントロール ツリーに追加した後、動的プロパティを設定します。

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);
    ValueLinkButton tempLink = new ValueLinkButton(); // [CASE 2]        
    tempLink.ID = "valueLinkButton"; // Not persisted to ViewState
    Controls.Clear();
    Controls.Add(tempLink);
    tempLink.Value = "new value";  // Persisted to ViewState
    tempLink.Text = "Click";       // Persisted to ViewState
}
于 2008-10-13T07:56:53.887 に答える
3

他の人が述べているように、Init メソッドを使用して作成していることを確認する必要があります。ASP.NET ページのライフ サイクルの詳細については、次の記事を参照してください: http://msdn.microsoft.com/en-us/library/ms178472.aspx

于 2008-10-13T02:58:43.863 に答える
1

OnLoadイベントですでにコントロールを再作成しています。

それはあなたの問題だ。OnLoadは遅すぎます。代わりにInitを使用してください。

于 2008-10-13T02:14:54.060 に答える
0

PageLoadのページに動的コントロールを追加すると、ViewStateがコントロールにバインドされ、「ViewStateはまだバインドする必要があります」フラグ(実際のフラグではなく、概念上)がクリアされると思います。次に、コントロールを再作成すると、既存のViewStateはバインドされなくなります。

私は昨年同様の問題に直面しましたが、私の場合のみ、ViewStateを再バインドしたくありませんでした。私の問題は、以前のコントロールを再作成していなかったことです。そのため、上記の疑似フラグの概念が当てはまると思います。

于 2008-10-13T02:28:07.263 に答える
0

を呼び出してみてくださいPage.RegisterRequiresControlState()RequiresControlState()すでに登録されているかどうかを確認するために使用することもできます。

于 2008-10-13T02:35:29.807 に答える
0

助けていただきありがとうございますが、試してみましたが、違いはありませんでした。その上、OnLoad は、コントロールに毎回同じ ID を与える限り、動的コントロールに対しても OnInit と同じように機能します。

于 2008-10-13T02:20:33.910 に答える
0

ViewState は Page とその子オブジェクトで機能します。[ケース 2] の新しいコントロールは、ページ (またはその子) に追加されていません。実際、上記のコードの場合、オブジェクトは OnPreRender メソッドが終了するとすぐにスコープ外になり、ガベージ コレクションが実行されます。

どうしてもコントロールを交換する必要がある場合は、Remove() メソッドを使用して親から古いコントロールを削除し、AddAt() を使用して適切な場所に新しいコントロールを追加する必要があります。

コントロールが親の唯一の子である場合、コードは次のようになります。

ValueLinkButton tempLink = new ValueLinkButton();
Control parent = FindControl("valueLinkButton").Parent;
parent.Remove(FindControl("valueLinkButton"));
parent.AddAt(0, tempLink);
于 2008-10-13T03:08:22.063 に答える
0

コントロールのライフ サイクルで呼び出される SaveViewState メソッドの前に追加されたコントロールは、それらの値を保持する必要があります。私はジョーの答えに同意します。この画像をチェック

http://emanish.googlepages.com/Asp.Net2.0Lifecycle.PNG

于 2008-10-13T19:55:25.387 に答える
0

昨日、loadviewstateevent が発生した直後にコントロール ツリーを読み込むことで、実際にアプリを通常どおりに動作させることができることがわかりました。loadviewstate イベントをオーバーライドし、mybase.loadviewstate を呼び出してから、その直後にコントロールを再生成する独自のコードを配置すると、それらのコントロールの値がページの読み込み時に利用可能になります。私のアプリの 1 つで、viewstate フィールドを使用して、これらのコントロールを再作成するために使用できる ID または配列情報を保持しています。

Protected Overrides Sub LoadViewState(ByVal savedState As Object)
    MyBase.LoadViewState(savedState)
    If IsPostBack Then
        CreateMyControls()
    End If
End Sub
于 2009-07-16T13:24:28.520 に答える