web-dev-qa-db-ja.com

ASP.Net FindControlが機能していません-どうしてですか?

.NET 2.0/3.0より前は、FindControlを以前に使用しました。なんらかの理由で、私のコントロールのIDに割り当てられたファンキーな名前が付けられたようです。たとえば、ID「cbSelect」をチェックボックスに割り当てましたが、FindControlはそれを見つけません。 HTMLを表示すると、割り当てられたctl00_bodyPlaceHolder_ctl02_cbSelect

それについて言及しているFindControlの例は1つも見つかりませんでした。実際、誰もが通常のように検索コントロールを使用しているようです。

それで、私は何か間違ったことをしていますか? .Netは変更されましたか?誰かが私にこれに光を当てることができますか?それは本当にイライラします!

29
LilMoke

おそらくMasterPageまたはユーザーコントロール(ascx)を使用しているため、クライアントIDが変更されるのはこのためです。マスターページに、ページ内のコントロールと同じIDを持つコントロールがあるとします。これにより、衝突が発生します。 IDの変更により、すべてのClientIDプロパティがページ上で一意になるようになります。

FindControlは、MasterPagesを操作するときに特別な注意が必要です。 ASP.NET 2.0 MasterPagesおよびFindControl() をご覧ください。 FindControlは 名前付けコンテナー 内で機能します。 MastePageとページは異なる名前付けコンテナーです。

29
Aleris

エクステンダーを記述して、再帰を使用してページ上の任意のコントロールを見つけることができます。これは、Util/Helperクラスにある可能性があります。

 public static Control FindAnyControl(this Page page, string controlId)
    {
        return FindControlRecursive(controlId, page.Form);
    }

    public static Control FindAnyControl(this UserControl control, string controlId)
    {
        return FindControlRecursive(controlId, control);
    }

    public static Control FindControlRecursive(string controlId, Control parent)
    {
        foreach (Control control in parent.Controls)
        {
            Control result = FindControlRecursive(controlId, control);
            if (result != null)
            {
                return result;
            }
        }
        return parent.FindControl(controlId);
    }
10
nemke

私は単純な拡張メソッドで「ほとんどの」ケースでこの問題を回避するためにかなりの幸運を持っています

コントロール階層全体をスキャンする場合は、ページ自体を含め、考えられる上位レベルのコンテナーコントロールで呼び出すことができます。

private static Control FindControlIterative(this Control control, string id)
{
    Control ctl = control;

    LinkedList<Control> controls = new LinkedList<Control>();

    while(ctl != null)
    {
        if(ctl.ID == id)
        {
            return ctl;
        }

        foreach(Control child in ctl.Controls)
        {
            if(child.ID == id)
            {
                return child;
            }

            if(child.HasControls())
            {
                controls.AddLast(child);
            }
        }

        ctl = controls.First.Value;
        controls.Remove(ctl);
    }

    return null;
}
8
Stephen M. Redd

コントロールコレクションでコントロールを検索するときは、ソースポストレンダリングに表示されるIDではなく、常にコントロールに割り当てたIDを使用してください。 FindControl()が存在することがわかっているコントロールを見つけられない場合は、コントロール階層の右側のブランチを検索していない可能性があります。再帰関数は私にとって成功しています。

VB.NET 3.5で使用する例を次に示します。

Function FindControlRecursive(ByVal ctrl As Control, ByVal id As String) As Control
    Dim c As Control = Nothing

    If ctrl.ID = id Then
        c = ctrl
    Else
        For Each childCtrl In ctrl.Controls
            Dim resCtrl As Control = FindControlRecursive(childCtrl, id)
            If resCtrl IsNot Nothing Then c = resCtrl
        Next
    End If

    Return c
End Function

これは、ベースページクラスでこの関数を局所的に実装する方法の例です。

Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm)
7
George

これは私のために働いたVB.NETコードです:

<Extension()> _
Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
    If controlToStartWith Is Nothing Then Return Nothing
    If controlToStartWith.ID = controlIdToFind Then Return controlToStartWith
    For Each childControl As Control In controlToStartWith.Controls
        Dim resCtrl As Control = FindChildControlById(childControl, controlIdToFind)
        If resCtrl IsNot Nothing Then Return resCtrl
    Next childControl
    Return Nothing
End Function ' Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control

クレジットはジョージの最初のVB.NETコードに使用されます。私はそれをほんの少し変更しましたが、2つの機能的な変更があります。入力コントロールとしてnull/Nothingが渡された場合、またはエラーが発生した場合、エラーは発生せず、拡張機能として実装されています。私の他の3つのマイナーな変更は機能に影響しませんが、私にとっては、コードの簡素化でした。しかし、私はそれが非常に主観的であることを知っています。

したがって、このメソッドは以下で使用できます。

Dim c1 As Control = Page.FindChildControlById("aspControlID")

そして、次のように、それをコントロールの特定の子クラスに変換したい場合:

Dim c1 As Control = Page.FindChildControlById("aspControlID")
Dim c As HyperLink = TryCast(c1, HyperLink)

更新:関数の名前は「FindChildControlById」になりました(以前は「FindMiControl」でした)。 SpeedNetの提案の方が気に入りました。

3
Shawn Kovac

Htmlをレンダリングするとき、ASP.NETはすべてのコントロールIDの前に、ドキュメントルートまでさかのぼる階層内の名前付けコンテナー(ユーザーコントロールなど)のIDを付けます。これにより、すべてのIDがポストバックなどで一意になります。

これは、元のマークアップでIDを使用する必要があるFindControlの使用には影響しません。

1
Nick

ここに、Webフォームコントロールの命名方法に関するリファレンスがあります...

WebフォームコントロールID

0
George