views:

470

answers:

1

I'm using the class listed below to create a UserControl wrapping a ComboBox that can accept a List<T> and return an object of type T when the internal ComboBox's selection is changed.

Everything works fine in code, exactly as I expect it to, but I can't get SelectedItemChanged event to show up in the Designer anymore when using my control. It worked fine when the abstract base class was non-abstract, but I'm trying to condense 5 essentially duplicate controls into one.

Unimportant parts have been snipped.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace UserComboTest
{
    public abstract partial class DropDownList<T> : UserControl where T : class
    {
        protected abstract int FindIndex(T item);
        public abstract void Populate(List<T> items, T defaultItem);

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Browsable(true)]
        public event EventHandler<SelectedItemEventArgs> SelectedItemChanged;

        private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (null != SelectedItemChanged)
            {
                SelectedItemChanged(this, new SelectedItemEventArgs(Selected));
            }
        }

        public class SelectedItemEventArgs : EventArgs
        {
            public SelectedItemEventArgs(T selectedItem)
            {
                Selected = selectedItem;
            }

            public T Selected { get; private set; }
        }
    }

    public class UserDropDownList : DropDownList<User>
    {
        protected override int FindIndex(User user)
        {
            // find index for item
        }

        public override void Populate(List<User> users, User defaultUser)
        {
            // populate the list
        }
    }
}

EDIT: Fixed the code-breaking problem. Turned out both my namespace and form were named UserComboTest, so when it serialized the fully-qualified type name (UserComboTest.UserDropDownList), it assumed that it was a member or class under the form, not the namespace. In other words, it thought it was looking for UserComboTest.UserComboTest.UserDropDownList, which doesn't exist. Renaming the form to UserComboTest.UserComboTestForm solved that half of the problem.

Still remaining is the fact that the designer doesn't show the SelectedItemChanged event, and if I set it manually, it gets removed, so I either have to set it outside of InitializeComponent, or figure out how to get it to be serialized.

+2  A: 

Generally, the winforms designer reacts badly to abstract base classes. You should turn the abstract methods into empty virtual methods and make the class non-abstract.

thecoop
refreshed to see your answer. I've deleted mine. You may want to mention having a protected or internal constructor to restrict use of the base class if that's what the intention is. Also, throw NotImplementedException or NotSupportedException in the empty virtuals.
Jeff Yates
I had thought about that, since the Designer's given me lip before about not having a public constructor with no arguments. Unfortunately, making the two methods virtual while making the class non-abstract still doesn't let the event show up in the designer, and I lose my compile-time checking to make sure the functions are implemented.
Chris Doggett