Use of static class in C# - c#

I'm developing an appliaction that has 2 forms and I ran into a problem. When I create a new instance of a class in Form2, then close Form2, I lose the instance values. So, I've solved this using static class, is this the correct approach?
The class name is Matriz_de_registracion and I have a function within it that's called "solver" that assigns values to the class properties ("Double MR0" is one of the variables as an example)
here's the code in Form2 (see I don't use the "new" statement otherwise once I close form2 I loose the instance values..
private void btn_iniciar_registro_de_puntos_Click(object sender, EventArgs e)
{
Matriz_de_Registracion.solver(_pois);
}
Then I can reference, in Form1, one of the properties of the Class by just doing this:
Matriz_de_Registracion.MR0
Now, is this correct approach or static classes are used for something else? I just wan to reference the values of the MR0 variable across all my forms without having to pass the instances through forms every time I open/close forms.

This is not the right approach. You should copy the values from the form object after it has closed but before you get rid of it.
The problem with using static data anything other than extremely sparingly is that you will find it makes the application much harder to work on as it gets larger - for example, you wouldn't be able to open two instances of the form at the same time, as they'd tread on each other's data.

Related

Using a class to store gamedata, best practise?

Im using Visual C# 2010 express. Im working on a game, and have come accross a small, newbie problem. Thing is, i guess we're dealing with a best practise type situation, and none of the few beginner books i have really helped with it, so i hope you guys can.
So, i have two forms, one is a splashscreen/startup form and the other is the main game window. I made a class that contains all world data, and when in the first screen user clicks on "new game", a new instance of this class is generated and populated with data.
So far so good.
The newgame button, in addition to creating the world instance, opens up the main game window. The problem is, in the main game window, when i try to use attributes of the gameworld instance, it says that it doesnt exist in this context.
So, if i get it right, the created instance only exists within the first form class... is that correct?
So if i'd like to move that whole data, should i actually serialize and save the world class instance data, and load it in the second form? Or how should i approach this.
I understand it's a very newbie question, and i could propably hack it to work, but the thing is - i really feel like i have to understand everything im doing.
Thanks in advance!
You need to create a constructor on your game form that accepts an instance of your world class and assign it to a field of the same type - the field will be accessible to the game form methods.
World world;
// constructor
public GameForm (World world)
{
this.world = world;
}
// Can now use `world` in all `GameForm` methods
Instead of constructor injection (as I have shown in my example), you can use property injection, though I like the former better (tends to ensure proper initialization - though you may want to check for a null being passed in).
If there is a reference of the world data object in the splash screen, you can assign this to a public member in the main screen, or pass it to the main screen through a constructor.
so in the splash screen
FrmMain frmMain = new FrmMain();
frmMain.WorldData = this.WorldData;
if it is an instance member of the splash screen
or maybe something like
FrmMain frmMain = new FrmMain();
frmMain.WorldData = new WorldData();
or even
FrmMain frmMain = new FrmMain(this.WorldData);
or
FrmMain frmMain = new FrmMain(new WorldData());
with the FrmMain constructor as
public FrmMain(WorldData worldData)
{
this.m_WorldData = worldData;
}
Have a look at Passing Data Between Forms
Assuming you're using just windows forms, and not XNA or similar framework, where theres no winforms.
Startup form:
void StartButton_Click(object sender, EventArgs e)
{
GameWorld gw = new GameWorld();
// Initialize gw instance here
GameForm mainForm = new GameForm(gw);
mainForm.Show();
}
And add a constructor to the game form:
public class GameForm
{
private GameWorld _gw;
public GameForm()
{
InitializeComponent();
}
public GameForm(GameWorld gw) : this()
{
_gw = gw;
}
}
At that point you can use private variable _gw in the game form.
Also, i would suggest passing the GameWorld instance through the constructor, not the property as that value is crucial for the form. Generally properties might be better suited to provide a way to adjust some behavior, and any constructor parameter can be seen as mandatory for the object to work as it should.
You can also make default constructor (the one without parameters) private.
Depending on the size of the data and if the world object class is serializable, You might think about caching it. Then each form that needs the data can just get it from the cache whenever it is needed.

Get variables from list in another method?

