You can use following trick to do that. I found out that RefreshItems()
and the constructor are key places to achieve that.
using System;
using System.Reflection;
namespace WindowsFormsApplication2
{
interface ICustomInterface
{
}
public class ArrayList : System.Collections.ArrayList
{
public override int Add(object value)
{
if (!(value is ICustomInterface))
{
throw new ArgumentException("Only 'ICustomInterface' can be added.", "value");
}
return base.Add(value);
}
}
public sealed class MyComboBox : System.Windows.Forms.ComboBox
{
public MyComboBox()
{
FieldInfo fieldInfo = typeof(System.Windows.Forms.ComboBox.ObjectCollection).GetField("innerList", BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(this.Items, new ArrayList());
}
protected override void RefreshItems()
{
base.RefreshItems();
FieldInfo fieldInfo = typeof(System.Windows.Forms.ComboBox.ObjectCollection).GetField("innerList", BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(this.Items, new ArrayList());
}
}
}
That is, ComboBox.ObjectCollection contains an inner list. All we have to do is to override it. Unfortunately we have to use reflection as this field is private. Here is code to check it.
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
class MyClass : ICustomInterface
{
}
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
this.myComboBox1.Items.Add(new MyClass());
this.myComboBox1.Items.Add(new MyClass());
//Uncommenting following lines of code will produce exception.
//Because class 'string' does not implement ICustomInterface.
//this.myComboBox1.Items.Add("FFFFFF");
//this.myComboBox1.Items.Add("AAAAAA");
base.OnLoad(e);
}
}
}