flowlayout control keeps adding control in the wrong direction in winforms - c#

I have a flowlayout control in winforms, i have set its flow direction to TopDown but it keeps adding controls from left to right, autoscroll is also set to true.
flowLayoutPanel1.Controls.Clear();
Label labelInput = new Label();
ListBox listBoxNewInput = new ListBox();
//Initialize label's property
labelInput.Text = " #" + Convert.ToInt32(sequence);
labelInput.AutoSize = true;
//Initialize textBoxes Property
listBoxNewInput.HorizontalScrollbar = false;
listBoxNewInput.Items.Add(efforts);
//Add the newly created text box to the list of input text boxes
inputTextBoxesList.Add(listBoxNewInput);
//Add the labels and text box to the form
flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
flowLayoutPanel1.Controls.Add(labelInput);
flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
flowLayoutPanel1.Controls.Add(listBoxNewInput);

Set the WrapContents property of the flowLayoutPanel1 to false, it will not allow to move those controls on the right if they don't fit. In order to be able to scroll clipped content you can set AutoScroll property to true
Here is the code:
flowLayoutPanel1.FlowDirection = FlowDirection.TopDown;
flowLayoutPanel1.WrapContents = false;
flowLayoutPanel1.AutoScroll = true;
flowLayoutPanel1.Controls.Add(labelInput);
flowLayoutPanel1.Controls.Add(listBoxNewInput);

Related

Position of link in LinkLabel

I want a box of a fixed size to show some text and have a link in it that is clickable in the bottom right corner for editing. Clicking this edit link shows a set of fields to fill in.
I tried LinkLabel, which does the trick, but, when I change the text, the size of the box changes. I set autosize to false and longer text forces the link outside the box. Short text puts the link to far up.
I could get fancy and calculate the position of the link and insert it at the appropriate place (adding new lines if needed), but I'm wondering if there isn't an easier way to do this.
Is there a better control for doing this or another way of doing this?
EDIT:
The boxes that are filled in are concatenated and replace the text in the linklabel. The Edit link is currently appended to this and a LinkArea (of the last 4 characters) is set.
You need to build a composite layout, for instance using a Panel with Label/TextBox (Dock = Fill) and LinkLabel (Dock = Bottom, TextAlign = MiddleRight) inside, like this
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Samples
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var text = "I want a box of a fixed size to show some text and have a link in it that is clickable in the bottom right corner for editing.";
int textSize = 50;
var form = new Form { Padding = new Padding(8) };
var panel = new Panel { Parent = form, BorderStyle = BorderStyle.FixedSingle, Padding = new Padding(4) };
var label = new Label { Dock = DockStyle.Fill, Parent = panel, AutoSize = false, Text = text, Height = textSize };
var link = new LinkLabel { Dock = DockStyle.Bottom, Parent = panel, AutoSize = false, TextAlign = ContentAlignment.MiddleRight, Text = "Edit" };
panel.Location = form.DisplayRectangle.Location;
panel.Width = form.DisplayRectangle.Width;
panel.Height = panel.Padding.Vertical + link.Height + label.Height;
Application.Run(form);
}
}
}
Result:
I found another way.
I use a text box and position a linklabel in its corner.
textbox is readonly and disabled so it acts like a label and the backcolor is set to white to over-ride the disabled/readonly colour.
The edit link now stays put

Why does setting a MinimumSize break the table layout?

