Get a random card and change the label - c#

I'm just fooling around in Windows Forms and wish to click a button and then give a player 2 random cards, but when I click the button the label is empty. How do i pass the value to the string?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void DealTheCardsButton_Click(object sender, EventArgs e)
{
TheCards theCards = new TheCards();
CardOneLabel.Text = theCards.card1;
}
}
public class TheCards
{
public TheCards()
{
Cards = new List<string>();
Cards.Add("1");
Cards.Add("2");
Cards.Add("3");
Cards.Add("4");
}
public List<string> Cards { get; set; }
public string card1;
public string card2;
public string cardTest = "hej";
public void GiveTwoRandomCardsFromCardsList()
{
Random random = new Random();
int slumptal = random.Next(0, 4);
card1 = Cards[1];
bool flag = false;
while (!flag)
{
Random random2 = new Random();
int slumptal2 = random2.Next(0, 4);
if (slumptal != slumptal2)
{
card2 = Cards[slumptal2];
flag = true;
}
}
}
}
If I call to change the CardOneLabel.Text to a string with a hardcoded value in it it works. It seems like the randomizing doesn't change the value of string card1 and string card2. As it is now, when I click on the button the label changes its value to nothing (empty).
How can i change the label value to a random card value?

You never call the GiveTwoRandomCardsFromCardsList method. Try this:
private void DealTheCardsButton_Click(object sender, EventArgs e)
{
TheCards theCards = new TheCards();
theCards.GiveTwoRandomCardsFromCardsList();
CardOneLabel.Text = theCards.card1;
}
By the way, don't create a new Random object for every random number you require. This might even give you the same random number due to how the pseudo-random number generator depends on the current time. Just use the same Random instance over and over again. It will give you a new random number every time.
Also, you will sometimes get the same card twice. I'll leave it to the OP to figure out how to always get two different cards, if that's the idea.

But when I click the button the label is empty. How do i pass the
value to the string?
When you try to assign the value
CardOneLabel.Text = theCards.card1;
The constructor of that class TheCards is not initiating the card1 variable to anything, you are retrieving an empty string.
The constructor below, is adding to the list Cards but nothing else is taking place.. Do you have additional code your not showing?
public TheCards()
{
Cards = new List<string>();
Cards.Add("1");
Cards.Add("2");
Cards.Add("3");
Cards.Add("4");
}
Your CardOneLabel is empty when you press the button because you are literally reading an empty string. Try calling your GiveTwoRandomCardsFromCardsList() method before assigning.

Related

moving images in visual studio c#

