Working with multiple forms using c# in Visual Studio - c#

I'm currently developing a Windows Form Application that uses two forms. I have no problems linking between the two forms. My issue is accessing a variable in Form2 that was created in Form1. How do you make a variable accessible to multiple forms in the same project?. I honestly tried to look for an answer, but could not find anything. Any help would be appreciated.
Here is the code for Form1:
namespace HourlyAlarm1
{
public partial class AlarmToneSetter : Form
{
public bool halfHourSelected;
public AlarmToneSetter()
{
InitializeComponent();
}
private void okButton_Click(object sender, EventArgs e)
{
if(halfHourRadio.Checked)
{
halfHourSelected = true;
}
else
{
halfHourSelected = false;
}
Form1 f1 = new Form1();
f1.ShowDialog();
}
public bool getHalfHourSelect()
{
return halfHourSelected;
}
}
}
Here is the code for Form2:
namespace HourlyAlarm1
{
public partial class Form1 : Form
{
int min;
System.Media.SoundPlayer sp;
public Form1()
{
InitializeComponent();
}
private void playSound()
{
sp = new System.Media.SoundPlayer(HourlyAlarm1.Properties.Resources.chipfork);
sp.Load();
sp.Play();
}
private void timer1_Tick(object sender, EventArgs e)
{
TimeLabel.Text = DateTime.Now.ToLongTimeString();
min = DateTime.Now.Minute;
if(HourlyAlarm1.AlarmToneSetter.g)
if(min == 0)
{
playSound();
}
}
}
}

If you want a variable which is accessible to any form within the project, mark it as static. That way you don't need a specific instance of the class that it's in to be able to access it.

You can use the forms Tag property if you want to pass just one variable.
Form1 f1 = new Form1();
f1.Tag="some value";
f1.ShowDialog();
and then in form 2 access it via it's own Tag property. Since it is stored as an object you will have to convert it to whatever datatype your application requires.
Example for getting the value in the new form:
string value = this.Tag.ToString();

As the question currently stands, it looks like you're trying to edit the halfHourSelected field in your AlarmToneSetter class from the Form1 class. To do that, there are several options:
Since this field is already public you can simply edit it like this (form Form1):
HourlyAlarm1.AlarmToneSetter.halfHourSelected = true;
or, if you plan on using it several times, add
using HourlyAlarm1;
/**
* declare the namespace, the class, etc.
*/
AlarmToneSetter.halfHourSelected = true
(Edit: As mentioned by Jason, this can be rewritten to be a property and comply with the style guide) However, since you already wrote a Java-style getter for this field, you should rewrite it in C# style; changing the declaration to
public bool HalfHourSelected{get;set;};
which will add the getter and setter for the property automatically.
Now, if you want to make this field persistent (that is, the configuration value should be saved across multiple executions of the program) then you should consider adding it to the settings of your project, and reference it like this
HourlyAlarm1.Properties.Settings.Default.halfHourSelected = true;
HourlyAlarm1.Properties.Settings.Default.Save();
or, as always, if you're gonna access them several times,
using HourlyAlarm1.Properties;
/**
* declare the namespace, the class, etc.
*/
Settings.Default.halfHourSelected = true;
Settings.Default.Save();
Yes, this is my first time answering a question in SO. If you have any recommendations, let me know in the comments! I'll appreciate the feedback.

Pass them as parameter of constructor. This way is used to set once time at creating an instance of class
public Form1(int i, string s, object o){}
Create public get/set. This way is used to set multiple times, but their value will be different among instances of class.
public int Price { get; set;}
Form1 frm1 = new Form1();
frm1.Price = 123;
Create public static field. This way is used to set multiple times, and it is same among instance of class.
public static int Price = 0;
Form1.Price = 123;

First of all public fields are discouraged in .NET: you should use properties.
Your problem is that bool is a value type and you can't "bind" it between forms, you need a reference type.
public class ReferenceBoolean
{
public bool Value{get;set;}
}
public class Form1
{
protected ReferenceBoolean HalfHourSelectedReference{get;set;}
public bool HalfHourSelected
{
get{return this.HalfHourSelectedReference.Value;}
set{this.HalfHourSelectedReference.Value = value;}
}
public Form1()
{
this.HalfHourSelectedReference = new ReferenceBoolean();
}
}
public class Form2
{
protected ReferenceBoolean HalfHourSelectedReference{get;set;}
public bool HalfHourSelected
{
get{return this.HalfHourSelectedReference.Value;}
set{this.HalfHourSelectedReference.Value = value;}
}
public Form2(ReferenceBoolean halfHourSelected)
{
this.HalfHourSelectedReference = value;
}
}
Now this might look all fine and dandy but there is one thing I did not do, because I'm not sure if you need it, if you update this value and have it bound to the UI in your form the update will not be reflected in the form. To do that you must implement something like the IPropertyNotificationChange pattern, which works much better in WPF.

