如何从控件中获取组件列表?

时间:2009-08-04 17:03:07

标签: .net winforms

我有一个派生自ErrorProvider的组件。我有一个BaseFormBaseUserControl,每个都在设计器中添加了这个自定义ErrorProvider。我在BaseUserControls和其他BaseForm上有许多嵌套BaseUserControls,我需要从顶级窗体或用户中找到嵌套控件上的所有自定义ErrorProviders控制以访问特殊功能。

如何浏览所有嵌套控件并查找所有ErrorProvider组件?例如:

List<ErrorProviderEx> customProviders = GetErrorProviders(myUserControl);

我最接近的是一个递归方法,循环遍历myUserControl.Controls并检查每个控件的Control.Container.Components集合,但这会导致一些疯狂的逻辑,不得不在递归调用中向后看控制的Container。我也试图避免使用反射。

2 个答案:

答案 0 :(得分:2)

FormUserControl的组件未在任何集合中公开。你必须自己做。

首先,声明一个UserControl将实现的接口:

public interface IComponentList
{
  List<Component> Components
  {
    get;
  }
}

接下来,在UserControl中,将组件添加到构造函数中的列表中,并通过接口属性Components公开此列表:

public partial class UserControl1 : UserControl, IComponentList
{
  private List<Component> _components = new List<Component>();

  public UserControl1()
  {
    InitializeComponent();

    _components.Add(errorProvider1);
  }

  List<Component> IComponentList.Components
  {
    get
    {
      return _components;
    }
  }
}

现在,以下函数应该为您提供实现ErrorProvider接口的所有UserControlIComponentList的列表:

public List<ErrorProvider> GetErrorProviders(Control myControl)
{
  List<ErrorProvider> foundErrorProviders = new List<ErrorProvider>();
  GetErrorProviders(myControl, foundErrorProviders);
  return foundErrorProviders;
}

protected void GetErrorProviders(Control myControl, List<ErrorProvider> foundErrorProviders)
{
  if (foundErrorProviders == null)
  {
    throw new ArgumentNullException("foundErrorProviders");
  }
  if (myControl is IComponentList)
  {
    foreach (Component component in ((IComponentList) myControl).Components)
    {
      if (component is ErrorProvider)
      {
        foundErrorProviders.Add((ErrorProvider) component);
      }
    }
  }
  foreach (Control control in myControl.Controls)
  {
    GetErrorProviders(control, foundErrorProviders);
  }
}

调用这样的方法:

GetErrorProviders(myUserControl);

注意: Windows窗体设计器将所有组件放在components文件中名为.designer.cs的变量中。您可以选择将components集合中的所有组件添加到_components列表中,但我会阅读以下here

  

[...]我意识到了   实际使用components成员   仅当一个组件有一个   具体的构造函数放在一个   形成。 [...]如果   该组件公开了一个构造函数   具有特定签名Public Sub   新的(ByVal c As IContainer),然后   components表单成员已实例化   并传递给组件   构造

...这就是为什么我在使用components集合时犹豫不决,因为它不一定包含你的所有组件。但ErrorProvider一起使用。

您可能也想查看this forum post

答案 1 :(得分:0)

我有类似的要求,因为我需要在自定义基本用户控件类派生的UserControls中查找和引用ErrorProvider实例。我在基类中使用了反射来做到这一点。代码如下所示(在VB.NET中)。

    Protected ErrorProvidersList As List(Of ErrorProvider) = New List(Of ErrorProvider)()

    Protected Overrides Sub OnLoad(e As EventArgs)
    MyBase.OnLoad(e)
    '' Get a collection of error providers that will allow us to check for errors
    For Each fi As FieldInfo In Me.[GetType]().GetFields(BindingFlags.NonPublic Or BindingFlags.Instance)
        Dim obj As Object = fi.GetValue(Me)
        If TypeOf obj Is ErrorProvider Then
            ErrorProvidersList.Add(obj)
        End If
    Next
End Sub