Лучший способ найти контроль в ASP.NET - PullRequest
46 голосов
/ 10 февраля 2011

У меня есть сложная форма asp.net, в которой есть от 50 до 60 полей в одной форме, например, Multiview, внутри MultiView у меня GridView, а внутри GridView у меня несколько CheckBoxes.

В настоящее время я использую цепочку метода FindControl() и извлекаю идентификатор ребенка.

Теперь мой вопрос заключается в том, существует ли какой-либо другой способ / решение для поиска вложенного элемента управления в ASP.NET.

Ответы [ 8 ]

72 голосов
/ 10 февраля 2011

Если вы ищете определенный тип управления, вы можете использовать рекурсивный цикл, подобный этому - 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);
            }
        }
    }
}
17 голосов
/ 08 декабря 2011

Поздно, как обычно.Если кто-то еще заинтересован в этом, есть ряд связанных с этим вопросов SO и Моя версия метода рекурсивного расширения для решения этой проблемы:

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;
            }
        }
    }
}
8 голосов
/ 04 сентября 2015

Все выделенные решения используют рекурсию (что требует больших затрат). Вот более чистый путь без рекурсии:

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);
}
6 голосов
/ 10 февраля 2011

FindControl не выполняет рекурсивный поиск во вложенных элементах управления. Он находит только те элементы управления, которые NamigContainer является элементом управления, для которого вы вызываете FindControl.

Существует причина, по которой ASP.Net по умолчанию не просматривает ваши вложенные элементы управления:

  • Performance
  • Как избежать ошибок
  • Повторное использование

Предположим, что вы хотите инкапсулировать ваши GridViews, Formviews, UserControls и т. Д. Внутри других UserControls по причинам повторного использования. Если бы вы реализовали всю логику на своей странице и получили доступ к этим элементам управления с помощью рекурсивных циклов, это будет очень трудно изменить. Если вы реализовали свою логику и методы доступа через обработчики событий (например, RowDataBound из GridView), это будет намного проще и менее подвержено ошибкам.

1 голос
/ 13 ноября 2015

Я решил просто построить словари управления.Сложнее в обслуживании, может работать быстрее, чем рекурсивный 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);

}

И прежде чем я опущу руки, чтобы не ответить на вопрос ОП ...

В: Теперь мойВопрос заключается в том, есть ли другой способ / решение, чтобы найти вложенный элемент управления в ASP.NET?A: Да, избегайте необходимости искать их в первую очередь.Зачем искать вещи, которые вы уже знаете, есть?Лучше построить систему, допускающую ссылку из известных объектов.

1 голос
/ 20 августа 2015

Рекурсивно найти все элементы управления, соответствующие указанному предикату (не включая корневой элемент управления):

    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 голос
/ 07 апреля 2015

Управление действиями в элементах управления

Создать класс ниже в базовом классе.Класс Чтобы получить все элементы управления:

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;
    }
}

Из базы данных: Получить все идентификаторы действий (например, divAction1, divAction2 ....) динамически в DATASET (DTActions) разрешают для конкретного пользователя.

ВAspx: в HTML Поместите действие (кнопка, привязка и т. Д.) В div или span и присвойте им идентификатор, например

<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;
                }

            }
        }
    }
0 голосов
/ 21 февраля 2017

В следующем примере определяется обработчик события Button1_Click.При вызове этот обработчик использует метод FindControl, чтобы найти элемент управления со свойством ID TextBox2 на содержащей странице.Если элемент управления найден, его родительский элемент определяется с помощью свойства Parent, а идентификатор родительского элемента управления записывается на страницу.Если 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");
      }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...