For starters, I would use Collection<Control>
instead of List<T>
. A list will often work, but it does expose your collection in ways you may not want.
To get the existing controls, you need to dig into context.Container.Components
in the LoadValues
override. It will have everything including the host form itself and components, so you will likely have to filter them. One thing for certain is to remove components (like DataGridViewColumns
and TabPages
) as they wont go into a List or Collection of controls; other things like TableLayoutPanels you will often want to remove also.
This version filters out some components and controls for the default dropdown:
protected override void LoadValues(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
bool bAdd = true;
Control thisCtl = null;
Collection<Control> tCollection = (Collection<Control>)value;
foreach (object obj in context.Container.Components) {
//Cycle through the components owned by the form in the designer
bAdd = true;
// exclude other components - this weeds out DataGridViewColumns which
// can only be used by a DataGridView
if (obj is Control) {
thisCtl = (Control)obj;
if (ExcludeForm) {
bAdd = !(thisCtl is Form);
}
// custom exclude list
if ((typeExclude != null) && (typeExclude.Count > 0)) {
if (typeExclude.Contains(thisCtl.GetType)) {
bAdd = false;
}
}
bool bCheck = false;
int ndx = 0;
if (bAdd) {
bCheck = tCollection.Contains(thisCtl);
ndx = myCtl.Items.Add(new ListItem(thisCtl));
myCtl.SetItemChecked(ndx, bCheck);
}
}
}
}

If you prefer, you can display the eligible controls Dialog style and use a CheckedListBox for the user to pick controls. There is an article on CodeProject Selecting Form's Controls at Design Time which goes into more detail.
It is in VB, but allows you to easily implement such a beast pretty easily (I wrote it, so I may be biased):
ExampleDropDownControlCollectionUIEditor : ControlCollectionDropDownUIEditor
{
public ExampleDropDownControlCollectionUIEditor() : base()
{
base.ExcludeForm = true;
base.CheckControlWidth = 200;
base.typeExclude.Add(typeof(RadioButton));
base.typeExclude.Add(typeof(Label));
}
}
The dialog form is as simple, just using a different base class, ControlCollectionDialogUIEditor