Related

How to pull data from datagridview to another form's textbox

I am trying to pull the data from a datagridview value in form1 to a textbox in form2 .
Form 1;
public string xxx;
public string GetX()
{
return xxx;
}
private void addADocumentToolStripMenuItem_Click(object sender, EventArgs e)
{
if (dataGridView1.SelectedRows != null)
{
xxx = dataGridView1.CurrentRow.Cells["Name"].Value.ToString();
AddDocumentForm adf = new AddDocumentForm();
adf.ShowDialog();
}
else
{
MessageBox.Show("Please choose a record.");
return;
}
}
In Form 2 trying to pull the xxx value into textbox;
using (Form1 f= new Form1())
{
string result= f.GetX();
txtSavedDocumentID.Text = result;
}
In Form2, you are creating a new instance of Form1:
using (Form1 f= new Form1())
As I can't see your whole code, I might be wrong - but I think it is very likely that this is not what you want.
What you actually want is to call GetX() on an existing instance of Form1.
Now you need some way to know the correct instance of Form1 on Form2. One easy possibility is, but only if you will always just use one instance of Form1, to expose a static property on Form1 that will provide a singleton instance of it to the outside world:
public class Form1
{
// ...
public static readonly Form1 Instance {get; private set};
public Form1()
{
Instance = this;
}
// ...
}
In Form2, instead of creating a new instance with your using statement, you'd access it like this:
string result = Form1.Instance.GetX();
txtSavedDocumentID.Text = result;
Now be aware that if your application has the possibility to have multiple instances of Form1 open, this won't work and will have bad side effects. In this case, another approach is needed. But I hope you got the idea now what might be wrong and you can work it out.
Edit: While this will solve your issue, hopefully, I want to add that it's not a very good approach having your Forms need to know about each other. You should have some model classes in the background where your Forms can read and write data on, without the need to interact with each other directly. But exploring this further would be out of scope of this question.
changed Form2 ;
public Form2(string qs)
{
InitializeComponent();
textBox1.Text = qs;
}
In Form1;
get the text from combobox and pass it to form2 ;
{
var xxxx = (cbxEmployeeName.GetItemText(cbxEmployeeName.SelectedItem));
Form2 f = new Form2(xxxx);
f.Show();
}

C#: Trying to use control elements in different class - "object reference is required"

