Problem description:
Hi Winforms team,
I’d like to raise an issue with Winforms about the way to check if the current code is run by designer or not. It’s rather confusing and I think there is room for improvement. The ways and suggestions I found from multiple sources (Stackoverflow and few of your team mates) are:
• DesignMode property is flag, but it doesn’t seem to be reliable. Some suggest its value is correct only in ctr after InitializeComponents. Others suggest walking the parents up and checking the property.
• LicenseManager.UsageMode == LicenseUsageMode.Designtime; This is also not reliable enough, at least from my experience, it Is sometimes false whereas it should be true.
• System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv" This seems clunky but seems to work for me (PR). However, if Visual Studio changes its process name it’ll stop working.
• Various sources suggest the combinations of the previous 3.
I am not blaming anyone (I guess that’s clear?), I am just pointing to something which would be beneficial to improve on. Ideally:
Thanks, Ogi!
Expected behavior:
Ideally I would have a Property on the System.ComponentModel.Component which would be completley reliable regardless of if it's used from constructor or not
Minimal repro:
Observe that none of them is 100% reliable
They are reliable for what they are designed, but you want to use them for something they are not designed for.
If I remember right it works like this:
None of those APIs will tell you whether you are running in a design-time environment, that is not their purpose.
In particular if a control has child-controls neither is going to be set for them, though LicenseManager may leak through depending on how child controls are constructed. The DesignMode API is designed for checking the direct user interaction, if you have a composite control the child controls are supposed to act as if they were hosted in a normal application.
I understand that devs may want to have more fine grained distinction so I suggest a new API to be added to detect whether you are currently running in a design time process. All Microsoft UI Frameworks after WinForms seem to have gotten such an API.
They are reliable for what they are designed, but you want to use them for something they are not designed for
Going through the documentation of LicenceManager and DesignMode I don't see any mentioning about the caveat about constructor. So at least the documentation should be improved explaining which one works when.
None of those APIs will tell you whether you are running in a design-time environment, that is not their purpose.
Hm, I thought DesignMode purpose is exactly that, solely judging on the name.
I suggest a new API to be added to detect whether you are currently running in a design time process.
I definitely agree. I would really like to see a single reliable API for that.
Hi @JeremyKuhne ,
UserControl.DesignMode also return false in design mode. Please check this condition in design mode in net core project.
Replication steps:
1) Close the designer
2) Rebuild the application and open the designer and check the design mode condition.
DesignMode is false.
If your user control is unsited, it would be false:
https://github.com/dotnet/runtime/blob/master/src/libraries/System.ComponentModel.Primitives/src/System/ComponentModel/Component.cs#L95-L101
Is there some workaround for this?
I cannot edit any Form on a WinForms Application that does uses Syncfusion Components because of this bug!
So is it a bug with Syncfusion components?
Hi @RussKie ,
No, the bug is due to the designer mode condition is not working for NetCore projects.
Just suggest us the way to find the designmode condition as like in .NetFramework.
No, the bug is due to the designer mode condition is not working for NetCore projects.
Just suggest us the way to find the designmode condition as like in .NetFramework.
Can you please provide more information?
The behaviour hasn't changed since .NET 1.1: https://docs.microsoft.com/dotnet/api/system.componentmodel.component.designmode?view=netframework-1.1#remarks
No, the bug is due to the designer mode condition is not working for NetCore projects.
Just suggest us the way to find the designmode condition as like in .NetFramework.Can you please provide more information?
The behaviour hasn't changed since .NET 1.1: https://docs.microsoft.com/dotnet/api/system.componentmodel.component.designmode?view=netframework-1.1#remarks
We have a problem with finding the design time in NetCore project. I have prepared the simple example for this.
public class MyControl : Control
{
public MyControl()
{
if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
{
MessageBox.Show("Design");
}
else
{
MessageBox.Show("Runtime");
}
}
}
Follow the below steps:
• Add the “MyControl” in the Form1.Designer and close the designer.
• Rebuild the project and open the designer
Observed result:
In Framework project it shows the MessageBox as “Design”
But in .NetCore project it shows the MessageBox as “Runtime” even in designer.
Also I have tried to check the design mode by using below code example. The below code also shows the same error like above scenario.
if ((bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(System.Windows.DependencyObject)).DefaultValue)
{
MessageBox.Show("Design");
}
else
{
MessageBox.Show("Runtime");
}
[EDIT] corrected mark-up
HI Team,
Any updates.?
We have a problem with finding the design time in NetCore project. I have prepared the simple example for this.
public class MyControl : Control { public MyControl() { if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) { MessageBox.Show("Design"); } else { MessageBox.Show("Runtime"); } } }Follow the below steps:
- Add the “MyControl” in the Form1.Designer and close the designer.
- Rebuild the project and open the designer
Observed result:
- In Framework project it shows the MessageBox as “Design”
- But in .NetCore project it shows the MessageBox as “Runtime” even in designer.
@ericstj @AaronRobinsonMSFT it looks like LicenseManager has undergone some makeover, specifically the current implementation of LicenseInteropHelper looks different from .NET Framework version.
Would you know why the .NET version could return an incorrect state?
I think the interop licensing is for AxHost and/or exposing .NET controls to COM clients, for .NET controls consumed by .NET this should not require any interop. Might be more of a problem of the new designer not setting up a design-time license context (not unreasonable considering that licx licensing story is no longer supported). The designer may have to setup a dummy license context just to support design mode detection - or just provide a new API instead.
We have a problem with finding the design time in NetCore project. I have prepared the simple example for this.
public class MyControl : Control { public MyControl() { if (LicenseManager.UsageMode == LicenseUsageMode.Designtime) { MessageBox.Show("Design"); } else { MessageBox.Show("Runtime"); } } }Follow the below steps:
- Add the “MyControl” in the Form1.Designer and close the designer.
- Rebuild the project and open the designer
Observed result:
- In Framework project it shows the MessageBox as “Design”
- But in .NetCore project it shows the MessageBox as “Runtime” even in designer.
@ericstj @AaronRobinsonMSFT it looks like
LicenseManagerhas undergone some makeover, specifically the current implementation ofLicenseInteropHelperlooks different from .NET Framework version.Would you know why the .NET version could return an incorrect state?
Yes, I like to know whey the .NET version could return an incorrect state. Also suggest me is there any other way to find the Design mode in NET core projects.
Also suggest me is there any other way to find the Design mode in NET core projects.
See my explanation above. You are supposed to wait for your control to placed in the designer and then can check its DesignMode mode property. (After the Site has been assigned to the control. Override the site accessor if you need detection when you are placed on the designer, but always use site in combination with the DesignMode property. Sites sometimes are used outside the designer as well, so just having a site doesn't necessarily mean its a designer site.)
If a developer places your control on a UserControl, and then proceed placing his own UserControl in the designer, you are not supposed to show design-time UI (the dev is placing his UserControl and not your control). This is why there is historically no "global" DesignTime check, because it is the wrong thing to do, most of the time. You have to use workarounds if you need it anyways. It has been acknowledged above that it would be nice to have such an API.
The LicenseManager.UsageMode only existed for checking design-time licensing, because you were supposed to do this in the constructor before the site has been assigned. This often is used as a workaround but as I explained above in my previous post it already was broken to abuse it this way. For .NET Core the licensing story is being completely reworked, I don't know how you currently are supposed to write licensed controls.
The Site workaround works for design-only code. (Keep in mind it gets set twice... once when you close the design surface, too!)
However this doesn't help for running runtime-only code since Site is never assigned. A use case is if you want to do further initialization in the constructor but don't want these changes serialized in the designer (or the code throws an exception in design mode for any number of reasons). A workaround could be to explicitly call a method on your form or control at runtime (which won't happen in the designer) to perform the additional initialization.
I also came up with this code snippet which works. This is specifically for the case where you want to run code in runtime, and not when a control is constructed by the designer, regardless of whether or not it can be edited (which is what DesignMode is for, TIL).
private bool isDesignTime; public override ISite Site { get => base.Site; set { base.Site = value; this.isDesignTime = true; } } private bool init = false; protected override void OnLoad(EventArgs e) { base.OnLoad(e); if (this.isDesignTime || this.init) { return; } this.init = true; // Do dangerous stuff here }
OnLoad seems to fire after Site is assigned (or not assigned) so this works.
Your approach looks equivalent to checking the existing DesignMode property, including the fact that it will not detect if a control in the parent hierarchy is placed in the designer (OnLoad will be called in this case without a site being set, since the child control is not being designed)
In other words, if your logic fits into the OnLoad event you can just check DesignMode instead of having to introduce a new variable.
Most helpful comment
See my explanation above. You are supposed to wait for your control to placed in the designer and then can check its
DesignModemode property. (After theSitehas been assigned to the control. Override the site accessor if you need detection when you are placed on the designer, but always use site in combination with the DesignMode property. Sites sometimes are used outside the designer as well, so just having a site doesn't necessarily mean its a designer site.)If a developer places your control on a UserControl, and then proceed placing his own UserControl in the designer, you are not supposed to show design-time UI (the dev is placing his UserControl and not your control). This is why there is historically no "global" DesignTime check, because it is the wrong thing to do, most of the time. You have to use workarounds if you need it anyways. It has been acknowledged above that it would be nice to have such an API.
The LicenseManager.UsageMode only existed for checking design-time licensing, because you were supposed to do this in the constructor before the site has been assigned. This often is used as a workaround but as I explained above in my previous post it already was broken to abuse it this way. For .NET Core the licensing story is being completely reworked, I don't know how you currently are supposed to write licensed controls.