My program consists of a grid with 8 images (one free space). At the moment when you click on one image and then another they swap, but I only want the image to move one space at a time and only if there is a clear box. (like those scramble games)
I have this swap method, but how can I change it to fit what I want?
string click1Name="";
string click1Loc="";
string click2Name="";
string click2Loc="";
private void swap()
{
var objName=(Image)this.FindName(click1Loc);
objName.Source = new BitmapImage(new Uri("pack://application:,,,/Pic1/"+click2Name));
objName = (Image)this.FindName(click2Loc);
objName.Source = new BitmapImage(new Uri("pack://application:,,,/Pic1/" + click1Name));
}
GridPic9 is the free space (Pic9.jpg)
Not sure of what your problem is. I'm guessing when you click over one Image, you load its name and location into the corresponding global variables (click(x)Name and click(x)Loc); and then, when you click over the second Image, you load again name and location, and call Swap afterwards. Is that it?
In order to manage the swapping constrains that you stated, I would create a matrix of objects. Each object would contain info about what is shown in each Image control. The following is a naive way to do it, but it can give you an idea.
class ImageInfo
{
public string Name;
Image AssociatedControl;
public ImageInfo(string name, string loc)
{
Name=name;
AssociatedControl=(Image)this.FindName(loc);
DisplayToControl();
}
void DisplayToControl()
{
if(Name!=null)
AssociatedControl.Source = new BitmapImage(new Uri("pack://application:,,,/Pic1/"+Name));
else
AssociatedControl.Source =null;
}
public void SetImage(string name)
{
Name=name;
DisplayToControl()
}
}
ImageInfo[][] myImagesLayout = new ImageInfo[3][3];
Tuple<int,int> PreviousClickedImageCoords = null;
void myWindow_Load()
{
//Initialize the 8 images in their initial positions
myImagesLayout [0][0] = new myImagesLayout(name1,location1);
//[...]
myImagesLayout [2][1] = new myImagesLayout(name8,location8);
myImagesLayout [2][2] = new myImagesLayout(null,location9);
}
void Image1_Clicked(object sender, RoutedEventArgs e)
{
Clicked(0,0);
}
//[...]
void Image9_Clicked(object sender, RoutedEventArgs e)
{
Clicked(2,2);
}
void Clicked(int row, int column)
{
if(PreviousClickedImageCoords == null )
{
if(myImagesLayout[row][column].Name!=null)
PreviousClickedImageCoords = new Tuple<int,int>(row,column);
}
else
{
if(myImagesLayout[row][column].Name!=null)
return; //only to empty images
int prevRow=PreviousClickedImageCoords.Item1;
int prevCol=PreviousClickedImageCoords.Item2;
int step = Math.Abs(Row-prevRow) + Math.Abs(Col-prevCol);
if(step!=1)
return; //only adjacent cells. No diagonals
ImageInfo PreviousClickedImage = myImagesLayout[prevRow][prevCol];
myImagesLayout[row][column].SetImage(PreviousClickedImage.Name);
PreviousClickedImage.SetImage(null);
PreviousClickedImage=null;
}
}

String to existing object

So i have my buttons like this :
text : Skarl, Name : btnHeroe1
text : Kled, Name : btnHeroe2
text : Kled, Name : btnHeroe3
My object are like this (price, damage)
Heroe Heroe1 = new Heroe(100,5);
Heroe Heroe2 = new Heroe(500,10);
Heroe Heroe3 = new Heroe(100,40);
They have properties (price,dps,level)
And when i click on my button, i use this method with these lines to get the name of the button pressed :
Button b = sender as Button;
string vButton = b.Name;
string strHeroeToBuy = vButton.Substring(3, vButton.Length - 3);
Now i'm asking. How can i get the properties like this : strHeroeToBuy.Price ?
Edit : Solved it by getting the id of my heroes and searching with button have the same id
If you keep your heroes in a list, and give them unique ids then you can find them:
// The id can be an int or a string, it's your choice
Heroes = new List<Heroe> {
new Heroe(id: 1, 100,5),
new Heroe(id: 2, 500,10),
new Heroe(id: 3, 100,40)
};
(...)
var id = //get Id from button
// needs 'using System.Linq'
var myHero = Heroes.FirstOrDefault( h => h.Id == id);
if(myHero == null) // error
One way to allow looking up an attribute would be to use a Dictionary, though it will require a unique key.
So, you would need to map your objects into the dictionary. Here is a sample console app to demonstrate:
using System;
using System.Collections.Generic;
namespace ConsoleApp
{
public class Hero
{
public Hero(int price, int points)
{
Price = price;
Points = points;
}
public int Price { get; set; }
public int Points { get; set; }
}
class Program
{
static void Main(string[] args)
{
var heros = new Dictionary<string, Hero>();
heros.Add("Hero1 Name", new Hero(10, 100));
heros.Add("Hero2 Name", new Hero(11, 101));
heros.Add("Hero3 Name", new Hero(12, 102));
if (heros.ContainsKey("Hero1 Name"))
{
Console.WriteLine(heros["Hero1 Name"].Price);
}
}
}
}
You could just store each hero in the .Tag() property of each button. Associate them in the Load() event of the form (assuming WinForms):
private Heroe Heroe1 = new Heroe(100,5);
private Heroe Heroe2 = new Heroe(500,10);
private Heroe Heroe3 = new Heroe(100,40);
private void Form1_Load(object sender, EventArgs e)
{
btnHeroe1.Tag = Heroe1;
btnHeroe2.Tag = Heroe2;
btnHeroe3.Tag = Heroe3;
}
Now you can just grab that hero from the tag:
Button b = sender as Button;
Heroe H = (Heroe)b.Tag;
// ... do something with "H" ...
You cannot do that for with a String. You could use the Tag-property on your Button to achieve it!
First you need a List of Heroes of some sort. This list need to be accessible from the form constructor, and from the click event.
public partial class Form1: Form
{
Hero[] data = new []{
new Hero{ Name= "Foo"},
new Hero{ Name= "Bar", Price=100, Dps=20, PropertyName=Value},
};
public Form1(){
// ...
}
// ...
}
At initialisation you will create the button based on your listing of heroes.
public Form1()
{
InitializeComponent();
// Have a Container that will hold the buttons
foreach(var hero in data){
var button = new Button();
//set text // set size
// set position. Compute it based on button size you just set.
// We put the whole hero in the tag not just the name `button.Tag = hero.Name`
button.Tag = hero;
// Add one even for all the button.
button.Click += new EventHandler(HeroButton_Click);
//Add button to the container
this.Controls.Add(button); // This or a container.
}
}
And the event that will be handle all the button click:
private void HeroButton_Click(object sender, EventArgs e)
{
Button btn = (Button) sender;
var hero = (Hero)btn.Tag
// Do thing with the Hero.
//Old Way, we search for the Hero in the list Data
// var hero = data.FirstOrDefault(x=> x.Name == (string)btn.Tag);
// if(hero==null) ; // error, could not find the hero
}

