One Common Class to Store Objects of All Forms - c#

I have a windows Forms project with 8 forms. Everytime I open a new Form I do this:
new FormX().Show();
this.Hide();
Due to this, I realized I am creating Multiple objects of Same form while it's previous copies exist, i.e if once i opened FormX and then I hid it and called next Form. When my work was done with it and I had to go back to FormX, I created the object once again. I do not want to do this as this consumes memory and makes application slow.
I want to know if there is a way to store all the objects of all forms in one class/form like this:
Form1 obj1=new Form1();
Form2 obj2=new Form2();
and everytime i need to make one of them visible I simply write obj1.show() or obj2.show()
Is it possible to store these objects in Program.cs class?

The question is somewhat vague. But based on what you seem to be asking, you have a couple of options in addition to the one you propose:
Don't try to reuse the form. Instead of calling Hide() just call Close().
Implement each Form class as a singleton. Then make sure you don't close each form (i.e. continue to call Hide() instead), and access the relevant instance from the static instance property.
Example of #2:
class Form1 : Form
{
private static readonly Lazy<Form1> _instance = new Lazy<Form1>(() => new Form1());
public static Form1 Instance { get { return _instance.Value; } }
}
then elsewhere…
Form1.Instance.Show();
// ... do some stuff with Form1
Form1.Instance.Hide();

Related

Is it a bad idea to give a C# form a static property pointing to the only instance of the same form?

I have a fairly simple application that monitors folder activity and logs it on a server.
In this application I start off with a Form object called Form1. On this form I have a NotifyIcon. Because I need to change the text in the BalloonTip of the NotifyIcon from different Forms along the way, I was thinking of setting a static property of Form1 that will point to the only instance of Form1. This is how it would look in my oppinion:
public partial class Form1 : Form
{
private static Form1 staticRef;
// Other private properties
public Form1()
{
InitializeComponent();
staticRef = this;
// Rest of constructor logic
}
public static void changeNotifyBalloonText(String newText, int timeInMillis)
{
if (staticRef != null && staticRef.notifyIcon1 != null)
{
staticRef.notifyIcon1.BalloonTipText = newText;
staticRef.notifyIcon1.ShowBalloonTip(timeInMillis);
}
}
// Rest of public and private methods
}
Other things to be noted:
a. There will never be more than 1 instance of Form1.
b. I always check the value of staticRef against null, before trying to use it.
c. I cannot afford to make a temporary, local instance of Form1 just to set a BalloonTip message.
d. This solution works very well, i'm more interested in knowing if it's "too hacky" and if so - what would be a better approach to my issue?
e. The closest thing I've found that may answer my question (about static properties) to some degree is here:
Is using a static property in a form bad practice knowing that there's only only one instance of the form?
What you have here is a form of the singleton pattern.
The singleton pattern certainly has its detractors and its defenders (google "singleton anti-pattern").
It is though a very convenient way of doing this.
I would recommend an approach like either::
Create a class that represents operations on a notify icon.
Have that class as the only class that accesses staticRef.notifyIcon1.
Have it do so as a reference to notifyIcon1, not as Form1.
Have a static method or property that gets the icon-controlling class.
Or:
Simply have a static method or property that returns the NotifyIcon object.
Make it the only method that accesses the static reference to the form.
The advantage of one over the other is around whether you want to expose the full interface of NotifyIcon or provide a set of operations that make sense to your application.
This way you are still using the singleton pattern, but in restricting the way that it is accessed the fact that there is global state has less of a global impact, relates more directly to the purpose of that global state (the icon itself), and is more readily extended to different uses. e.g. if you some day need to have two icons, you change the method that static method or property to one that does a lookup of some sort, and change all the current calls to use the key for the first icon. Meanwhile, implementation changes up to and including completely changing which form provides that icon can be done quickly in one place.
I think your current design is tightly coupled to other classes sending the notification and it requires your form to be a single instance as well.
You can decouple this a great deal by using an event broker to send the notification to any interested parties. Many frameworks have event brokers, I have used one from Prism but there are others as well.
Your code will then only know about the event broker and what events your class is interested in.
public partial class Form1 : Form
{
private static IEventBroker eventBroker;
// Other private properties
public Form1(IEventBroker eventBroker)
{
InitializeComponent();
this.eventBroker = eventBroker;
this.eventBroker.Register<NotifyBaloonText>(changeNotifyBalloonText);
}
public static void changeNotifyBalloonText(NotifyBaloonText args)
{
notifyIcon1.BalloonTipText = args.NewText;
notifyIcon1.ShowBalloonTip(args.TimeInMillis);
}
// Rest of public and private methods
}

