Windows Forms - Integer being reset upon form load - c#

My issue is that an integer created in my main class,
public int loadCountGold = 0;
that is incremented to when a button triggering the appearance of another form
public void goldButton_Click(object sender, EventArgs e)
{
loadCountGold += 5;
Console.WriteLine(loadCountGold);
GoldForm gForm = new GoldForm();
gForm.Show();
}
Is not having its incremented value carried over to the form where it needs to be used in an if statement.
private void GoldForm_Load(object sender, EventArgs e)
{
//Sets the random (within reason) value for gold
if (main.loadCountGold <= 1)//if its the firstload of the form
{
Console.WriteLine(main.loadCountGold);
Random rand = new Random();
currentGoldValue = rand.Next(1200, 1350);
}
}
I had included a few write lines at points before the form is opened, and one within the problem form to see what was happening to the value. This can be seen below
It shows the output that my program is giving, highlighted are the outputs from my "Main" class and the other are the ones being produced from the problem form.
The aim is to have the value incremented each time the form is opened so that the code within the if statement is only run the first time the form is opened, but currently it is running every time. (I am aware I would need to change the amount it is incremented)

In your main form, call GoldForm like this:
GoldForm gForm = new GoldForm(this);
In the constructor of GoldForm, do it like this:
Main main;
public GoldForm(Main main)
{
InitializeComponent();
this.main = main;
}
Now you don't create a new instance of Main every time you click the button.
Output after 3 button clicks:
5
10
15

This is an issue of needing a static variable rather than one instanced with the class. The easy answer is to change your integer declaration to:
public static int loadCountGold = 0;
now all references to this variable will point to the same thing.
I should specify that your reference in the later form needs to be Main with a capital M.
if (Main.loadCountGold <= 1)//if its the firstload of the form

Related

C# Get variable from popup form that will be closed

