Первый поиск в C # Control Collection - PullRequest
0 голосов
/ 02 марта 2012

Я пытаюсь написать метод расширения для System.Web.UI.Control, который будет искать в ControlCollection экземпляр конкретного Type и возвращать первый найденный экземпляр. Первая глубина проста, однако сначала я хочу найти ширину, чтобы более высокие коллекции имели приоритет.

Мой текущий метод некорректен и рано завершает работу, возвращая ноль в некоторых случаях, когда весь поиск не был завершен. Я надеюсь, что я близок к правильному решению, но мне нужно взглянуть на него свежим взглядом. Есть предложения?

public static T FindFirstControlOfType<T>(this Control rootControl, bool searchRecursively) where T : Control
{
    // list for container controls
    List<Control> controlsWithChildren = new List<Control>();

    // iterate the current control collection first
    foreach (Control child in rootControl.Controls)
    {
        if (child.GetType().IsAssignableFrom(typeof(T)))
        {
            return (T)child;
        }

        // track those controls containing children
        if (child.HasControls())
        {
            controlsWithChildren.Add(child);
        }
    }

    // if recursion is enabled, search the child nodes
    if (searchRecursively)
    {
        foreach (Control control in controlsWithChildren)
        {
            return FindFirstControlOfType<T>(control, true);
        }
    }

    // if never found, return null
    return null;
}

РЕДАКТИРОВАТЬ - Рабочий раствор на основе отмеченного ответа, для всех, кто заинтересован:

public static T FindFirstControlOfType<T>(this Control rootControl, bool searchNestedControls) where T : Control
{
    Queue<Control> queue = new Queue<Control>();

    EnqueueChildControls(queue, rootControl);
    while (queue.Count > 0)
    {
        Control current = queue.Dequeue();

        if (current.GetType() == typeof(T))
        {
            return (T)current;
        }

        if (searchNestedControls)
        {
            EnqueueChildControls(queue, current);
        }
    }
    return null;

}

private static void EnqueueChildControls(Queue<Control> queue, Control control)
{
    foreach (Control current in control.Controls)
    {
        queue.Enqueue(current);
    }
}

Ответы [ 2 ]

5 голосов
/ 02 марта 2012

Первый поиск по ширине (псевдокод)

Queue fringe 

fringe.Enqueue(rootControl)

while(fringe.Count > 0)
{
    current = fringe.Dequeue()
    Visit(current)
    fringe.EnqueueAll(current.Children)
}

Нет необходимости в рекурсии для поиска в ширину.

Visit - это все, что вы хотите сделать с текущим объектом. Если вы ищете что-то, то Visit будет означать: if(current matches criteria) return current

Обновление: Рабочий пример: https://gist.github.com/1960108

0 голосов
/ 02 марта 2012

Ну, главная проблема здесь:

foreach (Control control in controlsWithChildren)
{
    return FindFirstControlOfType<T>(control, true);
}

Вы возвращаете результаты рекурсивного поиска самого первого ребенка с детьми, независимо от того, был ли этот поиск успешным. Поиск в ширину является широко обсуждаемой темой, но сводится к использованию очереди:

Queue<Control> controlsWithChildren = new Queue<Control>();

и (обычно) цикл, а не рекурсия.

...