在 ASP.NET 中查找使用特定接口的控件

Posted

技术标签:

【中文标题】在 ASP.NET 中查找使用特定接口的控件【英文标题】:Finding controls that use a certain interface in ASP.NET 【发布时间】:2010-09-06 22:01:22 【问题描述】:

与这个玩得很开心,虽然我觉得我错过了一些明显的东西。我有一个继承自System.Web.UI.WebControls.Button 的控件,然后实现我设置的接口。所以想想……

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

在页面的代码隐藏中,我想从 ASPX 中找到此按钮的所有实例。因为我真的不知道 type 将是什么,只知道它实现的 interface,这就是我在循环控制树时所要做的一切。问题是,我从来不需要确定一个对象是否使用接口而不是只测试它的类型。 如何遍历控制树并以干净的方式拉出任何实现IMyButtonInterface 的内容(Linq 可以)?

再一次,知道这很明显,但刚刚开始大量使用接口,我似乎无法集中我的谷歌结果来弄清楚:)

编辑: GetType() 返回实际的类,但不返回接口,所以我无法对此进行测试(例如,它会返回“MyNamespace.Button”而不是“IMyButtonInterface”)。在尝试在递归函数中使用“as”或“is”时,type 参数甚至无法在函数中得到识别!这很奇怪。所以

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

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

这件事肯定让我摸不着头脑。

【问题讨论】:

【参考方案1】:

Longhorn213 几乎有正确答案,但正如 Sean Chambers 和 bdukes 所说,您应该使用

ctrl is IInterfaceToFind

而不是

ctrl.GetType() == aTypeVariable  

原因是,如果你使用.GetType(),你会得到一个对象的真实类型,不一定是它在继承/接口实现链中也可以转换成的类型。此外,.GetType() 永远不会返回抽象类型/接口,因为您无法新建抽象类型或接口。 GetType() 仅返回具体类型。

这不起作用的原因

if(ctrl is typeToFind)  

是因为变量typeToFind 的类型实际上是System.RuntimeType,而不是您为其设置值的类型。例如,如果您将字符串的值设置为“foo”,则其类型仍然是字符串而不是“foo”。我希望这是有道理的。使用类型时很容易混淆。与他们合作时,我一直很困惑。

关于 longhorn213 的回答,最重要的一点是 您必须使用递归,否则您可能会错过页面上的某些控件。

虽然我们在这里有一个可行的解决方案,但我也很想看看是否有更简洁的方法来使用 LINQ 来做到这一点。

【讨论】:

只有一个类型时,您可以在这种特殊情况下使用 IsAssignableFrom。【参考方案2】:

您可以在界面上搜索。如果控件具有子控件(即按钮位于面板中),这也会使用递归。

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】:

我将对 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”运算符进行了必要的更改。

【讨论】:

【参考方案4】:

接口足够接近类型,感觉应该差不多。我会使用as operator。

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

您也可以根据需要使用is operator 进行测试。

if (c is IMyButtonInterface) 
    ...

【讨论】:

【参考方案5】:

“is”运算符会起作用吗?

if (myControl is ISomeInterface)

  // do something

【讨论】:

【参考方案6】:

如果你要对它做一些工作,如果它属于那种类型,那么我会使用 TryCast。

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

【讨论】:

【参考方案7】:

你总是可以只使用 as cast:

c as IMyButtonInterface;

if (c != null)

   // c is an IMyButtonInterface

【讨论】:

以上是关于在 ASP.NET 中查找使用特定接口的控件的主要内容,如果未能解决你的问题,请参考以下文章

使用 jQuery 启用/禁用特定“验证组”中的 asp.net 验证控件?

如何为按钮文本asp.net的特定单词添加下划线

用户控件和 asp.net mvc

ASP.NET 获取不同frame中的控件

asp.net 如何访问gridview控件中每一行的label控件

Java/struts/jsp 中是不是有类似 ASP.NET 网络用户控件的东西