Поиск элементов управления, которые используют определенный интерфейс в ASP.NET - PullRequest
6 голосов
/ 26 августа 2008

Я провожу время с этим, хотя я чувствую, что упускаю что-то очевидное. У меня есть элемент управления, который наследуется от System.Web.UI.WebControls.Button, а затем реализует интерфейс, который я настроил. Вот и думай ...

public class Button : System.Web.UI.WebControls.Button, IMyButtonInterface { ... }

В коде страницы я хотел бы найти все экземпляры этой кнопки в ASPX. Поскольку я действительно не знаю, каким будет тип , просто интерфейс , который он реализует, это все, что мне нужно, когда я перебираю дерево управления. Дело в том, что мне никогда не приходилось определять, использует ли объект интерфейс, а не просто тестировать его тип. Как я могу перебрать дерево управления и вытащить все, что реализует IMyButtonInterface чистым способом (с Linq все будет в порядке)?

Опять же, знайте, что это что-то очевидное, но сейчас я начал активно использовать интерфейсы, и я не могу сосредоточиться на результатах Google, чтобы понять это:)

Редактировать: GetType() возвращает реальный класс, но не возвращает интерфейс, поэтому я не могу проверить это (например, он вернул бы "MyNamespace.Button" вместо " IMyButtonInterface "). При попытке использовать «as» или «is» в рекурсивной функции, параметр type даже не распознается внутри функции! Это довольно странно. Так

if(ctrl.GetType() == typeToFind) //ok

if(ctrl is typeToFind) //typeToFind isn't recognized! eh?

Определенно почесал голову над этим.

Ответы [ 7 ]

7 голосов
/ 26 августа 2008

Longhorn213 почти имеет правильный ответ, но, как говорят Шон Чемберс и bdukes, вы должны использовать

ctrl is IInterfaceToFind

вместо

ctrl.GetType() == aTypeVariable  

Причина в том, что если вы используете .GetType(), вы получите истинный тип объекта, не обязательно тот, к которому он также может быть приведен в своей цепочке реализации наследования / интерфейса. Кроме того, .GetType() никогда не вернет абстрактный тип / интерфейс, поскольку вы не можете создать новый абстрактный тип или интерфейс. GetType() возвращает только конкретные типы.

Причина, по которой это не работает

if(ctrl is typeToFind)  

Это потому, что тип переменной typeToFind на самом деле System.RuntimeType, а не тип, для которого вы установили ее значение. Например, если вы установите значение строки в «foo», его тип будет по-прежнему строкой, а не «foo». Я надеюсь, что в этом есть смысл. При работе с типами очень легко запутаться. Я хронически растерялся, работая с ними.

Самое важное, что следует отметить в ответе longhorn213, это то, что вы должны использовать рекурсию , иначе вы можете пропустить некоторые элементы управления на странице.

Хотя у нас здесь есть рабочее решение, я бы тоже хотел посмотреть, есть ли более лаконичный способ сделать это с помощью LINQ.

5 голосов
/ 26 августа 2008

Вы можете просто искать в интерфейсе. При этом также используется рекурсия, если элемент управления имеет дочерние элементы управления, т. Е. Кнопка находится на панели.

private List<Control> FindControlsByType(ControlCollection controls, Type typeToFind)
{
    List<Control> foundList = new List<Control>();

    foreach (Control ctrl in this.Page.Controls)
    {
        if (ctrl.GetType() == typeToFind)
        {
            // Do whatever with interface
            foundList.Add(ctrl);
        }

        // Check if the Control has Child Controls and use Recursion
        // to keep checking them
        if (ctrl.HasControls())
        {
            // Call Function to 
            List<Control> childList = FindControlsByType(ctrl.Controls, typeToFind);

            foundList.AddRange(childList);
        }
    }

    return foundList;
}

// Pass it this way
FindControlsByType(Page.Controls, typeof(IYourInterface));
3 голосов
/ 26 августа 2008

Я бы внес следующие изменения в пример Longhorn213, чтобы немного это исправить:

private List<T> FindControlsByType<T>(ControlCollection controls )
{
    List<T> foundList = new List<T>();

    foreach (Control ctrl in this.Page.Controls)
    {
        if (ctrl as T != null )
        {
            // Do whatever with interface
            foundList.Add(ctrl as T);
        }

        // Check if the Control has Child Controls and use Recursion
        // to keep checking them
        if (ctrl.HasControls())
        {
            // Call Function to 
            List<T> childList = FindControlsByType<T>( ctrl.Controls );

            foundList.AddRange( childList );
        }
    }

    return foundList;
}

// Pass it this way
FindControlsByType<IYourInterface>( Page.Controls );

Таким образом, вы получаете список объектов нужного типа, которые не требуют использования другого приведения. Я также внес необходимые изменения в оператор «как», на который указали другие.

1 голос
/ 26 августа 2008

Будет ли работать оператор "is"?

if (myControl is ISomeInterface)
{
  // do something
}
1 голос
/ 26 августа 2008

Интерфейсы достаточно близки к типам, что должно восприниматься примерно одинаково. Я бы использовал в качестве оператора .

foreach (Control c in this.Page.Controls) {
    IMyButtonInterface myButton = c as IMyButtonInterface;
    if (myButton != null) {
        // do something
    }
}

Вы также можете проверить, используя оператор , в зависимости от ваших потребностей.

if (c is IMyButtonInterface) {
    ...
}
0 голосов
/ 26 августа 2008

Вы всегда можете использовать только как приведение:

c as IMyButtonInterface;

if (c != null)
{
   // c is an IMyButtonInterface
}
0 голосов
/ 26 августа 2008

Если вы собираетесь поработать над ним, если он относится к этому типу, тогда я бы использовал TryCast.

Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
    'do work
End if
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...