Strange Label AutoSize issue on TableLayoutPanel resize - c#

Background:
I have a TableLayoutPanel placed in a UserControl, which then is placed in SplitContainer. Rows are added programmatically. TableLayoutPanel is anchored Top|Left|Right, so after rows are added, its height is recalculated and it expands downward.
Inside the TableLayoutPanel, there are two columns. The size of the first column is Absolute, the size of the second column is set to AutoSize.
In every cell, there is a Label. All labels in the second column are defined as follows:
Label vName = new Label();
vName.AutoSize = true;
vName.Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom;
vName.Margin = new Padding(3);
vName.TextAlign = ContentAlignment.MiddleLeft;
vName.Name = "controlName";
vName.Text = "Some text here";
vName.DoubleClick += new EventHandler(vName_DoubleClick);
vName.Dock = DockStyle.None;
The problem:
Usually, everything works all right, labels resize and everything, except for one strange scenario:
The text of the label is something like "immoballizes the device (33.33%)", width of TableLauoutPanel's second column is set exactly, so all text is shown in one line.
Splitter distance changes by one pixel and the UserControl is resized: width decreases, so the label should resize, and the text in a label should wrap.
The label is not resized, and the second line of text isn't shown, it also probably doesn't wrap (there would be a change in the text location in the label if it did).
Splitter distance changes by one pixel again, and the UserControl is resized: the width decreases further.
The label resizes all right and all text is shown, wrapped.
The same thing happens when the TableLayoutPanel's width increases, but always only if there is a difference of one pixel (between wrapping/not wrapping text).
Also, changing Dock and/or Anchor and/or BorderStyle properties of labels doesn't work (I probably tried all possible combinations...)
This picture illustrates the issue a little:

Apparently it is a label issue: when autosizing, it wasn't measuring text correctly and sometimes there was a one pixel difference. I've found a strange workaround, though, if someone knows something better please enlighten me.
This way text in my labels wraps correctly every time and everything is autosized properly:
void tableLayoutPanel1_Resize(object sender, EventArgs e)
{
float fWidth = tableLayoutPanel1.GetColumnWidths()[1];
foreach (Control ctr in tableLayoutPanel1.Controls)
{
if (ctr is Label && ctr.Name.Contains("vName_"))
{
// -7 for margins
Size s = TextRenderer.MeasureText(ctr.Text, ctr.Font, new Size((int)fWidth - 7,1000),
TextFormatFlags.VerticalCenter
| TextFormatFlags.Left
| TextFormatFlags.NoPadding
| TextFormatFlags.WordBreak);
if(!ctr.MaximumSize.Equals(s))
ctr.MaximumSize = new Size(s.Width, s.Height);
}
}
}

Related

AutoEllipsis=true affects the vertical positioning of the text

I have a label with AutoEllipsis = true and TextAlign = ContentAlignment.MiddleLeft. When I enter a text that is not extending the label width, the text is vertically aligned to the middle of the label.
However, when the text extends the label width the text is not aligned to the middle, but top aligned instead.
Why is it behaving this way, and is there a way to keep the text vertically center aligned?
I see it. This looks like a limitation in the underlying winapi, DrawTextEx(). Which doesn't get a lot of help from the Label class, it doesn't turn on the DT_SINGLELINE option (aka TextFormatFlags.SingleLine) since it is capable of rendering multiple lines. DrawTextEx() documents that this is required to get vertically centered text (DT_VCENTER). So the real bug is that it shouldn't be centered at all :) Do note that you do get centered text when you grow the label vertically.
The simplest way to work around it is by setting the label's UseCompatibleTextRendering property to True.
What I have done is set the top and bottom of the margin property to 3 and it worked well.
So have your margin be (3,3,3,3)!
One way to solve this is by implementing a custom control that overrides the OnPaint method and does not call the base method.
public class LabelEx : Label {
protected override void OnPaint(PaintEventArgs e) {
var flags = TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.WordEllipsis;
TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, flags);
}
}
One catch is that added event handlers will be ignored. (as a result of omitting the call to the base method)
Taken from here.

GroupBox autosize