I have a form populated with an array of userControls that is created from the main form. I need to be able to access this array of userControls from the main form once the popup has been closed when a button is pressed. If I fill out the forms and then press the button on the main form without closing the popup, the values are present. However, if I close the popup window, the values are not present. My main form is static so I can use it's variables in other forms.
Code for the popup:
public ScanChannel[] controls;
public ScanListSetup()
{
InitializeComponent();
int numChans = Convert.ToInt32(Form1.Self.numChannels.Text);
controls = new ScanChannel[numChans];
// Create the UserControls
for(int i = 0; i < numChans; i++)
{
controls[i] = new ScanChannel();
}
// Place them
for (int i = 0; i < numChans; i++)
{
controls[i].Location = new Point(13,(35+25*(i)));
this.Controls.Add(controls[i]);
}
doneButton.Location = new Point(82, 35 + (25 * (numChans + 1)));
this.Size =new Size(280, 110 + (25 * (numChans + 1)));
}
private void doneButton_Click(object sender, EventArgs e)
{
Form1.Self.setChannelsToScan(controls);
}
I need to access the controls array in the main form. The code for the main form is as follows:
private ScanChannel[] channelsToScan;
private void configureScanListButton_Click(object sender, EventArgs e)
{
var form = new ScanListSetup();
form.Show(this);
scanListConfigured = true;
this.channelsToScan = new ScanChannel[Convert.ToInt32(numChannels.Text)];
}
public void setChannelsToScan(ScanChannel[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
this.channelsToScan[i] = arr[i];
}
}
private void scanButton_Click(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine("Test: " + this.channelsToScan[0].getDeviceType());
// THIS PRINTS AN EMPTY STRING
}
So, the Debug writeLine outputs the correct value if I click the scanButton while the popup form is still open. However, if I close the form after clicking the doneButton on the popup form, the Debug writeLine outputs Test: with nothing else.
Any help with this would be greatly appreciated. Thanks.
Your problem essentially boils down to sending data from a secondary window (your 'pop-up' window) to the main window from where it was created. It doesn't matter whether you're working with Windows Control objects or simple data types like string, so I'm going to use a simple example to illustrate how to handle such a situation.
Let's assume you have a Main form that looks like this. It has an OPEN button and a TextBox.
When you click OPEN, it opens up this secondary input window (your pop-up) which looks like this:
Now the idea is this. You click OPEN and opens the Input form, and lets the user enter some text into the TextBox there. Once you click the OK button, it should close the Input window, and display the text entered by the user in the Main window. Remember that at this point the Input window is closed, which is equivalent to your situation.
So I'd make use of Delegates to accomplish this goal. A delegate lets you transfer data between windows which is what you want.
In my Main I'd declare a public delegate with a signature like this:
public delegate void DataTransfer(string data);
That is, this delegate represents a method that takes in a single string parameter, and has void return type. The idea is to let the secondary Input window 'call' a method in the Main, and that method takes in a string parameter. So, if there was a way for us to call a method that resides in the Main from Input, and pass a string, we can then take the user input text in the Input window, and pass it to the Main window. With me so far?
Now, if I write a method like this in the Main, and let it be called from Input, that should accomplish our goal. Here, txtDisplay is the TextBox in the Main form.
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
To accomplish this, I would define a delegate of type DataTransfer in the Main form like below, and register the ReceiveInput() method to it. Your Main form code behind should look like this:
public delegate void DataTransfer(string data);
public partial class MainForm : Form
{
public DataTransfer transferDelegate;
InputForm inputForm = null;
public MainForm()
{
InitializeComponent();
transferDelegate += new DataTransfer(ReceiveInput);
}
public void ReceiveInput(string data)
{
txtDisplay.Text = data;
}
private void BtnOpen_Click(object sender, EventArgs e)
{
inputForm = new InputForm(transferDelegate);
inputForm.Show();
}
}
BtnOpen is the OPEN button in the Main form, and when it's clicked, it passes the delegate to the Input form, then opens it. So, accordingly, we need to now modify our Input form:
public partial class InputForm : Form
{
DataTransfer transferDel;
public InputForm(DataTransfer del)
{
InitializeComponent();
transferDel = del;
}
private void BtnOK_Click(object sender, EventArgs e)
{
string data = txtInput.Text;
transferDel.Invoke(data);
Close();
}
}
Here, we modify the constructor so that it takes in a delegate of type DataTransfer, and sets it to the local instance of the same type. Then, at the click of BtnOK on the Input form, we take in the text input by user, and pass that text to the said delegate and invoke it. 'Invoking' is the same as calling the method in the Main form. At this point, you can Clsoe() the Input window as shown above, and you'd still have access to the user input string data from your Main form.
You can use this same approach, and instead of strings you can pass around Controls. However, it's not the best approach to pass around a bunch of controls back and forth, so ideally you would extract the data you need from those controls in your pop-up, and pass only the said data instead of the whole controls.
EDIT: After OP posted the erroneous code.
OK, so here's your issue. The testUserControl class is not a regular class but a control element derived from UserControl. In otherwise, a GUI element. You shouldn't use GUI elements to pass data around. Because, when you do your controlArr[i].getText();, it tries to get the text from the textItem, but textItem is a TextBox Control which doesn't exist at this point because you closed your window. Remember, you do the delegate.Invoke() only once, and at that point *you must send ALL the data back to your main window*.
What you should do is, simply define a class to hold ALL the data you want to pass to your main. For example something like this:
public class DataToPass
{
public string TextBoxText { get; set; }
public string SomeOtherData { get; set; }
// Other stuff you want...
}
Now, instead of passing an array of testUserControl, pass an array of DataToPass. That way, at the Main form you don't have to do the following:
controlArr[i].getText();
Instead you'd simply do something like:
controlArr[i].TextBoxText;
where controlArr now is an array of type DataToPass.
Simply, passing a control derived from UserControl is not a good idea. Just create one class that is capable of holding ALL the data you want to pass and pass it back to the main once.

c# random number generator for multiple forms in one solution.

