how to make a control visible in a panel? - c#

I want to add a control to my panel in WinForms.
public Form1()
{
InitializeComponent();
PictureBox a = new PictureBox();
a.Left = 100;
a.Top = 150;
a.Width = 50;
a.Height = 50;
a.BackColor = Color.Red;
Controls.Add(a);
}
Without the Panel, this code works perfect. But the Panel blocks the PictureBox, which properties should I change?

Basically, there are few options to achieve that:
1. When you add the controls to your Form like this:
Controls.Add(panel);
Controls.Add(button1);
Controls.Add(button2);
Controls.Add(pictureBox);
They will be shown in this very order: panel on the bottom, buttons between and pictureBox on the top.
2. As it was pointed in the comments, you can use BringToFront() after adding the control.
pictureBox.BringToFront();
This will make the pictureBox to be on top of other things.
3. You can change the order of controls by editing their Z-index, called ChildIndex in WinForms. You can set it with:
Controls.SetChildIndex(pictureBox, __yourIndex__);
4. You can add the pictureBox to your panel with:
panel.Controls.Add(pictureBox);

Related

Dynamic label parent not working

I'm creating a chat program and for the chatbox i want there to be a whatsapp kind of style message layout. My way of doing it (probably not the best) is by creating a picturebox dynamically with my blue background picture in it and then adding a label , making the picturebox the parent and then overlay the message over the picture box. I'm using this bit of code :
private void CreateChatBox(int height, string message)
{
PictureBox pb = new PictureBox();
Label pbl = new Label();
pb.Name = height.ToString();
pbl.Text = message;
pbl.Name = height.ToString();
pb.Image = LocalChat.Properties.Resources.ChatBox_Test;
pb.SizeMode = PictureBoxSizeMode.StretchImage;
// set picturebox possitions and margins
pb.Left = 15;
pb.Top = 100;
pb.Width = 250;
pb.Height = 75;
tabPage.Controls.Add(pb);
//set label positions and margins
pbl.Parent = pb;
pbl.AutoSize = true;
pbl.Width = 200;
pbl.BackColor = Color.Transparent;
pbl.Location = new Point(1, 1);
// Add button click event Handler and add buttons and lables to the panel
tabPage.Controls.Add(pbl);
}
my problem is that i'm making the picturebox the parent of the label, yet the label will just sit on the very top left of the form and not inside the picturebox as i want. Am i not getting what parent should be doing?
or how do i get my label to be confined inside the picturebox?
You must remove your line of code
tabPage.Controls.Add(pbl);
at the end of the file
because after you set the parent of the label to the PictureBox you're setting its parent to the TabPage, again
When you use anyControl.Controls.Add(otherControl) you're setting the otherControl.Parent to anyControl
But i'll say that if you want that kind of control settings you should instead of dynamically creating and setting its control you could create an usercontrol and inside the usercontrol you would put the logic to the display of the message, and you could dinamically create the userControl and put it anywhere you would like

Always Scroll to bottom in vertical scroll bar

I have a flowlayoutpanel in my winform in which the images are added dynamically. I want the vertical scroll bar to always be at the bottom showing the last image added. How can i do that?
I have
AutoScroll = true
FLow Direction = Top Down
Wrap Content = False
Scrollable container controls, like FlowLayoutPanel, automatically keep the control with the focus in view. But PictureBox is special, it cannot receive the focus. So you have to help by explicitly asking the FLP to make the added control visible, use its ScrollControlIntoView() method. Like this:
var pic = new PictureBox();
//...
flowLayoutPanel1.Controls.Add(pic);
flowLayoutPanel1.ScrollControlIntoView(pic);
With the strong advantage that this works for any layout setting you applied to the FLP. You can also tinker with the AutoScrollPosition property, but it is harder to get that right:
flowLayoutPanel1.AutoScrollPosition = new Point(
pic.Right - flowLayoutPanel1.AutoScrollPosition.X,
pic.Bottom - flowLayoutPanel1.AutoScrollPosition.Y);
Try this:
scrollBar.Value=scrollBar.Maximum;
here scrollBar is your ScrollBar control in winform.
For more detail, check this.
Here is a way to force the last control into view.
flowLayoutPanel.ScrollControlIntoView(Control_To_Add); // Control_To_Add is the control we want to scroll to
Button TempButton = new Button();
TempButton.Width = _Panel.ClientRectangle.Width - 6; // Make the last control in the _Panel
flowLayoutPanel.Controls.Add(TempButton); // We add this TempButton so we can scroll to the bottom of the _Panel.Controls
flowLayoutPanel.ScrollControlIntoView(b); // We scroll to TempButton at the bottom of the _Panel.Controls
flowLayoutPanel.Controls.Remove(b); // We remove TempButton
b.Dispose(); // clean up
Forcing A FlowLayoutPanel to scroll to and display all of a control.
Code Correction:
flowLayoutPanel.ScrollControlIntoView(Control_To_Add); // Control_To_Add is the control we want to scroll to
Button TempButton = new Button();
TempButton.Width = _Panel.ClientRectangle.Width - 6; // Make the last control in the _Panel
flowLayoutPanel.Controls.Add(TempButton); // We add this TempButton so we can scroll to the bottom of the _Panel.Controls
flowLayoutPanel.ScrollControlIntoView(TempButton); // We scroll to TempButton at the bottom of the _Panel.Controls
flowLayoutPanel.Controls.Remove(TempButton); // We remove TempButton
b.Dispose(); // clean up
This is the correct way:
MyControl uct = new MyControl();
uct.Parent = flowLayoutPanel;
this.ActiveControl = uct;
if (flowLayoutPanel.VerticalScroll.Visible)
{
flowLayoutPanel.ScrollControlIntoView(uct);
}