Advice on best way to resolve issue - C# Windows forms (list boxes, text box, user input)

I am new to C# and have started a program that I want to take in data from user, send to list box, sort list box and then save results. This happens via two text boxes:
txtUsername
txtResult
below the text box is a button that is disabled unless both text fields are entered, the button (btnAdd) adds the results and name of student to two separate list boxes:
lstUsername
lstResult
by disabling the button I ensure only both name and result are entered and sent to the list boxes in unison, the next bit is where it becomes tricky for me..
I want to be able to be able to sort the list boxes in ascending order to see at a glance the user with the highest result, but this wont be achieved due to the entries in each list box not being linked to one another. for example if a put a line of code to sort the high scores they then would not match the user in the list box parallel. I have only touched on arrays but understand the data between Username and result in a list box would need to be linked in some way so they are matched even after sorting.
This is the current code on the button that sends both the username and result to the list boxes:
InitializeComponent();
{
btnAdd.Enabled = !string.IsNullOrWhiteSpace(txtResult.Text);
btnAdd.Enabled = !string.IsNullOrWhiteSpace(txtUsername.Text);
}
private void btnAdd_Click(object sender, EventArgs e)
{
lstUsername.Items.Add(txtUsername.Text);
lstResult.Items.Add(txtResult.Text);
//There is also a counter that counts entries once being sent to the list
txtScoreCount.Text = lstUsername.Items.Count.ToString();
lstResult.Items.Count.ToString();
txtResult.Clear();
txtUsername.Clear();
txtUsername.Focus();
txtUsername.SelectAll();
}
If anyone can provide advice on how I am able to match the entries of two separate list boxes together I would be very grateful, I am also happy to provide more code if required. Any advice is beneficial to me. I will be able to work out saving the data and loading it back into the lists myself once I have the data in two lists bound, thank you.
This should get you somewhere.
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
namespace Students2
{
public partial class Form1 : Form
{
public class Student : ListViewItem
{
public Student(string name, float grade) : base()
{
this.Text = name;
//Add its grade as a subitem automatically.
this.SubItems.Add(new ListViewSubItem(this, grade.ToString()));
}
}
public class ListViewItemComparer : IComparer
{
private int ColIdx = 0;
public ListViewItemComparer(int index) { ColIdx = index; }
public int Compare(object x, object y)
{
switch(ColIdx)
{
case 1: //Numeric
{
var a1 = Convert.ToSingle(((ListViewItem)x).SubItems[ColIdx].Text);
var a2 = Convert.ToSingle(((ListViewItem)y).SubItems[ColIdx].Text);
return a1.CompareTo(a2);
}
default:
return String.Compare(((ListViewItem)x).SubItems[ColIdx].Text, ((ListViewItem)y).SubItems[ColIdx].Text);
}
}
}
public Form1()
{
InitializeComponent();
//Initialize ctrls
TextBox txtUsername = new TextBox();
TextBox txtGrade = new TextBox();
Button btnAdd = new Button();
ListView lBox = new ListView();
//POS
txtUsername.Location = new Point(0, 10);
txtGrade.Location = new Point(0, 40);
btnAdd.Location = new Point(0, 80);
lBox.Location = new Point(120, 0);
//ListView props
lBox.HeaderStyle = ColumnHeaderStyle.Clickable;
lBox.View = View.Details;
lBox.Size = new Size(200, 200);
//Modify the whole LView sorting so both are synced.
lBox.ColumnClick += new ColumnClickEventHandler((o, e) =>
{
lBox.ListViewItemSorter = new ListViewItemComparer(e.Column);
});
lBox.Columns.Add("Name");
lBox.Columns.Add("Grade");
this.Controls.Add(txtUsername);
this.Controls.Add(txtGrade);
this.Controls.Add(btnAdd);
this.Controls.Add(lBox);
btnAdd.Text = "Add";
//Add a new Student object upon click (Inherits from ListViewItem)
btnAdd.Click += new EventHandler((o, e) =>
{
try
{
lBox.Items.Add(new Student(txtUsername.Text, Convert.ToSingle(txtGrade.Text)));
lBox.Refresh();
}
catch (Exception ex)
{
MessageBox.Show("Incorrect input.");
}
});
}
}
}

