How to create dynamically C# panels - c#

I create a contact manager. The user can already enter some and they are stored in a file and re-opened when the program is started. Each contact is an object of my Person class.
When launching the program (in Load()) I created a for loop until all contacts have been explored (contacts are stored when opened in a Person table)
So now I come to my problem:
I have a panel that is scrollable (I have enabled the option) and I would like every 50 pixels in height, that a new panel is created with name, first name, email and phone number of my contacts and a pictureBox.
Except, I would like to be able to do it dynamically instead of creating the same thing more than 50 times and repeating the same code 50 times
Because for the moment I have done this:
for(int i = 0; i < contacts.Count; i++) //Afficher les contacts
{
if(!panel_contact1.Visible)
{
panel_contact1.Visible = true;
label_prenom_nom1.Text = contacts[i].Prenom + " " + contacts[i].Nom;
label_email1.Text = contacts[i].mail;
label_tel1.Text = contacts[i].tel;
pictureBox1.Image = Image.FromFile(contacts[i].pathImage);
}
else if(!panel_contact2.Visible)
{
panel_contact2.Visible = true;
label_prenom_nom2.Text = contacts[i].Prenom + " " + contacts[i].Nom;
label_email2.Text = contacts[i].mail;
label_tel2.Text = contacts[i].tel;
pictureBox2.Image = Image.FromFile(contacts[i].pathImage);
}
}
It's the code only for the first two contacts and I don't want to repeat it up to 100 times.
So my question is:
How to create panels, with in each of the labels and a pictureBox, every 50px in a panel.
Thank you for reading, if you just have advice said always the same if you all have the code I'm a taker especially since I think it should be easy to do because the content of the labels are already dynamically teaching.
Thank you.

On WinForms, you can use this:
int x = 0;
int y = 0;
int delta = 10;
for ( int i = 0; i < contacts.Count; i++ )
{
// Create picture box
var picture = new PictureBox();
picture.Image = Image.FromFile(contacts[i].pathImage);
picture.Location = new Point(x, y);
picture.Size = new Size(picture.Image.Width, picture.Image.Height);
int dx = picture.Width + delta;
// Create name label
var labelName = new Label();
labelName.AutoSize = true;
labelName.Location = new Point(x + dx, y);
labelName.Font = new Font(labelName.Font, FontStyle.Bold);
labelName.Text = contacts[i].Prenom + " " + contacts[i].Nom;
// Create mail label
var labelMail = new Label();
labelMail.AutoSize = true;
labelMail.Location = new Point(x + dx, y + labelName.Height);
labelMail.Text = contacts[i].mail;
// Create phone label
var labelPhone = new Label();
labelPhone.AutoSize = true;
labelPhone.Location = new Point(x + dx, y + labelName.Height + labelMail.Height);
labelPhone.Text = contacts[i].tel;
// Add controls
panel.Controls.Add(picture);
panel.Controls.Add(labelName);
panel.Controls.Add(labelMail);
panel.Controls.Add(labelPhone);
// Iterate
int dy1 = labelName.Height + labelMail.Height + labelPhone.Height;
int dy2 = picture.Height;
y += Math.Max(dy1, dy2) + delta;
}
But you may prefer create a custom control where you put a picture box and three labels designed as you want with colors, font size, bolding, margin, borderstyle and so on, with Height at 50.
Add new user custom control with Project > Add > User control and choose a file name like PersonControl.
public partial class PersonControl : UserControl
{
public PersonControl()
{
InitializeComponent();
}
public PersonControl(Person person) : this()
{
pictureBox.Image = Image.FromFile(person.pathImage);
labelName.Text = person.Prenom + " " + person.Nom;
labelMail.Text = person.mail;
labelPhone.Text = person.tel;
}
}
int x = 0;
int y = 0;
for ( int i = 0; i < contacts.Count; i++ )
{
var control = new PersonControl(contacts[i]);
control.Location = new Point(x, y);
panel.Controls.Add(control);
y += control.Height;
}
You should take care of the file image size that must be the same for all and the same as the picture box else you need to manage that by resizing for example.
How to resize an Image C#

