I'm trying to develop an application on which I have an MDIParent and several MDIchilds. I would like to create a global variable on my MDIParent, and I want that variable to be accessible from its children.
How can I do that??
If Matthew Watson's answer isn't what you're after...
If you just want your "global" variable to be accessible to the children of a particular MDI parent form, then just use a regular instance property on it. The children will be able to access it through child.MdiParent.MyVariable (after casting MdiParent to the appropriate type). For example:
class ParentForm
{
public int MyVariable
{
return 1;
}
}
class ChildForm
{
public void MyMethod()
{
var parent = this.MdiParent as ParentForm;
foo = parent.MyVariable;
}
}
A quick note: it's generally best to avoid using "global" variables (i.e. static fields/properties) as much as possible. Keep all the different parts of your program's state confined to the appropriate context to reduce coupling. See the Law of Demeter.
A global variable in C# is effectively a static field or property.
So just add a public static property to MDIParent:
public static int MyGlobalInt
{
get
{
return 42;
}
}
That will be shared among ALL instances of MDIParent. If that's not what you meant, then it's not a global you want.
Related
I am making a WinForms application using C#. I would like to declare a variable to access throughout the program but I do not know where to initialize it?
The program is BStree-based and this is what I am trying to initialize:
BSTree<string> record = new BSTree<string>();
If the program is trivial - eg just one form and no additional class files etc (eg a simple school assignment), then you'd probably just declare a static global inside your Form class but outside any methods, eg
public class MyForm : Form
{
static private BSTree<string> record = new BSTree<string>();
public MyForm()
{
...
}
...
}
And then access it from within your MyForm instance(s) as eg MyForm.record.
Note also that you can just declare the variable (eg static private BSTree<string> record;) outside the methods, but then initialise it (to eg new BSTree<string>()) from within eg your constructor. There's a very subtle difference between the two approaches (ie effects the order in which various members are initialised), but this is rarely of consequence.
Be aware that the static member "belongs" to the class, and so there's only one "version" of that member. ie there's not a separate "version" of that member for each instance of your class.
But otherwise, you might have a static "configuration" or "globals" class, that contains these values (and perhaps other values read from eg a config file):
public static class MyConfig
{
static public BSTree<string> record = new BSTree<string>();
...
}
and then you'd access this from within your MyForm class like MyConfig.record.
Although - ideally you should expose properties not fields, eg:
public static class MyConfig
{
static private BSTree<string> record = new BSTree<string>();
static public BSTree<string> Record
{
get {return record;}
set {record = value;}
}
...
}
and then you'd access this from within your MyForm class like MyConfig.Record. This would give direct access to the underlying record member.
But a more robust approach would be to create specific methods that operate on the members on behalf of the consumer, rather than just exposing the members directly to the consumer. That way you can limit the types of operations that are allowed on them, and can expose the results in a specific way etc. ie you're adding value to the underlying members, rather than just "holding" them.
public static class MyStaticBStreeInstance
{
public static BSTree Instance {get;private set;}
static MyStaticBStreeInstance()
{
Instance = new BSTree<string>();
}
}
and from anywhere , you can access it by using below code
var bstree = MyStaticBStreeInstance.Instance
Updated to reflect to my own source
I'm in process of building my first winform application in c# and I'm trying to figure out the best practice for structuring my classes to work smoothly when I use them in my forms.
I have a couple of examples which I will try to explain the best way i can.
When working with get/set variables in a class, the best practice should be something like this:
JobMove.cs
public class JobMove
{
private List<string> jobNames { get; set; }
public string Scanner;
public JobMove()
{
this.Scanner = Properties.Settings.Default.Scanner;
}
public void ListSelected(ListBox lbx)
{
foreach (string jName in this.jobNames)
{
lbx.Items.Add(jName);
}
}
public static List<string> GetCheckedJobs(ListView lw)
{
int countChecked = lw.CheckedItems.Count;
int itemCount = 0;
List<string> jList = new List<string>();
foreach (ListViewItem item in lw.CheckedItems)
{
JobInfo jobInfo = Job.Find(Convert.ToInt32(lw.Items[item.Index].SubItems[1].Text));
jList.Add(jobInfo.Name);
itemCount++;
}
return jList;
}
}
My problem is when I combine this with my forms and I call this, then I would try to do something like this:
MyForm1.cs
public partial class MyForm1 : Form
{
private void btnMoveJobs_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Scanner = cbxScanners.SelectedItem.ToString();
JobMove moveJobs = new JobMove();
frmMoveJobs FrmMoveJobs = new frmMoveJobs();
FrmMoveJobs.ShowDialog();
}
}
MyForm2.cs
public partial class frmMoveJobs : Form
{
public frmMoveJobs()
{
InitializeComponent();
JobMove moveJobs = new JobMove();
lblFrom.Text = moveJobs.Scanner;
moveJobs.ListSelected(lbxJobsToMove);
cbxMjScanners.DataSource = System.Enum.GetValues(typeof(Scanners));
}
}
But when I call MyClass in MyForm2 and I want to call the DoSomethingElse method, then myString will be reset to a null value. And that makes sense to me, but how do I work around this?
I tried to figure out what to use here to get easier around these flaws in my code, but my knowledge is far too weak to just implement an easy solution.
I know I could just store this variable in Settings.settings as an example, but to me that just seems like a real overload for such a simple task.
I might just need a point in the right direction to right on what to do in this situation.
If you do a MyClass myClass = new MyClass(); then indeed - the values are independent and unrelated. If you want to share the MyClass instance then pass the MyClass instance between the forms. Perhaps:
using(var form2 = new Form2()) {
form2.SensibleName = existingMyClassInstance;
form2.ShowDialog();
}
(note the using above btw; when using ShowDialog() it is your job to make sure the form is disposed; it only gets disposed automatically if using Show())
Firstly, they're properties, not variables (the variables are the underlying data source).
Secondly, the whole point of get/set accessors is so you can get and set the value without needing helper methods.
Thirdly, and as to your problem, you're creating a new instance of the class in each form (hinted at by the new keyword) and the value of the property will be whatever it is initialised as on construction of the instance (or not.) i.e. the values of properties are not shared between different instances of the same type.
Think of the mold for a key: I can get multiple instances of the key cut from a "blueprint", but any damage that one suffers won't be reflected by the rest - they're unique in that sense.
If you want the forms to both access the same instance of that type, then you will need to stash the instance somewhere in your code which is accessible to both.
A few options:
Pass in an instance of MyClass in the form2's constructor.
Make MyClass a static property of either Form1 or Form2 and access it via that on the other form.
Make MyClass static (not recommended).
If you want to use the instance of MyClass created in MyForm1 inside of MyForm2, you need to provide it to MyForm2.
Something like this would work:
public partial class MyForm2 : Form
{
public MyForm2(MyClass given)
{
InitializeComponent();
given.DoSomethingElse();
}
}
Easy Solution:
private static string myString { get; set; }
Why: because you initialize the class again when initializing Form2 and it will create a new class. With the "static" keyword you create a property which is the same in all instances of this class.
BUT: please read some books before continuing, this would be the solution to this problem, but the source of many others. Try to understand C# and Forms first, than (or alongside with reading/learning) start coding!
this is because each of your form has a new object of "MyClass".
To achieve what you want to do use a static property... this won't be initialized and gives back the same value for each object of MyClass
it looks like this
public class MyClass {
public static string myString { get; set; }
public void ChangeMyString(string newString)
{
myString = newString;
}
public void DoSomethingElse()
{
MessageBox.Show(myString);
}
}
Is it bad practice to put most variables at class level in a Form? Would these be considered global variables?
public partial class Form1 : Form
{
private string mode;
private int x, y;
public Form1()
{
InitializeComponent();
}
}
I'm using the variables in multiple controls when I declare them at class level.
What i get from the question is that if you are using as a Individual form that is not dependent on any form then all this variables will be private variables to the class. And if the form is called from somewhere else. Then also it will be private variables. If you really want to make a clear design then you can Create public properties over private variables that you want to expose to other class.
In that way you can put a limit access to the other class to the private variables by creating read only properties so that other classes cannot modify but can access it.
Those would be considered class-level globals (to distinguish from application globals.) The more important distinction in this case is that they are private to the class.
Class-level globals have their uses, so I definitely wouldn't call it a bad practice. A very good use for private class globals is when you plan to expose them through property accessors. For example:
public readonly properties whose values are controlled by logic internal to your class.
public properties with both set and get accessors (enabling custom validation logic in setter.)
However, I would say it's a good practice to make things local unless otherwise necessary. The reason is that you have less mutable state belonging to a class instance, so there is less potential for bugs like this:
private int EvilMethod1() {
x = (int) Math.Pow((double) y, 2);
return x;
}
private int EvilMethod2() {
y = (x + y) * 2;
return y;
}
// Assignments depend on the current values of x and y,
// as well as yielding unexpected side effects.
private void PureEvil()
{
// Return value depends on current y; has side effect on x while assigning y.
y = EvilMethod1();
// Return value depends on current x and y; has side effect on y while assigning x.
x = EvilMethod2();
}
Those aren't considered global variables. They are global only within the Form1 class, not the entire program.
It depends what the variables are used for.
If they are only used within a single method they should be local to that method.
If they describe the state of the class and are used in multiple places they should be declared as class members.
They are private to the class Form1
Without knowing what the intent of your form is, it's hard to say whether what you're doing is good or bad. The variables shown here have class scope, and since they are private, they are not accessible outside of Form1 and are not considered "global."
If you truly want global variables, create a static class with private static variables and public static accessors/mutators (a property in C#), and access the variable through the public property. See this answer for an example.
I'm pretty new to C# and I was trying out a few things. I have a label (named 'newLabel') in the form1.cs. I have a class named 'methods.cs'. In this class I have the method
public static void updateLabel()
what I want to do is:
public static void updateLabel()
{
newLabel.Text = "New Value";
}
but this doesn't work, probably because the method is in methods.cs and the newLabel is in form1.cs.
I had the same problem with declared variables. In the methods.cs I had the variable
int value;
but I couldn't use this variable in form1.cs. I fixed this by doing
public static int value { get; set; }
I have no idea what that did but it works, but I don't know how I can apply this trick with the label.
Could someone help me with this?
Thanks!
You should read up about OOP and encapsulation. Basically you want the form
to access private fields in another object (your class) - this is restricted by encapsulation, that's why you are running into problem - you can get around them by adding those fields and methods to the "public" interface that your class is declaring by making them public properties and methods, i.e in your example:
public int Value {get;set;}
Sometimes composition is used, i.e. in your example since your class is directly accessing the form you could have a form property on your class:
public Form ViewForm {get;set;}
It would be best if you learnt C# from tutorials, but the answer to this particular question lies with something called "scope"
Essentially, scope is the visibility of variables, classes, functions and objects. A variable marked "private" can only be seen within the thing that created it (if it's created inside a function it will always be private and any variables defined inside a function can only be used inside that function). If it's created inside a class only that class can use it.
Variables or functions denoted as public (this can only be done inside a class) can be seen from outside that class. To do that you would invoke myClass.myVariable to access the variable or myClass.myFunction() to access the function.
To denote the visibility of an object you use the keywords "public" or "private". Note: This only applies to variables and functions inside classes (it also applies to other things within classes, such as nested classes and structs, but that's outside the scope of this basic intro).
for example:
class myClass
{
private int myInt;
public void myfunction()
{
myInt = 1;
}
}
This will work, as myInt can be seen by anything inside myClass
class myOtherClass
{
private void myfunction()
{
myClass myObject = new myClass();
myObject.myInt = 2;
}
}
This will not, as myInt is private to myObject and only myObject can change it. myOtherClass does not have permission and it cannot see it.
class myOtherClassTwo
{
private void myfunction()
{
myClass myObject = new myClass();
myObject.myFunction();
}
}
This, thankfully, will work. myFunction was set as public in the myClass class, so it can be seen by anybody outside of the class.
Now the keyword static which you use has a whole different meaning. I advise you not to use it until you've learned about it as you're only adding additional complexity to your problems.
I hope this has cleared things up, though I must urge you to follow some real tutorials as these basics must be thoroughly detailed or you'll be caught out later on.
Since your updateLabel method accesses the label inside the form, correct object-oriented design would dictate that this method should be in the form, too. Then you have no problem accessing newLabel.
Technically speaking: newLabel doesn’t mean anything outside a form object. You could have several copies of your form, which would mean several copies of your newLabel; which of them should it refer to? Of course the computer won’t take a guess there; it’ll expect that you tell it which form you want to use.
The reason you couldn’t access the value variable is because it was private. If you had changed it simply to:
public static int value;
then it would have worked.
From the Form1, call the updateLabel method in the mothods class:
methods updateMethod = new methods();
newLabel.Text = updateMethod.updateLabel();
With this method in the methods class:
public static string updateLabel(){
return "New Value";
}
The case is this, I have two different forms from the same solution/project. What I need to do is to extract the value of a label in Form A and load it into Form B. As much as possible, I am staying away from using this code since it will only conflict my whole program:
FormB myForm = new FromB(label.Text);
myForm.ShowDialog();
What I am trying right now is a class with a property of get and set for the value I wanted to pass. However, whenever I access the get method from FormB, it returns a blank value.
I hope somebody can help me with this. Any other ways to do this is extremely appreciated. :)
public class Miscellaneous
{
string my_id;
public void SetID(string id)
{
my_id = id;
}
public string GetID()
{
return my_id;
}
}
You could do something like this:
Child form
public string YourText { get; set; }
public TestForm()
{
InitializeComponent();
}
public void UpdateValues()
{
someLabel.Text = YourText;
}
Initiate it
var child = new TestForm {YourText = someTextBox.Text};
child.UpdateValues();
child.ShowDialog();
With this approach you don't have to change the Constructor, you could also add another constructor.
The reason for them being empty is that the properties are set after the constructor, you could Also do someting like this to add a bit of logic to your getters and setters, However, I would consider not affecting UI on properties!
private string _yourText = string.Empty;
public string YourText
{
get
{
return _yourText;
}
set
{
_yourText = value;
UpdateValues();
}
}
In this case, the UI will be updated automaticly when you set the property.
You can use a static variable/method to hold/pass the value of a control (when it gets changed).
You can use form reference or control reference to get and pass values directly.
You can use custom event for that (notifying the code that subscribed).
btw. FormB myForm = new FromB(label.Text); did not work because you are passing by value and the value was empty at the moment of creation of FormB.
FormB myForm = new FromB(label); would have worked.
Well one approach to take is to create a singleton class in your application. When you form b loads or the label changes you update the singleton with the value. Then when form a needs the value it can just get the instance of the singleton within your application and it will have that value.
There are probably cleaner ways to do it but just thinking of an easy way to pass information back and forth and store any information needed for both forms.
EDIT: Here is an example of a singleton that I pulled from here:
http://www.yoda.arachsys.com/csharp/singleton.html
public sealed class Singleton
{
static readonly Singleton instance=new Singleton();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Singleton()
{
}
Singleton()
{
}
public static Singleton Instance
{
get
{
return instance;
}
}
}
Now all you need to do is put this class in a namespace that is accessible to both forms and then you can call the Instance property of this class and then reference your values. You can add properties to it as well for whatever you want to share. When you want to retrieve those values you would call it like this:
Singleton.Instance.YourProperty
((Form2)Application.OpenForms["Form2"]).textBox1.Text = "My Message";
declare public property varible in second form
Public property somevariable as sometype
and access it in first form using instance
Dim obj as New form2()
obj .somevariable ="value"