I have a windows Forms application with one form and a few classes.
I want to get the values of some textBoxes from the Form1 instance and extract the values.
My first way of achieving this was by using Application.OpenForms[] array to get the form but I realised that using a singleton on the class Form1 would be more efficient as I can have direct access and it would be impossible to make other instances.
Here is how I have set it up:
1. Controls class to gets controls from Form1
class Controls
{
//Request Form1 instance
private static Form1 form = Form1.GetInstance();
//Sets global values for easy access with getters and null setters
//--Variable 'form' is still null hence I get the NullReferenceException
private TextBox employer = form.Controls["textBoxEmployerName"] as TextBox;
private TextBox role = form.Controls["textBoxRole"] as TextBox;
private TextBox company = form.Controls["textBoxCompanyName"] as TextBox;
private TextBox website = form.Controls["textBoxWebsite"] as TextBox;
private TextBox refNumber = form.Controls["textBoxRefNumber"] as TextBox;
private TextBox reason = form.Controls["textBoxReason"] as TextBox;
private TextBox dateListed = form.Controls["textBoxDateListed"] as TextBox;
private Label charLimit = form.Controls["labelCharsRemaining"] as Label;
public TextBox Employer { get { return employer; } }
public TextBox Role { get { return role; } }
public TextBox Company { get { return company; } }
public TextBox Website { get { return website; } }
public TextBox RefNumber { get { return refNumber; } }
public TextBox Reason { get { return reason; } }
public TextBox DateListed { get { return dateListed; } }
public Label CharLimit { get { return charLimit; } }
}
}
2. Singleton set up inside class Form1
public partial class Form1 : Form
{
private static Form1 theInstance;
public Form1()
{
InitializeComponent();
}
//Return instance of Form1
//--This is obviously returning null for some reason
public static Form1 GetInstance()
{
if (theInstance == null)
theInstance = new Form1();
return theInstance;
}
As you can probably see I am getting the "NullReferenceException" when I attempt to get the Singleton from class Form1.
The following methods I have used are as follows:
Using Windows.OpenForms["Form1"].Controls["--somecontrol--"]
Using Windows.ActiveForm
Using a Singleton Design Pattern on class Form1
All of these ways are returning null and I cant think of a reason why it is returning null.
Any help would be appreaciated.
Thankyou
I want to get the values of some textBoxes from the Form1 instance and extract the values.
This is where you need to stop and re-think your approach. Forms represent views of your data; however, your data itself needs to be in the model, a separate place independent of the views.
Text boxes need to reflect the state of some model object, such as a Person object that has string properties for employer, company, role, web site, and so on. The form would read from that object's properties, display them in a text box, and then react to text box changes, and save values back to the model Person object.
If you make Person a singleton, or provide some other universal way of accessing it, you would be able to access person's properties from all forms, without accessing the forms themselves.
Related
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.
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();
}
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);
I need to interact with controls on other forms. Trying to access the controls by using, for example, the following...
i am accessing Backupform control from form2
in backupform : I have defined like this....
public partial class BackupForm
{
public bool ControlIsVisible
{
get { return this.btnrestore.Visible; }
set {this.btnrestore.Visible = value; }
}
public BackupForm()
{
InitializeComponent();
cbbackupforms.SelectedIndex = 0;
// btnrestore.Enabled = false;
}
}
i made the btnrestore properties visible = true; and modifiers = private in designer of backupform
and in form2 i am accessing the btnrestore visible property
public partial class form2
{
private Forms.BackupForm backs;
public form2()
{
InitializeComponent();
backs = new Forms.BackupForm();
}
public void restore()
{
backs.ControlIsVisible = false;
}
}
but i am not able to visible false for the button , would any one pls suggest any solution for this.....
Many thanks in advance
You can supply a reference to the instance of the first form, and use that reference to set properties of objects on that form. When you cast the object to Form1, the properties will be accesible.
When are you calling your Restore() method? Also, if all the Restore() method does is set the button's visible property on the seperate form, why not encapsaluate that method within your BackupForm object and call it using backs.Restore()?
I am wondering how I can update my listview in form1 by entering data via textboxes in form2. My code works fine if i put all the text boxes on the same form etc.
I figured I needed some reference to the first form on 2nd but can't get it working.
Any tips for putting me in the right direction would be nice, also any tips for any better way of doing this.
This is the code I have so far:
Form1:
public partial class form1 : Form
{
public form1()
{
InitializeComponent();
}
public ListView MyListView
{
get
{
return taskList;
}
}
Form2:
public partial class form2 : Form
{
public form2()
{
InitializeComponent();
}
form1 f;
public add(form1 f)
{
this.f = f;
}
public void AddToList()
{
ListViewItem item1 = new ListViewItem(txtName.Text);
item1.SubItems.Add(txtEmail.Text);
item1.SubItems.Add(txtPhone.Text);
f.MyListView.Items.AddRange(new ListViewItem[] { item1 });
}
The most straight forward way of doing things would be to use events. You could add an event on form2 that would fire each time an item is added, and includes the text to be inserted (you have multiple pieces of information, so a custom data type would be appropriate). You can then add a handler method to form2 which adds the item to its ListView. You then tie the two together in the code that is creating the two forms, and life should be good.
So, to provide some code, First up is the data structure for the event:
public delegate void HandleItemAdded(object sender, ItemAddedEventArgs e);
public struct ItemAddedEventArgs : EventArgs
{
public string Name;
public string Email;
public string Phone;
public ItemAddedEventArgs(string name, string email, string phone)
{
Name = name;
Email = email;
Phone = phone;
}
}
Then we have the event code on form2
public event HandleItemAdded ItemAdded;
// .. some other stuff
public void RaiseItemAdded(ItemAddedEventArgs e)
{
if(ItemAdded != null)
ItemAdded(this,e);
}
// ... now for your AddToList
public void AddToList()
{
RaiseItemAdded(new ItemAddedEventArgs(txtName.Text,txtEmail.Text, txtPhone.Text);
}
And now we can add a handler in form1
public void HandleItemAdded(object sender, ItemAddedEventArgs e)
{
ListViewItem item1 = new ListViewItem(txtName.Text);
item1.SubItems.Add(txtEmail.Text);
item1.SubItems.Add(txtPhone.Text);
MyListView.Add(item1);
}
And last but not least we need to tie them together
//...not sure what your code looks like, but we'll assume we have instances of the two forms named form1Form and form2Form
form2Form.ItemAdded += form1Form.HandleItemAdded
the listview control should be private, instead add a public method to your form that contains the listview control, which receives the data you want to insert and inserts it into the listview.
If form2 is not created by and displayed by form1, you're not going to have a reference to call. In that case, things are going to get a bit more interesting from a communication standpoint. When that happens, you'll need to use an eventing model to get the information from one place to another.