If you're using windows forms, create a user control with a constructor using the Person object, set the labels and picture boxes to the info of that person. In the main loop you posted, create a new instance of this and set it's position to 0, i * 50 to place it under the previous one.
Example:
for(int i = 0; i < contacts.Count; i++)
{
YourUserControl u1 = new YourUserControl(pass the person object);
Panel1.Controls.Add(u1);
u1.Location = new Point(0, i * 50);
}

This depends on the display technolgy you are using (WinForms, WPF/UWP, ASP.NET, other).
In Windows Forms you just create the elements and add them to the container. The designer wroks on it's own part of the partial class. The designer code is run with InitializeComponents() in the constructor. Anything it can do, you can do. And you can easily look at it.
In WPF/UWP stuff is a bit more complicated. The designer does not work on code, but on XAML, a dedciated markup language. You are not supposed to manually add anything to the UI from the code. WPF/UWP and XAML were designed with the MVVM pattern in mind. And dealing with lists of things is what it does best. While you can use other patterns, generally that looses 90% of it's power and runs into issues at every other corner.
For ASP.Net it would depend on wich pattern you use. While not originally designed for it, MVC has been extremely popular with WebApplication. So much so, it is almost synonimous with WebApplications and ASP.NET. However this does not look like a web Application.

Related

Adding a control to another control which is created at runtime

I am trying to add a picturebox control to a panel which is created at runtime.
It is for a chess game I am working on. I want to add a picture box to each panel , an assigning the image to the control later. Here is what I have so far:
//Sets the number of rows on the chess board
for (int i = 0; i < 8; i++)
{
//Set the number of columns on the board
for (int j = 0; j < 8; j++)
{
ChessSquare sq = new ChessSquare(((char)(65 + i)).ToString(), 7- j);
sq.Color = (i + (j % 2)) % 2 == 0 ? Color.Black : Color.White;
Panel p = new Panel()
{
Size = new Size(blockSize, blockSize),
BackColor = sq.Color,
Tag = sq,
Location = new Point(blockSize * i + 15, blockSize * j + 15),
BackgroundImageLayout = ImageLayout.Stretch
};
p.MouseEnter += new EventHandler(squareMouseEnter);
p.MouseLeave += new EventHandler(squareMouseLeave);
p.Click += new EventHandler(squareMouseClick);
chessBoardPanels[i, j] = p;
groupBox1.Controls.Add(p);
}
}
//SetUp Board
SetUpBoad Setup = new SetUpBoad();
SetUpBoad(chessBoardPanels);
Since you already put the Panels into the panel-array (?)
chessBoardPanels[i, j] = p;
You can add the PictureBoxes either now or later..:
PictureBox pb = new PictureBox ();
pb.Size = ..
pb.BackColor = Color.Transparent;
chessBoardPanels[i,j].Controls.Add(pb);
To access them later you can cast their first Control to PictureBox:
PictureBox pb = (PictureBox)chessBoardPanels[i,j].Controls[0];
pb.Image = aQueenImage;
If you want to add a PictureBox only where a piece is you need to do checks:
if (chessBoardPanels[i,j].Controls.Count > 0)
{
PictureBox pb = (PictureBox)chessBoardPanels[i,j].Controls[0];
pb.Image = aQueenImage;
}
To move a piece from <i1,j1> to <i2, j2> you do as expected:
chessBoardPanels[i1,j1].Controls[0].Parent = chessBoardPanels[i2,j2];
I notice that you are hooking up mouse events. If you want to use them to move the pieces, remember that transparency will not work for overlapping controls in Winforms and so while a piece-Box is crossing Panels it will not have working tranparency around the Image.
While the pBox is nested in a Panel all is well but to move it you would have to first make it a child of the parent of those panels and only add it to the target Panel upon MouseUp; the coordinate corrections can be solved but the tranparency, if you need it, will be a bigger problem..
The usual advice it to consider drawing at least those board squares and maybe even the pieces onto a base board-Panel (or board-PictureBox)

Displaying pictureBox array