Why are Anchor properties not being honored within dynamically created nested components?

Let me begin by saying that I have not done a lot of Windows Forms development -- if there is an obvious mistake that I may be making, please don't hesitate to mention it.
Steps to reproduce my issue:
Create a new C# Windows Forms Project using VS 2010 or VS 2012
Using the VS Form Designer, add three FlowLayoutPanel components to the form
Set each FlowLayoutPanel to have the same height as the form and approximately 1/3 the width of the form
Position each FlowLayoutPanel so that they do not overlap each other horizontally and collectively consume approximately the entire area of the Form.
The leftmost FlowLayoutPanel is configured to have an Anchor of Top, Bottom, Left
The middle FlowLayoutPanel is configured to have an Anchor of Top, Bottom
The rightmost FlowLayoutPanel is configured to have an Anchor of Top, Bottom, Right
Add an event for Form_Shown:
private void Form1_Shown(object sender, EventArgs e)
{
Panel p = new Panel();
p.BorderStyle = BorderStyle.FixedSingle;
p.Width = 200;
p.Height = 100;
Label label1 = new Label();
label1.BorderStyle = BorderStyle.FixedSingle;
label1.Text = "Hello";
label1.Anchor = AnchorStyles.Top;
Label label2 = new Label();
label2.BorderStyle = BorderStyle.FixedSingle;
label2.Text = "World!";
label2.Anchor = AnchorStyles.Bottom;
p.Controls.Add(label1);
p.Controls.Add(label2);
middleFlow.Controls.Add(p); // add to the center most FlowLayoutPanel on Form1
}
The result seems to be that label1 is placed on top of label2, despite label2 being added second. Moreover, the anchor values seem to be ignored (as label1 is covering label2 when I intend for them to be anchored to the top and bottom of the Panel component, respectively)
If I use the Dock property instead of the Anchor property, the behavior is as desired. Why does the Anchor property not work in this situation?
Also, is there a way to anchor components to other components? I notice as I increase the size of my Form at runtime, horizontal "gaps" between panels appear. Ideally, I would like the panels to grow together, preventing any gaps/whitespace between them horizontally?
Thanks in advance for any suggestions or tips.
I'm still starting to learn c# and winforms, so the following may not be optimal but it does what you required.
Handled the labels with Dock=Top. Note that the labels are switched so that label1 is on top of label2, i.e., registering label1 last pushes down the already registered label2.
The positioning of the three panels is done without anchors and docks with an event handler for resize. Setting the size of the form after that raises a resize event. Colored to see the components.
using System;
using System.Drawing;
using System.Windows.Forms;
public class ThreePanel : Form {
FlowLayoutPanel leftFlow;
FlowLayoutPanel middleFlow;
FlowLayoutPanel rightFlow;
public ThreePanel(){
leftFlow = new FlowLayoutPanel() {
BackColor = Color.Yellow
};
middleFlow = new FlowLayoutPanel() {
BackColor = Color.LightGreen
};
rightFlow = new FlowLayoutPanel() {
BackColor = Color.LightBlue
};
this.Controls.Add(rightFlow);
this.Controls.Add(middleFlow);
this.Controls.Add(leftFlow);
this.Load += (s,e)=>Form1_Shown(s,e);
this.Resize += (s,e)=>{
int w=this.Width/3;
leftFlow.Width=middleFlow.Width
=rightFlow.Width=w;
leftFlow.Height=middleFlow.Height
=rightFlow.Height=this.Height;
leftFlow.Location=new Point(0,0);
middleFlow.Location=new Point(w,0);
rightFlow.Location=new Point(2*w,0);
};
this.Size = new Size(750,450);
}
private void Form1_Shown(object sender, EventArgs e)
{
Panel p = new Panel() {
BorderStyle = BorderStyle.FixedSingle,
Width = 200,
Height = 100,
BackColor = Color.Fuchsia,
};
Label label1 = new Label() {
BorderStyle = BorderStyle.FixedSingle,
Text = "Hello",
Dock = DockStyle.Top
};
Label label2 = new Label() {
BorderStyle = BorderStyle.FixedSingle,
Text = "World!",
Dock = DockStyle.Top
};
p.Controls.Add(label2);
p.Controls.Add(label1);
// add to the center most FlowLayoutPanel on Form1
middleFlow.Controls.Add(p);
}
public static void Main()
{
Application.Run(new ThreePanel());
}
}
I would expect exactly the behaviour that you mentioned.
The Anchor property only tells the parent container that the label should be sticked
to the parent. In your case AnchorStyles.Top means stick the label to the top and leave it there if the parent moves or resizes.
You did not specify dimensions or positions for the labels, so both overlapp.
The z-order of the controls is created implicitly from the order when added to middleFlow.Controls. You can check this using VS forms designer. Select "Bring to Front" or "Send to Back" and watch how the x.designer.cs changes.
Why it is in reverse order is one of the little .net secrets. The workaround is to change the order. Sometimes it is easier to do it manually than in the designer.