Take a GroupBox, put let say Label inside and then set AutoSizeMode = GrowAndShrink and AutoSize = true.
Two problems will arise:
There is a huge gap between Label and bottom of GroupBox (almost enough to fit another Label lol);
AutoSize doesn't respect the GroupBox.Text property.
Question is how to make GroupBox.AutoSize working properly? Properly means: minimum Width should be enough to fit GroupBox.Text, there should be no gaps below for unknown reason (it's not Margin, nor Padding and it looks pretty ugly).
I've tried to measure string length in OnPaint and setting MinimumSize right there. It works, but I have doubts about this, as if I would want to actually set MinimumSize later - it will be lost after repaint.
Update, here is screenshot:
You can get rid of the unwanted yellow space at the bottom by deriving a new class from GroupBox that adjusts the bottom edge a bit. In VB something like ...
Public Class BetterGroupBox
Inherits GroupBox
Public Overrides Function GetPreferredSize(ByVal proposedSize As Size) As Size
Dim ns = MyBase.GetPreferredSize(proposedSize)
Return New Size(ns.Width, ns.Height - 15)
End Function
End Class
It's simple that the location of your Label is fixed at some point other than (0,0), try this:
label1.Location = Point.Empty;
You may also want to try setting the Padding of your GroupBox to 0 for all (default is 3):
groupBox1.Padding = new Padding(0);
It seems as though the GroupBox control has a predefined padding of sorts when growing the control if AutoSize = true. That is, once a control (inside the GroupBox) gets within 20 pixels or so of the bottom of the GroupBox, the GroupBox starts growing. This causes a 20 pixel or so padding from the bottom of the bottom-most control to the bottom of the GroupBox (as highlighted in yellow by #Sinatr's attached image).
Based on my observations, the padding seems to be less when growing the Width of the GroupBox.
At any rate, you can do something like the following "get around" the issue:
public void MyFunction()
{
groupBox1.AutoSize = true;
// Do stuff (e.g., add controls to GroupBox)...
// Once all controls have been added to the GroupBox...
groupBox1.AutoSize = false;
// Add optional padding here if desired.
groupBox1.Height = myBottomMostControl.Bottom;
}

Row Autosize property not working of Table Layout?

I am working on a windows application, in which i am using a table layout panel, in this table layout i have created 5 rows and that is autosize, now dynamically i am adding 4 radio buttons and text for radio button is a bit long but the problem is it is behaving like absolute and not showing the full text.
I am adding radio button like this-
for (int i = 0; i < 4; i++)
{
rbtn1 = new RadioButton();
rbtn1.Name = "rbtn" + (i + 1);
rbtn1.Text = "A jogger running at 9 kmph alongside a railway track in 280 metres ahead of the engine of a 120 metres long train running at 45 kmph in the same direction. In how much time will the train pass the jogger?";//ansList[i].ToString();
rbtn1.Dock = DockStyle.Fill;
rbtn1.Font = new Font("Verdana", 10);
tableLayoutExamPanel.Controls.Add(rbtn1, 1, i + 8);
}
I am working on this from last 10 hours.
Need help, Thanks a lot.
I realise this is an old question, however:
Set the dock style of each RadioButton to DockStyle.None
Set AutoSize = True for each RadioButton.
Autosize won't work if you have a dock style set. Make sure you the above is true for each child control on the table.
Try setting the radio buttons autosize property to true.
And remember that a control in a TableLayoutPanel cell always shrinks to fit in the cell until its MinimumSize is reached.
P.S. You could also try setting the AutoSizeMode property to GrowOnly.
See MSDN for more info
EDIT: try this...
.RowStyles.Clear();
.RowStyles.Add(new RowStyle(SizeType.AutoSize));

Anchor/Dock to position DataGridView

I am trying to figure out how to position my DataGridView correctly inside of the parent container, but despite trying widths/heights/docks/anchors/etc. I absolutely cannot figure this out.
I would like to have the table anchored to the left/right/bottom but have some padding to keep it from being flush against the sides/bottom.
I want to keep some extra space at the top as I plan to put a second container there with additional options.
Not sure if this is related, but I would like the rows to be a percentage of the DataGridView's width. Can this be done?
How can I achieve this? I currently have the following set, but as can be seen from the screenshot, it only seems to anchor to the left and for some reason stays near the top.
dgv.Width = parent.Width;
dgv.Anchor = (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom);
You can use following properties of DataGridView(dgv)to work
Anchor: Top,Left // dgv.Anchor = AnchorStyles.Top | AnchorStyles.Left
AutoSizeColumn: Fill // we can fill for all columns or else it is enough to fill the last column dgv..Columns[0].AutoSizeModeDataGridViewAutoSizeColumnMode.Fill;
Dock: Fill // dgv.Dock = DockStyle.Fill
Just see the link How to resize datagridview control when form resizes

How to resize a button depending on its text

In the process of translating an application with C# + Winforms, I need to change a button's text depending on the language.
My problem is the following :
Let's say I want to translate a button from "Hi all!" to "Bonjour tout le monde" !
As you can guess, the button's size won't be the same if I enter english text or french one... My question is "simple", how can I manage to resize the button on the fly so the text fits its content in the button ?
So far I got something like that !
[Hi all!]
[Bonjour]
There's absolutely no need to use the underlying Graphics object as the other posters have said.
If you set the button's AutoSize property to true, the AutoSizeMode to GrowAndShrink, and the AutoEllipsis to false, it will resize automatically to fit the text.
That being said, you may need to make several layout adjustments to make this change fit into your UI. You can adjust the button's padding to add space around the text, and you may want to place your buttons in a TableLayoutPanel (or something) to stop them from overlapping when they resize.
Edit:
#mastro pointed out that: AutoEllipsis is only valid when AutoSize is false (As explained in the documentation), so it can be safely ignored as long as the other three properties are set correctly.
Your best bet is to set the AutoSize property as described ach's answer
However if AutoSize isn't working for you, resizing the button in code is easy enough. You can just need to set the button's width. The trick is making it big enough to fit your text.
using(Graphics cg = this.CreateGraphics())
{
SizeF size = cg.MeasureString("Please excuse my dear aunt sally",this.button1.Font);
// size.Width+= 3; //add some padding .net v1.1 and 1.0 only
this.button1.Padding = 3;
this.button1.Width = (int)size.Width;
this.button1.Text = "Please excuse my dear aunt sally";
}
Try this:
Button.AutoSize = true;
Button.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
Button.TextAlign = ContentAlignment.MiddleLeft;
Button.Padding = new Padding(0, 0, 0, 0);
To enable a Button in WinForms grow and/or shrink depending on the size of the Text, you need to set the button's AutoSize property to True and the AutoSizeMode property to GrowAndShrink.
// C#
btn.AutoSize = true;
btn.AutoSizeMode = AutoSizeMode.GrowAndShrink;
' VB.NET
btn.AutoSize = True
btn.AutoSizeMode = AutoSizeMode.GrowAndShrink
Please note that the AutoSize property will only allow the button's size to grow if the AutoSizeMode property is set to GrowOnly; by changing the AutoSizeMode property to GrowAndShrink, the button will now automatically extend or reduce in width and height based on its Text property.
Also note that in setting the two properties as shown above, you can make use of new lines (Environment.NewLine or vbCrLf) in the Text property and the button will scale down as needed.
As Andrew Hanlon explains, you can set AutoSize = true.
When doing so, you can also attain a perfect layout of the buttons automatically by placing them on a FlowLayoutPanel.
The horizontal distance between them will always stay the same when the FlowDirection of the FlowLayoutPanel is LeftToRight or RightToLeft. You can adjust this distance by setting the Margin property of the buttons appropriately. You can create groups of buttons by increasing the left margin of buttons beginning a new group.
If you set the Dock property of the buttons to DockStyle.Fill, they will even grow their width automatically in order to fit to the widest button if the FlowDirection of the FlowLayoutPanel is TopDown or BottomUp.
btn.AutoSizeMode = AutoSizeMode.GrowOnly;
btn.AutoSize = true;
btn.Dock = DockStyle.Fill;
In addition to setting the AutoSize to true and the AutoSizeModeto GrowAndShrink, as suggested in the other answers, you may also need to set the TextImageRelation property, if you have set the button image, so that the text doesn't overlap the image.

Categories

Resources