Confusion with using properties from another class with instances - c#

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.

Related

How can i pass a list from my first form to a second form, add data to it and then show it on my first form? C#

From what i've read so far i've done this:
On my first form:
public partial class FPrincipal : Form
{
List<Grua> ListaGruas = new List<Grua>();
List<Semirremolques> ListaSemirremolques = new List<Semirremolques>();
List<Clientes> ListaClientes = new List<Clientes>();
// this is the menu strip i click to create my new form,
// send my list and add my values
private void miEquipoCargar_Click(object sender, EventArgs e)
{
EquiposCargar FormEquiposCargar = new EquiposCargar(ListaGruas);
FormEquiposCargar.ShowDialog();
}
}
And on my second form:
public partial class EquiposCargar : Form
{
// I saw some videos on youtube and this is how the pass some values,
// but it doesnt work with lists
public EquiposCargar(List<Grua>listaGrua)
{
InitializeComponent();
}
}
Could anyone please help me? im stuck.
The error says the parameter List<Grua>listaGrua is less accesible than the method EquiposCargar.EquiposCargar(List<Grua>)
just another question! how do i use the list on my second form? lol...
because it says the name listaGrua is not defined in the actual
content. It looks like i have to create a new variable and assign the
list parameter than i sent, right? but im doing it and its still not
working
That's correct, you need to create a variable in your second form to hold that reference. In the constructor, simply assign the passed in reference to your form's reference:
public partial class EquiposCargar : Form
{
private List<Grua> listaGrua;
public EquiposCargar(List<Grua> listaGrua)
{
InitializeComponent();
this.listaGrua = listaGrua;
}
}
Note the use of the this keyword. Now you should be able to use listaGrua from anywhere in your second form.

Create a label dynamiclay in form by calling a method from a different class

As the title implements, how can I call method that adds a control in a form say Form1. I want to call the method and inside that creates several controls like a textbox or labels in the Form that called it
You can prepare controls in a static class and use it both of your forms as follows
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Controls.Add(MyControls.AddLabel());
}
}
public static class MyControls
{
public static Control AddLabel()
{
Label label = new Label
{
AutoSize = true,
Location = new Point(48, 47),
Name = "label1",
Size = new Size(46, 17),
TabIndex = 1,
Text = "label1"
};
return label;
}
}
Once you've instantiated the second form from your first form, before you call form2.Show(), you can access public properties and functions.
So, either make your label control public, and access it's .Text property, or implement a public method that takes a string parameter, and within that method, assign the string to your label.Text property.
As mentioned, you should post the code you've already tried so people have a better chance of helping you!

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

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.

Calling method from another window (Class) issue

In code behind file of the main window of WPF application I have a method quering a database with LINQ to SQL and writing results to an ObservableCollection:
public void GetStateByDate(string shcode)
{
MydbDataContext contextSts = new MydbDataContext();
_ShAvaQuCollection.Clear();
var sts = from p in contextSts.SAties where p.ShID == shcode select p;
foreach (var p in sts)
_ShAvaQuCollection.Add(new ShAvaQu
{
ShCode = p.ShID,
SiID = p.SiID,
PrCat = p.PrCat
});
}
When I call this method from the same code behind file (the same window), everything is OK.
If I call this method from another window, using an instanse of the main window, ObservableCollection remains empty.:
SWindow sw = new SWindow();
sw.GetStateByDate(stringpar);
What is the reason for this? Does in this case method create yet another instance of ObservableCollection?
(I can see in debugger that sw._ShAvaQuCollection contains values. Is sw._ShAvaQuCollection not the same instanse of collection as _ShAvaQuCollection? If yes, how it can be resolved?)
Edited (added)
The ObservableCollection declared this way:
ObservableCollection<ShAvaQu> _ShAvaQuCollection =
new ObservableCollection<ShAvaQu>();
public ObservableCollection<ShAvaQu> ShAvaQuCollection
{ get { return _ShAvaQuCollection; } }
public class ShAvaQu
{
public string ShCode { get; set; }
public string SiID { get; set; }
public int PrCat { get; set; }
}
I call the method from a window, where another collection ShQuCollection displayed through ListView. In SelectionChanged event handler I take an argument for this database quering:
private void ShSelList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SWindow sw = new SWindow();
string str = sw.ShQuCollection[ShSelList.SelectedIndex].ShCode;
sw.GetStateByDate(str);
Close();
}
}
1) Most importantly you shouldn't be calling db logic from you windows / forms. You should abstract it out into another class. Then you could have your method return a observable collection.
However in your case I am assuming that you are trying to use the secondary form to reload / load the collection and you want it used on your primary form. The problem with this is you are creating a new instance of the form so your collection is being populated but not on your main form but a copy.
There are a couple ways you can try to get around that.
1) Make the method static and your observable collection static so that it updates a single instance.
2) Pass an instance handle of your primary form into your secondary form so that you re-use the instance you already have. This would be preferable so that you are not creating new instances all over the place.
In the constructor of the second form you could pass in the instance of your primary window so then you can use it directly. This should solve your problem.
UPDATE: Here is some code samples. Basically there are many ways to pass a reference.
You could do it like this with a constructor:
// This is the constructor for your second window
private Window _parentHandle;
public SecondWindow(Window obj)
{
this._parentHandle = obj;
}
Then from your primary form that has the method you would open that window like this.
SecondWindow w = new SecondWindow(this);
w.Show();
Now your second window has a direct handle to your first window so you can call your method on that variable and it will update.
Another way is to have a public Setter method on your second window as well.
public Window ParentContext
{
get { return this._parentHandle; }
set { this._parentHandle = value; }
}
Then you could create your form instance like this:
SecondWindow w = new SecondWindow(); // so just like normal
w.ParentContext = this; // set the instance to the calling form
w.Show();
That is the basics. This type of scenario works in just about any scenario where you need to pass a reference.
Hope that helps.

Categories

Resources