I am very new to programming and I am working on a project for school in Visual Studio but I am kinda stuck. I have multiple forms in my solution. One of my forms is an invoice and I am trying to create an invoice number when the checkout button on the previous form is clicked. I have the following code in the textBox field that I want to display my number but the number is not showing in the textBox. Please help!!
private void txtBoxInvoiceNo_TextChanged(object sender, EventArgs e)
{
Random rndNo = new Random();
int invoiceNo = rndNo.Next(1, 500);
txtInvoiceNo.Text = invoiceNo.ToString();
}
Probably need to see a bit more code here, but from what you have shown it suggests you are generating the invoice number on the textChanged event of txtBoxInvoiceNo. This event will fire when the text changes within that box. Not on creation of the form.
My suggestion would be to call a function on construction of your form. The code you have written should work, it just needs to be called in the right place.
I'm assuming you're writing winforms but something like:
public MyForm()
{
InitializeComponent();
GenerateInvoiceNumber();
}
private void GenerateInvoiceNumber()
{
Random rndNo = new Random();
int invoiceNo = rndNo.Next(1, 500);
txtInvoiceNo.Text = invoiceNo.ToString();
}
You can refactor this later into a static or extension method so it can be used by multiple forms, but the call should be made in the constructor, not in a text box changed event.
If you want to utilize something on multiple forms you better Add a Class and write a method which will return integer. Refer below sample
Public class GenerateNumber
{
public static int GetRandomNo()
{
Random rndNo = new Random();
int invoiceNo = rndNo.Next(1, 500);
return invoiceNo;
}
}
Then you can make object of class and call this function on the required form. Refer Below code
GenerateNumber randomNo = new GenerateNo();
txtInvoiceNo.Text = randomNo.GetRandomNo().ToString()

Manipulating an object with a method in another class

Hi I'm very new to c# and I was hoping someone could point me in the right direction. I have created a text box with the value "Total" set to 0 in my main class, and I have created a button "button1_Click" in my "AddFunds" class in which I want it to change the Total value by reading in what the user has in putted "Deposit" putting through a loop and incrementing the "Total". How do I get the AddFunds class to recognize the int Total in my main class?
public void textBox1_TextChanged(object sender, EventArgs e)
{
int Total = new int();
Total = 0;
////string str = Convert.ToString(Total);
////Total.Text = str;
}
public void button1_Click(object sender, EventArgs e)
{
for (int Deposit = 0; Deposit <= 0; ++Deposit)
{
Total = Deposit;
}
}
public void richTextBox1_TextChanged(int initialDeposit)
{
int Deposit = int.Parse(Console.ReadLine());
}
You have some ways of doing that, but remember if this classes you're talking about are forms, they need to exist simultaneously, anything else will end up on you trying to access a null reference.
You can create a public property Total on your main class and pass an instace of Main to AddFund
If the composition is the oposite as the above, and Main holds an instance of AddFund you can make Main inject itself on the other class or pass a Funciotn to AddFund so it can access the value
This one is the only one that doesn't sound like a code smell given the information you provided, abstract your logic to some classes that are not forms and manipulate them on the forms.

Brute Force- c#

I tried to make simple brute force algorithm.It s working normal.But I was watching this video
http://www.youtube.com/watch?v=v2xwficgRYk&feature=relmfu
(time 10:30) as you can see in textbox2 posibilities changes .But in my program.I create 1323 as a password and then when i click brute i waited 5 second and get 99999 in textbox2 and 1323 in textbox3.Why i cant see the flow of number in textbox2 like on video?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int a, b;
private void button1_Click(object sender, EventArgs e)
{
a = Convert.ToInt16(textBox1.Text);
}
private void button2_Click_1(object sender, EventArgs e)
{
for (int i = 0; i < 100000; i++)
{
textBox2.Text = "" + i;
if (a == i) textBox3.Text = "" + i;
}
}
}
That's because the program in the video is running the brute force loop in a separate thread.
In your program the loop runs in the main thread, so as long as it's running there is no thread watching the message pump where all the user interface updates happen.
Whenever the Text property of the text box is changed there is a message dropped in the message queue that the text box needs to be redrawn to show the value, but the main thread is busy running the loop and won't act on the messages until the loop is done.
In windows forms, there is a single thread for the user interface and all the code in code behind is processed on this thread too so while it's running your for loop, it's not re-drawing the changes in the screen.
The way you can get round this is to use a BackgroundWorker to do the processing on a separate thread and allow the user interface thread to re-draw the changes to the screen.
A couple of points about your code sample, you should declare your fields like this:
public partial class Form1 : Form
{
private int a;
private int b;
...
}
You should also give them more meaningful names!
Additionally, you should use the .ToString() method on int instead of concatenating it with an empty string to get the text value.
textBox2.Text = i.ToString();

