Passing arrays to a method inside event C# - c#

Im trying to create a section of a program, where a user presses a button and a image is placed in one of 9 pictureboxes. Each time the button is clicked, a different picturebox should be selected. However, before i get to that, i'm having trouble getting my method to see the arrays i am trying to pass it.
I have 2 arrays, Slots and SlotsUsed and i am trying to initalise them when the program starts. However, when i try to pass them to the method "randomBox" which is called within "Button1" visual studio says they do not exist. How can i make these arrays visible throughout my code?
Many thanks
Anthony
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace pin_program
{
public partial class Mainscreen : Form
{
//Sets where users files are to be stored (for later use)
string activeDir = #"C:\Users\Tony\Downloads\Programs\pin program\Users";
public Mainscreen()
{
InitializeComponent();
}
//method to generate random number
private int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
public void randomBox(int pictureVal, PictureBox[] Slots, bool[] SlotsUsed)
{
//generate random number
int j = RandomNumber(0, 9);
if (SlotsUsed[j] == false)
{
// Create image, assign it and set slots value to used
Image newImage = Image.FromFile(#"C:\Users\Tony\Downloads\Programs\pin program\pin program\pin program\Images\" + pictureVal + ".jpg");
Slots[j].Image = newImage;
SlotsUsed[j] = true;
}
else
do
{
j = RandomNumber(0, 9);
} while (SlotsUsed[j] == false);
return;
}
private void button1_Click(object sender, EventArgs e)
{
//for use later
string userName = textBox1.Text;
//for use later
label1.Visible = true;
//test call of method.
randomBox(1, Slots, SlotsUsed);
}
public void Mainscreen_Load(object sender, EventArgs e)
{
//array for slots
PictureBox[] Slots = new PictureBox[9];
Slots[0] = pictureBox1;
Slots[1] = pictureBox2;
Slots[2] = pictureBox3;
Slots[3] = pictureBox4;
Slots[4] = pictureBox5;
Slots[5] = pictureBox6;
Slots[6] = pictureBox7;
Slots[7] = pictureBox8;
Slots[8] = pictureBox9;
//array for used slots
bool[] SlotsUsed = new bool[9];
for (int i = 0; i != (SlotsUsed.Length); i++)
{
SlotsUsed[i] = false;
}
}
}
}
EDIT:
I dont seem to be able to post comments for some reason, so i'll just ask here. How would i declare my arrays as instance variables instead of local? Does instance variable have another name i might know it by?
CHeers

Currently you're declaring Slots and SlotsUsed as local variables in Mainscreen_Load. They need to be instance variables in your form, as otherwise you can't refer to them elsewhere - and indeed they won't logically exist elsewhere. They're part of the state of your form, so they should be instance variables.
Additionally, your approach for generating random numbers is broken - see my article on random numbers for more information.
I'd also add that you might consider just using a single collection, shuffling it to start with, and then removing items from it as you go - that way you can easily tell when you've run out of images, and you don't have to loop round until you find an unused slot.

well, the easiest way to do this would be to declare a field.
protected PictureBox[] Slots
inside your Form class (outside of any methods.

Related

What do I put in my .NET/C# MouseOver method to show a tooltip over a PictureBox?

Good afternoon,
I am new to object-oriented programming, .NET and C#. I am studying these previous mentioned topics and presently am doing a relatively simple programming assignment which turned out not to be so simple after all, at least ... for me still.
I want to create a Windows Form Application which contains one form that is filled with country flags (.png, 128px x 128px). In the Form_OnLoad() the files are read and the flags are stored array of PictureBox objects and set several object attributes. Then the form is filled neatly in rows of 8 flags. So far so good.
Problem:
I would like to add a MouseOver event-handler attached to each PictureBox that generates a ToolTip with the country name of the specific flags. In the event-handler I don't know what code to put after what I have managed to do myself already. Specifically, I would like to address the array with flags from the MouseOver event-handler method, but it's not visible from there. I am just stuck here, although my intuition tells me that I am not far from my goal, at this moment my mind decided to give up on me a few meters away from the finish line. Would someone be so kind to help me out with this please?
Here's what I got already:
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace WorldFlags
{
public partial class FormWorldFlags :Form {
public FormWorldFlags() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
int col = 0, row = 0;
string imageDirectory = #"D:\Documents\Visual Studio 2017\Projects\ITvitae\WorldFlags\flags\";
string[] imageFileList = Directory.GetFiles(imageDirectory);
PictureBox[] countryFlag = new PictureBox[imageFileList.Length];
for (int i = 0; i < imageFileList.Length; i++) {
countryFlag[i] = new PictureBox();
countryFlag[i].Name = Path.GetFileNameWithoutExtension(imageFileList[i]);
countryFlag[i].Image = Image.FromFile(imageFileList[i]);
countryFlag[i].Location = new Point(col * 128 + 1, row * 128 + 1);
countryFlag[i].Size = new Size(128, 128);
countryFlag[i].MouseHover += FormWorldFlags_MouseHover;
if (col + 1 == 8) {
row++;
col = 0;
} else
col++;
Controls.Add(countryFlag[i]);
}
}
private void FormWorldFlags_MouseHover(object sender, EventArgs e) {
ToolTip countryName = new ToolTip();
countryName.SetToolTip(?????)
}
}
};
Thanks so much in advance.
Joeri van der Heijden
change your handler to the following:
private void FormWorldFlags_MouseHover(object sender, EventArgs e) {
ToolTip countryName = new ToolTip();
countryName.SetToolTip(sender, "country name");
}
If you want to access the array within the handler you can can just move it out of the form load function. Alternatively you can make use of the Tag property when loading the images and access the value in the handler.

max number from array in library

I'm trying to create a library for C#, that would get the maximum number in a listbox.
Currently I am just trying the method in the program before creating the library. The following code is what I have:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace SPE16
{
public partial class FormExamStatistics : Form
{
List<double> ExamScores = new List<double>();
double highScore = 0;
public FormExamStatistics()
{
InitializeComponent();
}
private double HighScore(List<double> anyList) //return the highest score
{
return highScore = ExamScores.Max();
}
private void buttonAddFromFile_Click(object sender, EventArgs e)
{
StreamReader reader;
reader = File.OpenText("ExamScores.txt");
while (!reader.EndOfStream)
{
double Scores;
double.TryParse(reader.ReadLine(), out Scores);
ExamScores.Add(Scores);
listBoxScores.Items.Add(Scores);
labelHighScore.Text = highScore.ToString();
}
reader.Close();
/////////////
HighScore(ExamScores);
/////////////
}
}
}
Now, it is supposed to return the maximum value from the list created on top, which is populated by a text file "ExamScores.txt". This text file contains 60 (double) scores with a maximum number of 120.
The maximum number, should be 120, but it returns "0".
Now I need to make this as a method first, in order to create a (dll) library later.
What am I doing wrong?
you need to check your file because.NET Framework design guidelines recommend using the Try methods. Avoiding exceptions is usually a good ide
if (value == null)
{
return 0.0;
}
return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider)
please post a your file content
did you tried,
private void buttonAddFromFile_Click(object sender, EventArgs e){
StreamReader reader;
reader = File.OpenText("ExamScores.txt");
while (!reader.EndOfStream){
double Scores;
double.TryParse(reader.ReadLine(), out Scores);
ExamScores.Add(Scores);
listBoxScores.Items.Add(Scores);
labelHighScore.Text = highScore.ToString();
}
reader.Close();
/////////////
HighScore(ExamScores);
/////////////
}
Proper sample for the question would be:
var highScore = 0;
labelHighScore.Text = highScore.ToString();
highScore = 42;
Written this way it clearly demonstrates that showing value first and only than changing it does not actually display updated value.
Fix: set value before showing it, likely labelHighScore.Text = highScore.ToString(); should be just moved to the end of the function.
Note that there are likely other problems in the code based on strange way HighScore returns result and how code completely ignores result of the function.

