Лучший способ найти элемент управления в ASP.NET
У меня есть сложная форма asp.net, имеющая хотя бы 50-60 полей в одной форме, например Multiview
, внутри MultiView у меня есть GridView
, а внутри GridView у меня есть несколько CheckBoxes
.
В настоящее время я использую цепочку метода FindControl()
и получаю дочерний идентификатор.
Теперь, мой вопрос: есть ли другой способ/решение найти вложенный элемент управления в ASP.NET.
Ответы
Ответ 1
Если вы ищете определенный тип управления, вы можете использовать рекурсивный цикл, подобный этому,
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);
}
}
}
}
Ответ 2
это может помочь.
public static class ControlExtensions
{
/// <summary>
/// recursively finds a child control of the specified parent.
/// </summary>
/// <param name="control"></param>
/// <param name="id"></param>
/// <returns></returns>
public static Control FindControlRecursive(this Control control, string id)
{
if (control == null) return null;
//try to find the control at the current level
Control ctrl = control.FindControl(id);
if (ctrl == null)
{
//search the children
foreach (Control child in control.Controls)
{
ctrl = FindControlRecursive(child, id);
if (ctrl != null) break;
}
}
return ctrl;
}
}
public void Page_Load(object sender, EventArgs e)
{
//call the recursive FindControl method
Control ctrl = this.FindControlRecursive("my_control_id");
}
Ответ 3
Поздно, как обычно. Если кто-то еще заинтересован в этом, существует ряд связанных 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;
}
}
}
}
Ответ 4
Все выделенные решения используют рекурсию (которая является дорогостоящей). Вот более чистый путь без рекурсии:
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);
}
Ответ 5
FindControl не выполняет поиск внутри вложенных элементов управления рекурсивно. Он находит только элементы управления, которые NamigContainer - это элемент управления, который вы вызываете FindControl.
Это причина, по которой ASP.Net не рекурсивно просматривает ваши вложенные элементы управления:
- Производительность
- Предотвращение ошибок
- Повторное использование
Считайте, что вы хотите инкапсулировать свои GridViews, Formviews, UserControls и т.д. внутри других UserControl для повторного использования. Если бы вы выполнили всю логику на своей странице и получили доступ к этим элементам управления с помощью рекурсивных циклов, это будет очень сложно реорганизовать. Если вы внедрили свою логику и методы доступа с помощью обработчиков событий (f.e. RowDataBound of GridView), это будет намного проще и менее подвержено ошибкам.
Ответ 6
Управление действиями при управлении
Создайте ниже класс в базовом классе.
Класс Чтобы получить все элементы управления:
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;
}
}
}
}
Ответ 7
Рекурсивно найти все элементы управления, соответствующие указанному предикату (не включая root Control):
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");
Ответ 8
Я решил просто создать словари управления. Сложнее поддерживать, может работать быстрее, чем рекурсивный 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: Да, не нужно искать их в первую очередь. Зачем искать вещи, которые вы уже знаете? Лучше создать систему, позволяющую ссылку известных объектов.
Ответ 9
В этой статье описывается, как найти управление рекурсивно по типу, но его реализация содержит один изъян, который приводит к потере "основанного" элемента управления
Ниже представлена фиксированная версия:
/// <summary>
/// Find control (recursively) by type
/// (http://weblogs.asp.net/eporter/archive/2007/02/24/asp-net-findcontrol-recursive-with-generics.aspx)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="controls"></param>
/// <returns></returns>
public static T FindControl<T>(System.Web.UI.ControlCollection controls) where T : class
{
T found = default(T);
if (controls != null && controls.Count > 0)
{
for (int i = 0; i < controls.Count; i++)
{
if (found != null) break;
if (controls[i] is T)
{
found = controls[i] as T;
break;
}
found = FindControl<T>(controls[i].Controls);
}
}
return found;
}
Ответ 10
В следующем примере определяется обработчик события 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 parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}