Krzysiek Derkowski
Krzysiek Derkowski

Reputation: 21

How can I override the winforms combobox item collection to implement a specific interface

The combobox control accepts an object as its collection member, is there a way to constrain that object to implement a certain interface?

so instead of

public int Add(object item)

I would like to override the add method to something along the lines below

public int Add<T>(T item) : where T : ICustomInterface

I am writing my own custom control that inherits from the combobox, but I'm not quite sure how best to go about getting the custom combobox to only deal with items that implement a specific interface.

Thank you

Upvotes: 2

Views: 1065

Answers (1)

DotNet Developer
DotNet Developer

Reputation: 3018

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

Upvotes: 1

Related Questions