I'm currently playing around with layouts and made a test project where I construct a Form which displays a Panel which contains a TableLayoutPanel with three rows:
a text box
a button
a placeholder label which is supposed to take up the remaining vertical space.
This test works properly, but if I set the Minimum Size of the Text Box to e.g. (400, 200), I can no longer see the button. Shouldn't the first row in the table layout AutoSize to its content? Note that
setting RowStyles explicitly to SizeType.AutoSize doesn't change anything.
No minimum size set:
Minimum size set:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace LayoutTest
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var sampleForm = new Form();
var samplePanel = new Panel() { Dock = DockStyle.Fill };
var sampleTextBox = new TextBox() { Dock = DockStyle.Fill };
// This line breaks the layout
//sampleTextBox.MinimumSize = new Size(400, 200);
var sampleButton = new Button() { Dock = DockStyle.Fill };
var panelLayout = new TableLayoutPanel() { Dock = DockStyle.Fill };
panelLayout.Controls.Add(sampleTextBox, 0, 0);
panelLayout.Controls.Add(sampleButton, 0, 1);
// Add a placeholder label to take up the remaining space
panelLayout.Controls.Add(new Label() { Text = String.Empty, Dock = DockStyle.Fill });
samplePanel.Controls.Add(panelLayout);
sampleForm.Controls.Add(samplePanel);
Application.Run(sampleForm);
}
}
}
The button is underneath the textbox. You need to set the multiline property to true.
E.g.
sampleTextBox.Multiline = true;
The source of this behavior is either the TableLayoutPanel or the TextBox. It would be strange for the TableLayoutPanel to explicitly test if a Control is a TextBox and if Multiline property is set to true before deciding to adhere to the the MinimumSize constraint. However, in my testing, it appears that the Multiline property must be set before adding it to the TableLayoutPanel and if Multiline is unset, then the control goes back underneath the text box and never goes back even if Multiline is set to true again.
E.g.
sampleButton.Click += delegate {
Size s1 = sampleTextBox.MinimumSize; // always returns the set MinSize
sampleTextBox.Multiline = !sampleTextBox.Multiline;
Size s2 = sampleTextBox.MinimumSize; // always returns the set MinSize
panelLayout.Invalidate(true);
panelLayout.PerformLayout();
};

How do I align controls in FlowLayoutPanel properly

I am currently trying to play around with c#. I want to create a simple GUI containing (as minimal example) three labels. The first two should be aligned from top to buttom and the third one to the right of these two button.
I have this in a panel, like
Label p_LabelX = new Label();
p_LabelX.Text = "I am to the right";
FlowLayoutPanel p_ButtonLayout = new FlowLayoutPanel();
p_ButtonLayout.Width = 200;
Label p_Label1 = new Label();
p_Label1.Text = "I am upper left";
Label p_Label2 = new Label();
p_Label2.Text = "I am lower left";
p_ButtonLayout.Controls.Add(p_Label1);
p_ButtonLayout.Controls.Add(p_Label2);
FlowLayoutPanel p_MainLayout = new FlowLayoutPanel();
p_MainLayout.FlowDirection = FlowDirection.LeftToRight;
p_MainLayout.WrapContents = false;
p_MainLayout.AutoScroll = true;
p_MainLayout.Controls.Add(p_ButtonLayout);
p_MainLayout.Controls.Add(p_LabelX);
this.Controls.Add(p_MainLayout);
With this code, it kind of works, but I have some scrollbars and the mainlayout is not fullscreen within the panel. However, if I skip the AutoScroll line, the scrollbars are gone and the layout seems to be fullscreen, but the right button is not visible.
Any suggestions?

Add vertical scroll bar to panel