C# windows forms reference control - NullReferenceException

Could anyone explain why I get a NullReferenceException, when I create a new Button and try to reference it? Creating the Button and assigning the Name works fine, but referencing it does not.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DragNDrop_1
{
public partial class Form1 : Form
{
//Variables----------------------------------------------------------------------
int ButtonID = 100;
bool isDraggingButton = false;
public Form1()
{
InitializeComponent();
}
//----------------------------------------------------------------------Variables
private void btn_addButton_Click(object sender, EventArgs e)
{
AddButton();
}
public void AddButton()
{
Button b = new Button();
b.Name = "Button" + ButtonID.ToString();
b.Text = "Button" + ButtonID.ToString();
b.Location = new Point(ButtonID, ButtonID);
ButtonID = ButtonID + 100;
pnl_DragNDrop.Controls.Add(b);
isDraggingButton = true;
}
private void DragTimer_Tick(object sender, EventArgs e)
{
if (isDraggingButton == true)
{
Point mouse = PointToClient(MousePosition);
this.Controls["Button" + ButtonID.ToString()].Location = new Point(mouse.X + 20, mouse.Y + 20);
}
}
}
}
The Exception occurs in the timer, where I try to reference the last button created. I read trough some threads regarding this Exception, but I still can't spot the error.
Yes, I know that this is very messy and I should propably create a custom Loop or de-/re- activate the timer, but this is just for testing purposes. Note that I'm new to C# and Windows Forms.
EDIT: As explained by Lukasz M, this is a Problem regarding Ownership (maybe the Term is not correct, it's the best german-english Translation I can come up with). This is neither the Focus of the Question from the Thread I "duplicated", nor is it mentioned in the Answer. If it is though, I have to question my English-skills. Anyway, I just wanted to make clear, that I indeed read the Thread, but wasn't able to spot a Solution. Maybe it's just the lack of English- and C#-Skills, but I'm pretty sure that this is not a duplicate.
It's because in AddButton method You create the button, but do not add it directly to the form's controls, but to the pnl_DragNDrop.Controls collection.
You can try to change this:
this.Controls["Button" + ButtonID.ToString()].Location = new Point(mouse.X + 20, mouse.Y + 20);
to this:
pnl_DragNDrop.Controls["Button" + ButtonID.ToString()].Location = new Point(mouse.X + 20, mouse.Y + 20);
and it should work fine.
Another way to do it would be saving the b button in a class field instead of a variable inside the method. This way, You could refer to the control in a different method without the need to find it by Id in the Controls collection. You may also want to add more than one button with different Id values, so the exact implementation for storing and refering to buttons created then, may depend on actual use case.
Update
To make the code actually work, please also notice that after You create the b control, You modify the variable used to compose its name:
ButtonID = ButtonID + 100;
Then, in DragTimer_Tick method You use the modified value to rebuild the control's name, but it's already different, so the control is not found.
When searching the control by name, You can either save the previous value of ButtonID or save the whole string used as button's name (as mentioned in the comments) to be able to use it to find the control later.

retrieve a list view item created in one class to main form

The goal of my program is to simulate the rolling of two dice, the display the random numbers generated and their sum in a three column list view.
I am having trouble getting the ListViewItem generated in my Roller class back to my Form1 so I can add it to my list view.
I have tried adding the ListViewItem directly to the list view from the roller class, but I can not figure out how to access the list view from my roller class.
Here is my code from my form1 that calls my roller class.
private void btnRoll_Click(object sender, EventArgs e)
{
Roller roller1 = new Roller();
lvRollResults.Items.Add(Roller.ListViewItem(item));
}
Here is the code for my Roller class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class Roller
{
ListViewItem item;
private void randomizer()
{
int counter = 100;
int temp1;
int temp2;
int sum;
Random rand = new Random();
for (int i = 0; i < counter; ++i)
{
temp1 = rand.Next(1, 7);//set temp1 to a random number betwen 1&6
temp2 = rand.Next(1, 7);//set temp2 to a random number between 1&6
sum = temp1 + temp2;//set sum equal to temp1+temp2
String one = Convert.ToString(temp1);
String two = Convert.ToString(temp2);
String three = Convert.ToString(sum);
item = new ListViewItem(new string[] { one, two, three });
}
}
}
}
I have read my text books, searched the internet and I cannot for the life of me figure this out. I have a hunch it is something to do with my method constructor, but every time I try to change it I end up with more errors.
=======================================Update==========================================
I could not get any of the suggestions to work. To solve my problem I just put the all the code from my Roller class in Form1 under the Roll_Click function.
I appreciate all the help offered.
One way to do this based on the code you have shown is:-
Your listviewitem needs to be public
public ListViewItem item;
then you can get it using
Roller roller1 = new Roller();
lvRollResults.Items.Add(roller1.item);
Provided you invoke randomizer() method in your Roller class constructor.
public Roller()
{
randomizer();
}
Make your list static in form1 so you can access it from outside of the class as well. Now for your problem you all have to do is this:
1. Make your lvRollResults static, code:
static ListView lvRollResults
2. Now in the Roller class you can directly put the values into the lvRollResults. code for Roller class:
Form1.lvRollResults.Items.Add(item); //put this code after the 'for loop' in randomizer' method
3. Code for your btnRoll_Click method:
Roller roller1 = new Roller();
roller1.randomizer();
Edit:
To make your list box static do this:
In your form1, create listbox by coding like static ListBox lvRollResults
set its dimensions in the constructor of form1.
Create a constructor in Roller calling Randomizer...
Or, change void randomize() by Roller()
And in Form1, use roller1.item instead of Roller.item
Another way is to make your Randomizer method public instead of private and instead of void return it as ListviewItem.
public ListviewItem Randomizer()
And then your Randomizer will return the ListViewItem.
return item;
So, in your button click it would be like this.
private void btnRoll_Click(object sender, EventArgs e)
{
Roller roller1 = new Roller();
lvRollResults.Items.Add(roller1.Randomizer());
}

