runtime: IComponent is missing designer attributes

In particular, IComponent is missing the following two attributes, which were defined on .NET Framework:

[Designer("System.ComponentModel.Design.ComponentDesigner, " + AssemblyRef.SystemDesign, typeof(IDesigner))]
[Designer("System.Windows.Forms.Design.ComponentDocumentDesigner, " + AssemblyRef.SystemDesign, typeof(IRootDesigner))]

This affects both designer and runtime IDesignerHost scenarios. cc @ericstj.

While we’ve worked around this in our designer by hard-coding knowledge of IComponent’s missing attributes in our own IDesignerHost implementation, third-parties would be hard-pressed to do the same for runtime scenarios where the designer is hosted in an application at runtime. An example of such a scenario is DevExpress’s Reporting library where they allow a report designer based on CodeDom serialization to embedded directly into an end user application. This is a very meaningful for certain line-of-business apps.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 20 (20 by maintainers)

Most upvoted comments

Do you think you could share a repro that demonstrates the bug so that we can both validate the fix is working and determine if reference update is necessary?

The repro would be to create an IComponent instance and call TypeDescriptor.CreateDesigner(...) with the base type as typeof(IDesigner) and then again with typeof(IRootDesigner). Today, both calls will return ComponentDesigner, but the second should return ComponentDocumentDesigner.

This blocks designer scenarios where the user opens a component or control as a root designer. When the user drops some component on a form designer, the designer host will already had a root component. So, it’ll ask to create a designer with a base type of IDesigner. However, if the user double-clicks a component or control in the Solution Explorer, it’ll be opened as the root component. So, the designer host will ask to create a designer with a base type of IRootDesigner. Without this change, the latter case is broken. I can work around it in the new designer, but’ll still be broken from runtime designer hosting scenarios.

https://github.com/dotnet/winforms/blob/6a4da4de1c03d3778c63b2b0195045d00c490fd5/src/System.Windows.Forms.Design/src/System/ComponentModel/Design/DesignSurface.cs#L283-L305

I’m a bit surprised the designer has access to runtime assemblies, for instance in the case where the app is targeting net5.0 without a RID and tooling might be running on a different framework. Where would it find the runtime assembly?

Everything is done via reflection using TypeDescriptor and PropertyDescriptor, typically on runtime objects and types. In the classic designer, there was a filtering done to hide runtime properties that didn’t appear on reference assemblies. This was necessary to hide properties that were available on runtime objects that didn’t appear in the TFM that the project was referencing, since VS typically ran on a different TFM. However, the designer has always worked on runtime types and object instances.

In the .NET Core designer, we construct a server process (much like WPF does) using a runtimeconfig.json and deps.json that matches up with the user’s project. That way, the process runs using the runtime, NuGet references, etc. that the user’s app targets. So, the designer will be running on the same RID that the user is targeting. So, the runtime assemblies that it needs are in the default AssemblyLoadContext.

You’re right… somehow I can’t read anymore and read IRootDesigner 😆

So the following attributes need to be applied to all the types that had them in desktop:

T:System.ComponentModel.DesignerAttribute
T:System.ComponentModel.Design.Serialization.DesignerSerializerAttribute
T:System.ComponentModel.EditorAttribute
T:System.ComponentModel.ToolboxItemAttribute
T:System.ComponentModel.TypeDescriptionProviderAttribute

These types should be pushed down as low as necessary to apply them in all cases.

In places where these attributes depend on other types, like here https://github.com/dotnet/runtime/blob/0e23ef47ff8a2de6a5b5898a849ba00303aba8df/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/DesignerAttribute.cs#L23

We should avoid that dependency by using type name, as is done here: https://github.com/dotnet/runtime/blob/0e23ef47ff8a2de6a5b5898a849ba00303aba8df/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ToolboxItemAttribute.cs#L40

cc @Anipik since this is related to work he’s doing WRT attributes in references.