Accessing a Variable inForm1 from another class - c#

I have been searching for some time now and can't really find a good solution to my problem.
I got a class (lets call it TaskbarNotifier) and my Form1
In TaskbarNotifier I got this:
private Form1 form = new Form1();
And later in that class I got this:
this.form.NotifiersCount = this.form.NotifiersCount - 1;
switch (notifier)
{
case 0:
this.form.NewsShown = false;
break;
case 1:
this.form.ThreadsSown = false;
break;
}
now my problem is that when I do this I get a StackOverflow error at:
private Form1 form = new Form1();
Id there another better way to access variables in Form1 from another class?
Many thanks for reading :)
----EDIT----
Okay so in Form1 constructor I got this:
private ContextMenuStrip contextMenu = new ContextMenuStrip();
private ToolStripMenuItem mnuItemExit = new ToolStripMenuItem();
private ToolStripMenuItem mnuItemShow = new ToolStripMenuItem();
Which is where the stackoverflow actually starts.
But by removing:
private Form1 form = new Form1();
from TaskbarNotifier it don't throw any errors.

Clearly, you are creating a TaskbarNotifier somewhere in the construction process of Form1.
That could happen if:
You explicitly wrote var test = new TaskbarNotifier() in the constructor
You dropped a control of that type onto the designer
In either case, Form1 will construct a TaskbarNotifier which then constructs a Form1 and, well, this happens a whole bunch of times and you get a Stack Overflow.
Make sure that the TaskbarNotifier is not created as part of Form1 creation and the error will go away.

Related

C# Using function from another file

Ok, so, I have functions.cs file where i stored following function
public static void Global_Reset()
{
Form1 blok = new Form1();
blok.userControl1.Visible = false;
blok.userControl2.Visible = false;
blok.userControl3.Visible = false;
if (Properties.Settings.Default.client == 1)
{
blok.userControl1.Visible = true;
MessageBox.Show("First");
}
else if (Properties.Settings.Default.client == 2)
{
blok.userControl2.Visible = true;
MessageBox.Show("Second");
}
else if (Properties.Settings.Default.client == 3)
{
blok.userControl2.Visible = true;
MessageBox.Show("Third");
}
else
{
MessageBox.Show("Error");
}
}
When I call fun.Global_Reset() in Form1 or in any user control that is used in Form1, visibility never changes but I got messages (First, Second, Third). Is there any way to solve this?
I tried to use this directly in Form1 and it used to work, but when I call it from userControl that was used in Form1 it's not working again.
This is the form you're modifying:
Form1 blok = new Form1();
It only exists during the scope of that method (function), and it is never shown to the user. It's not the form instance you're seeing on the screen.
As an analogy... Imagine the form you're seeing is a car. What you're doing is getting another car that looks just like it and putting something in the trunk of that car, then noticing that what you put in the trunk of the second car can't be found in the trunk of the first car.
Instead of creating a new form instance, pass the existing instance to this method:
public static void Global_Reset(Form1 blok)
{
// don't create an instance here, just use the blok that was passed
}
Then pass that instance from your form, for example:
fun.Global_Reset(this);

changing textlabel in form1 using different class