I am brand new to C# (I apologise if my question is noobish - I'm teaching myself, so it's a bumpy process). I am trying to develop a winform and since some of the methods are pretty long, I am trying to keep it in a couple classes. This is what I'm kind of hoping to achieve:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1();
}
}
public class longCalculations
{
private void LongMethod1()
{
// Arbitrarily long code goes here
}
}
I'm doing this in an attempt to keep the formMainForm class tidy and be able to split any calculations into manageable chunks. However, I'm encountering problems with using form controls (e.g. check boxes, numeric up-down controls, etc.) in my non-form classes.
If I leave them as is (e.g. CheckBox1) I get a the name does not exist in the current context error. I searched around and I found that it's because that box is defined in a different class. However, if I change it to formMainForm.CheckBox1, the error is now an object reference is required for the non-static field, method or property. Again, I looked around and it appears that that is due to the form initialization method not being static.
If I change public formMainForm() to static formMainForm(), the error now moves to InitializeComponent(); and I do not know where to go from here. I also tried making an instantiation of the formMainForm() method, but that didn't do anything (the code I attempted to use is below. I found it somewhere on this site as an answer to a similar problem).
private void formLoader(object sender, EventArgs e)
{
shadowrunMainForm runForm = new shadowrunMainForm();
runForm.Show();
}
How can I use the formcontrol names in other classes?
P.S. It is my first post here - I am super sorry if I have missed this question already being asked somewhere. I did search, but I didn't find what I was looking for.
EDIT
It seems I hadn't made myself clear - this was just an example of code and my problem is with the second class, not the first one. I have now simplified the code to:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
}
public class longCalculations
{
private void LongMethod1()
{
List<CheckBox> listOfBoxes = new List<CheckBox>();
listOfBoxes.Add(CheckBox1);
// The code displays an "object reference is required for the non-static field, method or property" error at this stage. Changing the "CheckBox1" to formMainForm.CheckBox1 doesn't help
// Arbitrarily long code goes here
}
}
LongMethod1 works perfectly fine when placed in the formMainForm partial class. Moving it to the other form makes it unable to take data from those checkboxes.
I believe this line longCalculations.LongMethod1(); is throwing error cause you are trying to access a instance method as if it's a static method and as well it's defined as private method which won't be accessible outside the class. You need to create an instance of longCalculations class before accessing any of it's member or method(s) and mark the method public like
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations ln = new longCalculations();
ln.LongMethod1();
}
public class longCalculations
{
public void LongMethod1()
{
// Arbitrarily long code goes here
}
}
(OR) If you really want it to be a static method then define accordingly with static modifier like
public class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
Now you can call it like the way you are trying
public static class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
If you're going to make a call longCalculations.LongMethod1();, then you need to make your class static as such.
Or you leave it as not static method by calling
longCalculations lc = new longCalculations()
lc.LongMethod1();
As for accessing controls in separate classes, you can pass in the form and make the controls public which can be dangerous.
So on your Form.designer.cs, change any control you may have to public modifier. Then you would make a call like this...
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1(this);
}
public void LongMethod1(Form1 form)
{
// Arbitrarily long code goes here
form.label1.Text = someString;
//more settings and whatnot
}
Or do something like this:
public class longCalculations
{
public string LongMethod1()
{
// Arbitrarily long code goes here
return myString;
}
}
longCalculations lc = new longCalculations()
string result = lc.LongMethod1();
this.label1.Text = result;
Ideally, your longCalculations class would not attempt to modify the form directly. Instead it would return an object that the form could use to update its controls.
If you need to access the form directly from the longCalculations class, first change the method to accept an instance of your form
public void LongMethod1(formMainForm myForm)
Then you can pass the form itself as a parameter
var calc = new longCalculations();
calc.LongMethod1(this);
In your other class, you need to have an instance of your formMainForm class:
var myForm = new formMainForm();
Then you can access its members like this:
myForm.CheckBox1.Checked = true;

How do I use accessors?

