Problem: Have two classes that already inherit from one another in the Windows.Forms framework (BindingNavigator and ToolStrip), so can't insert inheritance. What are the options, or best option, for extending two different classes with the same functionality (for UI consistency)?
I've had some success with decorator, but that requires casting to the shared interface.
I've managed to get it working using a variation of a strategy pattern, together with the c# 8 default interface. Each extended class has a helper object with all the added functionality. I extracted an interface from the helper class, added a helper parameter to that, and the extended classes implement that. The Helper is passed the parent, while the interface remaps methods so they appear direct. (Add() => Helper.Add()). This way all the functionality shows on the extended class as if it was inherited, and the classes can be completely unrelated.
public class ToolStripCustomUI
{
private ToolStrip _toolStrip;
public ToolStripButton ButtonAdd { get; set; } = new();
public ToolStripButton ButtonDelete { get; set; } = new();
// more controls
public ToolStripCustomUI(ToolStrip toolStrip)
{
_toolStrip = toolStrip;
Setup();
}
public void Setup() { // do stuff }
// More methods
}
public interface ICustomToolStrip
{
public ToolStripButton ButtonAdd
{
get => CustomUI.ButtonAdd;
set => CustomUI.ButtonAdd = value;
}
public ToolStripButton ButtonDelete
{
get => CustomUI.ButtonDelete;
set => CustomUI.ButtonDelete = value;
}
// more controls
ToolStripCustomUI CustomUI { get; }
public void Setup() => CustomUI.Setup();
// Other methods
}
public class ToolStripDecorator : ToolStrip, ICustomToolStrip
{
public ToolStripCustomUI CustomUI
=> new ToolStripCustomUI(this);
public ToolStripDecorator()
=> CustomUI.Setup();
}
public class CustomBindingNavigator : BindingNavigator, ICustomToolStrip
{
public ToolStripCustomUI CustomUI => new
ToolStripCustomUI(this);
public CustomBindingNavigator() : base(true)
{
Items.Remove(AddNewItem);
Items.Remove(DeleteItem);
CustomUI.Setup();
}
}
Is there a better more correct approach?