Detecting design mode from a Control's constructor - c#

Following-on from this question, is it possible to detect whether one is in design or runtime mode from within an object's constructor?
I realise that this may not be possible, and that I'll have to change what I want, but for now I'm interested in this specific question.

You can use the LicenceUsageMode enumeration in the System.ComponentModel namespace:
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);

Are you looking for something like this:
public static bool IsInDesignMode()
{
if (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) > -1)
{
return true;
}
return false;
}
You can also do it by checking process name:
if (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv")
return true;

Component ... as far as I know does not have the DesignMode property. This property is provided by Control. But the problem is when CustomControl is located in a Form in the designer, this CustomControl is running in runtime mode.
I have experienced that the DesignMode property works correct only in Form.

Controls(Forms, UserControls etc.) inherit Component class which has bool property DesignMode so:
if(DesignMode)
{
//If in design mode
}

IMPORTANT
There is a difference of using Windows Forms or WPF!!
They have different designers and and need different checks.
Additionally it's tricky when you mix Forms and WPF controls. (e.g. WPF controls inside of a Forms window)
If you have Windows Forms only, use this:
Boolean isInWpfDesignerMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
If you have WPF only, use this check:
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");
If you have mixed usage of Forms and WPF, use a check like this:
Boolean isInWpfDesignerMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
Boolean isInFormsDesignerMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv");
if (isInWpfDesignerMode || isInFormsDesignerMode)
{
// is in any designer mode
}
else
{
// not in designer mode
}
To see the current mode you can show a MessageBox for debugging:
// show current mode
MessageBox.Show(String.Format("DESIGNER CHECK: WPF = {0} Forms = {1}", isInWpfDesignerMode, isInFormsDesignerMode));
Remark:
You need to add the namespaces System.ComponentModel and System.Diagnostics.

You should use Component.DesignMode property. As far as I know, this shouldn't be used from a constructor.

You can use this
if (DesignerProperties.GetIsInDesignMode(this))
{
...
}

Like many others, I have had this problem several times already when designing Windows Forms UserControls.
But today, I had a situation where none of the mentioned solutions worked for me.
The problem is, that LicenseManager.UsageMode only works reliably in the constructor, while DesignMode only works outside the constructor and not always. This is my experience, and this is what is said in a discussion on GitHub.
And another problem comes with inheritance, and embedding user controls in another user controls in another user controls. At the latest in the 2nd level of embedding a user controls, both ways fail!
This can be shown in the UserControls that I created for this test. Every UC has 3 labels:
its (project name) and type name
The values of
DesignMode (true: "DM=1"),
LicenseManager.UsageMode == LicenseUsageMode.Designtime, queried locally, (true: "local_LM-DT=1")
LicenseManager.UsageMode == LicenseUsageMode.Designtime, queried from a private field that was written in the constructor (true: "ctor_LM-DT=1")
all taken inside the constructor ("CTOR") and inside a method that was called from the constructor ("CFCtor")
The same values as in 2)
all taken inside the Load event ("Load()") and inside a method that was called from the Load event ("CFLoad")
The UserControls and the Form that I created are (all screenshots shown them in the WinForms Designer):
UserControl1:
contains 3 labels
The Designer does not execute the construtor or events, therefore the labels are not filled.
UserControl1a:
inherits from UserControl1
contains 2 more labels
The Designer executes the construtor and events of the parent UserControl.
UserControl2: contains
contains 3 labels
contains 1 UserControl1
contains 1 UserControl1a
The Designer executes the construtors and events of the embedded UserControls.
Only 1 level of embedding.
UserControl3:
contains 3 labels
contains 1 UserControl2
The Designer executes the construtors and events of the embedded UserControls.
2 level of embedding: The values inside the UserControl at 2nd embedding level are wrong.
Form1:
contains 3 labels
contains 1 UserControl1
contains 1 UserControl1a
contains 1 UserControl2
contains 1 UserControl3.
The Designer executes the construtors and events of the embedded UserControls.
3 level of embedding: The values inside the UserControl at 2nd and 3rd embedding level are wrong.
As you can see from the screenshots, "ctor_LM-DT" is always 1.
This means, that storing the value from the LicenseManager in a member field is necessary to get a valid status of the Designer usage:
private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;
For the sake of completeness, here's some of my code that can be used to reproduce the test:
public static string CreateText(bool i_isInDesignMode, LicenseUsageMode i_localLicenseUsageMode, LicenseUsageMode i_ctorLicenseUsageMode)
{
return $"DM={(i_isInDesignMode ? 1 : 0)} local_LM-DT={(i_localLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)} ctor_LM-DT={(i_ctorLicenseUsageMode == LicenseUsageMode.Designtime ? 1 : 0)}";
}
The other UserControls are identical or similar:
public partial class UserControl1 : UserControl
{
private LicenseUsageMode m_ctorLMUsageMode = LicenseManager.UsageMode;
public UserControl1()
{
InitializeComponent();
label2.Text = $"CTOR: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
CalledFromCtor();
}
private void UserControl1_Load(object sender, EventArgs e)
{
label3.Text = $"Load(): {CInitTester.CreateText(DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
CalledFromLoad();
}
private void CalledFromCtor()
{
label2.Text += $"\r\nCFCtor: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
}
private void CalledFromLoad()
{
label3.Text += $"\r\nCFLoad: {CInitTester.CreateText (DesignMode, LicenseManager.UsageMode, m_ctorLMUsageMode)}";
}
}