Accessing private functions on another form

I have a function named private void QuizReset() on a form called FormMain and I was wondering if there was a way to access it on a form named Form2 without getting build errors? Might seem like a really simple question or something I'm missing, but I've tried changing it from private to public and I mustn't be doing it right as I get build errors and such. I'm all up for modifying it if it can be done without errors. If anyone could help me out that'd be great.
Thank you.
The current code for the function is:
private void QuizReset()
{
//resets the difficulty selection control and shows it again upon resetting the quiz
difficultySelectionControl.Reset();
difficultySelectionControl.BringToFront();
btnNext.Enabled = false;
lblStatus.Text = "Please select a difficulty";
iCorrectACount = 0;
iCurrentQIndex = 0;
}
If you want to access the method it can't be private. static public is a simple work around. Then you can call it with MainForm.LoadQuiz(). Another option is to move the logic into a helper class.
Put them in a public common class. Then put LoadQuiz function as a private static method that belongs to that class. You can also make LoadQuiz a static public, which is quick and dirty. I don't recommend that, because exposing methods publically could cause memory and allocation problems down the road.
I think you cannot put this function in common static class, because, if I understand right, the function use a controls of the form(btnNext.Enabled = false;). This mean that function can/must be used only with instance of the FormMain class.
If you want call this function from Form2, then Form2 must to have a reference of FormMain.
My approach will be next:
Create a variable in Form2:
private FormMain frmMain;
Then create a constructor of Form2 where i assign a reference of FormMain in Form2
public Form2(FormMain inFrmMain)
{
this.frmMain = inFrmMain;
}
Code for opening of Form2 will be then:
Form2 frm2 = New Form2(this);
frm2.Show();
After this you can call your FormMain function from Form2:
this.frmMain.QuizReset()
And of course, at first change function QuizReset to public

Accessing Form3.pictureBox1 out of Form1

I search a easy way to access different controls on different forms without any workarounds like I would do this e. g. in Visual Basic 6.
Example:
Form3.pictureBox1.Image = MyImage;
But somehow C# doesn't allow accessing another controls on another forms not even from my own classes. I already changed the "pictureBox1" in Form3 to public and still C# doesn't know this control if I type "Form3.".
What I have to do, to access my controls? I already run Visual Studio with elevated privileges (Microsoft answered me on my question in their support area, that elevated privileges are important for accessing the other forms and the controls on it) but nothing helped me sofar. So I stay now with the one form always in C# and this is not suitable to develop any application. Most applications need multiple forms and therefor should be a easy way to access controls from any context in a class or another form. I don't want to use any "set...or get properties" - I do not know even how! Somewhere I found this specific workaround but I usually have so many controls and labels to access in my application, that this would generate a lot of useless overhead, if each control property needs a get- and set-statement or whatever to write to it.
Maybe someone of you knows a more elegant method to do this in a more simple way even if elevation needed.
In VB6 you could access the default instance of your form by using the Class name, in VB.Net they have continued that behavior. C# doesn't have that behavior, therefore you have to create your own instance of your Form. Otherwise you are trying to use it like a static Class. Even though you do not want to, the best way to do want you want is to expose them through properties it keeps everything encapsulated.
Form3 frm3 = new Form3();
frm3.pictureBox1.Image = Image.FromFile("ImageName");
frm3.Show();
I think I know what is wrong. Form1 and Form3 are in fact classes, so typing Form1.something means that something must be a static member. In order to be able to access the picture, you need an instance of the class.
To explain this better, here is an example:
string a;
string is the class type, and a is an instance of that class.
A method to do this would be to modify the startup code (in windows forms that would be in the Program.cs source file), and save the form in a static class, and access it from there.
This is what Program.cs probably looks like:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
You can see that a new instance of Form1 is being created, that is what the new keyword does. You could also do the following:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 f = new Form1();
Application.Run(f);
}
The variable f contains the form being displayed.
I don't really know how your program works, but anyway... to be able to access members of Form3, you need to find the instance. Maybe you have new Form3().Show() somewhere in your code, I don't know exactly... but you need to save that to a variable, and that's how you can access it.
You need to change the modifier property of the objects to public, than you make a instance of the form and call the object you want
Form2 frm2 = new Form2();
frm2.show();
frm2.pictureBox1.Image = "MyImage";
Form3 may refer to the class. You need to use an object to access picturebox1 (or make the field static)

