Another beginners question here, coming from Delphi you always have access to another forms controls but in my early days with C# / Visual Studio I am faced with a problem which is proving more difficult than it should be.
I have been getting started by writing a simple notepad style application, I have my main form and a secondary form used to select a line number.
From my main form, I call the goto line number form like so:
private void mnuGoTo_Click(object sender, EventArgs e)
{
Form gotoForm = new GoToForm();
var dialogResult = gotoForm.ShowDialog();
if (dialogResult == DialogResult.OK)
{
// get the text from gotoForm.editLineNumber.Text
MessageBox.Show(gotoForm.editLineNumber.Text); // doesn't work
}
}
As you can see from the commented code I have a TextBox control called editLineNumber which is on my other form (GoToForm).
My problem (and likely a beginner question) is why does editLineNumber not show in the intellisense menu when I type gotoForm.?
How do I access the editLineNumber control from the form GoToForm?
The error message for the // doesn't work commented line is:
Error CS1061 'Form' does not contain a definition for 'editLineNumber'
and no extension method 'editLineNumber' accepting a first argument of
type 'Form' could be found (are you missing a using directive or an
assembly reference?)
Unless I am missing something obvious, why are controls that exist on another form not publically available to all forms? I understand that C# / Visual Studio is different to Delphi but the way Delphi lets you access and see all controls on all forms without any extra works seems more logical to me. Why does C# / Visual Studio hide controls on secondary forms, for what purpose can this be beneficial?
The editLineNumber control is private. You can change it to be public, but that's discouraged.
Instead, create a property in GoToForm that returns the value you want.
public string LineNumber
{
get { return this.editLineNumber.Text; }
}
Now you can just reference your new property:
if (dialogResult == DialogResult.OK)
{
MessageBox.Show(gotoForm.LineNumber);
}
Especially if you're new to C# and WinForms, don't touch designer code with a 10 foot pole. As Grant Winney said, use a property:
public string GetLineNumberText
{
get { return this.editLineNumber.Text; }
}
It should be mentioned that it's important to be aware of the directional nature of forms. That is to say, if I make Form1 and then define Form2 inside of it, you'll want to be careful how you communicate between the two forms. Properties are nearly always a better alternative than accessing form elements directly - it makes the code very difficult to change otherwise. If you, for example, removed editLineNumber from the other form or renamed it, every instance in the parent form would have to be edited. If you use a property, then you only have to change it in one place.
Related
In my app namespace = DRT, I'm creating control classes (e.g., button, textbox) that derive fron their corresponding Windows control classes, e.g.,
internal abstract class DRT_Button_Abstract : Button
{
....
}
internal class DRT_Button_CancelSearch : DRT_Button_Abstract
{
....
}
internal class DRT_Button_StartSearch : DRT_Button_Abstract
{
....
}
All together I currently have 13 derived classes that derive either from one of my abstracts or from a Windows control class. After a successful build, I see my control classes (e.g., DRT_Button_CancelSearch and DRT_Button_StartSearch) on the Toolbox and I successfully drop them onto my main form. All is fine for a while, but ultimately, I'll go to open the main form.cs [Design] (i.e., the UI designer) and it will show the error The variable '{control property name}' is either undeclared or was never assigned. for some combination of my controls.
When I examine the main form Designer.cs file, the expected code for all the controls is present EXCEPT for the expected new statement. They are not present in the main form Designer.cs file. For example, I expect to see this.drt_Button_CancelSearch = new DRT.DRT_Button_CancelSearch(); but its missing
I've tried ignoring the error, proceeding to the UI designer windows to re-apply the lost controls, but the problem just repeats with the newly applied control
What the heck is going on? Is there a way to recover from this situation?
This is most likely a problem of the Designer not being able to clear/reload its cache. There is not much you can do. In the past I:
closed and reopened all designers that have user controls
put all the controls in a separate project (in the same solution)
put all the controls in a separate solution/Visual Studio instance and set a proper reference to the controls' dll (or even nuget package)
With the first two options I have had varying success. Reopening the designer is not very convenient and doesn't work.
That last option is the best but also the most annoying because every adjustment requires a rebuild of the project and update of the reference/package.
Also make sure that all controls that you create have public default constructors and function well when this constructor is used.
I'm using a user control (uc1) inside a Windows form (f1) in order to Display some of the elements of my form.
There (uc1) though I Need to Access a few elements of the form (f1). Thus I had the following line i the load:
private void UC1_Load(object Sender, EventArgs e)
{
F1 parentFrom = (F1)this.parent;
}
Now this works absolutely fine on execute BUT when I try to open F1 in the designer I get the error (Translation from my mother language):
The object of the type "System.Windows.Forms.Form" can not be
transformed into the type "F1".
Thus I can't open it in the designer without ignoring this "error". My question here is thus am I doing something wrong or can I somehow avoid this error?
You can either check for null and only work with it if it's valid, which you should probably be doing anyway:
F1 parentFrom = this.parent as F1;
if(parentForm != null)
{
// Do something.
}
Or you can check LicenceManager.UsageMode to see if the control is running in design mode:
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
F1 parentFrom = (F1)this.parent;
}
Or why not even a mix of both.
As a side note, it seems to defeat the point of a user control if it can only be used directly on one specific form. Perhaps you do have a valid use case, or perhaps you should think about refactoring your approach. For example, if you want something to happen on the form when the user control is updated you could use a custom event and the form can take the appropriate action when the event is fired.
My application (namespace) has a master form (Form) that contains a panel (panel).
When the master form loads, it calls a subform into it's panel. That subform acts as a splash page. It has a "launch" button on it. When the button is clicked, the subform should hide and a new form should load into the panel.
private void buttonLaunch_Click(object sender, EventArgs e)
{
this.Hide();
Hub NewHub = new Hub();
NewHub.TopLevel = false;
NewHub.AutoScroll = true;
Master.panelMaster.Controls.Clear();
Master.panelMaster.Controls.Add(NewHub);
NewHub.FormBorderStyle = FormBorderStyle.None;
NewHub.Show();
}
I'm getting the error:
Error 1 An object reference is required for the non-static field, method, or property 'Manager_0._2.Master.panelMaster'
I'm not sure how to interpret the error to resolve the issue.
Okay, assuming you have a class called namespace.class that contains a member named panel, the compiler is telling you that you seem to be trying to access panel via the class itself rather than an instance of the class (i.e. an object). To make an instance of class, do something like this:
namespace.class c = new namespace.class();
Then you can access the property or field named panel on that object:
c.panel.Controls.Clear();
Note: your naming choices are very poor. Calling a namespace namespace or a class class is just asking for trouble. Here are some recommended naming conventions:
Naming Guidelines
Update: from a closer read of your question, it appears that you're trying to add a Form to a Panel. Once you get past this compilation issue, you're going to start getting runtime errors, because that's just not how Windows Forms works. You can't put a Form in a Panel. Forms are top-level UI elements. I honestly don't understand your goals here well enough to suggest what to do instead.
I was wondering is it possible to prevent Visual Studio from updating specific lines that are changed by me?
For example i have separate resource only project (images, sounds, etc). I change some lines in Form.Designer.cs and make so all images are loaded from resource dll. But once i update Form it self everything goes back to default and all resources that were used by form gets copied to Form.resx file.
How could i solve this?
Nope.
As stated in the begining of the file, the *.Designer.* is an auto generated file. It's rebuilt every time that the file it depends upon is saved, so you should never change any code there that you don't want to be messed.
It is preferable to separate the code that the form designer generates from the code that you want to have some control over. The order in which you need to address this code can then be handled within the constructor of the form. Example:
namespace FormTest
{
public partial class Form1 : Form
{
private Label PostAddedLabel;
public Form1()
{
InitializeComponent();
PostInitializeComponents();
}
private void PostInitializeComponents()
{
if (!this.DesignMode)
{
PostAddedLabel = new Label();
PostAddedLabel.Left = 100;
PostAddedLabel.Top = 30;
PostAddedLabel.Text = "The Post-added Label";
this.Controls.Add(PostAddedLabel);
}
}
}
}
We can simply design the form within the designer, after a successful design phase we then can MOVE the declaration, assignments and related code that we want to separate to the PostInitializeComponents method.
By using the !this.DesignMode decision, the form will show the separated controls in Runtime mode. When in designer-mode these controls will not be shown, assuring that the system will not affect these controls when designing the form.
In case you want to use this methodology also in usercontrols, try to embed the "IsDesignerHosted" method over "DesignMode" from the following article: DesignMode with Controls
Hope this answers the question?
No. Visual Studio does not "update" the Designer file, it deletes it and writes an all new copy. No possible way to do what you want.
You should add your code to your code behind. It's the same class.
I have an object that starts a thread, opens a file, and waits for input from other classes. As it receives input, it writes it to disk. Basically, it's a thread safe data logging class...
Here's the weird part. When I open a form in the designer (Visual Studio 2008) that uses the object the file gets created. It's obviously running under the design time vhost process...
The odd thing is I've not been able to reproduce the issue in another project. I'm not sure what the rules are for code that gets executed in the designer and code that does not. For example, creating a file in a Windows Forms constructor doesn't actually create the file at design time...
What is the explanation? Is there a reference?
The constructor of a control or form does not get executed when editing that class in the designer (nor does OnLoad get called). I've occasionally used this to set one value in the designer (eg. making its child controls all Visible in the designer) but override some of them to a different default value in the constructor (eg. hiding certain child controls which will only show in certain circumstances, such as an indicator on a status bar).
However, the constructor does get executed if the control is placed as a child on another control or form in the designer. OnLoad gets executed as well. This may be how your logging code was getting accidentally triggered in the designer.
For detecting design vs runtime, an answer to another question has screenshots of some emperical tests showing the values returned by some common approaches. It appears that a child control of a child control (two levels down) of the form or control being edited in the designer sees its own DesignMode == false, so the normal property check will fail to protect code (eg. in the OnLoad method) for controls nested within a control added in the designer. If you were checking DesignMode as one would expect, it could be the nesting which caused it to get around that check. It also always sees DesignMode == false within the constructor.
Also, note that the LicenseManager.UsageMode check only sees DesignTime within the constructor; when OnLoad is called it is within a RunTime LicenseContext. The most complete solution seems to be to check LicenseManager.UsageMode in the constructor of the control or form (or component) and save the setting to a member variable or property which you can check later to avoid running code that should never run in the designer even when nested. There's also another approach in another answer to that other question which accounts for nesting but only works outside the constructor.
You can check the UsageMode of the LicenseManager, to check if the code is in design time or not.
System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime
Here is a quick example:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Test
{
public class ComponentClass : Component
{
public ComponentClass()
{
MessageBox.Show("Runtime!");
}
}
}
When this component gets add to your form in the designer, you will immediatly get a message box.
To prevent this you can add a simple if statement to check if the code is not in design time
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Test
{
public class ComponentClass : Component
{
public ComponentClass()
{
if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
{
MessageBox.Show("Runtime!");
}
}
}
}
After adding the if statement, the messagebox no longer appears when the component is added to the form via the designer.
Well, since this has been resurrected anyway, here's the function I use to determine whether I'm in design mode:
public static bool IsAnyInDesignMode(Control control){
while(control != null){
if(control.Site != null && control.Site.DesignMode)
return true;
control = control.Parent;
}
return false;
}
This handles the case where the control is a child created by another control. The DesignMode property is only set for controls created by the designer itself.
You could also use this to check if the Visual Studio Designer is running the code:
public static bool DesignMode
{
get { return (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv"); }
}
Then in Form_Load:
if (!DesignMode)
{
// Run code that breaks in Visual Studio Designer (like trying to get a DB connection)
}
However, this is less elegant than using the LicensManager.UsageMode, but it works (until Microsoft changes the name of the process Visual Studio runs under).
There are some things you shouldn't do with the designer. I don't have any hard evidence, but I found that the Windows Forms designer hates it when you take away the default constructor from it. Just go ahead and create new overloads, but leave the empty constructor in place.
Also try to avoid doing Form_Load events in base classes you inherit from.