5

I have these classes:

class Foo<T1, T2> : Form 
    where T1, T2 : EventArgs

class MiddleGoo : Foo<X,Y>

class Goo : MiddleGoo

X,Y are just simple classes derived from EventArgs.

I see Goo in designer, but i want to create a class Boo between Foo and Goo like this:

class Boo<T1, Y> : Foo<T1, Y>
where T1 : EventArgs

class MiddleGoo : Boo<X,Y>

class Goo : MiddleGoo

Workaround with middle class doesn't work, any ideas?

EDIT: I meant Y and X are classes like YEventArgs and XEventArgs and my problem is about seeing in designer class Boo when i defined Y as T2 but still want to keep it generic through T1.

EDIT2: I just realized I misspelled something about Y class...

public class Foo<T1, T2> : Form
    where T1 : EventArgs
    where T2 : EventArgs
{
}

public class Boo<T1> : Foo<T1, MyEventArgs2>
    where T1 : EventArgs
{
}

public class MiddleGoo : Boo<MyEventArgs1>
{
}

class Goo : MiddleGoo
{
}

public class MyEventArgs2 : EventArgs
{
}

public class MyEventArgs1 : EventArgs
{      
}

And to be clear I just can't see Boo in Designer... ( I can't see MiddleGoo too but i don't need to)

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
Plondrein
  • 87
  • 2
  • 5
  • 3
    "Doesn't work" - Why? What's the error? – wingerse Oct 13 '15 at 21:14
  • 2
    Assuming the declaration of `Foo` hasn't changed, the second piece of code is surely invalid as `Y` does not inherit from `EventArgs`. Is that your "between" class? This looks like an X-Y problem. What are you trying to do? The Winforms designer doesn't like _forms_, let alone inherited forms with generic arguments. – stuartd Oct 13 '15 at 21:19
  • @stuartd Using forms with generic arguments has many benefits, but unfortunately designer doesn't support them, I am using forms with generic arguments in a very large project using the trick that I described [here](http://stackoverflow.com/a/33112824/3110834) and I have designer support, hope you take a look at and find it helpful:) – Reza Aghaei Oct 13 '15 at 21:37
  • The designer needs to create an instance of the base class in order to do its job, the most visible aspect of that is the WYSIWYG appearance. That of course is not possible when the base class is generic, it cannot possibly guess at which particular type argument to pick. You can make this class work in code but you'll have to do without the point-and-click view. – Hans Passant Oct 13 '15 at 21:37
  • `class Boo : Foo where T1 : EventArgs` is only valid if you add `Y:EventArgs` too, here `Y` is a generic parameter name, It is not the `Y` that you said inherits from `EventArgs` – Reza Aghaei Oct 13 '15 at 23:32
  • look at my edit please, i think i was not clear about my problem. – Plondrein Oct 14 '15 at 00:47
  • No differenec, if you are using `class Boo : Foo where T1 : EventArgs` that `YEventArgs` is not your `YEventArgs` class, it is just a generic parameter like `T` or `K`, also there is an **Error** The type `'YEventArgs'` cannot be used as type parameter 'T2' in the generic type or method `'Foo'`. There is no boxing conversion or type parameter conversion from `'YEventArgs'` to `'System.EventArgs'`. – Reza Aghaei Oct 14 '15 at 01:59
  • I think if you follow what I did in my answer you can overcome the problem. – Reza Aghaei Oct 14 '15 at 02:01
  • I corrected my classes, it wasn't only about syntax, it changed meaning of my problem.. – Plondrein Oct 14 '15 at 16:07
  • @Plondrein It's obvious that you can't see `Boo` in designer. And also `MiddleGoo` your class must have a non-generic base can show in designer. Check my answer. – Reza Aghaei Oct 14 '15 at 18:27
  • @But your answer allows me to see designer with all generic types defined in upper classes and it's something i don't want yet. Can't i fake somehow this T1 class just for designer? – Plondrein Oct 14 '15 at 18:45
  • @Plondrein If you read my answer carefully, `BaseForm:Form` will show, but `MyForm:BaseForm` will not show. And It is not my fault ;) – Reza Aghaei Oct 14 '15 at 18:48

2 Answers2

9

For Visual Studio Version >= VS2015.1

Starting from VS2015.1, Windows Forms Designer shows classes which have generic base classe without any problem. So the workaround which is in other posts is no more required for newer versions of VS and the following class will be shown in designer without any problem.

So having a base generic class like this:

public class BaseForm<TModel,TService> : Form
{
    public TModel Model {get;set;}
    public TService Service {get; set;}
}

You can create the derived form without any problem in designer:

public class FooForm: BaseForm<Foo,FooService> 
{
}

Older Versions of Visual Studio

In older versions of Visual Studio, when the designer wants to host your form in designer, it tries to create an instance of base class of your form, and your class must have a non-generic base to so the designer can show it.

So you can see BaseForm<T>:Form can be shown in designer but CategoryForm:BaseForm<Category> can not be shown in designer. As a workaround in these cases you should create a BaseCategoryForm:BaseForm<Category> and then CategoryForm:BaseCategoryForm will be shown in designer.

Example

Suppose this is your base class that accepts TModel as Model and TService as Service for example:

public class BaseForm<TModel,TService> : Form
{
    public TModel Model {get;set;}
    public TService Service {get; set;}
}

Then create an intermediate form this way, with this line of code:

Public Class BaseFooForm: BaseForm<Foo, FooService>{ }

And the final form this way:

public class FooForm: BaseFooForm
{
}

Now the final FooForm has designer and you can work with it normally. This way you can create your classes to be supported in designer.

Note

The update is also applied on control designer. So also in generic base class for WinForm UserControl you no more need such workaround for VS>=VS2015.1 .

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • 1
    "BaseForm: Form can be show in designer" Not without going into the Designer.cs file and adding the generic parameter(s) to the Ctor like this: partial class BaseForm – BillW Mar 26 '16 at 01:29
  • 1
    @BillW Surly in all cases the constructor should match with your class definition. – Reza Aghaei Mar 26 '16 at 09:32
  • It works fine if you inheritance chain is 'regular class -> generic class -> form/usercontrol' . But with 2+ levels of generics, it still breaks. – Arno Peters Sep 12 '18 at 11:31
0

The T2 Type parameter in Foo class needs to be convertible to EventArgs. But when you are defining your Boo class, you aren't including that constraint. Change your Boo class to this:

class Boo<T1, Y> : Foo<T1, Y>
    where T1 : EventArgs
    where Y : EventArgs

Also, you have got a syntax error at the Foo class declaration. Change it to :

class Foo<T1, T2>
    where T1 : EventArgs
    where T2 : EventArgs
wingerse
  • 3,670
  • 1
  • 29
  • 61