Another interesting method is described on that blog: http://www.undermyhat.org/blog/2009/07/in-depth-a-definitive-guide-to-net-user-controls-usage-mode-designmode-or-usermode/
Basically, it tests for the executing assembly being statically referenced from the entry assembly. It circumvents the need to track assembly names ('devenv.exe', 'monodevelop.exe'..).
However, it does not work in all other scenarios, where the assembly is dynamically loaded (VSTO being one example).

With cooperation of the designer... It can be used in Controls, Components, in all places
private bool getDesignMode()
{
IDesignerHost host;
if (Site != null)
{
host = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (host != null)
{
if (host.RootComponent.Site.DesignMode) MessageBox.Show("Design Mode");
else MessageBox.Show("Runtime Mode");
return host.RootComponent.Site.DesignMode;
}
}
MessageBox.Show("Runtime Mode");
return false;
}
MessageBox.Show( lines should be removed. It only makes me sure it works correctly.

This is the method I used in my project:
//use a Property or Field for keeping the info to avoid runtime computation
public static bool NotInDesignMode { get; } = IsNotInDesignMode();
private static bool IsNotInDesignMode()
{
/*
File.WriteAllLines(#"D:\1.log", new[]
{
LicenseManager.UsageMode.ToString(), //not always reliable, e.g. WPF app in Blend this will return RunTime
Process.GetCurrentProcess().ProcessName, //filename without extension
Process.GetCurrentProcess().MainModule.FileName, //full path
Process.GetCurrentProcess().MainModule.ModuleName, //filename
Assembly.GetEntryAssembly()?.Location, //null for WinForms app in VS IDE
Assembly.GetEntryAssembly()?.ToString(), //null for WinForms app in VS IDE
Assembly.GetExecutingAssembly().Location, //always return your project's output assembly info
Assembly.GetExecutingAssembly().ToString(), //always return your project's output assembly info
});
//*/
//LicenseManager.UsageMode will return RunTime if LicenseManager.context is not present.
//So you can not return true by judging it's value is RunTime.
if (LicenseUsageMode.Designtime == LicenseManager.UsageMode) return false;
var procName = Process.GetCurrentProcess().ProcessName.ToLower();
return "devenv" != procName //WinForms app in VS IDE
&& "xdesproc" != procName //WPF app in VS IDE/Blend
&& "blend" != procName //WinForms app in Blend
//other IDE's process name if you detected by log from above
;
}
Attention!!!: The code returned bool is indicating NOT in design mode!

I wasn't able to get any of these solutions to work for me in Visual Studio 2019 when creating a WinForms app on .NET Core 3.1.
Both Appllication.ProcessName and Process.ProcessName are returning "DesignToolsServer" for me and LicenseManager.UsageMode returns LicenseUsageMode.Runtime when the Control is in another control or just on a form itself.
I did get it to work using Application.ProcessName == "DesignToolsServer".

Yes, you can check for whether you're in "design mode" from within an object's constructor. But using the WinForms DesignMode property doesn't always work as expected. An alternative:
This is my technique to check DesignMode in C# using Visual Studio and it does work in constructors.
// add this class...
public static class Globals
{
static Globals() => DesignMode = true;
public static bool DesignMode { get; set; }
}
// and modify your existing class...
public static class Program
{
public static void Main()
{
Globals.DesignMode = false;
// ...
// ... and then the rest of your program
//
// in any of your code you can check Globals.DesignMode for
// the information you want.
}
}
This solution is lightweight and simple. The downside is that you have to remember to clear the flag in your Main code.
When checking for "design mode," we're essentially checking for whether our code is being executed because our whole program is being run or because parts of our code are being executed by the VS designer. With this solution, the flag only gets set to false when the whole program is being run.

The LicenseManager solution does not work inside OnPaint, neither does this.DesignMode. I resorted to the same solution as #Jarek.
Here's the cached version:
private static bool? isDesignMode;
private static bool IsDesignMode()
{
if (isDesignMode == null)
isDesignMode = (Process.GetCurrentProcess().ProcessName.ToLower().Contains("devenv"));
return isDesignMode.Value;
}
Be aware this will fail if you're using any third party IDE or if Microsoft (or your end-user) decide to change the name of the VS executable to something other than 'devenv'. The failure rate will be very low, just make sure you deal with any resulting errors that might occur in the code that fails as a result of this and you'll be fine.

If you want to run some lines when it is running but not in the Visual Studio designer, you should implement the DesignMode property as follows:
// this code is in the Load of my UserControl
if (this.DesignMode == false)
{
// This will only run in run time, not in the designer.
this.getUserTypes();
this.getWarehouses();
this.getCompanies();
}

private void CtrlSearcher_Load(object sender, EventArgs e)
{
if(!this.DesignMode) InitCombos();
}

Timers that are enabled by default can cause crash when using custom/user controls. Disable them by default, and enable only after design mode check
public chartAdapter()
{
try
{
//Initialize components come here
InitializeComponent();
//Design mode check
bool designMode = (LicenseManager.UsageMode == LicenseUsageMode.Designtime);
if (designMode)
return;
//Enable timers ONLY after designmode check, or else crash
timerAutoConnect.Enabled = timerDraw.Enabled = true;

Related

Reload UI language strings after changing settings

I have a problem with changing my UI strings after the user has changed the language in the option window. To change the UI strings of the main form, I have to restart the program every time, so that changes take effect, but that's annoying. So I tried it with a delegate to call the function, which loads the strings for the main window in the option window after saving the new settings. The function is called in the option window, but it doesn't change the strings of the main window.
Code in the main window
public delegate void CallLoadUIStrings(SupportedLanguages lang);
public CallLoadUIStrings callLoadUIStrings;
public Renamer()
{
callLoadUIStrings = new CallLoadUIStrings(LoadUIStrings);
}
public void LoadUIStrings(SupportedLanguages lang)
{
try
{
switch (lang)
{
#region "DE/JA/FR/ES/NL"
case SupportedLanguages.De:
case SupportedLanguages.Ja:
case SupportedLanguages.Fr:
case SupportedLanguages.Es:
case SupportedLanguages.Nl:
// reads the language file where the ui strings are stored
langHelper.Read(RenamerLangOpener.RenamerMainWindow);
this.mnuFile.Text = langHelper.Files;
this.mnuClose.Text = langHelper.Close;
this.mnuEdit.Text = langHelper.Edit;
this.mnuUndo.Text = langHelper.Undo;
this.mnuCut.Text = langHelper.Cut;
this.mnuCopy.Text = langHelper.Copy;
this.mnuPaste.Text = langHelper.Paste;
this.mnuDelete.Text = langHelper.Delete;
this.mnuSelectAll.Text = langHelper.SelectAll;
#endregion
}
}
catch (Exception ex) { //exception handling }
}
private void mnuOpt_Click(object sender, EventArgs e)
{
Preferences opt = new Preferences(this);
opt.ShowDialog();
}
Code in the option window
internal Renamer instance = null;
public Preferences(Renamer form)
{
instance = form;
}
public void UpdateUI()
{
langHelper.ReadSettingsValues();
instance.BeginInvoke(instance.callLoadUIStrings,new object[] { langHelper.GetLang});
}
Since I've never worked with delegates I don't have a clue where the mistake is.
I've googled so much to find a solution for a similar problem, but I haven't found something that matched my problem.
I assume this is winforms and not WPF question, and that you have one main form that is open from app's Main function. My solution to changing a language is to open this one form in a loop, and continue the loop as long as the form has a property set to some language identifier. If this property is set then I change the language to that value, and go for another loop iteration. I copy all other properties that need be copied form one form to another, with main being the form's position.
If the form is closed without the language ID being set then we break the loop and exit application as usual.

What causes Winforms to silently discard unhandled exceptions (with no try/Catches)?

I'm in the middle of adding new functionality to my winforms controls, and part of that requires that a variable that was once always used to now be optional (if it's null, get the data from a second source). I made some changes and ran my form, only to find out nothing was happening, even functionality that previously worked. Confused I stepped through the code and found out that my Winforms user control was throwing a NullReferenceException when it encountered my variable, but in the UI no errors were being thrown.
My setup is I have a UserControl with a combo box. When the user changes that combo box it loads a secondary UserControl in a panel the first control has. The second control is what is throwing the exception.
Here are the code paths:
private void cmbActionType_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading)
return;
// ActionType was changed, update the action.ActionType value
if (cmbActionType.SelectedItem != null)
{
if (cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
_action.ActionType = ActionTypes.SetValue;
else if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION)
_action.ActionType = ActionTypes.CheckValue;
else
_action.ActionType = ActionTypes.CustomAction;
}
RefreshActionPanel();
_editor.DataModified();
}
private void RefreshActionPanel()
{
// Control defaults
AnchorStyles styles = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
UserControl subControl = null;
// Clear the currently active control
pnlActionDetails.Controls.Clear();
// Determine what type of control to load in the panel
if (cmbActionType.SelectedItem != null && cmbCaseType.SelectedItem != null)
{
// SetValue or CheckValue actions
if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION || cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
{
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
subControl = new SetCheckActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
// CustomAction action type
else
{
// Check if the requested case is a type or defined in a script
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
{
subControl = new CustomActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
else if (_editor.ScriptDefinitions.Any(x => x.CaseName == cmbCaseType.SelectedItem.ToString()))
{
var definitions = _editor.ScriptDefinitions.Where(x => x.CaseName == cmbCaseType.SelectedItem.ToString()).ToList();
subControl = new CustomActionControl(_action, _editor, definitions);
}
}
}
if (subControl != null)
{
subControl.Anchor = styles;
subControl.Height = pnlActionDetails.Height;
subControl.Width = pnlActionDetails.Width;
pnlActionDetails.Controls.Add(subControl);
}
}
public CustomActionControl(TestAction action, fmEditor editor, IList<TcScriptDefinition> scriptDefinitions) : base(action, editor)
{
_loading = true;
InitializeComponent();
_scriptDefinitions = scriptDefinitions;
PopulateActionList();
SetupDataGrid();
_loading = false;
}
private void SetupDataGrid()
{
// Clear the current contents of the datagrid
grdParameters.Rows.Clear();
if (cmbAction.SelectedItem == null)
return;
// Retrieve the action code from the drop down
string actionCode = cmbAction.SelectedValue.ToString();
// Check if any paramters are available for this action
if (!_availableActionParameters.ContainsKey(actionCode))
return;
// Add a new row for each parameter available for this action
foreach (string param in _availableActionParameters[actionCode])
{
string display = param;
// Determine if the parameter has a display string
if (_formInstance.CodeDisplayMap.ContainsCode(param))
display = _formInstance.CodeDisplayMap.GetDisplayStringFromCode(param);
// Create the array for the row, with an empty string as the current value
string[] row = { display, string.Empty };
// Check if the current action uses this action code.
// If so, retrieve the value for this parameter and use it in the row
// Note: Case-INsensitive comparison must be performed here
if (_action.Attributes["action"].Equals(actionCode, StringComparison.CurrentCultureIgnoreCase))
if (_action.Attributes.ContainsKey(param))
row[1] = _action.Attributes[param];
grdParameters.Rows.Add(row);
}
}
The NullReferenceException is coming from the SetupDataGrid() method where _formInstance is being called. However, usually when an application encounters an unhandled exception the JIT system throws an error message saying such (and as you can see, there's no try/catch statements used unless I am blind).
Why does my winforms application show no signs of an exception occurring. I'd rather an unhandled exception message occur rather than nothing happening, as that makes it harder for users to know something critical went wrong (as opposed to it not responding to their commands)
Edit: To clarify since there seems to be some confusion, I do NOT care about breaking on this exception in visual studio when debugging. The fact of the matter is that the application should not be hiding unhandled exceptions, and my application should crash (or rather show the JIT message that an unhandled exception occurred), even when not in debug mode outside of visual studio.
This is not a debug time question but a production run time question. If this code throws an OutOfMemoryException for instance, I need it to not be silently ignored. Right now it is being ignored.
Go to Debug->Exceptions... (Ctrl-D, E if you are using default shortcuts) from your menu bar in Visual Studio and check the box for Thrown under Common Language Runtime Exceptions. This will cause your program to break on exceptions even if they are in a try/catch block. You can then do a step forward and see where the code is jumping to for the next instruction. That should bring you to the catch block that is hiding your exception.
It may be jumping in to .NET code for the catch, you can go to Debug->Options and Settings.. and turn on Enable .NET framework Source Stepping to see what it is jumping in to.
Here is a example of catching the unhandeled execptions in code
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new Form1());
MessageBox.Show("0");
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("1");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
throw new ArgumentNullException();
}
}
Click the button and 1 appears, the program should still run afterwards.
However as I said in my last comment, check that user-unhandeled is checked (maybe uncheck and recheck) in Debug->Exceptions first it may solve your initial issue..
They can be caught if you have a try/catch in your Main, or if you have a ThreadException handler. Also check out SetUnhandledExceptionMode.
Note that if they're caught in Main, your program will just exit silently. ThreadException can "catch" and ignore them.
EDIT: Since the debugger doesn't break when you uncheck the box for Thrown under Common Language Runtime Exceptions, it's being caught by the code for Windows Forms. This is not ideal, but a lot of the BCL does this. You don't need to worry about it catching OutOfMemoryException or anything like that; the BCL should only be catching exceptions that it expects (vexing exceptions).
To be clear, the exception is not "unhandled". It is handled by the BCL code.

`DesignMode` in subcontrols is not set correctly?

I have a compound control contains nested controls. The problem i am facing is that control read properties from a global setting class which is static and intern read from setting file. To stop individual control from accessing configuration in design mode i added check in each control.
If(!DesignMode){
...
//Initialize properties e.g. prop = AppConfig.GetProperty("prop1");
}
The problem is that individual control work fine when open in VS. But when i open top control containing nested control i get error by VS designer. The error is that in a nested control DesignMode=false for some reason.
I also created a test app and created a simple control within another control to test if there is a problem with VS but it seem to work correctly for any depth of controls.
I dont even know how to debug this. For now i comment out the property initializing code and build it and then open designer and there uncomment it and build it again to run it.
Did anyone came across this problem or is there any way to fix it.
The problem you're facing is that the DesignMode is not set while in Constructor (at any level).
Move your initialization methods to Load event, to avoid this problem.
Also, you could add additional comparison with:
protected bool IsInDesignMode
{
get
{
return DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime;
}
}
This would definitely provide an acurate way to determine the design mode because sometimes VisualStudio
returns DesignMode = false while you're placing user controls on the form, or refreshing the form display itself in design.
i do define static bool NotInDesignMode in Program.cs and set it to true in Main()
that way i dont take any dependencies on LicenseManager.UsageMode
however you wouldnt do that if you are writing a generic class lib.
I had same problem.
Maybe this will help you.
protected override void Dispose(bool disposing)
{
if (Application.ExecutablePath.IndexOf("devenv.exe", StringComparison.OrdinalIgnoreCase) < 0)
{
try
{
if (m_NormalImage != null) m_NormalImage.Dispose();
if (m_DownImage != null) m_DownImage.Dispose();
if (m_HoverImage != null) m_HoverImage.Dispose();
m_NormalImage = null;
m_DownImage = null;
m_HoverImage = null;
}
catch
{
}
}
base.Dispose(disposing);
}
I've ran into the problem that the DesignMode flag was set after the Load EventHandler has been invoked. I solved this by writing this extension method which checks if the parent control DesignMode flag has been set.
public static bool InDesignModeSelfOrAncestors(this Control control) {
static bool GetDesignModePropertyValue(Control c) {
if (c.GetType().GetProperty("DesignMode", BindingFlags.Instance | BindingFlags.NonPublic) is {} property) {
return (bool) property.GetValue(c, null);
}
return false;
}
var designModeFlag = GetDesignModePropertyValue(control);
while (control.Parent is {} parent) {
control = parent;
designModeFlag |= GetDesignModePropertyValue(control);
}
return designModeFlag;
}

What happens when you attempt to access a winforms TreeView by keyword and that Keyword is not present?

I'm writing an application where I fill out a TreeView with the schema of a database. I do so by iterating over each table name and type in GetSchema. Then, depending on the DataType and name, I select the parent Node into which I want to add a new item. Sometimes that item does not exist in the treenode (depending on user settings certain tables may or may not have been added as nodes of the treeview), which is fine, in that case I want either:
A) An exception to be thrown so I KNOW that it failed to find the node as asked for. Or B) null to be returned for the failed accessor.
A (highly modified) snippet of my code:
TreeNode parent = null;
if( tableName.StartsWith("prefix") )
{
parent = tablesNode.Nodes["Node Name which might not exist"];
}
if (parent == null && IgnorePrefixedTables)
{
continue;
}
else if (parent == null)
{
throw Exception();
}
....<More Code For Filling Out that node>...
The problem is, that when I step through this code (or rather, the real code) when I reach tablesNode.Nodes["Node Name which might not exist"] for a node name that doesn't exist I am unable to catch the exception because none is thrown. If I step into or over that line of code the whole method returns me up to the highest level (my form immediately gets shown and the UI is partially complete). What's up with that?
[EDIT]
Here's a VERY simplified version of my problem:
namespace TestZone
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
treeView1.Nodes.Add("Hello", "Hello");
var x = treeView1.Nodes["Hello"];
x.Nodes.Add("World-PL", "Swiat");
x.Nodes.Add("World-EN", "World");
var y = treeView1.Nodes["World-EN"];
MessageBox.Show(y.Text);
y = treeView1.Nodes["World-SP"];
MessageBox.Show(y.Text);
y = treeView1.Nodes["World-PL"];
MessageBox.Show(y.Text);
}
}
}
The code relies on textBox1 being on Form1. (P.S. PL is Polish). Apparently treeView1 can't find World-EN either which makes me think I'm really not understanding how treeView works. The first MessageBox never gets shown and breakpoints on y = treeView1.Nodes["World-SP"]; fail to break (since that line of code never gets called).
Avoid using exceptions to control program flow. Use the TreeViewCollection.IndexOfKey() method.
There's a strange bug on a 64-bit operating system when an exception is raised in the form's OnLoad() method or Load event and a debugger is attached. It is swallowed without notification. Sounds like a match. Workaround is to set the Platform target to x86.

