Сведения о вопросе

Faridun

13:14, 23rd August, 2020

Теги

c#   asp.net    

Поиск элементов управления, использующих определенный интерфейс в ASP.NET

Просмотров: 377   Ответов: 7

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

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

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

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

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

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

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

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



  Сведения об ответе

DINO

19:35, 19th August, 2020

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

ctrl is IInterfaceToFind

вместо

ctrl.GetType() == aTypeVariable  

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

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

if(ctrl is typeToFind)  

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

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

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


  Сведения об ответе

fo_I_K

15:11, 17th August, 2020

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

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


  Сведения об ответе

crush

04:58, 3rd August, 2020

Я бы внес следующие изменения в пример 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 );

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


  Сведения об ответе

DO__IT

08:56, 28th August, 2020

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

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

Вы также можете протестировать с помощью оператора is, В зависимости от ваших потребностей.

if (c is IMyButtonInterface) {
    ...
}


  Сведения об ответе

lourence

03:06, 3rd August, 2020

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

if (myControl is ISomeInterface)
{
  // do something
}


  Сведения об ответе

9090

04:30, 21st August, 2020

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

Dim c as IInterface = TryCast(obj, IInterface)
If c IsNot Nothing
    'do work
End if


  Сведения об ответе

piter

05:06, 29th August, 2020

вы всегда можете просто использовать as cast:

c as IMyButtonInterface;

if (c != null)
{
   // c is an IMyButtonInterface
}


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться