C# generics usercontrol
This works
public class Control1<T> : UserControl { ... }
public class Control2 : Control1<double> { ... }
public class Control3 : Control2 { ... }
had read it here:
Generic User Controls?
Generic base class for WinForm UserControl
We're doing the same thing and we work around by specializing a class first and derive from the specialized class.
Using the code from your example this means something like:
public partial class UserControl : UserControlDesignable
{
...
}
public class UserControlDesignable : BaseUserControl<Someclass> { }
The designer is still acting flaky sometimes - but most of the time it works.
Abstract generic UserControl inheritance in Visual Studio designer
I suppose you have a control AbstractGenericBase<T> : GenericBase<T>
which GenericBase<T>
is a control having such definition: GenericBase<T>: UserControl
.
So if you want to show AbstractGenericBase<T>
in designer, you can use this code:
using System.ComponentModel;
using System.Windows.Forms;
#if DEBUG
public abstract partial class AbstractGenericBase<T> : NonGenericBase
#else
public partial class AbstractGenericBase<T> : GenericBase<T>
#endif
{
public AbstractGenericBase()
{
InitializeComponent();
}
}
#if DEBUG
public class NonGenericBase : GenericBase<object> { }
#endif
Note
- The goal is showing this class in designer:
public abstract partial class AbstractGenericBase<T> : GenericBase<T>
- If
T
has some type constraints, instead ofobject
inGenericBase<object>
use aDummy
which satisfies the generic constraints. - The solution is based on this fact: When the designer wants to show your control in design surface, it tries to create an instance of base class of your control. When the base class of your control is a generic class the designer doesn't know how to create an instance of base class.
In above solution, for design-time support, we said to designer the base for our control isNonGenericBase
, but for run-time, we keepGenericBase<T>
as base class of our control.
Is it Possible to Make a Generic Control in .Net 3.5?
Try this
public partial class MessageControl : MessageControlBase
{
public MessageControl()
{
InitializeComponent();
}
}
public class MessageControlBase : MessageBase<Post>
{}
The key to getting the designer to work is that the base class of the class you are editing must not be generic.
Why do base Windows Forms form class with generic types stop the designer loading?
When a Windows Form or a user UserControl is loaded in the designer, basically the designer is creating an instance of the base class (that class that your custom form or control directly derives from) and then executes the InitializeComponents()
method manually/explicitly through reflection to build up the intended design of your control.
In your case however it can not create an instance of the base class, because it has a generic parameter. The same thing happens if the base class of your form or your control is abstract or does not have a default constructor. In those cases the designer will also not be able to create an instance of your base class.
There is a workaround for this using the TypeDescriptionProviderAttribute where you can give the designer a replacement class that it should instantiate instead.
UserControl with generic control - broken in designer
I've done a somewhat dirty workaround but I can use the designer for the base and derived classes. I removed the generic and replaced the Activator-class with a call to the constructor. When I'm done with designing the base class I coment this line. The derived classes call the constructor to pass the instance:
public TimeBarForm(TimeBarPanel timeBarPanel)
{
this.m_timeBarPanel = timeBarPanel;
InitializeComponent();
}
To make the designer for the derived classes happy, a second constructor provides a default instance:
public TimeBarForm()
{
this.m_timeBarPanel = new TimeBarPanel();
InitializeComponent();
}
Not pretty but I can live with it.
Generic control to have inherit methods in WinForm
The inheritance and designer in Windows Forms is a problem.
I have a Form with an splitter, two listboxes and some other controls. That form is used to translate (map) some items. You select one item at left, one at right and click button to match. They are the same item in different providers.
I have another provider that require some extra controls to do the translation. May be 90% or more of the code is the same, but I need some extra for this provider.
The options that I saw:
Add these extra controls (protected or public) to the Form, hidden by default and without use. In Form derived class, you use them. You haven't the designer in derived Form, but you don't need because controls are in base Form. The problem with this approach is that the designer part of inheritance of derived Form is in base Form. It's a nonsense. I don't recomend this option.
Don't use the designer in derived Form. Starting in the previous point, copy the designer code added for your derived Form into your derived Form and leave your base Form as at first stage, without nothing of derived Form. You don't use the designer but you can use it temporary, copy/paste and have a good inheritance... without the designer in derived Form. It's a good option if your derived Forms has few changes, few maintenance in the designer part.
You can "Add" some logic to your base Form to allow extensions. For example, below of the ListBox, I can add a
Panel
(hidden by default) and some methods likeShowLeftPanel/ShowRightPanel
. By default, these panels aren't used, but in derived class I can add anUserControl
in left panel and show it. And thatUserControl
show the properties that I need to show in the special provider. Add some virtual methods for listbox selection changed, to update theUserControl
. In this way, yourUserControl
has designer and also the base Form. You only need add some "extension points" in your form (aPanel
, aSplitter
...) and give some methods to interact with this parts of the base Form. And this is ok with inheritance because is something generic, likeTag
property in controls.
UPDATE
Check this solution and tell me about it. Make your Forms like this:
public partial class MyForm1 : UserControl, IMyUserControl
{
private readonly MyOwnClass myClass;
public MyForm1(MyOwnClass myClass, MyMiddleClass myMiddle)
{
InitializeComponent();
this.myClass = myClass;
this.MyMiddle = myMiddle;
}
public MyMiddleClass MyMiddle { get; }
}
In this way, all your panel's forms are IMyUserControl
:
public class MyUserControl : IMyUserControl
{
public MyMiddleClass MyMiddle { get; }
}
So, having any of your panel's form, you can cast to IMyUserControl
and get the related MyMiddleClass
having access to methods like MethodForAllChild
:
public class MyMiddleClass
{
public void MethodForAllChild()
{
}
}
In your main form, you may have some property or method that give you access to your UserControl
. Create a method that give you the middle instance of the current UserControl
:
private MyMiddleClass GetMyMiddle()
{
UserControl userControl = GetYourMainFormCurrentUserControl();
IMyUserControl myUserControl = userControl as IMyUserControl;
return myUserControl?.MyMiddle;
}
And use it in your main form when you need:
MyMiddleClass myMiddle = GetMyMiddle();
if (myMiddle != null)
{
myMiddle.MethodForAllChild();
}
In this way, you only need implement the interface and add a property in your forms/usercontrols. In the main form you can get this middleclass and the code to reuse is only in that class and shared in all places. You don't need copy/paste if you add or change something in the middle class.
UPDATE 2
I'm going to explain in other form how it works because the code is written above. The goal is having the code only in one place, without duplicate it.
You define an interface in a very similar way as a class but without implementation (this is not really true in lastest C# versions but we can suppose that is without code). C# don't allow multiple inheritance but you can derive from a class and implement as many interfaces as you want.
When we define IMyUserControl
we are telling that every class that implements IMyUserControl
, has a property MyMiddle
. When MyForm1
implements IMyUserControl
, if you don't add the MyMiddle
property, you get a compiler error. The key with this solution is that add and implement this interface in each form is very easy: add IMyUserControl
, the property and a parameter in the constructor to set the property.
So, all your forms implements now IMyUserControl
. I don't know where are your forms but it's sure that you have a way to get access to your UserControl
. Maybe a variable or an array in which you add your user controls. You are working with them, so you can access to your user controls. Well, if you have an UserControl
instance, and you know that your UserControl
implements IMyUserControl
, you can cast your UserControl
to IMyUserControl
and after the cast, you have access to the interface, in this case, to the MyMiddle
property.
And we put in MyMiddle
all the code that you want to share.
If you add some code of your main form, where you work with your forms, I can help you with the code. I haven't more code than existing in my answer.
Related Topics
Why Doesn't Xmlserializer Support Dictionary
How to Execute Task in the Wpf Background While Able to Provide Report and Allow Cancellation
JSON.Net Serialize by Depth and Attribute
C#: Prepending to Beginning of a File
How to Save Console.Writeline Output to Text File
Serializing an Object as Utf-8 Xml in .Net
Save and Retrieve Image (Binary) from SQL Server Using Entity Framework 6
Shellexecute Equivalent in .Net
Print Webbrowser Without Previewing I.E. Single Click Print
Datetime Conversion from String C#
Programmatically Get a Screenshot of a Page
Ziparchive Creates Invalid Zip File
How to Perform a Unicode Aware Character by Character Comparison