I'm writing a webcam app and I need to write and read about 15 variables. I have two forms, the main window and the options window. When I save my options I do something like this:
string[] lines = {x , y, ..., z };
System.IO.File.WriteAllLines(#"config.cfg", lines);
In my main window I read the variables using the StreamReader function:
public void Foo()
{
List<string> lines = new List<string>();
while (!reader.EndOfStream)
{
lines.Add(reader.ReadLine());
reader.Close();
}
x = Convert.ToInt32(lines[0]);
y = Covert.ToString(lines[1]);
// and so on...
}
The problem is I don't know how to access x and y in another method. Btw: I declared all my variables as public static. Can anyone please help?
Edit
It is a windows forms app, the two windows do not exist at the same time. Maybe someone can give me a hint how to store those variables using a different method? The only thing I know I could do is store the vars using a MySQL database, but doesn't make much sense.
I'll try to clarify: what I would like to do, is pass x and y from the method Foo to another method. I can't use global variables, because reading the variables from the file requires a method.
use properties=> setting to save your values if you will need it the next time.
it's simple and help you to avoid some problems
Do both forms exist at the same time? i.e in skype you have your main skype window and your chat windows?
If so just make a CameraUpdated event, which sends the lines changed to any subscribers, then that way you can just get your main window to bind to any new child windows events, so it will be notified.
To do this you would need to make a custom event arg to pass the data, a delegate for the event name and args, and expose the actual event on your form.
If however only one form exists at a time, you could either have an in memory store you push data to and then read it out of (much like your current implementation), or when you flip from one form to the other you pass in the data that has changed.
Ultimately I would try to avoid having global style data, be it in a file, memory or a global program variable, and opt for some loosely coupled approach, but without knowing your actual implementation its difficult to advise a specific solution.
Class members that are declared as public static are accessible with:
ClassName.MemberName

Is it bad design to pass a form as an argument to a class just to access some of its variables or methods?

I found that I can either pass 8 arguments to a class constructor or just pass the form variable instead.
However, since I am not using everything on the form it seems like it may be bad design?
Also, the objects I do access I would need to provide accessors for.
Does it violate the principles of OOP?
It depends - if you're using the form as that specific type of form, and "logically" it makes sense that you're working with the form, then by all means, pass a reference to the form.
It's just like any other class - If I was going to be accessing elements of an "employee", I'd write:
void DoSomething(Employee employee) { ...
Instead of:
void DoSomething(string firstName, string lastName, DateTime hireDate...) { ...
The first is very clean and obvious.
However, if the data you're using is unrelated to the form, it'd be better to encapsulate it into its own class usable by both the form and your class.
Also, the objects I do access I would need to provide accessors for.
If this is the case, I suspect that having a class encapsulating the data is likely a better design... The form could expose a property or method that returns an instance of that class, and pass it into your second class.
Passing a gui form to either other gui components or even worse, a model/library that does work does break encapsulation and creates a tight coupling.
The form should abstract the data and the model below. Other model or library classes should be passed model objects. A typical pattern is to "bind" the gui layer to the model.
Instead of passing 8 variables, do the 8 variables logically break into different objects? Ideally, you would pass an object or set of objects which may collectively contain 8 member variables. Then you can simply pass references to objects that are contained in the same model that your gui is abstracting and bound to.
Without seeing the class, I can almost guarantee the class taking 8 arguments is violating the Single Responsibility Principle. It could be a class generated to represent a table in a database (or something to that effect) in which case you should encapsulate it in its own class as pass it around instead of the form.
Something else to consider is that the form you're reviewing is also violating SRP since it's both displaying data and being used as backing for another form.
It typically is, because typically people are lazy or don't understand how to use events, so they write code like this:
class MainForm : Form
{
// stuff
}
class ChildForm : Form
{
private MainForm _mainFrm;
public ChildForm( MainForm frm )
{
_mainFrm = frm;
}
private void someButton_Click( ... )
{
_mainFrm.UpdateSomeText();
}
}
That code creates a terrible coupling between two different UI classes. Now, in a simple, internal, maybe throwaway project it is probably fine and you can write it once and move on. In general it means that you very well may need to change your ChildForm class in response to changes in your MainForm class, which is undesirable and can be avoided via weak coupling mechanisms like events.
On the other hand, there are valid cases to pass in a form to a method or constructor, though these situations are less common in practice. It all boils down to what you code is doing and if it is optimally designed. There is no rulebook for this, it takes years of practice and requires that you make many mistakes first so that you know what to avoid before writing any code at all.
I can imagine a class that controls the formatting of a form (font, size, color etc) that could take a variable of type Form as an argument. I could argue that THAT structure wouldn't violate OO principles. Anything short of that probably not.
Even if you need customer details in the new class and you're tempted to pass the CustomerForm, which contains all the details you need, DON'T DO IT. Create a customer class, provide an instance of that class from the form and pass that instance to the new class instead. If you ever change the UI, or if you ever need to automate part of the workflow that used to be manual you'll be glad you did.

What is the best practice for communicating forms?

When I need to pass some information from a form to another I usually do the following:
Form2 form = new Form2(this);
form.ShowDialog();
And inside Form2.cs, I use a constructor like:
private Form1 parent;
public Form2(Form1 form)
{
...
parent = form;
}
This way I can get a information from a textbox doing parent.textbox1.Text only if textbox1 is not a private member from Form1. Ok, a lot of time I need to get information about controls in Form1, should I make the setters and getters for each attribute of a control needed in Form2? For example: I need to know the values of Text, ReadOnly and Location. Should I make the setters and getters for each one of these attributes? Is the use of internal modifier a bad practice?
The correct way to do it is with delegates. They are really pretty simple but it takes awhile to get your head around them. Here is a great example of what I think you're looking for: http://samgaut.blogspot.com/2007/11/use-delegates-to-pass-data-between.html
Since I am not allowed to add comments to answers I'm going to add this.
The linked blog post from the accepted answer does not make sense to me (could just be my lack of thorough understanding of delegates).
If the next-in-line form frmDestination has a publicly accessible setter method (SetCustomerID(string strCustID)), then why do you need to pass that into a delegate when you can just pass customerID directly to the setter?
I noticed he mentioned that
Basically, the member variable that is set within the delegate method will be populated before the Form_Load event is executed. If you notice the delegate call is executed before the frmDestination.Show() call is made. This way, you have that variable available to execute in your Form_Load processing.
Would just calling dest.SetCustomerID(customerID) before dest.Show() not do the same thing?
Seeing as this is not a reusable framework from what I can tell, I wouldn't create wrapper properties around the control properties.
If there was something that needed to be flexible about this parent form then the proper course might be to use an interface that specifies the particular controls exist or a specific base form class.

Any repercussions to shorthand dialog display?

Anyone who's done any UI work with .Net and WinForms is very familiar with this type of code:
TestForm frm = new TestForm();
frm.ShowDialog();
I found myself wishing that a call to show a modal dialog was a little less verbose, more like a static call. Andf there is a simpler way. All you really need, in a simple case, is something like this:
new TestForm().ShowDialog();
Am i missing anything? Could there be any repercussions from this kind of shorthand? E.g. windows messages not handled/routed correctly, dialog's resources not disposed etc.?
Was working on this when i saw Ray's feedback:
i suppose an even shorter way would be to create a static member withing TestForm that creates an instance of itself and calls ShowDialog internally. So, this code:
public static DialogResult DoModal()
{
return new TestForm().ShowDialog();
}
could be invoked thusly:
TestForm.DoModal();
If you don't want to reuse the form object anywhere in your code you can just use the short form
new TestForm().ShowDialog();
If you want to do something later with that object then you must assign it to a variable.
Pretty simple. Hide form constructor (make it private), then add static factory method that would initialize new instance of the form and show it straight away.
For example see MessageBox source codes (Mono, if I'm not mistaken)
link
Typical use of ShowDialog should look like this:
using (Form form = new Form())
{
// here setup your form instance
if (DialogResult.OK == form.ShowDialog())
{
// here read data from form instance
}
}
Please be aware that ShowDialog() causes form instance to not dispose itself. You should dispose it manually once you are done with it - hence using clause See http://msdn.microsoft.com/en-us/library/w61zzfwe.aspx for details. In your scenario this should look like below:
public static DialogResult DoModal()
{
using (Form form = new TestForm())
return form.ShowDialog();
}
But this is useful only when you don't need to read any data back from your form instance. So the only scenario that fits here is message box. MessageBox.Show(...) methods utilize pattern you want to implement in your post.
in other scenarios forms are supposed to return data other than DialogResult back to application after they are closed. And that's why standard Form does not have static ShowDialog() or DoModal() methods. Static method should dispose temporal form instance. Such disposal would make impossible to read data back from form. What is more, in static method scenario there is no form instance to read data back from.
Putting all together, your method, to be compliant with guidelines, should look more like:
public static YourResultClass DoModal()
{
using (TestForm form = new TestForm())
if (DislogResult.OK == form.ShowDialog())
{
YourResultClass result = new YourResultClass();
// Here initialize YourResultClass instance with data from form instance
return result;
}
}
But that is very use case specific and quite far from your one-liner utility method.

Categories

Resources