I would like to display 13 pictureBox, however, it ends up with only the last one visible.
So I was wondering if I did it in a wrong way.
The following code get image from resources folder.
var testP = new PictureBox();
for (int i = 0; i < 13; i++)
{
testP.Width = 65;
testP.Height = 80;
testP.BorderStyle = BorderStyle.None;
testP.SizeMode = PictureBoxSizeMode.StretchImage;
test[i] = getImage(testP, testPTemp[i]);
}
The following code is trying to display 13 pictureBox with shifting location.
These two codes segments should be able to perform the action.
test = new PictureBox[13];
for (var i = 0; i < 13; i++)
{
test[i].Image = (Image)Properties.Resources.ResourceManager.GetObject("_" + testTemp[i]);
test[i].Left = 330;
test[i].Top = 500;
test[i].Location = new Point(test[i].Location.X + 0 * displayShift, test[i].Location.Y);
this.Controls.Add(test[i]);
}
Here is the getImage()
private PictureBox getImage(PictureBox pB, string i) // Get image based on the for loop number (i)
{
pB.Image = (Image)Properties.Resources.ResourceManager.GetObject("_" + i); // Get the embedded image
pB.SizeMode = PictureBoxSizeMode.StretchImage;
return pB;
}
I'm pretty sure there are all PictureBox Controls but they have all the same location so they are lying above each other. That's why only the last one is visible to you.
I think you should replace the 0 with the i variable.
test[i].Location = new Point(test[i].Location.X + i * displayShift, test[i].Location.Y); this.Controls.Add(test[i]);
It's hard to tell the exact problem based off the code you've provided. One possible issue could be that when you are creating the PictureBoxes you only create a single instance before the for loop and then fill the array with references to that instance. Another possibility is that when you're calculating the X position of the controls, you're multiplying by 0 which will always result in 0 (meaning all the controls are at location 330).
Below is code that will achieve basically what you're trying but without all your code I can't give you a more specific example.
In Your Class
const int PICTURE_WIDTH = 65;
const int PICTURE_HEIGHT = 85;
Inside You Function
//Loop through each image
for(int i = 0; i < testTemp[i].length; i++)
{
//Create a picture box
PictureBox pictureBox = new PictureBox();
pictureBox.BorderStyle = BorderStyle.None;
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
//Load the image date
pictureBox.Image = (Image)Properties.Resources.ResourceManager.GetObject("_" + testTemp[i]);
//Set it's size
pictureBox.Size = new Size(PICTURE_WIDTH, PICTURE_HEIGHT);
//Position the picture at (330,500) with a left offset of how many images we've gone through so far
pictureBox.Location = new Point(330 + (i * PICTURE_WIDTH), 500);
//Add the picture box to the list of controls
this.Controls.Add(pictureBox);
}
If you need to keep a list of the picture boxes, just create a new list before the loop and add each pictureBox to the list inside the loop. If the control/window you're adding these PictureBoxes to needs to scroll left or right to see all the images set the AutoScroll property to true.

Adding objects during run time?

Background
I have a tab which is made active if there is more than one record returned from a query on my database.
For each record returned I would like a set of labels created and placed on the tab. For example if there are 8 records I would like 8 labels created.
Question
My loop only creates one label, even though my count is showing I have 8 records? Not sure why?
How do you create labels in a loop 8 times and not have them draw in the same location 8 times? I would them to appear in a horizontal list. Pretty sure the way I have coded the solution ,they will all be drawn in the same place?
Code
for (int i = 1; i <= rowCount; i++)
{
// Create objects
LinkLabel Linklabel1 = new LinkLabel();
Linklabel1.Text += ds.Tables[0].Rows[0]["code"].ToString();
Linklabel1.Location = new Point(10, 50);
Linklabel1.Height = 40;
Linklabel1.Width = 100;
tabControl1.TabPages[0].Controls.Add(Linklabel1);
}
Try something like this out:
for (int i = 0; i < rowCount; i++)
{
// Create objects
LinkLabel Linklabel1 = new LinkLabel();
Linklabel1.Text = ds.Tables[0].Rows[i]["code"].ToString();
Linklabel1.Height = 40;
Linklabel1.Width = 100;
Linklabel1.Location = new Point((i + 1) * 10 + (i * Linklabel1.Width), 50);
tabControl1.TabPages[0].Controls.Add(Linklabel1);
}
If you don't want to explicitly position them by setting the Location() property, consider putting a FlowLayoutPanel on the TabPage and added the controls to that instead. Then they will positioned automatically for you.

Seat reserving software: Drawing lots of Seats in C# instantly