How to detect that C# Windows Forms code is executed within Visual Studio?

Is there a variable or a preprocessor constant that allows to know that the code is executed within the context of Visual Studio?
Try Debugger.IsAttached or DesignMode property or get ProcessName or a combination, as appropriate
Debugger.IsAttached // or
LicenseUsageMode.Designtime // or
System.Diagnostics.Process.GetCurrentProcess().ProcessName
Here is a sample
public static class DesignTimeHelper {
public static bool IsInDesignMode {
get {
bool isInDesignMode = LicenseManager.UsageMode == LicenseUsageMode.Designtime || Debugger.IsAttached == true;
if (!isInDesignMode) {
using (var process = Process.GetCurrentProcess()) {
return process.ProcessName.ToLowerInvariant().Contains("devenv");
}
}
return isInDesignMode;
}
}
}
The DesignMode property isn't always accurate. We have had use this method so that it works consistently:
protected new bool DesignMode
{
get
{
if (base.DesignMode)
return true;
return LicenseManager.UsageMode == LicenseUsageMode.Designtime;
}
}
The context of your call is important. We've had DesignMode return false in the IDE if running in an event under certain circumstances.
There is the DesignMode property for Components. It is handy when you use the Design Viewer of VS.
But when you talk about debugging in Visual Studio you need to use the Debugger.IsAttached property. Then, you can use
#if DEBUG
#endif
too
I think the simplest and most reliable way to determine if your extension is executed in the WinForms designer is to check the current process.
public static bool InVisualStudio() {
return StringComparer.OrdinalIgnoreCase.Equals(
"devenv",
Process.CurrentProcess.ProcessName);
}
I use this extension method:
internal static class ControlExtension
{
public static bool IsInDesignMode(this Control control)
{
while (control != null)
{
if (control.Site != null && control.Site.DesignMode)
return true;
control = control.Parent;
}
return false;
}
}
There is a DesignMode property that you can check but in my experience it's not always accurate. You could also check to see if the executable is DevEnv.exe
Take a look here. Might make this question a dup but it all depends on what you're trying to accomplish.
You can use this:
protected static bool IsInDesigner
{
get { return (Assembly.GetEntryAssembly() == null); }
}
I use this code to distinguish whether it's running in Visual Studio or if it's deployed to customers.
if (ApplicationDeployment.IsNetworkDeployed) {
// do stuff
} else {
// do stuff (within Visual Studio)
}
Works fine for me for ages. I skip some logic when inside Visual Studio (such as logging in to application etc).
I want to add to this that in Visual Studio 2022 with .Net 6, the process that actually opens winforms designers is called DesignToolsServer. From my experience so far, DesignMode works outside of the constructor and checking for ProcessName = "DesignToolsServer" works within the constructor.

Categories