Method executing several times even though it is called once

I am doing a project which includes dynamic controls creation and removal from the WinForm,
So I decided to that part on a small test project.
Test project has two files Form1.cs and NewControls.cs. This program creates additional buttons whenever user clicks an Add button already on the form.And removes the newly created button when it is clicked (self removal button). Also after removal of button other button's Name, Text and their position are changed according to a local variable (controlIndex).
Form1.cs
public partial class Form1 : Form
{
static List<NewControl> newControlsList = new List<NewControl>();
public Form1()
{
InitializeComponent();
}
private void Add_Click(object sender, EventArgs e)
{
newControlsList.Add(new NewControl(newControlsList.Count));
}
public static void RemoveButton(object sender, EventArgs e)
{
NewControl tempNewControl = (NewControl)(sender as Button).Tag;
tempNewControl.RemoveControl();
newControlsList.Remove(tempNewControl);
MessageBox.Show("Removed!");
foreach (NewControl tempcontrol in newControlsList)
{
tempcontrol.controlIndex = newControlsList.IndexOf(tempcontrol);
tempcontrol.PlaceControl();
}
}
}
NewControl.cs
class NewControl
{
public int controlIndex = 0;
Button newButton = new Button();
public NewControl(int index)
{
controlIndex = index;
PlaceControl();
}
public void RemoveControl()
{
newButton.Dispose();
Form1.ActiveForm.Controls.Remove(newButton);
}
public void PlaceControl()
{
newButton.Tag = this;
newButton.Name = "btn" + controlIndex.ToString("D2");
newButton.Text = "btn" + controlIndex.ToString("D2");
newButton.Size = new Size(100, 20);
newButton.Left = controlIndex * 100;
Form1.ActiveForm.Controls.Add(newButton);
newButton.Click += new EventHandler(Form1.RemoveButton);
}
}
Program works nearly as expected. Problem is the MessageBox which I used in form1.cs in RemoveButton() fires many time (as opposed to just one time), which implies whole method being executed several times. Actually I pasted that MessageBox for debugging (sort of).
Since I cannot debug the application as when "Form1.ActiveForm.Controls.Add(newButton);" statement is executed, debugger Throws NullReferenceException, as there is not an active form while debugging.
I know that's like a bonus question but I thought to just put it there. I am a beginner and can't see the way through both the problems. 1st problem is really important for my original project as it will cause problem when many controls are added.
I think it is because you call PlaceControl from Form1.cs AND in the constructor of the NewControl class, Because you say newButton.Click += new EventHandler(Form1.RemoveButton);.
You are adding EventHandlers, so there can be more of them.
So when you call placeControl multiple times, you've got multiple event handlers, i think.
Probably the EventHandler hasn't been removed by RemoveButton. (I've been working in java most recently so my terms might be a little off for C#.) Suggestion: set control visibility to true when you want it and false otherwise rather than adding and removing.
Everytime a button is removed you go over your existing list of controls, and you call "PlaceControl", which attaches yet another handler.
foreach (NewControl tempcontrol in newControlsList)
{
tempcontrol.controlIndex = newControlsList.IndexOf(tempcontrol);
tempcontrol.PlaceControl();
}
Remove the above code block from RemoveButton, and you will see that your dynamically added buttons will each only trigger the event once.
In your RemoveButton event you loop on each button and call again PlaceControl.
The only reason is to reposition the remainder controls.
I think it's better a call to a separate method that do only this work.
public void RepositionControl()
{
newButton.Left = controlIndex * 100;
}
this will prevent to mess with event handlers added more than one time

Categories