I am trying to make a Panel scrollable, but only vertically (so AutoScroll won't work because the child controls go past the left edge and must).
So how is this done?
Try this instead for 'only' scrolling vertical.
(auto scroll needs to be false before it will accept changes)
mypanel.AutoScroll = false;
mypanel.HorizontalScroll.Enabled = false;
mypanel.HorizontalScroll.Visible = false;
mypanel.HorizontalScroll.Maximum = 0;
mypanel.AutoScroll = true;
Assuming you're using winforms, default panel components does not offer you a way to disable the horizontal scrolling components. A workaround of this is to disable the auto scrolling and add a scrollbar yourself:
ScrollBar vScrollBar1 = new VScrollBar();
vScrollBar1.Dock = DockStyle.Right;
vScrollBar1.Scroll += (sender, e) => { panel1.VerticalScroll.Value = vScrollBar1.Value; };
panel1.Controls.Add(vScrollBar1);
Detailed discussion here.
Panel has an AutoScroll property. Just set that property to True and the panel will automatically add a scroll bar when needed.
AutoScroll is really the solution!
You just have to set AutoScrollMargin to 0, 1000 or something like this, then use it to scroll down and add buttons and items there!
Below is the code that implements custom vertical scrollbar. The important detail here is to know when scrollbar is needed by calculating how much space is consumed by the controls that you add to the panel.
panelUserInput.SuspendLayout();
panelUserInput.Controls.Clear();
panelUserInput.AutoScroll = false;
panelUserInput.VerticalScroll.Visible = false;
// here you'd be adding controls
int x = 20, y = 20, height = 0;
for (int inx = 0; inx < numControls; inx++ )
{
// this example uses textbox control
TextBox txt = new TextBox();
txt.Location = new System.Drawing.Point(x, y);
// add whatever details you need for this control
// before adding it to the panel
panelUserInput.Controls.Add(txt);
height = y + txt.Height;
y += 25;
}
if (height > panelUserInput.Height)
{
VScrollBar bar = new VScrollBar();
bar.Dock = DockStyle.Right;
bar.Scroll += (sender, e) => { panelUserInput.VerticalScroll.Value = bar.Value; };
bar.Top = 0;
bar.Left = panelUserInput.Width - bar.Width;
bar.Height = panelUserInput.Height;
bar.Visible = true;
panelUserInput.Controls.Add(bar);
}
panelUserInput.ResumeLayout();
// then update the form
this.PerformLayout();
3 steps:
1- just set AutoScroll property to true
2- in Form load()add the following:
my Panel Vertical Scroll Maximum = 10000
3- after my Panel controls Add(item) add the following:
Invalidate();
Done!
Add to your panel's style code something like this:
<asp:Panel ID="myPanel" runat="Server" CssClass="myPanelCSS" style="overflow-y:auto; overflow-x:hidden"></asp:Panel>

Groupbox with a flowlayout panel inside and autosize = true shrinks like it is empty

I have a groupbox that holds a flowlayout panel and the flowlayout panel holds a bunch of controls. I set the flowlayout panel to dock with the parent. Since I don't know how many controls will be in the panel, I set the group box autosize to true and autosizemode to grow and shrink. When I do this the groupbox shrinks as if it is empty. I need the caption so I can't remove the groupbox. Anyone know why this is happening?
There's nothing that stops the FlowLayoutPanel from shrinking to nothing. You'll at least have to set its AutoSize property to True as well.
I was trying to do the same thing today. Below is the solution i came up with, which is to dock the FlowLayoutPanel inside of the GroupBox and then use the Resize and ControlAdded events of the FlowLayoutPanel to trigger resizing the parent GroupBox.
The resize handler finds the bottom of the last controls in the FlowLayoutPanel, and resizes the GroupBox with enough space to hold the bottom-most control(s) in the FlowLayoutPanel.
I tried using the AutoSize=true on the FlowLayoutPanel and the GroupPanel. But unfortunately this allows the FlowLayoutPanel to grow horizontally.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
int numGroupBoxes = 4;
for (int groupBoxIndex=0; groupBoxIndex<numGroupBoxes; groupBoxIndex++ )
{
GroupBox groupBox = new GroupBox();
groupBox.Text = "Group " + groupBoxIndex;
groupBox.Size = new Size(this.Width, 0);
groupBox.Dock = DockStyle.Top;
this.Controls.Add(groupBox);
FlowLayoutPanel groupBoxFlowLayout = new FlowLayoutPanel();
groupBoxFlowLayout.Dock = DockStyle.Fill;
groupBox.Controls.Add(groupBoxFlowLayout);
int extraSpace = 25; // the difference in height between the groupbox and the contents inside of it
MethodInvoker resizeGroupBox = (() =>
{
int numControls = groupBoxFlowLayout.Controls.Count;
if ( numControls > 0 )
{
Control lastControl = groupBoxFlowLayout.Controls[numControls - 1];
int bottom = lastControl.Bounds.Bottom;
groupBox.Size = new Size(groupBox.Width, bottom + extraSpace);
groupBoxFlowLayout.Size = new Size(groupBoxFlowLayout.Width, bottom);
}
});
groupBoxFlowLayout.Resize += ((s, e) => resizeGroupBox());
groupBoxFlowLayout.ControlAdded += ((s, e) => resizeGroupBox());
// Populate each flow panel with a different number of buttons
int numButtonsInGroupBox = 3 * (groupBoxIndex+1);
for (int buttonIndex = 0; buttonIndex < numButtonsInGroupBox; buttonIndex++)
{
Button button = new Button();
button.Margin = new Padding(0, 0, 0, 0);
string buttonText = buttonIndex.ToString();
button.Text = buttonText;
button.Size = new Size(0,0);
button.AutoSize = true;
groupBoxFlowLayout.Controls.Add(button);
}
}
}
}
Here are three screenshots of the control resized to various different widths:
You state "I don't know how many controls will be in the panel". Do you have any controls in the FlowLayoutPanel at design time? If you don't, this sounds like expected behavior. The Panel has nothing so its desired size is zero, so the GroupBox's desired size is zero.
If this is the case, then it should all hopefully size up when you actually add controls at runtime.
You set properties Anchor: Top, Bottom, Left, Right for groupBox.

Categories