I am a complete amateur at programming and am trying to learn proper code design. I`m trying to learn how to use accessors but can't seem to get it to run properly. This is what I am trying to run:
class Classy
{
public void changeLine(string change)
{
Form1 form1 = new Form1();
form1.Line = change;
}
}
public partial class Form1 : Form
{
string line = "";
public string Line
{
get
{
return line;
}
set
{
line = value;
}
}
private void button2_Click(object sender, EventArgs e)
{
line = "";
string change = "cake";
Classy classy = new Classy();
classy.changeLine(change);
MessageBox.Show(line);
}
When I click the button, it shows blank text. From what I understand these are the steps it take:
variable change with "cake" value is passed to classy's changeLine method.
changeLine method sets Form1 line to variable change with "cake" value.
MessageBox displays line variable of "cake" value.
Why does this not work?
This is happening because you are creating a new instance of Form on the changeLine method. This new instance is different from the one the event was fired, or the button was clicked.
In order to use the correct Form reference, you may pass the actual reference as an argument:
public void changeLine(Form1 form, string line) {
form.Line = line;
}
You would call this method (from the form) like this:
classy.changeLine(this, change);
this is the current Form1 instance, it is the one you want to modify. You don't want to create a new one.
Okay. You've got a Form1 object and the window it represents and controls is displayed on screen. You click a button and it invokes a method.
line = "";
This line is a private field which happens to be the backing field to the Line property. At this point accessing either the line field or the Line property will return "".
string change = "cake";
A string local to this method.
Classy classy = new Classy();
Okay, we've a new object of type Classy called classy.
classy.changeLine(change);
Let's look at what this call does:
Form1 form1 = new Form1();
You now have a different Form1 object. If you called form1.Show() you would now have two windows on the screen`.
form1.Line = change;
Sets the Line property (and hence the line field) of this new, different Form1.
We now return back to the calling method:
MessageBox.Show(line);
Shows the value of the line field of the original Form1 object.
To demonstrate a property being set from outside the class you could do something like:
class Classy
{
public void changeLine(Form1 form1, string change)
{
form1.Line = change;
}
}
public partial class Form1 : Form
{
string line = "";
public string Line
{
get
{
return line;
}
set
{
line = value;
}
}
private void button2_Click(object sender, EventArgs e)
{
string change = "cake";
Classy classy = new Classy();
classy.changeLine(this, change);
MessageBox.Show(line);
}
}
Here because the Form1 passes itself (this refers to the object of the method running) to classy its own Line property will now be used.
Alternatively:
class LineStorer
{
private string _line;
public string Line
{
get { return _line; }
set { _line = value; }
}
}
public partial class Form1 : Form
{
private void button2_Click(object sender, EventArgs e)
{
var storer = new LineStorer();
storer.Line = "cake";
MessageBox.Show(storer.Line);
}
}
Here the form is first setting and then getting a property in another object.
Note also that objects can use their own properties instead of the backing field:
public partial class Form1 : Form
{
private string _line;
public string Line
{
get { return _line; }
set { _line = value; }
}
private void button2_Click(object sender, EventArgs e)
{
Line = "cake";
MessageBox.Show(Line);
}
}
From the inside, so to speak, there's really not much difference whether one uses a field or a property, but using properties does have an advantage in that if some day you changed from this simpler property (read and write from and to a field and do nothing else) to one that is more complicated (common cases including validation checks on all setting, but you are far from limited to that) then you'd only have to change the one place where the property is defined rather than the, perhaps very many, places where it is used.
(It may seem like using Line is more work than just using line, because it does after all call into more code, and therefore using properties rather than fields would be a slight inefficiency that would add up over time. Luckily the jitter is smart enough to "inline" simple getters and setters when the code is run, so there is in fact no cost to them).
What you do is what you get. You want to show the value of line, but you never set it to another value before showing it. Whatever you do in these three lines of code has nothing to do with changing the value of line IN THIS PARTICULAR INSTANCE OF THE CLASS FORM1.
string change = "cake";//You declare and initialize a variable
Classy classy = new Classy();//You create an instance of class Classy
classy.changeLine(change);//You invoke a method in that class that has no clue of what is going on this side
Yes, it does set the value of line to "cake", but on ANOTHER OBJECT. But you could still get the behavior you need in at least two ways:
You could have an instance variable in the Classy class of type Form1 and have a constructor that would receive a Form1 object as a parameter. Then in your changeLine method, instead of creating a brand new Form1 object you could change the line of that particular instance variable, like this:
public class Classy{
private Form1 _form1;
public Classy(Form1 form1){
_form1=form1;
}
public void changeLine(string change){
_form1.Line=change;
}
}
You could change your changeMethod to accept an additional parameter of type Form1 and then pass it this when invoking it inside Form1
public void changeLine(string change,Form1 form1){
form1.line=change;
}
And on the Form1 side:
classy.changeLine("cake",this);

Opening new Windows Form from another Form

