I need to add a simple at the bottom of an existing view. It is composed of nested panels in a code which I know is not proper. But what I want given my available time is (simple as it sounds) to add my link below what is existing.
In a few words, there is a ControlCollection object being displayed (this.Controls), and I can't locate an element (LinkLabel or TableLayoutPanel) below the other elements.
Here is the minimal existing code :
private void SetAppearance()
{
pnlTitle = new Panel();
pnlTitle.x = ...
this.Controls.Add(pnlTitle);
lblTitle = new Label();
lblTitle.x = ...
pnlTitle.Controls.Add(lblTitle);
tlpnlCountryOfOrigin = new TableLayoutPanel();
tlpnlCountryOfOrigin.x = ...
pnlTitle.Controls.Add(tlpnlCountryOfOrigin);
CountryOfOrigin = new Label();
CountryOfOrigin.x = ...
tlpnlCountryOfOrigin.Controls.Add(CountryOfOrigin, 0, 0);
cbbCountryOrigin = new ComboBoxWithBorders();
cbbCountryOrigin.x = ...
tlpnlCountryOfOrigin.Controls.Add(cbbCountryOrigin, 1, 0);
pnlSupportInfo = new TableLayoutPanel();
pnlSupportInfo.x = ...
this.Controls.Add(pnlSupportInfo);
}
And I am just basically wanting to add my LinkLabel at the bottom of that, with that :
lnkSendLogs = new LinkLabel
{
Font = new Font(ArialBold12px, FontStyle.Regular | FontStyle.Underline),
AutoSize = true,
LinkColor = InfomaxConstants.Colors.Red,
Margin = new Padding(0),
Text = LabelManager.GetLabel("TEXTTOGETLABEL")
};
this.Controls.Add(lnkSendLogs);
Or even with a nested TableLayoutPanel (which I know is not a good practice) :
tlpnlSendLogs = new TableLayoutPanel();
tlpnlSendLogs.ColumnCount = 2;
tlpnlSendLogs.ColumnStyles.Clear();
tlpnlSendLogs.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100));
tlpnlSendLogs.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
lnkSendLogs = new LinkLabel
{
Font = new Font(ArialBold12px, FontStyle.Regular | FontStyle.Underline),
AutoSize = true,
LinkColor = InfomaxConstants.Colors.Red,
Margin = new Padding(0),
Text = LabelManager.GetLabel("TEXTTOGETLABEL")
};
lnkSendLogs.Dock = DockStyle.Fill;
tlpnlSendLogs.Controls.Add(lnkSendLogs, 0, 0);
this.Controls.Add(tlpnlSendLogs);
But the link is always appearing behind other elements, instead of below them.
The question is thus the very basic : How to add a simple LinkLabel appearing at the bottom of a view containing a few elements like Panels and TableLayoutPanels ?
The first problem was that the controls had no location settings, which makes room for random and unwanted things.
Two things to have in mind for the ControlCollection elements:
Locate them
Order them
The thing to know is that the Controls of a ControlCollection are ordered based on their index, AND the one of bigger index will be the one the most at the border of the container (whatever the order in which the children elements anchor are being defined) (https://stackoverflow.com/a/7685041/6617804)
A solution is
1-To set the position of all the ControlCollection elements to the top of their container
pnlTitle.Dock = DockStyle.Top;
pnlSupportInfo.Dock = DockStyle.Top;
tlpnlSendLogs.Dock = DockStyle.Top;
Or the exact same :
pnlTitle.Anchor = (AnchorStyles.Left | AnchorStyles.Top);
pnlSupportInfo.Anchor = (AnchorStyles.Left | AnchorStyles.Top);
tlpnlSendLogs.Anchor = (AnchorStyles.Left | AnchorStyles.Top);
2.1-To arrange the child in the opposite order If we need to (in my case where we want to display them in the opposite order)
this.Controls.SetChildIndex(pnlTitle, 2);
this.Controls.SetChildIndex(pnlSupportInfo, 1);
this.Controls.SetChildIndex(tlpnlSendLogs, 0);
2.2-OR to add them directly in the order they need to be for the display :
this.Controls.Add(tlpnlSendLogs);
this.Controls.Add(pnlSupportInfo);
this.Controls.Add(pnlTitle);
Instead of :
this.Controls.Add(pnlTitle);
this.Controls.Add(pnlSupportInfo);
this.Controls.Add(tlpnlSendLogs);
Related
I have MainForm parent mdi window which conatan Menu, ToolBar and StatusStrip created from designer in Visual Studio.
In that MainForm am showing child forms which content was created programmaticly (panels, textboxes, labels, grids etc...)
I have problem when i create DataGridView and set Dock.Top, Dock.Fill my grid is hidden behind parent toolbar.
I can't use Document Outline on programmaticlly created controls.
I try to use BringToFront but again i have the some problem.
To understand better check my screenhsot.
private void InitializeDefaultObjects()
{
/// SPLIT CONTAINER
_splitContainer = new SplitContainer()
{
SplitterDistance = 270,
Panel1MinSize = 270,
Margin = new Padding(15, 15, 15, 15),
Dock = DockStyle.Fill,
BackColor = Color.Gainsboro,
BorderStyle = BorderStyle.None,
Orientation = Orientation.Vertical,
SplitterWidth = 4,
FixedPanel = FixedPanel.Panel1,
RightToLeft = RightToLeft.No,
IsSplitterFixed = false,
Panel1Collapsed = false,
};
_splitContainer.Panel1.Padding = new Padding(5, 5, 5, 5);
_splitContainer.BringToFront();
this.Controls.Add(this._splitContainer);
/// TOOLSTRIP IN SPLIT CONTAINER 1
/// This toolstrip is merged with parent tolstrip
_toolStrip = new System.Windows.Forms.ToolStrip();
_toolStrip.Height = 100;
_toolStrip.Dock = DockStyle.Bottom;
_toolStrip.Visible = false;
_toolStrip.SendToBack();
_toolStrip.BringToFront();
// Toolstrip title
_toolStripTitleLabel = new ToolStripLabel()
{
Text = this.Text,
Alignment = ToolStripItemAlignment.Left,
Font = new Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold),
Image = this.ToolStripTitleImage,
ImageAlign = ContentAlignment.MiddleCenter,
ImageScaling = ToolStripItemImageScaling.SizeToFit
};
// separatar
ToolStripSeparator toolStripSeparator = new ToolStripSeparator() { Alignment = ToolStripItemAlignment.Right };
// Close button
ToolStripButton closeToolStripButton = new ToolStripButton()
{
Text = "Zatvori",
Alignment = ToolStripItemAlignment.Right,
Image = DFMSoftware.Core.Properties.Resource.Close_icon,
TextImageRelation = TextImageRelation.ImageAboveText
};
// Close button event
closeToolStripButton.Click += new EventHandler(closeToolStripButton_Click);
_toolStrip.Items.Add(_toolStripTitleLabel);
_toolStrip.Items.Add(closeToolStripButton);
_toolStrip.Items.Add(toolStripSeparator);
// add toolstripe to splitpanel
this._splitContainer.Panel2.Controls.Add(_toolStrip);
// datagridview
_dataGridView = new System.Windows.Forms.DataGridView();
_dataGridView.Dock = Dock.Fill;
// add grid to splitpanel 2
_splitContainer.Panel2.Controls.Add(_dataGridView);
}
Here in code you can see.
1. I create SplitContainer and set BringToFront() and set Dock.Fill
2. In SplitContainer in Panel2 i add DataGridView with Dock.Fill and again is behind parent.
Am not shure how to slove this does anyone know? THanks
Screensho1
I am writing my Windows Forms app. And I have some problem with TableLayoutContainer element. Or rows are superpose (without needed scroll bar) or there is a big interval between first and second row.
I need a container with dynamic changing sizes according to Form size, with auto vertical scroll (if the container's size to big). Please help me to correct my code or container's properties.
Label LabelG = new Label[len];
NumericUpDown NumberControlBars = new NumericUpDown[len];
for (int i = 0; i < len; i++)
{
TablePanelContainer.RowCount++;
TablePanelContainer.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 25F));
LabelG[i] = new System.Windows.Forms.Label();
LabelG[i].Name = "Label" + i.ToString();
LabelG[i].Size = new System.Drawing.Size(40, 23);
LabelG[i].Text = Groups[i].ToString();
LabelG[i].Dock = DockStyle.Right;
LabelG[i].Anchor = (AnchorStyles.Right | AnchorStyles.Top);
LabelG[i].TextAlign = ContentAlignment.MiddleRight;
TablePanelContainer.Controls.Add(LabelG[i], 0, i);
NumberControlBars[i] = new System.Windows.Forms.NumericUpDown();
NumberControlBars[i].Name = "Label" + i.ToString();
NumberControlBars[i].MaximumSize = new System.Drawing.Size(40,23);
NumberControlBars[i].Text = "0";
NumberControlBars[i].Dock = DockStyle.Left;
NumberControlBars[i].Anchor = (AnchorStyles.Left | AnchorStyles.Top);
TablePanelContainer.Controls.Add(NumberControlBars[i], 1, i);
}
Properties
Bug
I have recreated your functionality in a small app. These are the settings for your TablePanelLayout control
Anchor: Top, Bottom, Left, Right
AutoScroll: True
AutoSize: False
Specially the AutoSize setting to false is important. If you don't do that the control will resize itself to the height needed to accommodate all rows. Because the container has enough space in that case to show everything it will not show the scrollbars. It doesn't care that its size doesn't fit on the form.
This is what the designer should look like:
To overcome the quirks with the first row I adapted the Style of that first row. It looks like the designer plays some tricks here. Your code will look like this.
tableLayoutPanel1.SuspendLayout();
// adapt styling of first row
if (tableLayoutPanel1.RowStyles.Count > 0)
{
tableLayoutPanel1.RowStyles[0].SizeType = SizeType.Absolute;
tableLayoutPanel1.RowStyles[0].Height = 25F;
}
for(int i=0; i<100; i++)
{
var lbl = new Label();
lbl.Text = i.ToString();
tableLayoutPanel1.Controls.Add(lbl, 0, i);
var num = new NumericUpDown();
tableLayoutPanel1.Controls.Add(num,1 ,i);
tableLayoutPanel1.RowCount++;
}
tableLayoutPanel1.ResumeLayout();
When run this is the result:
I'm trying dynamically add panels within a panel dependent on the count of people in a list using the following code when the form loads:
private void Form1_Load(object sender, EventArgs e)
{
const int xConst = 2;
var people = new List<string>
{
"Person1",
"Person2",
"Person3",
"Person4",
};
var y = 2;
for (var x = 0; x < people.Count; x++)
{
var newpan = new MyPanel
{
BorderStyle = BorderStyle.None,
Height = 25,
Width = panel1.Width - 5,
Location = new Point(xConst, y)
};
var newlbl = new Label
{
BorderStyle = BorderStyle.None,
AutoSize = false,
Text = people[x],
Font = new Font("Segoe UI", 9.5F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(0))),
Size = new Size(75,20),
Location = new Point(newpan.Location.X + 2, newpan.Location.Y + 2),
};
var newbtn = new Button
{
FlatStyle = FlatStyle.Flat,
FlatAppearance = { BorderSize = 0 },
UseVisualStyleBackColor = true,
Text = #"+",
Size = new Size(15,21),
Location = new Point(newpan.Width - 20,newpan.Location.Y - 1),
Font = new Font("Segoe UI", 9.0F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)))
};
newpan.Controls.Add(newlbl);
newpan.Controls.Add(newbtn);
panel1.Controls.Add(newpan);
y += 27;
}
}
The problem is that if I specify the Location property in both the button and the label, only the first iteration of the labels and buttons show up for the Person1 iteration. But, if I leave the Location property out, they all show up. The problem with that is that I have a custom panel that overrides some stuff allowing me to put a customer border and color around the panels, and if I don't specify a location, the labels and buttons aren't positioned correctly on the panel, so it covers my border and looks sloppy.
Can someone help me figure out why this is happening? I've stepped through the program completely and watched all the values I can think of increment accordingly in the watch window. All the panels show up correctly, so I don't understand why their respective labels and buttons don't show up when I specify the location.
Looking at your code I notice that you are setting your newpan height to 25, and its position is offset by 27 with each iteration. You also are using
'Location = new Point(newpan.Location.X + 2, newpan.Location.Y + 2)
to set the location of your button and label within your newpan panel. newpan.Location is referenced in the coordinates of your panel1, your button and label's location is referenced in the coordinates of your newpan panel therefore after the first iteration of your For statement your label and buttons y location value is 29 which is greater than the height of your newpan panel making it not able to be seen, the next iteration after that will be y will be 56 and so forth. Each content control, in this case your panels will have its own coordinate system, the easiest fix would be to do something like this:
'Location = new Point( 2, 2) //for your label
'Location = new Point(newpan.Width - 20, - 1) //for your button
The other alternative is to do like jmcilhinney suggests and make an UserControl with your button and label already in position, you would then create individual instances of it and assign it to your panel1.
I am trying to make a text editor and I have 2 rich text boxes. I am uses the 1st rich text box as a number like and setting its Enabled property to false. Then the second text box is going next to it
I have currently set the dock of the first text box to left and the second one to fill. But the 2nd one keeps taking up the whole tabpage? And going slightly more left towards the number line and its hidden under there a little bit. Here is my create new document void I have... T2 is the number line and T is the default text box they will type into.
TabPage t = new TabPage("new " + getNumber());
tabControl1.TabPages.Add(t);
tabControl1.SelectedTab = t;
RichTextBox T2 = new RichTextBox();
t.Controls.Add(T2);
T2.Dock = DockStyle.Left;
T2.Enabled = false;
RichTextBox T = new RichTextBox();
t.Controls.Add(T);
T.Dock = DockStyle.Fill;
T.Font = new Font("Microsoft San Serif", 11);
Random R = new Random();
int RandomNumberHere = R.Next(1000, 100000);
T.Text = "Welcome, type your text...";
T.Select();
The problem is that you define your fill-docked text box at the end of the control list... winforms likes the fill-docked elements first in the list.
Easily solved:
RichTextBox T = new RichTextBox();
t.Controls.Add(T);
T.Dock = DockStyle.Fill;
T.Font = new Font("Microsoft San Serif", 11);
// Add this line
T.BringToFront();
Or you could also do T2.SendToBack(); after T is added to the controls collection.
Or you could simply create (and add to t.Controls), the fill-docked textbox first, and the left-docked textbox second.
Either way works
By the way, try to name your variables correctly. t, T, T2 are just not good names
Here you go:
t.Controls.Add(T2);
t.Controls.Add(T);
t.Controls.SetChildIndex(T, 1);
t.Controls.SetChildIndex(T2, 0);
t.PerformLayout(); // needed after SetChildIndex!
T2.Dock = DockStyle.Left;
T.Dock = DockStyle.Left;
If you want your boxes to grow with the TabPage here is one way to do it:
private void t_Resize(object sender, EventArgs e)
{
// assuming you want the two RTBs to fill the TabPage
// if you want something else, best add an anchored container panel
// and use its resize event instead
T2.Width = t.Width / 4;
T.Width = t.Width / 4;
}
And yes, t, T and T2 are really bad names!
There's a few things going on:
Fill does just that; it Fills the entirety of the PARENT control. Whether anything else is there or not.
Your other text box will be hidden until it is set to Enabled.
What you Might? be looking for is a way to have the text box size itself based on the size of the tab page being created:
{
TabPage t = new TabPage("new " + 1);
tabControl1.TabPages.Add(t);
tabControl1.SelectedTab = t;
RichTextBox T2 = new RichTextBox();
t.Controls.Add(T2);
T2.Dock = DockStyle.Left;
T2.Enabled = true ;
RichTextBox T = new RichTextBox();
t.Controls.Add(T);
T2.Dock = DockStyle.Right;
var AdjustedSize = T2.Size;
AdjustedSize.Width = t.Size.Width * 2 / 3;
T2.Size = AdjustedSize;
T.Font = new Font("Microsoft San Serif", 11);
Random R = new Random();
int RandomNumberHere = R.Next(1000, 100000);
T.Text = "Welcome, type your text...";
T.Select();
}
I wish to add a button for every line in a file to a panel.
My code so far is:
StreamReader menu = new StreamReader("menu.prefs");
int repetition = 0;
while(!menu.EndOfStream)
{
Button dynamicbutton = new Button();
dynamicbutton.Click += new System.EventHandler(menuItem_Click);
dynamicbutton.Text = menu.ReadLine();
dynamicbutton.Visible = true;
dynamicbutton.Location = new Point(4+repetition*307, 4);
dynamicbutton.Height = 44;
dynamicbutton.Width = 203;
dynamicbutton.BackColor = Color.FromArgb(40,40,40);
dynamicbutton.ForeColor = Color.White;
dynamicbutton.Font = new Font("Lucida Console", 16);
dynamicbutton.Show();
menuPanel.Controls.Add(dynamicbutton);
repetition++;
MessageBox.Show(dynamicbutton.Location.ToString());
}
menu.Close();
The problem is that only the first control gets created.
The code looks fine but there could be a following situations.
1.You might have only one entry in the file, so you are experiencing only One Button added to the panel.
2.Your panel width is smaller than the sum of all the dynamic buttons width.
I suspect no 2 is the main reason that is causing problem.
So, I recommend that you use FlowLayoutPanel. To add a dynamic content as it automatically layout all the child controls.
Each time it is generating the same name for dynamic controls. That's the reason why it is showing only the last one. It simply overwrites the previous control each time.
int x = 4;
int y = 4;
foreach(PhysicianData pd in listPhysicians)
{
x = 4;
y = panPhysicians.Controls.Count * 30;
RadioButton rb = new RadioButton();
rb.CheckedChanged += new System.EventHandler(rbPhysician_CheckedChanged);
rb.Text = pd.name;
rb.Visible = true;
rb.Location = new Point(x, y);
rb.Height = 40;
rb.Width = 200;
rb.BackColor = SystemColors.Control;
rb.ForeColor = Color.Black;
rb.Font = new Font("Microsoft Sans Serif", 10);
rb.Show();
rb.Name = "rb" + panPhysicians.Controls.Count;
panPhysicians.Controls.Add(rb);
}
Try this code
StreamReader menu = new StreamReader("menu.prefs");
var str = menu.ReadToEnd();
var items = str.Split(new string[] {"\r\n" } , StringSplitOptions.RemoveEmptyEntries);
foreach (var item in items)
{
Button dynamicbutton = new Button();
dynamicbutton.Click += new System.EventHandler(menuItem_Click);
dynamicbutton.Text = item;
dynamicbutton.Visible = true;
dynamicbutton.Location = new Point(4+repetition*307, 4);
dynamicbutton.Height = 44;
dynamicbutton.Width = 203;
dynamicbutton.BackColor = Color.FromArgb(40,40,40);
dynamicbutton.ForeColor = Color.White;
dynamicbutton.Font = new Font("Lucida Console", 16);
dynamicbutton.Show();
menuPanel.Controls.Add(dynamicbutton);
repetition++;
}
The problem with Panel and similar controls other than the FlowLayoutPanel is when you create a control and a second one, the second is created at the same position if you are not changing it's location dynamically or setting it according to the other already added controls. Your control is there, it's in the back of the first control.
A flowLayoutPanel is better as it will add the controls next to each other as you add them while compromising more finer control at their positioning.
I also have similar problems with panels. For what you are doing it could be useful to just add strings to a listbox rather than using labels and a panel. That should be simpler.