I'm building Seat reserving software using C# and I am confusing how I draw lots of seats instantly.
I'm trying three way which is..
Using Usercontrol
public void DrawUsercontrol(int x, int y)
{
int space = 4;
int SeatLimit = 165;
int RowSeatLimit = 15;
for (var i = 1; i < SeatLimit; i++)
{
UserControl1 ctrl = new UserControl1();
ctrl.Size = new System.Drawing.Size(25, 25);
ctrl.Location = new Point(x + space, y);
if (i % RowSeatLimit == 0)
{
x = 1;
y = y + 25 + space;
}
x = x + 25 + space;
ctrl.label1.Text = i.ToString();
ctrl.label1.Click += new EventHandler(label1_Click);
panel1.Controls.Add(ctrl);
}
}
Using "Panel" control
public void DrawingPanel(int x, int y)
{
Panel myPanel = new Panel();
int width = 16;
int height = 16;
myPanel.Size = new Size(width, height);
myPanel.BackColor = Color.White;
myPanel.Location = new Point(x, y);
Label mylabel = new Label();
mylabel.Text = "4";
myPanel.Controls.Add(mylabel);
myPanel.BackColor = Color.YellowGreen;
// this.Controls.Add(myPanel);
panel1.Controls.Add(myPanel);
}
Using Graphics and draw Rectangle
public void DrawingSquares(int x, int y)
{
SolidBrush myBrush = new SolidBrush(System.Drawing.Color.Red);
Graphics graphicsObj;
graphicsObj = this.panel1.CreateGraphics();
Rectangle myRectangle = new Rectangle(x, y, 30, 30);
graphicsObj.FillRectangle(myBrush, myRectangle);
graphicsObj.Dispose();
}
I refer first option but it's too slow.
And how can I decide?
Your problem is that you are adding only one control at a time. Adding a control forces a full refresh (software GDI+ rendering is quite slow) of the parent panel (best case) and perhaps the whole form (worst case).
Try creating all your controls and adding them in one line using Panel.Controls.AddRange. This will only prompt one refresh.
You should also only add these controls when the form is first shown and when the number of seats change - it is an expensive (and relatively slow) operation.
Consider creating a UserControl for each seat so that you don't have to manage the seat labels and seat borders separately - this way you can just have one list. If you add the seats in order, the index of an item in the list will map to its seat number! You probably wont get a performance increase from this but your code will be easier to work with.

How to automaticly locate buttons on panel c#

I have a few buttons to add on the form. In the code I'm setting up some button properties:
class DigitButton : Button
{
private static int digitBtnTag;
public DigitButton()
: base()
{
this.Size = new Size(30, 30);
this.Tag = digitBtnTag;
this.Text = (this.Tag).ToString();
this.Margin = new Padding(2);
this.Padding = new Padding(2);
digitBtnTag++;
}
}
In the MainForm.cs I have
for (int i = 0; i < dgtBtns.Length; i++)
{
dgtBtns[i] = new DigitButton();
dgtBtns[i].Click += new EventHandler(this.digitButtonClick);
digitPanel.Controls.Add(dgtBtns[i]);
}
So when I launch a program I see all my buttons in the one place: (0;0) on digitPanel despite property Margin. So why don't all these buttons automaticly "push" each other in the different directions? And how to make it?
Have you tried using a FlowLayout Panel ?
Also, this video might help:
Windows Forms Controls Lesson 5: How to use the FlowLayout Panel
that's not the way controls works in c#. i'm guessing you programed at java a bit because the layout in jave works that whay, but in c# just do
for (int i = 0; i < dgtBtns.Length; i++)
{
dgtBtns[i] = new DigitButton();
dgtBtns[i].Location = new Point(50, 50 * i); // Multiplying by i makes the location shift in every loop
dgtBtns[i].Click += new EventHandler(this.digitButtonClick);
digitPanel.Controls.Add(dgtBtns[i]);
}
you'll have to figure out the location parameters by trying and see
You need to define Left and Top then add the button height or width each time you loop to position your buttons correctly i.e.
int bTop=0;
int bLeft=0;
for (int i = 0; i < dgtBtns.Length; i++)
{
dgtBtns[i] = new DigitButton();
dgtBtns[i].Click += new EventHandler(this.digitButtonClick);
dgtBtns[i].Top = bTop;
bTop += dgtBtns[i].Height;
digitPanel.Controls.Add(dgtBtns[i]);
}

Categories

Resources