2

In our Project we have the following class structure for our forms:

public partial class InterceptorForm : Form

public partial class EntityPage<T> : InterceptorForm where T : IDBEntityWithId

Every Form within the application now either inherits from InterceptorForm directly, or is an extension of the EntityPage<T>, for example:

public partial class PurchaseOrderPage : EntityPage<PurchaseOrder>

InterceptorForm provides very Basic stuff, such as Logs for Button-Clicks, Form-Values, etc.

EntityPage<T> provides all the generic functionality around entities (CRUD + stuff)

So, this works fine and as intended, also during runtime. However, after the first Debug-Run of the application, VisualStudio somehow gets stuck with the child forms EntityPage<T>. The designer now fails to load these forms, with - what it seems - one of two error messages:

1.)

GenericArguments[0], 'Project.DBConnection.PurchaseOrder', on Project.Client.Forms.EntityPage'1[T]' violates the constraint of type parameter 'T'.

2.)

The designer could not be shown for this file because none of the classes within it can be designed. The designer inspected the following classes in the file: PurchaseOrderPage --- The base class 'Project.Client.Forms.EntityPage`1' could not be loaded. Ensure the assembly has been referenced and that all projects have been built.

Now, the only thing that helps is: Cleaning, Building, Closing all Forms, Restarting VS, Cleaning, Building - and then it works again, until the application is debugged again.

Any Idea what kind of "Hick-Up" VS has with that particular code?

Especially the error about EntityPage could not be loaded is strange - because that file works in the Designer all the time.

Only thing to mention is that the classes implementing IDBEntityWithID are in a different Project, which is added as dependency. (The Project.DBConnection namespace)

This is annoying, because DesignTime is actually the only time, where these Generic-Forms are handy - cause then VS knows the type of

T entity (in `EntityPage<T>`)

And code in the implementing forms comes down to

entity.MethodOfPurchaseOrder();

rather than

((PurchaseOrder)entity).MethodOfPurchseOrder();
dognose
  • 20,360
  • 9
  • 61
  • 107
  • The designer can be fussy. Generally, it requires that you find a work-around and use it. The constraint violation error doesn't, however, sound like it's related to the designer error. – Flydog57 Dec 21 '21 at 15:44
  • @Flydog57 that error appears in the designer / designview only. Found a Workaround, see answer bellow. – dognose Dec 21 '21 at 15:55
  • 2
    Visual inheritance is still a big problem for the designer. The code works perferct, builds, runs without any problems. The problem is in the designer of visual studio. We have to restart VS more than once because the designer can't figure it out again. Also often lots of errors appear when you open a form in designer, a restart of VS always fixed it for us. I know your pain, there is no good solution for this, but still I don't want to abandon visual inheritance – GuidoG Dec 21 '21 at 16:00
  • [Windows Forms Generic Inheritance](https://stackoverflow.com/a/33112824/3110834) – Reza Aghaei Dec 23 '21 at 00:19
  • [Abstract generic UserControl inheritance in Visual Studio designer](https://stackoverflow.com/a/38291922/3110834) – Reza Aghaei Dec 23 '21 at 00:21

1 Answers1

2

I've now found this post about .net 2.0 and just tested the same out of curiosity. What should I say, It works :) http://madprops.org/blog/designing-generic-forms/

Leaving the question here, maybe there is a more elegant solution, or somebody is facing the same issue:

Adding a non-generic class in between resolves the issue:

public partial class InterceptorForm : Form

public partial class EntityPage<T> : InterceptorForm where T : IDBEntityWithId

public partial class PurchaseOrderPageStub : EntityPage<PurchaseOrder>

public partial class PurchseOrderPage : PurchaseOrderPageStub

where the stub just passes on the constructors:

public partial class PurchaseOrderPageStub : EntityPage<PurchaseOrder>
{
    public PurchaseOrderPageStub() : base() => InitializeComponent();

    public PurchaseOrderPageStub(PurchaseOrder purchaseOrder, PageModes pageMode) : base(purchaseOrder, pageMode) => InitializeComponent();

    public PurchaseOrderPageStub(long entityId, PageModes pageMode) : base(entityId, pageMode) => InitializeComponent();
}

Now the "Stub" cannot be viewed in Designer after debugging the project once - but that's something we can live with.

dognose
  • 20,360
  • 9
  • 61
  • 107