auto resizing panel on a form

I have two panels on a form. I want one of them, when an user maximizes the form, the panel to be maximized too, depending on the form. I tried and the panel is shown on the entire form,hiding the other panel.
Here is my code:
public MainForm()
{
InitializeComponent();
panel2.Anchor = (AnchorStyles.Bottom | AnchorStyles.Right);
panel2.Dock = DockStyle.Fill;
TaskControl t = new TaskControl();
int x, y;
x = 0;
y = 0;
t.Location = new Point(x, y);
panel2.Controls.Add(t);
t.BringToFront();
}
I managed to do it. I changed the values of Anchor from Properties. Thank you for help!
It sounds like you want a splitcontainer. With this control you get two panels. Set the "fixedpanel" property to the panel that you want to not resize. The other panel will resize as the form is resized (or maximised)
You should NOT only do so in initialization, but also in Form_Resize event etc. For instance,
you can handle Form.ResizeEnd event, see reference here.

How do I put a panel of buttons into flow layout panel?

I have a panel of labels, buttons and image that I wish to put into a flow layout panel.
As seen in some tutorial, I understand that it is possible to auto align new and additional buttons into a flow layout panel.
what I would like to ask is that is it possible to put a panel WITHIN a flow layout panel and call multiple instances of the same panel to appear within the flow layout panel.
My panel code would be
this.panelNotification.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelNotification.Controls.Add(this.button1);
this.panelNotification.Controls.Add(this.lblImage);
this.panelNotification.Controls.Add(this.lblName);
this.panelNotification.Controls.Add(this.lblLinkName);
this.panelNotification.Controls.Add(this.lblLinkLocation);
this.panelNotification.Controls.Add(this.lblLocation);
this.panelNotification.Location = new System.Drawing.Point(3, 3);
this.panelNotification.Name = "panelNotification";
this.panelNotification.Size = new System.Drawing.Size(506, 100);
this.panelNotification.TabIndex = 17;
So is it possible to include the whole panel into a flow layout panel? if yes, how do i do it. thank you.
Yes, you can put a Panel into a FlowLayoutoutPanel.
No, you can't put a control several times into a FlowLayoutoutPanel (in fact you can, but it is only displayed once).
But what you could do is writing some kind of Factory-Method that creates a new Panel with new Buttons/Labels/other Controls etc. every time you call it, and add these new instances to your FlowLayoutpanel. Something like this:
public class Form1
{
private Panel CreateNotificationPanel()
{
var p = new Panel { BackColor = Color.Red };
p.Controls.Add(new Button { Text = "Test" });
return p;
}
private void Form1_Load(System.Object sender, System.EventArgs e)
{
var flp = new FlowLayoutPanel { Dock = DockStyle.Fill };
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
this.Controls.Add(flp);
}
public Form1() { Load += Form1_Load; }
}
Another (and problably better) approach would be to create a UserControl that contains your Buttons/Labels/etc. instead of using a panel and adding all controls manually. Just create with the Designer and add new instances of the UserControl to the FlowLayoutPanel.

Categories