How do I use a custom constructor in a WinForm?

I need to instantiate a Winform within another project. How is this done? I am currently attempting to chain the default constructor. It seems that my custom constructor is not called.
Also.. the entry point for this application will not be in the project that owns this form. Meaning the following will not run:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new HtmlTestForm());
I am not entirely sure what this code is doing. Will the form still function?
private HtmlTestForm()
{
InitializeComponent();
OpenBrowser(new Uri(TestURL));
}
public HtmlTestForm(Uri uri)
:this()
{
TestURL = uri;
}
//New up form in another project.
HtmlTestForm form = new HtmlTestForm(new Uri("http://SomeUri.html"));
The form will work.
However, TestURL will only be assigned after the OpenBrowser call. (: this() will execute the entire default constructor first)
Instead, you should probably call InitializeComponent separately in your custom constructor and not chain to the default.
.Net form classes are normal classes that happen to contain an automatically generated method called InitializeComponent.
They do not have any magic that you need to be aware of (unlike VB6); as long as you understand the purpose of InitializeComponent (read its source), you can do anything you want with them.

Trying to figure how to call function from other class without making it static

I'm trying to change a listbox in my main form from another file (nodes.cs) which contains another class. I created a class in my main form that changes the textbox for me so all I need to do it pass the string to it. Unfortunately, I can't access the function from the other class unless I make the String-changing-class static. If I make it static, I can't change the listbox without getting an error:
An object reference is required for the non-static field, method, or property...
I know this means I need to create the object or make it non-static. I find the whole class thing rather confusing. I have to initiate a whole new form object to access it? Anyways.
How do I go about accessing a Listbox from another Class, contained in another file? The two classes are in the same namespace.
there's no real point in adding what I have, it's a huge amount of code, and i erased everything I've tried already...
MAIN.CS
namespace neuralnetwork
{
public partial class mainform : Form
{
yada yada
public static void changetext(string text)
{
listbox1.items.add(text);
}
}
}
Secondary.cs
namespace neuralnetwork
{
class lolercopter
{
public static void dolol()
{
//here is where I want to change the mainforms textbox.
mainform.changetext(s);
}
}
}
This is essentially what I have. I've been reading for over an hour on this...
You can pass a reference to mainform into your method:
public static void dolol(mainform frm)
{
frm.changetext(s);
}
Your question leads me to suspect that you have some serious architecture issues with this application, but hopefully this solution can work for you.
classes are like blueprints.
What you're asking is like asking how to open the door down the hall on the blueprint.
It sounds like you want action on one form to trigger action or changed state on another form. That could be achieved by storing state in a database, or in memory, but ideally by having a reference to the instantiated mainform.
How is your nodes class created? Is it created by the form? If so, you could pass in a reference to the form when you create the nodes class.
For example, say you have this code in a callback in the form.
var nodes = new Nodes();
nodes.UpdateSomething( args );
You could change the constructor for the Nodes class so that it takes a reference to form. This is called Dependency Injection, specifically constructor injection. Your class has a dependency on the form, you provide the form when you create the class.
var nodes = new Nodes( this ); // "this" is a reference to the form
nodes.UpdateSomething( args );
Your Nodes class would then use the helper as:
public class Nodes
{
private Form TheForm { get; set; }
public Nodes( Form form )
{
this.TheForm = form;
}
public void UpdateSomething( EventArgs args )
{
...
this.Form.ChangeText( newValue );
...
}
}
The basic idea is to provide the class the resources that it needs access to via the constructor so you don't have to make use of long-lived object references and static classes.
EDIT: I've updated this to reflect your code sample. Note that you're not providing a new class in the form to change the list box, but rather a method.

Categories