Edit the content of a text block in a list C# (WPF Application)

So I have five text blocks I've added to a list, and each one is supposed to get its own random number between one and 6.
I know I can just do a new int for each text block (int randomNumberOne, randomNumberTwo, etc) but I'm trying to see if I can figure out how to make a list and a for each loop to work.
Is there some way to edit the content of a TextBox in a list as it goes through? If there is, I haven't found any way to do so.
Here's my code so far.
List<TextBlock> randomBoxList = new List<TextBlock>();
public MainWindow()
{
InitializeComponent();
randomBoxList.Add(randomBoxOne);
randomBoxList.Add(randomBoxTwo);
randomBoxList.Add(randomBoxThree);
randomBoxList.Add(randomBoxFour);
randomBoxList.Add(randomBoxFive);
}
Random randomGenerator = new Random();
int randomNumber;
private void randomButton_Click(object sender, RoutedEventArgs e)
{
foreach (TextBlock textBlock in randomBoxList)
{
randomNumber = randomGenerator.Next(1, 7);
//Code to change randomBox content goes here.
}
}
If this is WPF, you should just be able to use textBlock.Text property like so:
public partial class MainWindow : Window
{
List<System.Windows.Controls.TextBlock> randomBoxList = new List<System.Windows.Controls.TextBlock>();
public MainWindow()
{
InitializeComponent();
randomBoxList.Add(randomBoxOne);
randomBoxList.Add(randomBoxTwo);
randomBoxList.Add(randomBoxThree);
randomBoxList.Add(randomBoxFour);
randomBoxList.Add(randomBoxFive);
}
Random randomGenerator = new Random();
int randomNumber;
private void randomButton_Click(object sender, RoutedEventArgs e)
{
foreach (System.Windows.Controls.TextBlock textBlock in randomBoxList)
{
randomNumber = randomGenerator.Next(1, 7);
textBlock.Text = randomNumber.ToString();
}
}
}

