C# WPF - Not all images show up on grid - c#

I can't load all grid spots with images at once. I have a 5x5 grid and it is intended to load 25 random images in random spots. With 25 images it should fill out the entire grid.
I can't figure out why there are empty spots when I load 25 or when I load less. I'm having one image repeat itself throughout the entire grid in order to avoid image format related issues. I think the problem might be related to the Random class.
Here is the code:
private readonly Random _r = new Random();
public void LoadPictures(int numberOfPictures)
{
// Create a 2d array of specified dimensions
var picArr = new bool[5, 5];
for (int j = 0; j < numberOfPictures; j++)
{
// Get the images from the specified folder
string[] imagePaths = Directory.GetFiles(
Environment.CurrentDirectory + "/images");
bool invalidPlacement = true; // default is true
while (invalidPlacement)
{
var i = new Image();
try
{
// Load the image with a random Picture
var uri = new Uri(imagePaths[_r.Next(0, imagePaths.Length)]);
i.Source = new BitmapImage(uri);
Debug.WriteLine(uri.AbsolutePath);
i.Width = ImageWidth;
i.Height = ImageHeight;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
// Put it somewhere
int row = _r.Next(5);
Thread.Sleep(TimeSpan.FromMilliseconds(50));
int col = _r.Next(5);
// Check to see if there is something there
if (picArr[col, row] == false)
{
picArr[col, row] = true;
Grid.SetColumn(i, col);
Grid.SetRow(i, row);
Background2.Children.Add(i);
AnimateControl(i, 100, 100, 0, 0);
invalidPlacement = false;
}
}
}
}

Related

How to delete image created with code and how to interact with it at all

I am working on a game. For this game i create around 200 images in a box 20x10.
My problem is that pressing 1 button creates them a lot of times which garbages the Memory, which i want to avoid. So i created a little if/else function which is supposed to check wether the images were created or not. In case they weren't, code creates them, but if they were, the code should delete them, and i have no idea how to delete code generated images or how to interract with them at all.
public void GameStart(bool load = false)
{
Random rnd = new Random();
Pause.IsEnabled = true;
Save.IsEnabled = true;
Shuffle.IsEnabled = true;
byte datasave = 0;
int[,] TileID = new int[20,10];
for(int i = 0; i < 20; i++)
{
for(int j = 0; j < 10; j++)
{
if(TileID[i,j] != 0)
{
datasave = 1;
}
TileID[i, j] = rnd.Next(1,9);
CreateImage(i, j, TileID[i,j], datasave);
}
}
}
public void CreateImage(int a, int b, int TileID, byte datainfo)
{
if(datainfo != 0)
{
Image image = new Image();
image.Width = 40;
image.Height = 40;
image.Name = $"Tile{a}{b}";
image.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
image.VerticalAlignment = System.Windows.VerticalAlignment.Center;
image.Margin = new Thickness(-1000 + 80 * a, -200 + 80 * b, 0, 0);
string way = #"C:\Users\ignat\Desktop\Игра\Images\";
image.Source = new BitmapImage(new Uri(way + $"icon{TileID}.jpg", UriKind.Absolute));
Grid.Children.Add(image);
}
else
{
CreateImage(a, b, TileID, datainfo);
}

Interchange two PictureBoxes

I'm trying to make the game 2048 in C#, but I have a problem when I move the tiles.
Here is where I keep the tiles:
picture = new PictureBox[4, 4] {
{pic1,pic2,pic3,pic4},
{pic5,pic6,pic7,pic8},
{pic9,pic10,pic11,pic12},
{pic13,pic14,pic15,pic16} };
And when I press 'W' I move it up :
public void Up()
{
for (int i = 1; i < picture.GetLength(0); i++)
for (int j = 0; j < picture.GetLength(1); j++)
if(picture[i,j].Image!=null && picture[i-1,j].Image==null)
{
picture[i - 1, j].Image = picture[i, j].Image;
picture[i, j].Image = null;
Up();
}
}
but that code only interchanges images from picturebox not the picturebox itself. How can I interchange the picturebox with image and all its property ?
There is no switching functionality in C#, so you will need a temporary helper variable.
It is up to you to decide what you want to switch:
the pictureBoxes referenced in your array
just their locations
their images
or any combination..
Here is an example of a simple helper function that exchanges the references and their Locations:
void SwitchControls(PictureBox pb1, PictureBox pb2)
{
PictureBox temp = pb1;
Point tempLoc = pb1.Location;
pb1 = pb2;
pb2 = temp;
pb1.Location = pb2.Location;
pb2.Location = tempLoc ;
}
You would call it for example like this:
SwitchControls(picture[i - 1, j], picture[i, j]);
To exchange the Images you would write the function as
void SwitchImages(PictureBox pb1, PictureBox pb2)
{
Image temp = pb1.Image;
pb1.Image = pb2.Image;
pb2.Image = temp.Image;
}
etc..

Remove controls of flowlayoutpanel and recreating it in C#

I had been experimenting on writing a code to generate images inside a FlowLayoutPanel.
This is what i had done so far, when i click on a button for the first time (by using a checkboxes - read in number of images to open), it will generate the images, when i click on the button on second try, it will not update the flowlayoutpanel.
Even though i tried to remove the controls inside the FlowLayoutPanel, it still doesn't show the second try of the images.
This is the code snippet of the method:
FlowLayoutPanel fwPanel = null;
private void btnOpenFile_Click(object sender, EventArgs e)
{
//if there is content inside the flowpanel, dump it
if (fwPanel != null)
{
listOfFile.Clear();
}
//create a new FLP
fwPanel = new FlowLayoutPanel();
int panelWidth = width * 4 + 50;
int panelHeight = height * 4 + 50;
fwPanel.Size = new Size(panelWidth, panelHeight);
fwPanel.Location = new Point(0, 0);
this.Controls.Add(fwPanel);
//each checked item would be stored into an arraylist
foreach(object itemChecked in clbFile.CheckedItems)
{
listOfFile.Add((clbFile.Items.IndexOf(itemChecked)+1).ToString());
}
int noOfCheckedFile = listOfFile.Count;
PictureBox[] listOfPicture = new PictureBox[noOfCheckedFile];
int positionX = 0, positionY = 0;
int maxPaddingX = (width * MATRIX_SIZE) - 1;
int maxPaddingY = (height * MATRIX_SIZE) - 1;
//dynamically create images.
for (int i = 0; i < noOfCheckedFile; i++)
{
listOfPicture[i] = new PictureBox();
listOfPicture[i].Image = resizeImage((Image)show_picture(Convert.ToInt32(listOfFile[i])), new Size(width, height));
listOfPicture[i].Size = new Size(width, height);
if (positionX > maxPaddingX)
{
positionX = 0;
positionY += height;
}
if (positionY > maxPaddingY)
{
positionY = 0;
}
listOfPicture[i].Location = new Point(positionX,positionY);
listOfPicture[i].Visible = true;
fwPanel.Controls.Add(listOfPicture[i]);
positionX += width;
}
}
show_picture is a method that takes in and integer and returns a bitmap image.
listOfFile is to trace which file to return.
listOfPicture is to store each images.
i tried replacing this lines
//if there is content inside the flowpanel, dump it
if (fwPanel != null)
{
listOfFile.Clear();
}
i have added this line into it, when i do a second click, everything just gone missing, but this is not what i want, because it does not re-populating the FlowLayoutPanel.
if (fwPanel != null)
{
fwPanel.SuspendLayout();
if (fwPanel.Controls.Count > 0)
{
for (int i = (fwPanel.Controls.Count - 1); i >= 0; i--)
{
Control c = fwPanel.Controls[i];
c.Dispose();
}
GC.Collect();
}
fwPanel.ResumeLayout();
listOfFile.Clear();
}
I also tried this, but on second click, nothing will happen.
if (fwPanel != null)
{
List<Control> listControls = fwPanel.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
fwPanel.Controls.Remove(control);
control.Dispose();
}
listOfFile.Clear();
}
I wonder if i miss out anything, can someone enlighten me on what did i miss out ? Or guide me for the best practice of doing this.
as Suggested, i shifted the creation outside (credit to Sinatr for spotting it)
FlowLayoutPanel fwPanel = new FlowLayoutPanel();
private void createFLP()
{
int panelWidth = width * 4 + 50;
int panelHeight = height * 4 + 50;
fwPanel.Size = new Size(panelWidth, panelHeight);
fwPanel.Location = new Point(0, 0);
this.Controls.Add(fwPanel);
}
that solves the nothing happen part. Followed by using this to remove controls
if (fwPanel != null)
{
List<Control> listControls = fwPanel.Controls.Cast<Control>().ToList();
foreach (Control control in listControls)
{
fwPanel.Controls.Remove(control);
control.Dispose();
}
listOfFile.Clear();
}
and everything works like a charm, hope that this answer will be able to help others who are facing the same problem too.

Multiply images boxes

I have a simple form with 10 picture boxes like: pictureBox1, pictureBox2, pictureBox3...
And I have a folder with 10 images like: image1, image2, image3...
Now I am smart enough to know that I don't want to hard code pictureBox1.ImageLocation = image1, pictureBox2.ImageLocation = image2... Rather, I need to create some kind of loop or array that will populate my picture boxes with their respective images, but I am not smart enough to figure out how.
Something like:
for (int i = 0; i < 10; i++)
{
pictureBox[i].ImageLocation = image[i];
}
Eventually, I was hoping this project would scale dynamically, if I have a file with say 12 images, the program will simply create 12 picture boxes and load the images. A little help would be great.
What you have there would roughty work though I would suggest a list.
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<Image> images = new List<Image>();
//code to populate your lists
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
If you want to make sure you have enough images for your PictureBox list you could check ahead of time:
if (images.Count >= pictureBoxes.Count)
{
for (int i = 0; i < pictureBoxes.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
}
...or fill out as many as you can before running out of images.
for (int i = 0; i < pictureBoxes.Count && i < images.Count; i++)
{
pictureBoxes[i].Image = images[i];
}
EDIT:
So if you want to use strings to set the location of the images instead you can do that. Check this out:
List<PictureBox> pictureBoxes = new List<PictureBox>();
List<string> imageLocations = new List<string>();
private void Form1_Load(object sender, EventArgs e)
{
PictureBox PB1 = new PictureBox();
PB1.Location = new Point(0, 0);
PB1.Size = new Size(144, 197);
Controls.Add(PB1);
PictureBox PB2 = new PictureBox();
PB2.Location = new Point(145, 0);
PB2.Size = new Size(327, 250);
Controls.Add(PB2);
pictureBoxes.Add(PB1);
pictureBoxes.Add(PB2);
imageLocations.Add(#"C:\PicExample\image1.jpg");
imageLocations.Add(#"C:\PicExample\image2.jpg");
for (int i = 0; i < pictureBoxes.Count && i < imageLocations.Count; i++)
{
pictureBoxes[i].ImageLocation = imageLocations[i];
}
}
EDIT for Iteratively Creating PictureBoxe List:
If you want to not have to worry about hard-coding your list (and your picture boxes will be the same size) you could do something like this:
for (int i = 0; i < HoweverManyPictureBoxesYouWant; i++)
{
PictureBox PB = new PictureBox();
PB.Name = "PB" + i.ToString();
PB.Location = new Point(250 * i, 0); //Edit this as you see fit for location, i'm just putting them in a row
PB.Size = new Size(250, 250);
PB.ImageLocation = #"C:\PicExample\image" + i.ToString() + ".jpg";
Controls.Add(PB);
pictureBoxes.Add(PB); //You only need to do this if you want the PB's in a list for other reasons than setting the image location
}

Image Appearing without being called

I am making a whack a mole game, I can not use MVVM, and I am making a random mole image appear at a random time but when I start the game, one or sometimes two moles appear, that are not apart of that code (I have it so that when you click a mole, it will disappear, these unwanted moles do not disappear if clicked). Thank you for your help! I have added all of my Grid Population code, which is probably where the problem lies.
Code:
private void PopulateGrid()
{
MoleChanges = TUtils.GetIniInt(Moleini, "MoleChangeTimes", "AmountofChanges", 50);
ImageSize = TUtils.GetIniInt(Moleini, "ImageSize", "imageSize", 10);
NumofImages = TUtils.GetIniInt(Moleini, "NumPictures", "pictures", 8);
int ImageBorderSize = TUtils.GetIniInt(Moleini, "ImageBorder", "imageBorder", 2);
NumberOfColumns = TUtils.GetIniInt(Moleini, "NumRowsColumns", "columnNum", 4);
ImageHeight = ImageSize * 0.7;
// More Columns than Rows \\
if (NumberOfColumns > NumofImages)
{
MessageBox.Show("There is something wrong with the .ini file.");
MainWin.Close();
}
// Math - Get Necessary Variables \\
int ColumnSize = (ImageSize + (2 * ImageBorderSize));
int RowSize = (ImageSize + (2 * ImageBorderSize));
NumberofRows = (int)Math.Ceiling(NumofImages / NumberOfColumns);
int MainWindowWidth = (TUtils.ToInt(NumberOfColumns.ToString(), 2) * ColumnSize) + 15;
int MainWindowHeight = (NumberofRows * RowSize) + 200;
// Set Window Size \\
MainWin.Width = MainWindowWidth;
MainWin.Height = MainWindowHeight;
// Create Grid \\
Content_Grid.Children.Add(grid_Main);
grid_Main.Height = MainWindowHeight;
grid_Main.Width = MainWindowWidth;
grid_Main.Background = Brushes.Transparent;
// Grid Properties \\
for (int i = 0; i < NumberOfColumns; i++)
{
ColumnDefinition newColumn = new ColumnDefinition();
newColumn.Width = new GridLength(ColumnSize, GridUnitType.Pixel);
grid_Main.ColumnDefinitions.Add(newColumn);
}
for (int i = 0; i < NumberofRows; i++)
{
RowDefinition Row = new RowDefinition();
Row.Height = new GridLength(RowSize, GridUnitType.Pixel);
grid_Main.RowDefinitions.Add(Row);
}
// Fill Grid \\
int RowCount = 0;
int ColumnCount = 0;
for (int i = 0; i <= NumofImages; i++)
{
Image newImage = HoleImage();
if (RowCount < NumberofRows)
{
if (ColumnCount < NumberOfColumns)
{
Console.WriteLine("ColumnCount: " + ColumnCount.ToString());
Grid.SetRow(newImage, RowCount);
Grid.SetColumn(newImage, ColumnCount);
grid_Main.Children.Add(newImage);
ColumnCount++;
}
else
{
RowCount++;
ColumnCount = 0;
Grid.SetRow(newImage, RowCount);
Grid.SetColumn(newImage, ColumnCount);
grid_Main.Children.Add(newImage);
ColumnCount++;
Console.WriteLine("RowCount: " + RowCount.ToString());
}
}
else
{
break;
}
ChangeImage();
}
}
// Create Image for "Hut" \\
private Image HoleImage()
{
// Initialize Image \\
Image newImage = new Image();
// Image Properties \\
newImage.Width = ImageSize;
newImage.Height = ImageHeight;
// Define Name and Content \\
newImage.Name = "Image";
String ImageFunction = TUtils.GetIniString(Moleini, "ImagePath", "Hole", Root + "hole.jpg");
if (File.Exists(ImageFunction))
{
newImage.Source = new BitmapImage(new Uri(ImageFunction));
}
else
{
MessageBox.Show("Cannot find " + ImageFunction + ".", "Please fix the ini file");
}
return newImage;
}
// Change Image from "Hut" to Mole \\
private void ChangeImage()
{
Image newImage = HoleImage();
molePopup = MoleImage();
int numCol = Convert.ToInt32(NumberOfColumns);
//Random Number - Col
Random randomColumns = new Random();
int ranCol = randomColumns.Next(1, numCol);
//Random Number - Row
Random randomRow = new Random();
int ranRow = randomRow.Next(1, NumberofRows);
string Moleimage = TUtils.GetIniFileString(Moleini, "ImagePath", "PictureFile", Root + "mole2.png");
//Populate Grid with Mole at Random Times \\
Grid.SetRow(molePopup, ranRow);
Grid.SetColumn(molePopup, ranCol);
grid_Main.Children.Add(molePopup);
molePopup.MouseUp += new MouseButtonEventHandler((o, e) =>
{
MolePoints++;
grid_Main.Children.Remove(molePopup);
});
}
After a quick read over my gut reaction is that your ChangeImage() method is being called on each pass over the grid, causing a "random" cell to be "mole'd".
As for the click not working, I don't have VS to hand so can't be 100% on this but when you pass molePopup to grid_Mail.Children.Add it could be being passed as a value parameter meaning that your MouseUp handler is not actually there when the object is "copied" over to the grid.

Categories