1

カスタムGridViewに動的に追加されるTemplateFieldがあります。

void ITemplate.InstantiateIn(System.Web.UI.Control container)
    {
        switch (_templateType)
        {
            case ListItemType.Header:
                if (this.ParentGridView.ShowDeleteHeaderImage)
                {
                    Image hImg = new Image();
                    hImg.ImageUrl = this.ParentGridView.DeleteHeaderImageUrl;
                    hImg.AlternateText = "Mark for Deletion";
                    container.Controls.Add(hImg);
                }
                else
                {
                    Label l = new Label();
                    l.Text = "Del";
                    container.Controls.Add(l);
                }
                break;
            case ListItemType.Item:
                container.Controls.Add(new CheckBox());
                break;
            case ListItemType.EditItem:
                break;
            case ListItemType.Footer:
                QLImageButton deleteButton = new QLImageButton();
                deleteButton.Settings.ImageId = "cmdQLGVDelete";
                deleteButton.Settings.ImageUrl = this.ParentGridView.DeleteImageUrl;
                deleteButton.CommandName = "Delete";
                container.Controls.Add(deleteButton);
                break;
        }
    }

グリッドコマンド(挿入/更新/削除)に応答して、GetRowControlsと呼ばれるメソッドが呼び出されます。このメソッドは、特定のグリッド行の列を反復処理し、その各コントロールをディクショナリに追加します。

Dictionary<string, WebControl> GetRowControls(GridViewRow row)
...

rowControls.Add(ctrl.ID, (WebControl)ctrl);

...

したがって、これは、宣言的に追加されたテンプレートフィールドとバインドされたコントロールの両方、およびプログラムで追加された動的非テンプレートフィールドの両方で正常に機能します。

ただし、コントロールが動的に追加されたTemplateFieldコントロールの場合、ctrl.IDは常にnullであるため、上記のステートメントは例外をスローします。

リフレクターでこれを調べたのは、VS 2005のイミディエイトウィンドウで変数を調べたときに、?ctrl、ctrl.IDが値を一覧表示することがわかったためです。それ以来、これは、イミディエイトウィンドウに?ctrlを一覧表示するときに、プロパティClientIDが呼び出され、ClientIDがEnsureId()を呼び出して、IDを設定するためであることがわかりました。

public virtual string ClientID
{
    get
    {
        this.EnsureID();
        string uniqueID = this.UniqueID;
        if ((uniqueID != null) && (uniqueID.IndexOf(this.IdSeparator) >= 0))
        {
            return uniqueID.Replace(this.IdSeparator, '_');
        }
        return uniqueID;
    }
}

したがって、ClientID、UniqueId、およびIDはすべてnullであると想定しています。ただし、上記のように、最初の2つを読み取るだけで、すべてが設定されます。また、NamingContainerはnullではないことに注意してください。設定されています。

したがって、これを回避する方法は非常に簡単です。つまり、ctrl.ID == nullを確認し、その場合はctrl.ClientIDを読み取ります。そして、それは私がやったことです。なぜなら、時間的には本当にうごめく必要があるからです。しかし、誰かが頭のてっぺんからそれを知っているなら、私はまだ答えに興味があります。

動的に追加されたTemplateFieldの子コントロールのID値が、他のコントロールのID値とは異なる時間に設定されるのはなぜですか?

4

2 に答える 2

2

動作が異なるわけではありませんが、ほとんどの場合、宣言的にコントロールを追加すると、すぐにIDを設定します。IDのないラベルをページに追加し、コントロールコレクションを参照して、そのIDを確認してみてください。nullになります(IDが入力されるため、clientIDを表示しないようにしてください)。

<asp:Label runat="server">something</asp:Label>

また、そのように実行すると、IDのないスパンが取得されることに注意してください。

于 2009-04-01T17:42:34.617 に答える
2

フレディは正しいです。

InstantiateIn メソッド内で ID を設定する責任があります。また、特に指定されていない場合、ClientID がそれらを自動生成することは理にかなっています。

宣言型コントロールは、ページのコンパイル中にページ ビルダーによって割り当てられた ID を取得します。"Temporary ASP.NET Files folder" に生成された一時 .cs ファイルの 1 つを見ると、次のようなファイルが見つかります (プラグマは削除されています)。

//creating a template field, where CopiledBindableTemplateBuilder is the ITemplate
//and its InstantiateIn = @__BuildControl__control9
@__ctrl.ItemTemplate = new System.Web.UI.CompiledBindableTemplateBuilder(
    new System.Web.UI.BuildTemplateMethod(this.@__BuildControl__control9),
    new System.Web.UI.ExtractTemplateValuesMethod(this.@__ExtractValues__control9));

//and @__BuildControl__control9 calling @__BuildControlButton1
private global::System.Web.UI.WebControls.Button @__BuildControlButton1()
{
    global::System.Web.UI.WebControls.Button @__ctrl;

    @__ctrl = new global::System.Web.UI.WebControls.Button();
    this.Button1 = @__ctrl;
    @__ctrl.ApplyStyleSheetSkin(this);
    @__ctrl.ID = "Button1"; //<-- here it gets an ID
    @__ctrl.Text = "Button";
    return @__ctrl;
}
于 2009-04-01T20:17:57.660 に答える