Generating Random Color Produces Same Color Each Time [duplicate]

This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
I am trying to create a dynamically added array of user-controls where each one will have a random color assigned to it to make the user more able to differentiate it from others, but when I do that it produces pattern of colors. It will create 10 of the user-controls with the same color then it will change the color for the next 10, I want each separate one to have a different color.
The code for the user-control:
public partial class EquationBox : UserControl
{
public EquationBox()
{
InitializeComponent();
this.panel4.BackColor = RandomColor();
}
private void button1_Click(object sender, EventArgs e)
{
this.Visible = false;
this.textBox1.Text = "";
}
private Color RandomColor()
{
Random rnd = new Random();
/*KnownColor[] names = (KnownColor[])Enum.GetValues(typeof(KnownColor));
KnownColor randomColorName = names[r.Next(names.Length)];
Color randomColor = Color.FromKnownColor(randomColorName);
return randomColor;*/
Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));
return randomColor;
}
}
The Code for form1:
public partial class Form1 : Form
{
public static EquationBox[] EquationBoxArray = new EquationBox[100];
public Form1()
{
InitializeComponent();
for (int x = 0; x < 100; x++)
{
EquationBoxArray[x] = new EquationBox();
EquationBoxArray[x].Parent = flowLayoutPanel1;
EquationBoxArray[x].Visible = false;
}
}
private void add_line_Click(object sender, EventArgs e) //Add Line
{
for(int x = 0; x < 100; x++)
{
if(!EquationBoxArray[x].Visible)
{
EquationBoxArray[x].Visible = true;
EquationBoxArray[x].Refresh();
break;
}
}
}
private void clear_Click(object sender, EventArgs e) //Clear Lines
{
for (int x = 0; x < 100; x++)
{
EquationBoxArray[x].Visible = false;
EquationBoxArray[x].ResetText();
}
}
private void Form1_SizeChanged(object sender, EventArgs e) //Window Size Changed
{
}
}
Thanks in advance, any help would be much appreciated!
The Random class is only a pseudo-random number generator, controlled by the seed parameter in the constructor. To achieve a better distribution of random numbers, try putting the creation of the Random object outside of the loop, or seed it with a different value each time.
For example
public partial class EquationBox
{
private static Random rnd;
static EquationBox()
{
rnd = new Random();
}
public EquationBox()
{
this.panel4.BackColor = GetRandomColor();
}
private Color GetRandomColor()
{
Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));
return randomColor;
}
}
You need to create global Random instance, or use another it constructor
https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx
More the Random to a field, then use it in the RandomColor function, as below.
Random _rnd = new Random();
private Color RandomColor()
{
Color randomColor = Color.FromArgb(_rnd.Next(256), _rnd.Next(256), _rnd.Next(256));
return randomColor;
}
This fixes it because Random uses a seed to initialize the pseudorandom number generator, which is the number of milliseconds since the computer was started. Therefore, if you create more than one Random in the same millisecond, it will start with the same seed.
you should only use one instance of Random Class.The problem could be because you are creating new instance of Random every time you call RandomColor .
You can move it to another class
public class MyRandom
{
private static Random _randColor=new Random();
private Color GetRandomColor()
{
Color randomColor = Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256));
return randomColor;
}
}
and in your user control call it using
public EquationBox()
{
InitializeComponent();
this.panel4.BackColor = MyRandom.GetRandomColor();
}
Your error comes from creating the Random Number Generator everytime you need a new random colour. The RNG is usually seeded with the current time and because you are creating new ones very quickly the get the same seed.
public partial class EquationBox
{
static Random rnd = new Random();
public EquationBox()
{
InitializeComponent();
lock (rnd)
{
this.panel4.BackColor = Color.FromArgb(rnd.Next(257), rnd.Next(257), rnd.Next(257));
}
}
}
Random.Next is not thread safe, so I have a lock around it. Also it returns a value LESS than the max parameter. So you most likely want to pass 257 instead of 256.

Categories