How do I use accessors? - c#

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);

Related

Working with multiple forms using c# in Visual Studio

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.

Change private string from another class

I'm wondering as to why my private variable 'name' within my Events class won't change when I access the property from my Leisure class which inherits from Events. I need Leisure to use the properties to change it, and then in my form class, it should be able to read the value of 'name' from events. See below:
public partial class Form1 : Form //Main form class
{
private string eventType; //used for event type selection
private string formEventName; //used to store selected event name
private void itemSend_Click(object sender, EventArgs e)
{
//encapsulation
Events myEv = new Events();
string name=itemInput.Text;
myEv.myEvent(eventType, name);
formEventName = myEv.myName;
txtOutput.Text = "Event name is " + formEventName + "\r\n";
}
class Events:Form1
{
private string name; //private variable for event name
public string myName //used to change property value depending on what eveny type/ event name
{
get { return name; }
set { name = value; }
}
public void myEvent(string eventType, string eventName) //variable recieved from main form class
{
if (eventType == "Leisure")
{
Leisure myLes = new Leisure();
myLes.eventNames(eventName);
}
else
{
//test for other event types
}
}
class Leisure:Events
{
public void eventNames(string eventName)
{
//when adding new items add one with a capital and one without
myEventNames.Add("music");
myEventNames.Add("Music");
if (myEventNames.Contains(eventName))
{
myName = eventName;
}
else
{
MessageBox.Show("item not found, please try again"); //error message
}
}
}
It seems wrong that Events inherits from Form1.
When you say new Events(), you get a new object, unrelated to the existing form, and any changes you make to it have no effect on the existing form. That happens again when you say new Leisure().
The myName property you are using changes the name private field of myLes instance and not the name private field of myEv instance created in the ItemSend_Click.
In an Object Oriented Language when you create an instance of a class, that instance has a copy of every non-static private/public variable declared in the class. So when you write
Leisure myLes = new Leisure();
you are creating an instance of Leisure class, but this instance, while inherithing from Events has a different set of internal variables and not the same variables of the current Event instance (myEv).
Looking at your code I suggest to create a third class called
public class EventFactory
{
public Event CreateEvent(string eventType, string eventName)
{
switch(enventType)
{
case "Leisure":
Leisure myLes = new Leisure();
myLes.eventNames(eventName);
return myLes;
// case Add other specialized events here:
// break;
default:
return null;
}
}
}
change your Events class removing the inheritance from Form1 (not needed as far as I can tell) and the method myEvent
now your ItemSend_Click could be written in this way
private void itemSend_Click(object sender, EventArgs e)
{
Events myEv = new EventFactory().CreateEvent(eventType, itemInput.Text);
formEventName = myEv.myName;
txtOutput.Text = "Event name is " + formEventName + "\r\n";
}
this works because Leisure derives from Events and you could treat every Leisure instance as an Event instance.
You just change myName of the myLes (Leisure) variable in your myEv field, thats why myEv.myName is still empty.
So the problem that you're having is just a small symptom of major fundamental problems in your code that will only continue to manifest themselves as you continue.
I've re-written what you have into something that's more in line with what is more traditionally seen for what you're trying to do. It's not perfect, and I've tried to keep things fairly simple so as to not throw too much at you at once.
public partial class Form1 : Form //Main form class
{
private TextBox itemInput;
private TextBox txtOutput;
private string eventType; //used for event type selection
private string formEventName; //used to store selected event name
private void itemSend_Click(object sender, EventArgs e)
{
string name = itemInput.Text;
try
{
Event myEvent = Event.Create(eventType, name);
txtOutput.Text = "Event name is " + myEvent.Name + "\r\n";
}
catch (ArgumentException ex)//if the event name isn't valid
{
MessageBox.Show(ex.Message);
}
}
}
public abstract class Event
{
public string Name { get; private set; }
public Event(string eventName)
{
Name = eventName;
}
public static Event Create(string eventType, string eventName)
{
if (eventType == "Leisure")
{
Leisure myLes = new Leisure(eventName);
return myLes;
}
// else if { ... } test for other event types
else
{
return null;
}
}
}
public class Leisure : Event
{
private static List<string> myEventNames =
new List<string>() { "music", "Music" };
public Leisure(string eventName)
: base(eventName)
{
if (!myEventNames.Contains(eventName))
{
throw new ArgumentException("Not a valid Leisure event name");
}
}
}
So, let's go over some of the changes. First off, Event doesn't inherit from Form1. It should not do so. An event is not conceptually a type of form at all, let alone that particular type of form. An Event should have no knowledge of any form, in any way, not just inheritance. It's just some other class that Form1 will use, but it could just as easily be used by any other type of class, form or otherwise.
In addition to making Event not inherit from Form, I've made it abstract. It doesn't have any abstract methods, it's just that you shouldn't ever be creating just an plain Event, you should only ever actually create some specific type of event. Being a common base class, it's easiest to prevent accidental creation and to help improve readability by making it abstract.
I've also made Event immutable. Rather than allowing name to be changed at any time, creating an event without giving it a name, and then changing it later, I have configured it such that you need to provide the name and type before creating the event, and then there's no way of changing it once it's created. The Name is set in the constructor, and I have added a static Create method which is where the logic can go for choosing the proper subtype of Event and actually creating it. This is a simple version of the "Factory Pattern". Note that normally I wouldn't pass the type in as a string. I would make it something like an Enum, so that it's easier to tell what the valid options are.
Now onto Leisure. Logically, Leisure really is an Event and should inherit from it. Your problems were steming from the fact that you created an instance of Event, and also an instance of Leisure, and assumed that they shared the same variables. They don't, but that confusion should go away now that you can't ever have an instance of Event.
When a Leisure is created it uses the base class constructor to set Name, since it doesn't have access to set the property itself.
From what I can see myEventNames is just a list of valid names, and it doesn't appear to change between different types of Leisure instances, so it makes sense for it to be static, which means it's shared between all instances and is only created once.
I also moved the MessageBox call out of the Leisure type's constructor. Instead I'm throwing an exception. The main idea here is that you shouldn't mix your UI code with your business code. Event and Leisure are both business objects and shouldn't know anything about what, if any, UI exists. You should be able to use them from a console app, an ASP application, etc. On top of that, since what we're trying to say is that this is an invalid name and the type shouldn't exist, the end result of throwing an Excpetion in the constructor is that the object never becomes "valid". We don't allow the creation of an object that shouldn't exist, as opposed to allowing them to continue using the object anyway.
That exception is caught with the try/catch block in Form1, where it shows the appropriate MessageBox based on the failure to create the event.

Confusion with using properties from another class with instances

I have instantiated an object from another class in order to use properties from that class. Everything works fine within the button event, however, outside of the button event I get an error telling me my instantiated object is being used as a type. If I take this very same code and cut and paste it into the button event, I do not receive an error message. I do not understand what is happening and why. The object is instantiated whether it is inside or outside of the button event so why doesn't it work outside of the button event? I need those two label fields auto-filled from another form as soon as the form opens, not when the button is clicked.
Here is my code:
public partial class MeasurementsForm : Form
{
private MeasurementsBOL busObject = new MeasurementsBOL();
//autofill bodyfat and body weight from nutrition form when form opens
busObject.BodyFatB4 = double.Parse(lblBodyFatB4FromNutrition.Text);
busObject.BodyWeightB4 = double.Parse(lblWeightB4FromNutrition.Text);
//default constructor
public MeasurementsForm()
{
InitializeComponent();
busObject.InitializeConnection();
}
//event handler for B4 input data
private void btnEnterMeasurementsB4_Click(object sender, EventArgs e)
{
//convert input data and assign to variables
busObject.ChestMeasurementB4 = double.Parse(txtChestB4.Text);
busObject.WaistMeasurementB4 = double.Parse(txtWaistB4.Text);
busObject.HipsMeasurementB4 = double.Parse(txtHipsB4.Text);
busObject.RightThighB4 = double.Parse(txtRightThighB4.Text);
busObject.LeftThighB4 = double.Parse(txtLeftThighB4.Text);
busObject.RightArmB4 = double.Parse(txtRightArmB4.Text);
busObject.LeftArmB4 = double.Parse(txtLeftArmB4.Text);
//call method to save input data
busObject.SaveB4Data();
//clear text boxes of data
this.txtChestB4.Clear();
this.txtWaistB4.Clear();
this.txtHipsB4.Clear();
this.txtRightThighB4.Clear();
this.txtLeftThighB4.Clear();
this.txtRightArmB4.Clear();
this.txtLeftArmB4.Clear();
//close form
this.Close();
}
Here are my two properties from the MeasurementsBOL class. Although I don't show it, the object has been instantiated:
//properties for variables
public double BodyFatB4
{
get { return bodyFatB4; }
set { bodyFatB4 = nutritionObject.BodyFatStart;}
}
public double BodyWeightB4
{
get { return bodyWeightB4; }
set { bodyWeightB4 = nutritionObject.BodyWeight; }
}
This code isn't in any method, constructor etc:
private MeasurementsBOL busObject = new MeasurementsBOL();
//autofill bodyfat and body weight from nutrition form when form opens
busObject.BodyFatB4 = double.Parse(lblBodyFatB4FromNutrition.Text);
busObject.BodyWeightB4 = double.Parse(lblWeightB4FromNutrition.Text);
It's fine to have a variable declaration, but you can't just add extra statements like that. Fortunately, you can use an object initializer:
private MeasurementsBOL busObject = new MeasurementsBOL()
{
BodyFatB4 = double.Parse(lblBodyFatB4FromNutrition.Text),
BodyWeightB4 = double.Parse(lblWeightB4FromNutrition.Text)
};
Basically, a type can only contain members such as field declarations, constructor declarations, property declarations, method declarations etc. It can't contain just statements.

C#, access (get or read) the textBox values in a static method?

I have a form (form1) that has a text field (textBox1)
I have a class that has the method "public static string getValue()"
how I can read the value of the textBox1 within the method getValue() ??
here is my code
namespace MyProgram
{
public partial class Form1: Form
{
---------------------------------
---------------------------------
---------------------------------
}
}
the other class
namespace MyProgram
{
class values
{
public static string getValues()
{
string v;
v = ------get value from textBox1 in Form1
return v;
}
}
}
the whol software is build in this structure, so I hope there is some standard way in C# to get these values in the method getValue()
You can not. The property is in the instance of the class, the static method has no pointer to it. Broken by design.
You have to instantiate new object of Form1 and get the value. Or else add a delegate in form1 and call it from getValue, such that the return value of delegate should be the textbox value.
You can instantiate, show, and dispose of the form inside the static method. An example:
public static string GetValues()
{
string value = null;
using (var form = new Form1())
{
DialogResult result = form.ShowDialog();
if (result == DialogResult.OK)
{
value = form.textBox1.Text;
}
}
return value;
}
The using block takes care of freeing the resources allocated for the form. ShowDialog shows the form as a modal dialog.
While this works for simple dialog boxes, it is probably not what you want to do in every case. The method will block the current thread until the user closes the form. Look at other applications and sample code. As #Dan Abramov wrote, Reconsider your design.
foreach(Control c in Form1.Controls) {
if(c.getType() == TextBox) {
TextBox tb = (TextBox)c;
string value = tb.Text;
}
}
But why don't you just read the value from the form?
Textbox1.Text
Consider the KISS-principle!
With few assumptions - you can use this code snippet
private static void GetValue(object sender, TransferEventArgs e)
{
Application.OpenForms["FormSomeForm"].Controls["textBoxSomeTextbox"].Text = #"Some Value";
}
Depend on your other code it is also helpful to define the control / variable "public" as for example:
public System.Windows.Forms.TextBox textBoxSomeTextbox;
... or use the VS Studio GUI - Properties:
Tested; VS 2019 - NET 4.8 - 1/29/2022

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