web-dev-qa-db-ja.com

ASP.NETでコントロールを見つけるより良い方法

複雑なasp.netフォームがあり、1つのフォームにMultiviewのような50〜60個のフィールドもあります。MultiViewにはGridViewがあり、GridViewにはいくつかのCheckBoxes

現在、FindControl()メソッドのチェーンを使用して、子IDを取得しています。

さて、私の質問は、ASP.NETでネストされたコントロールを見つける他の方法/ソリューションがあるということです。

46
santosh singh

特定の種類のコントロールを探している場合は、このような再帰ループを使用できます- http://weblogs.asp.net/eporter/archive/2007/02/24/asp-net-findcontrol -recursive-with-generics.aspx

これは、指定されたタイプのすべてのコントロールを返す私が作成した例です

/// <summary>
/// Finds all controls of type T stores them in FoundControls
/// </summary>
/// <typeparam name="T"></typeparam>
private class ControlFinder<T> where T : Control 
{
    private readonly List<T> _foundControls = new List<T>();
    public IEnumerable<T> FoundControls
    {
        get { return _foundControls; }
    }    

    public void FindChildControlsRecursive(Control control)
    {
        foreach (Control childControl in control.Controls)
        {
            if (childControl.GetType() == typeof(T))
            {
                _foundControls.Add((T)childControl);
            }
            else
            {
                FindChildControlsRecursive(childControl);
            }
        }
    }
}
72
jimmystormig

いつものように遅い。まだ誰かがこれに興味があるなら、多くの関連するSO questions および answers 。これを解決するための再帰的拡張メソッドの私のバージョン:

public static IEnumerable<T> FindControlsOfType<T>(this Control parent)
                                                        where T : Control
{
    foreach (Control child in parent.Controls)
    {
        if (child is T)
        {
            yield return (T)child;
        }
        else if (child.Controls.Count > 0)
        {
            foreach (T grandChild in child.FindControlsOfType<T>())
            {
                yield return grandChild;
            }
        }
    }
}
17
David Clarke

強調表示されているすべてのソリューションは、再帰を使用しています(パフォーマンスに負荷がかかります)。再帰なしのよりクリーンな方法を次に示します。

public T GetControlByType<T>(Control root, Func<T, bool> predicate = null) where T : Control 
{
    if (root == null) {
        throw new ArgumentNullException("root");
    }

    var stack = new Stack<Control>(new Control[] { root });

    while (stack.Count > 0) {
        var control = stack.Pop();
        T match = control as T;

        if (match != null && (predicate == null || predicate(match))) {
            return match;
        }

        foreach (Control childControl in control.Controls) {
           stack.Push(childControl);
        }
    }

    return default(T);
}
9
Ondrej Svejdar

FindControl は、ネストされたコントロール内を再帰的に検索しません。 NamigContainer がFindControlを呼び出しているコントロールであるコントロールのみを検索します。

デフォルトでは、ASP.Netがネストされたコントロールを再帰的に調べない理由があります。

  • 性能
  • エラーを回避する
  • 再利用性

再利用の理由から、GridViews、Formviews、UserControlsなどを他のUserControls内にカプセル化することを検討してください。ページにすべてのロジックを実装し、再帰ループでこれらのコントロールにアクセスした場合、それをリファクタリングすることは非常に困難です。イベントハンドラー(f.e. GridViewのRowDataBound)を介してロジックとアクセスメソッドを実装している場合は、はるかにシンプルでエラーが発生しにくくなります。

6
Tim Schmelter

コントロール辞書を作成することにしました。保守が難しく、再帰的なFindControl()よりも高速に実行される場合があります。

protected void Page_Load(object sender, EventArgs e)
{
  this.BuildControlDics();
}

private void BuildControlDics()
{
  _Divs = new Dictionary<MyEnum, HtmlContainerControl>();
  _Divs.Add(MyEnum.One, this.divOne);
  _Divs.Add(MyEnum.Two, this.divTwo);
  _Divs.Add(MyEnum.Three, this.divThree);

}

そして、私はOPの質問に答えていないことを否定する前に...

Q:さて、私の質問は、ASP.NETでネストされたコントロールを見つける他の方法/ソリューションはありますか? A:はい、そもそもそれらを検索する必要はありません。既に知っているものを検索する理由は何ですか? 参照 ofknownオブジェクトを許可するシステムを構築することをお勧めします。

1
B H

指定した述語に一致するすべてのコントロールを再帰的に検索します(ルートコントロールを含めないでください)。

    public static IEnumerable<Control> FindControlsRecursive(this Control control, Func<Control, bool> predicate)
    {
        var results = new List<Control>();

        foreach (Control child in control.Controls)
        {
            if (predicate(child))
            {
                results.Add(child);
            }
            results.AddRange(child.FindControlsRecursive(predicate));
        }

        return results;
    }

使用法:

myControl.FindControlsRecursive(c => c.ID == "findThisID");
1
DavidWainwright

コントロールのアクション管理

基本クラスに以下のクラスを作成します。クラスすべてのコントロールを取得するには:

public static class ControlExtensions
{
    public static IEnumerable<T> GetAllControlsOfType<T>(this Control parent) where T : Control
    {
        var result = new List<T>();
        foreach (Control control in parent.Controls)
        {
            if (control is T)
            {
                result.Add((T)control);
            }
            if (control.HasControls())
            {
                result.AddRange(control.GetAllControlsOfType<T>());
            }
        }
        return result;
    }
}

データベースから:DATASET(DTActions)で動的にすべてのアクションID(divAction1、divAction2 ....)を取得すると、特定のユーザーで許可されます。

Aspxの場合:HTMLの場合、divまたはspanにアクション(ボタン、アンカーなど)を入れ、次のようなIDを指定します。

<div id="divAction1" visible="false" runat="server" clientidmode="Static">   
                <a id="anchorAction" runat="server">Submit
                        </a>                      
                 </div>

IN CS:ページで次の機能を使用します。

private void ShowHideActions()
    {

        var controls = Page.GetAllControlsOfType<HtmlGenericControl>();

        foreach (DataRow dr in DTActions.Rows)
        {          

            foreach (Control cont in controls)
            {

                if (cont.ClientID == "divAction" + dr["ActionID"].ToString())
                {
                    cont.Visible = true;
                }

            }
        }
    }
1
atif

次の例では、Button1_Clickイベントハンドラーを定義しています。呼び出されると、このハンドラーはFindControlメソッドを使用して、包含ページでTextBox2のIDプロパティを持つコントロールを見つけます。コントロールが見つかった場合、その親はParentプロパティを使用して決定され、親コントロールのIDがページに書き込まれます。 TextBox2が見つからない場合、「Control Not Found」がページに書き込まれます。

private void Button1_Click(object sender, EventArgs MyEventArgs)
{
      // Find control on page.
      Control myControl1 = FindControl("TextBox2");
      if(myControl1!=null)
      {
         // Get control's parent.
         Control myControl2 = myControl1.Parent;
         Response.Write("Parent of the text box is : " + myControl2.ID);
      }
      else
      {
         Response.Write("Control not found");
      }
}
0
Sudhakar Rao