saving variables between page refresh

i need to do a basic web page (homework)
the user need to input number into textbox. after every number he need to press the "enter number" button.
and after a few numbers he need to press a different button to display his number and some calculations.
i cant use arrays ( homework limitations).
the problem is that after every time the user press "enter number" , the variables reset.
what can i do?
here's the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication1
{
public partial class WebForm1 : System.Web.UI.Page
{
int totalSum=0;
int mulOdd=1;
int small=0;
int big=0;
float avg=0;
int pairsum=0;
int counter = 0;
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
int t;
counter++;
t = Convert.ToInt16(TextBox1.Text);
totalSum = totalSum + t;
avg = totalSum / counter;
int odd = t % 2;
if (odd > 0)
{
mulOdd = mulOdd * t;
}
else
{
pairsum = pairsum + t;
}
if (t < small)
{
small = t;
}
if (t > big)
{
big = t;
}
TextBox1.Text = " ";`enter code here`
Label1.Text = Convert.ToString(counter);
}
protected void Button2_Click(object sender, EventArgs e)
{
Label1.Text = "total Sum" + Convert.ToString(totalSum);
}
}
}
thank you.
You need to save the variables in state. There are several ways to pass variables
[1] Cookies (rarely found use for this)
[2] Session (Good for storing between pages for a different user)
[3] ViewState (Same page saving for a user)
[4] Query Strings (passing between pages)
Have a read about these and this should do the trick. Forgive me if i missed some out.
You need to read about the page life cycle and about state management, in particular view state.
It's difficult to help without knowing the conditions of your assignment, but a method that would be usable would be to have a hidden field (webusercontrol) on the page that would hold a string. Each time the button is clicked, append the string representation of the number to the value of that control, making sure to separate the values with a symbol (comma, #, |, anything will do really). Then at any point during the process you would be able to get the value of that control, split it on the character, and compute whatever you needed to compute.
Since this is identified as homework, I won't be posting code, but this process should be pretty straight-forward.
In your page load event, check the Page.IsPostback property. If true, then reset your variables based on the user input from the server controls HTML markup.
Read the links provided by #Oded. Page life cycle is a very important topic.
Some pointers that you could extend to all your variables...
Remove the global declaration of all of these variables, you don't need to have a global scope for them:
int totalSum=0;
int mulOdd=1;
int small=0;
int big=0;
float avg=0;
int pairsum=0;
int counter = 0;
On Button1_Click store the totalSum as so:
ViewState["Sum"] = Convert.ToInt16(string.IsNullOrEmpty(ViewState["Sum"])?"0":ViewState["Sum"].ToString() )+ Convert.ToInt16(TextBox1.Text);
Finally, on Button_Click2 do:
Label1.Text = "total Sum" + Convert.ToString(string.IsNullOrEmpty(ViewState["Sum"])?"0":ViewState["Sum"].ToString());

Categories

Resources