having a bit of a problem changing the label text when a button is pressed. my code looks like this. i searched a bit in this forum and tried this solution in form1 i have this code.
public string info
{
get
{
return label11.Text;
}
set
{
label11.Text = value;
}
}
in class search i have this
public void fighting()
{
character tom = new character();
Form1 f = new Form1();
Random explore = new Random();
int exploration = explore.Next(0, 3);
if (character.location == "Forest" || character.location == "Dungeon")
{
switch (exploration)
{
case 0:
f.info = "You didnt find anything";
f.Refresh();
f.herodamage = exploration.ToString();
break;
...
the button has this
public void button8_Click(object sender, EventArgs e)
{
Search find = new Search();
find.fighting();
}
what am i doing wrong? everytime i press the button the text wont change but it works because it does change a buttons text.
Fighting method is creating a new instance of Form1, different from your UI.
While it is updating label1.Text, it refers to different Form1.
My suggestion is for refactoring of your code to make responsibilities more clear.
Something like
var info = find.fighting(); // Where fighting returns string, instead of creating new Form1 and setting value, just return the value.
this.info = info;
If you still insist to update UI from search method, which is not correct way to approach this problem, you can pass around Form1 from the parameter.
Search find = new Search(this); // Store it as instance of Search class.
find.fighting(); // fighting should never create new instance of Form1 (reason of problem you are facing)
Instead of creating a new instance of Form1 you need to get a reference to the already existing instance of this form.
One simple way to do this is to use the Application.OpenForms property:
character tom = new character();
Form1 f = Application.OpenForms.OfType<Form1>().FirstOrDefault();
Random explore = new Random();
...

stop executing code after new form is loaded

Some method call this method which has this code:
Form frm = new Form();
frm.Show();
but i do not want to execute first method anymore after form is loaded. How can i prevent and stop loading code in forst form
Very unclear, I'm guessing that you want to make sure that only one instance of a form can be created. You do so by keeping track of the life of the instance. Like this:
private Form2 instance;
private void showForm2() {
if (instance == null) {
instance = new Form2();
instance.FormClosed += delegate { instance = null; };
instance.Show();
}
else {
instance.WindowState = FormWindowState.Normal;
instance.Focus();
}
}
Edit: question is very unclear so I give an answer based on my understanding of it...
to block execution after a form has been created, until such form is closed, try to use ShowDialog()
using(var frm = new Form1())
{
frm.ShowDialog();
// here your code is not executed until frm is closed...
//...
//...
}
Please pay attention that you do not want to create an object of type Form as that is the default base class and will not contain your controls...

c# Windows form application forms problem

I have a c# windows form app which contains several forms.
Generally, for example, in form1, I create a instance of form2 and then
form1.hide();
form2.show();
But sometimes I want the previous form to show and dispose current form. How can I call the previous form?
Thanks in advance.
To answer your question, you need to maintain references in your views to each other. While this might work it's messy and error prone. It sounds like all your control logic is probably contained within your form class code and I would suggest moving away from that and separate your concerns.
Solving your form management issues becomes very simple if you create a controller class that, at a minimum, manages the creation and disposal of your forms in whatever way you see fit.
So your code sample would actually be launched from a controller class as something like:
public class FormsController
{
private Form form1 = new Form();
private Form form2 = new Form();
public void SwitchForms()
{
form1.hide();
form2.show();
}
}
For further edification checkout the MVC architectural pattern for cleanly working with data, biz logic and UI.
You might consider extending Form to include some properties/fields that allow you to access other forms. the Form class can be inherited from just like most other .Net classes.
You may also consider doing some of that management in the Program.cs file that is part of you project, if neither form is really supposed to be a child of the other.
If you inherit a new class for your form1 from Form and add a method like closeSecondForm you can have it close and dispose the second form.
There are probably a bunch of different ways to solve the issue. These are just a few.
If you set the new form's Owner to a reference to the current form, you can reference that Owner from the new form. You could also subscribe to the new form's Closed() event from the old form, with code to dispose it (though the form can dispose itself by overriding OnClosed, if it doesn't happen there anyway).
This logic should be handled in Program.cs. The Main() method initializes Form1. You want to take control there instead of passing control to the form.
Example:
static class Program
{
internal static Form1 MyForm1;
internal static Form2 MyForm2;
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
// Initialize Form1
MyForm1 = new Form1();
MyForm1.FormClosing += new FormClosingEventHandler(MyForm1_FormClosing);
// You may want to initialize Form2 on-demand instead of up front like here.
MyForm2 = new Form1();
MyForm2.FormClosing += new FormClosingEventHandler(MyForm2_FormClosing);
// Show Form1 first
MyForm1.Show();
// Now we need to occupy the thread so it won't exit the app. This is normally the job of Application.Run.
// An alternative to this is to have a third form you pass on control to.
while (true)
{
Application.DoEvents();
System.Threading.Thread.Sleep(10);
}
}
static void MyForm1_FormClosing(object sender, FormClosingEventArgs e)
{
// Do something, for example show Form2
MyForm2.Show();
// EXAMPLE: We only want to hide it?
e.Cancel = true;
MyForm1.Visible = false;
}
static void MyForm2_FormClosing(object sender, FormClosingEventArgs e)
{
// Do something, for example show Form1
MyForm1.Show();
// EXAMPLE: We only want to hide it?
e.Cancel = true;
MyForm2.Visible = false;
}
}
Since Program is static you can access MyForm1 and MyForm2 anywhere in that project by:
Program.MyForm1.Show();
Program.MyForm2.Hide();
If you plan to have many forms/complex logic I suggest moving this to a separate class. Also consider using a single form and rotate user controls inside it instead.
Form2 myform = new Form2();
myform.show();
this.hide();
You could do this in form1:
...
var form2 = new form2();
form2.Closing += (form2_Closing);
this.hide();
form2.show();
...
private void form2_Closing(object sender, System.EventArgs e)
{
this.show();
}

Adding Controls to Form from another class

I have a program, which creates one pictureBox in Form1, and then creates an instance of a class that I called InitialState. The InitialState puts the source to the Image so that it is displayed, and after some time has passed, for which I used a Timer, it creates the next class, MainMenuState. Now, in that MainMenuState class that I've created, I would like to create another pictureBox and make it display on that Form1. Later on, I would like to make the pictures inside it change a bit, and then (possibly) destroy that pictureBox. After that, the program enters the next state (which is in yet another class), and again I would like that class to add a picture box to the original form, and so on.
Basically, I would like to dynamically add controls to the main Form1, but not in the said form, but from the classes I create later on. I've been searching on the internet for a way to do that, and it seems like I would have to use a delegate in order to invoke the Controls.Add method of the Form1 class. I've tried that, and the code compiles, but the pictureBox still doesn't show up.
Here's my code:
Form1 class:
public const string RESOURCE_PATH = "C:/Users/Noel/Documents/Visual Studio 2010/Projects/A/Resources/Animations/";
public Form1()
{
InitializeComponent(); //here, the first pictureBox shows
iInitializeComponent();
zacetnaAnimacija.Dock = DockStyle.Fill; //zacetnaAnimacija is the first pictureBox that appears
zacetnaAnimacija.Anchor = AnchorStyles.Top | AnchorStyles.Left;
zacetnaAnimacija.SizeMode = PictureBoxSizeMode.StretchImage;
InitialState intialState = new InitialState(this, zacetnaAnimacija); //entering InitialState
}
InitialState class:
class InitialState : State
{
System.Timers.Timer initialTimer;
PictureBox pictureBox1;
Form1 form;
public InitialState (Form1 form, PictureBox pictureBox1) {
this.form = form;
GifImage zacetnaSlika = new GifImage(Form1.RESOURCE_PATH + "Presenting.gif"); //this is just a .gif picture I'm displaying
Image trenutnaSlika = zacetnaSlika.GetFrame(0); //a method that plays the .gif
pictureBox1.Image = trenutnaSlika; //makes the first .gif display
this.pictureBox1 = pictureBox1;
initialTimer = new System.Timers.Timer(2500);
initialTimer.Enabled = true;
initialTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
initialTimer.Enabled = false;
MainMenuState menuState = new MainMenuState(form, pictureBox1); //enters main menu state with the Form1 argument passed on
}
MainMenuState class:
class MainMenuState : State
{
Form1 form;
public MainMenuState (Form1 form, PictureBox pictureBox1) {
this.form = form;
GifImage zacetnaSlika = new GifImage(Form1.RESOURCE_PATH + "animated.gif");
Image trenutnaSlika = zacetnaSlika.GetFrame(0);
pictureBox1.Image = trenutnaSlika; //this simply makes another .gif appear in the picture box instead of the first one
PictureBox a = new PictureBox(); //HERE'S my problem, when I want to add ANOTHER pictureBox to that form.
a.BackgroundImage = trenutnaSlika;
a.Location = new System.Drawing.Point(0, 0);
a.Name = "zacetnaAnimacija";
a.Size = new System.Drawing.Size(150, 150);
a.TabIndex = 1;
a.TabStop = false;
AddControl(a); //calling the delegate
}
public delegate void AddControls(PictureBox a);
public void AddControl(PictureBox a)
{
if (form.InvokeRequired)
{
AddControls del = new AddControls(AddControl);
form.Invoke(del, new object[] { a });
}
else
{
form.Controls.Add(a);
}
}
As I've said, the code compiles, but it doesn't create the PictureBox a on the Form1, when the MainMenuState is created. The thing is, if I don't use the delegate in the MainMenuState and just try to do something like form.Controls.Add(a), then I get a "cross-thread operation not valid" exception, and it doesn't even compile. That's why I used the delegate, but even now, it doesn't work.
Can someone please help me?
initialTimer = new System.Timers.Timer(2500);
That's part of the reason you're having trouble. The Elapsed event runs on a threadpool thread, forcing you to do the BeginInvoke song and dance. Use a System.Windows.Forms.Timer instead, its Tick event runs on the UI thread.
You'll also run into trouble with memory management, these classes need to implement IDisposable.
Oh my God, I just found the reason X_x
It was the fact that since the first pictureBox was covering the entire form, and the second one, which was created by the delegate, showed behind it! I just need to bring it to front!
Thank you guys, nonetheless, I probably wouldn't have come to that without you.
Edit: However, may I ask how to bring that control to the front? The a.BringToFront() function doesn't seem to work.
Instead of
form.Invoke(del, new object[]{a});
try:
form.Invoke(new ThreadStart(delegate
{
form.Controls.Add(a);
}
));

Categories