i've often had this issue where i do not really understand how to pass userform variables into classes. for example i have a button:
private void button1_Click(object sender, EventArgs e)
{
DoStuff();
}
and a method in the form class:
DoStuff()
{
Class123 myclass = new Class123();
}
...
...
class Class123
{
//how do i pass for example in myotherClass whether or not my checkbox on the userform is checked? i dont want to have to pass from method to method to class to class. what is the logical/smart way of handling this?
ClassData myotherClass = new ClassData();
}
how do i pass for example in myotherClass whether or not my checkbox on the userform is checked? i dont want to have to pass from method to method to class to class. what is the logical/smart way of handling this?
I think you are looking for function arguments:
// notice the declared function argument isMyCheckboxChecked
DoStuff(bool isMyCheckboxChecked)
{
Class123 myclass = new Class123(isMyCheckboxChecked);
}
private void button1_Click(object sender, EventArgs e)
{
// passing the state of the checkbox to DoStuff as an argument
DoStuff(chkMyCheckbox.Checked);
}
class Class123
{
readonly ClassData myotherClass = new ClassData();
Class123(bool isMyCheckboxChecked)
{
myOtherClass.isMyCheckboxChecked = isMyCheckboxChecked;
}
}
I can see a few things here. The code posted is rather vague, so it is hard to say what the correct answer may be.
If myOtherClass needs to know if a checkbox is checked when the checkbox changes then you should probably look into using a subscriber pattern.
However, if you mean that you just need to know if the checkbox was checked at the moment DoStuff() ran, there is nothing wrong about passing a variable. In fact, passing a variable is the preferred way - it's what variables exist for. That said, you need to pass variables intelligently; if you find that you are just slinging parameters across classes constantly, that's a sign of poorly-designed code. If you need to pass some parameters to myClass to tell it what to do, build them into a (descriptively named) class of their own, and pass that class to myClass's constructor instead of a long list of parameters.
I disagree with this approach.
Any 'smart' method, if it even exist, will break the golden rules of Object Oriented Programming.
An object is a self contained item of data that can only be accessed or changed in a controlled way. This prevents side effects, a common problem in procedural code, where data is globally accessible. In OOP, the objects can receive or send messages to other objects only by calling their methods.
EDIT: To show a way to do it
public static class MyApp
{
public static bool MyCheckBox {get; set;}
}
in your doStuff
MyApp.MyCheckBox = this.checkBox1.Checked;
inside a method of your myOtherClass
if(MyApp.MyCheckBox == true)
...
this is the same as using a global variable in the old days of procedural languages. This paves the way to difficult to track bugs and creates state mode that render an application hard to maintain
Related
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;
I am kind of new to programming in this manner - is there a way that I can work around or a recommended practice to using events and handlers?
eg:
class objectA
{
public List<Handler> handlers;
...
public onActionHappened
{
foreach(Handler h in handlers)
{
raiseEvent(this, eventArgs);
}
}
...
public void DeleteThis()
{
handlers = null
}
}
raiseEvent() will go on an call a few other methods, one of which will invoke DeleteThis(). When everything ends and the program flow returns back to raiseEvent() at the "}" for the foreach loop, it finds that handler has been modified = null, thus throwing the error of InvalidOperationException.
Some method handling should disable this objectA as part of the functionality - thus Deletethis() MAY be called by client code at some point. To fix this, I had modified from List handlers to just a single Handler object, but I feel that that should be a better way of workaround. Or better way of coding.
Any advice? Thanks in advance!
If you use ToArray on the list, you create a copy of its contents and are not dependant on the handler variable itself:
foreach(Handler h in handlers.ToArray()
{
//optional break if you don't want the loop to continue after DeleteThis is called: if(handlers==null)break;
raiseEvent(this, eventArgs);
}
To address the core of your question: The most straightforward way to fix the issue is to assign the list to a local variable before enumerating over it.
class objectA
{
public List<Handler> handlers;
...
public void OnActionHappened()
{
List<Handler> lh = handlers;
// TODO: Would probably make sense to check if lh is null here.
foreach(Handler h in lh)
{
h.raiseEvent(this, eventArgs);
}
}
...
public void DeleteThis()
{
handlers = null;
}
}
There is really no need to create a copy of the list as suggested elsewhere.
Since you seem to be new to C# programming, let me give you some idea what is going on here.
List<T> is a reference type. Let us assume that you create a new List<T> by calling its constructor:
List<Handler> handlers = new List<Handler>();
Now, executing this statement creates two things in the computer's memory:
The list object itself.
A variable ("handlers") that refers to the list object.
Now, if the computer executes the following line:
List<Handler> lh = handlers;
we end up with something like this:
Finally, if the computer executes the following line:
handlers = null;
the situation looks as follows:
As you can see, this way we maintain a valid reference to the list object via the local list variable "lh" and setting the member variable "handlers" to null doesn't affect the foreach enumeration any longer.
An event cannot be triggered outside the class in which the event is defined. So, if you move handlers outside class A, you can no more trigger events in handlers in the class A.
To work around this issue, put handlers in another class, say class B, and define a public method that triggers the events in the handlers in the class B (in this case, the onActionHappened method). For class A, simply call that public method (onActionHappened) of the class B.
I have a WPF/C# program with several classes, and the MainWindow.cs class has user controls which I'd like to update with the status of the computation occurring inside other classes. After googling around and borrowing from examples, I figured out how to set up an Event inside the other class, and invoking it when something changed. Then as long as the main class has a handler tied that event, I could appropriately update UI stuff (status bars, etc). Below is a stripped-down version of what I'm doing:
namespace Program
{
public partial class MainWindow : Window
{
public void SetUpHandler()
{
TestA.WorkerProgressThingie += new ProgressChangedEventHandler(TestA_ProgressChanged);
}
void TestA_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage
}
}
public class TestA
{
public static event ProgressChangedEventHandler WorkerProgressThingie;
public static void SomeFunction()
{
int value = 0;
//...(some boring code that does something here)
ProgressChangedEventArgs e = new ProgressChangedEventArgs(value, null);
if (WorkerProgressThingie != null)
WorkerProgressThingie.Invoke(null, e)
}
}
}
Is there not a way to simply call the progressBar property from the other class? (i.e. MainWindow.progressBar.Value)?
What is the purpose of the "object sender" parameter when I invoke the event, and how is it supposed to be used normally? The examples I see always use 'null'.
Thanks!
1) Yes, you can access any part of any class if it is declared public. In this case, you could declare the progressBar control as public, and anything that has a reference to class MainWindow can fiddle with it. HOWEVER, this would be pretty poor practice. Instead, you could bind to some 'value' which updates in relation to the current progress of the activity and let the MainWindow class worry about how it represents that change (in this case by updating a ProgressBar),
2) object sender in all events is meant to be a reference to the object which raised the event, so the event consumer knows where the event came from. Using null is also poor practice IMO, and in general, an object which raises an event should do so like;
SomeEvent(this, someEventArgs);
I need to attach an event handler to an object, and I placed this code on a button click event. However, I noticed that this will cause the same event to attach multiple times with each click.
Is there a way to run a piece of code on class creation? The class in question is a static class btw.
I can do something like:
if (bool == false)
{
attach event handler;
bool = true;
}
Just not sure if this is the right way to do it. Thanks.
There are static constructors, that are (in principle) only run once per class.
Something like this:
public static class MyStaticClass
{
public static int MyStaticProperty;
//no accessors required, as this is never explicitly invoked
static MyStaticClass() //no parameters either
{
MyStaticProperty = 100;
}
}
....
//writes: 100
Console.WriteLine(MyStaticClass.MyStaticProperty);
However, if a constructor won't do it, because you have some parameters that need to be set, or there are some prerequisite steps that need to be done, I would indeed recommend a private boolean check, as you have done.
You use a constructor - it will run on class creation.
Constructors are class methods that are executed when an object of a class or struct is created. They have the same name as the class or struct, and usually initialize the data members of the new object.
For static classes, use static constructors:
A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced.
try
if(Button1.Click == null)
Button1.Click += new System.EventHandler(this.myEventHandler);
I am getting ready to create a generic EventArgs class for event args that carry a single argument:
public class EventArg<T> : EventArgs
{
// Property variable
private readonly T p_EventData;
// Constructor
public EventArg(T data)
{
p_EventData = data;
}
// Property for EventArgs argument
public T Data
{
get { return p_EventData; }
}
}
Before I do that, does C# have the same feature built in to the language? I seem to recall coming across something like that when C# 2.0 came out, but now I can't find it.
Or to put it another way, do I have to create my own generic EventArgs class, or does C# provide one? Thanks for your help.
No. You probably were thinking of EventHandler<T>, which allows you to define the delegate for any specific type of EventArgs.
I personally don't feel that EventArgs<T> is quite as good of a fit, though. The information used as a "payload" in the event args should be, in my opinion, a custom class to make its usage and expected properties very clear. Using a generic class will prevent you from being able to put meaningful names into place. (What does "Data" represent?)
I must say I don't understand all the 'purists' here.
i.e. if you already have a bag class defined - which has all the specifics, properties etc. - why the hack create one extra unnecessary class just to be able to follow the event/args mechanism, signature style?
thing is - not everything that is in .NET - or is 'missing from' for that matter - is 'good' - MS's been 'correcting' itself for years...
I'd say just go and create one - like I did - cause I needed it just like that - and saved me lot of time,
It does exist. At least, it does now.
You can find DataEventArgs<TData> in some different Microsoft assemblies/namespaces, for instance Microsoft.Practices.Prism.Events. However these are namespaces that you might not find natural to include in your project so you might just use your own implementation.
In case you choose not to use Prism, but still would like to try a generic EventArgs approach.
public class GenericEventArgs<T> : EventArgs
{
public T EventData { get; private set; }
public GenericEventArgs(T EventData)
{
this.EventData = EventData;
}
}
// Use the following sample code to declare ObjAdded event
public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;
// Use the following sample code to raise ObjAdded event
private void OnObjAdded(TargetObjType TargetObj)
{
if (ObjAdded!= null)
{
ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
}
}
// And finnaly you can subscribe your ObjAdded event
SubscriberObj.ObjAdded += (object sender, GenericEventArgs<TargetObjType> e) =>
{
// Here you can explore your e.EventData properties
};
THERE IS NO BUILT-IN GENERIC ARGS.
If you follow Microsoft EventHandler pattern, then you implement your derived EventArgs like you suggested:
public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.
HOWEVER - if your team style guide accepts a simplification - your project can use a lightweight events, like this:
public event Action<object, string> MyStringChanged;
usage :
// How to rise
private void OnMyStringChanged(string e)
{
Action<object, string> handler = MyStringChanged; // thread safeness
if (handler != null)
{
handler(this, e);
}
}
// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);
Usually a PoC projects use the latter approach. In professional applicatons, however, be aware of FX cop justification #CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx
The problem with a generic type is that even if DerivedType inherits from BaseType, EventArgs(DerivedType) would not inherit from EventArgs(BaseType). Using EventArgs(BaseType) would thus prevent later using a derived version of the type.
The reason this does not exist is because what would end up happening is you implement this, and then when you go to fill in the T you should create a class with strongly typed unambiguous properties that acts as the data bag for your event arg, but halfway through implementing that you realize there's no reason you don't just make that class inherit from EventArgs and call it good.
Unless you just want a string or something similarly basic for your data bag, in which case there are probably EventArgs classes standard in .NET which are meant to serve whatever simple purpose you're getting at.