Я бы предложил такой подход (только в качестве идеи).
Пишем классы поведения, каждый из которых отвечает за какой-то аспект поведения контрола (подписавшись на соотв. события)
Скажем CloseOnEsc(Form form) и т.п.
Делаем базовую форму с абстрактным методом, в потомках применяем нужное поведение к нужным контролам.
Понятное дело, такой подход применим если требуемого поведения можно добиться через публичный интерфейс соотвествующего контрола,
иначе без наследования никак не получится обойтись.
И примерчик:
public partial class SomeForm : Form
{
ArrayList behaviors = new ArrayList();
public SomeForm()
{
InitializeComponent();
}
protected override void OnHandleCreated( EventArgs e )
{
base.OnHandleCreated( e );
behaviors.Clear();
behaviors.Add( new CloseOnEsc( this ) );
behaviors.Add( new ComboBoxPrompt( comboBox1, ProvidePrompts ) );
}
protected override void OnHandleDestroyed( EventArgs e )
{
for ( int i = behaviors.Count - 1; i >= 0; --i )
{
IDisposable disp = behaviors[i] as IDisposable;
if ( null != disp )
disp.Dispose();
behaviors.RemoveAt( i );
}
base.OnHandleDestroyed( e );
}
IEnumerable<string> ProvidePrompts( string str )
{
if ( str.StartsWith( "A" ) )
{
yield return "AA";
yield return "AAAA";
yield return "AAAAAA";
}
}
}
public sealed class CloseOnEsc : IDisposable
{
readonly SomeForm Target;
bool disposed;
public CloseOnEsc( SomeForm form )
{
Target = form;
Target.PreviewKeyDown += Target_PreviewKeyDown;
}
public void Dispose()
{
if ( !disposed )
{
Target.PreviewKeyDown -= Target_PreviewKeyDown;
disposed = true;
}
}
void Target_PreviewKeyDown( object sender, PreviewKeyDownEventArgs e )
{
if ( e.KeyCode == Keys.Escape )
{
Target.Close();
}
}
}
public sealed class ComboBoxPrompt : IDisposable
{
readonly ComboBox Target;
Func<string, IEnumerable<string>> GetVariants;
bool disposed;
public ComboBoxPrompt( ComboBox cb, Func<string, IEnumerable<string>> getVariants )
{
Target = cb;
Target.TextChanged += Target_TextChanged;
GetVariants = getVariants;
}
void Target_TextChanged( object sender, EventArgs e )
{
string text = Target.Text ?? "";
IEnumerable ie = GetVariants( text );
Target.BeginUpdate();
Target.Items.Clear();
foreach ( string str in ie )
Target.Items.Add( str );
Target.EndUpdate();
Target.Select( text.Length, 0 );
}
public void Dispose()
{
if ( !disposed )
{
Target.TextChanged -= Target_TextChanged;
disposed = true;
}
}
}