Now before anyone goes and marks this question as a duplicate, I'd like to say that my problem differs from the other ones. I'm trying to open an existing Form from another, but I'm having problems in the sense that I've set some Forms to 'host' others (To transfer variables between them). Here's what I mean:
public partial class Schedule_Tasks : Form
{
readonly Schedules schedules;
public Schedule_Tasks(Schedules host)
{
this.schedules = host;
InitializeComponent();
}
So in this snippet of code, I'm trying to get the value of some variables from the Schedules form, into the Schedule_Tasks Form. So I've used the 'host' system. SO far this method works fine, but my problem occurs when I try to open a specific Form, from another that isn't 'hosting'. For example using:
new Schedules().Show();
So obviously when I'm declaring this, I'd put something like 'this' in the brackets after Schedules, but that doesn't work if the Form is being called outside of the 'host' Form. I'd just like to now is there something I'm missing or can change? Please let me know if any part isn't clear, it's a little difficult to explain. Any help is appreciated, Cheers.
EDIT
Here's the code that I'm working with now:
public partial class Schedual_Tasks : Form
{
readonly Scheduals scheduals;
public string selectedDevice;
public string getPath;
public string totalPath;
public Schedual_Tasks(Scheduals host)
{
this.scheduals = host;
InitializeComponent();
selectedDevice = scheduals.itemSelected;
}
private void Schedual_Tasks_Load(object sender, EventArgs e)
{
}
private void changeDirectory_Click(object sender, EventArgs e)
{
new Folder_Browser(this).Show(); //Error Occurs here
}
}
And here is the constructor for Folder_Browser, which is the Form I'm trying to call:
readonly Back_up_Options backOptions;
public string deviceSel;
public Folder_Browser(Back_up_Options host)
{
InitializeComponent();
this.backOptions = host;
deviceSel = backOptions.deviceSel;
}
Your (Folder_Browser) Form's constructor is declared as
public Folder_Browser(Back_up_Options host)
That means you cannot pass a Schedual_Tasks instance as the host parameter because there is no way to convert from a Schedual_Tasks object into a Back_up_Options object. The compiler detects this and creates an error message.
If you cannot pass the host parameter, you can pass null instead:
new Folder_Browser(null).Show();
But then you need to make sure that you check the backOptions member for null reference each time you use it. For example:
if(backOptions != null)
{
deviceSel = backOptions.deviceSel;
}
else
{
deviceSel = null;
}
That in turn means that you will need to check deviceSel for null each time you use it and so on.
And of course, using your Form without a "host" needs to be possible at all. If you have code that requires a "host", it will fail.

How to pass a reference into and out of a class

I would like to pass the reference of a variable into a class, use it and then get it out later.
Something like this:
// Create the comment Screen
string newCommentText = "";
commentsScreen = new CommentEntry(this, ref newCommentText);
commentScreen.ShowDialog();
...
_dataLayer.SaveOffComment(newCommentText);
And then in the comment class:
public partial class CommentEntry : Form
{
public CommentEntry(Control pControl, ref string commentResult)
{
InitializeComponent();
control = pControl;
// ***** Need a way for this to store the reference not the value. *****
_commentResult = commentResult;
}
private string _commentResult;
private void CommentEntry_Closing(object sender, CancelEventArgs e)
{
_commentResult = tbCommentText.Text.Trim();
}
}
Is there someway that newCommentText can have the value set in _commentResult in the closing method?
NOTE: Clearly it would be easy to just set a variable in my class and access it after the ShowDialog. This example is only a an approximation of my real issue and accessing any variables in the class after ShowDialog is done is not possible.
This will never work with a String as they are immutable and the variable will change to point to a new instance.
You have two basic options. The first is to simply have a getter for the result so it can be accessed when it is needed later. The other option is to have the owner pass in a delegate method that can be called passing in the resulting value. The owner would then receive the value when the CommentEntry is closing.
You generally can't directly store a 'reference to a reference' in C#, but you could do something like this:
public interface ICommented
{
string Comment { get; set; }
}
public class MyClass : ICommented
{
public string Comment { get; set; }
}
public partial class CommentEntry : Form
{
public CommentEntry(Control pControl, ICommented commented)
{
InitializeComponent();
control = pControl;
// ***** Need a way for this to store the reference not the value. *****
_commented = commented;
}
private ICommented _commented;
private void CommentEntry_Closing(object sender, CancelEventArgs e)
{
_commented.Comment = tbCommentText.Text.Trim();
}
}
So now your form can edit the comment of any class that has said it knows how to be commented upon.
As Dan Bryant pointed out, you cannot do that directly. One option is to wrap the reference into a class, but that requires writing a lot of boilerplate code. A simpler option is to use delegate and lambda functions (in C# 3.0) or anonymous delegates (C# 2.0):
string newCommentText = "";
// Using lambda that sets the value of (captured) variable
commentsScreen = new CommentEntry(this, newValue => {
newCommentText = newValue });
commentScreen.ShowDialog();
_dataLayer.SaveOffComment(newCommentText);
A modified version of the CommentEntry form would look like this:
public partial class CommentEntry : Form {
public CommentEntry(Control pControl, Action<string> reportResult) {
InitializeComponent();
control = pControl;
// Store the delegate in a local field (no problem here)
_reportResult = reportResult;
}
private Action<string> _reportResult;
private void CommentEntry_Closing(object sender, CancelEventArgs e) {
// Invoke the delegate to notify the caller about the value
_reportResult(tbCommentText.Text.Trim());
}
}
Make newComment property of CommentEntry class.
Here, try out what this guy is doing.
http://www.c-sharpcorner.com/UploadFile/gregory_popek/WritingUnsafeCode11102005040251AM/WritingUnsafeCode.aspx

Categories

Resources