bebo
bebo

Reputation: 839

WinForms Button: Autosize Maximumsize

I want to add Buttons to a FlowLayoutPanel. The Buttons might contain longer texts with spaces between the words. The Buttons are Autosize=true and AutoSizeMode = AutoSizeMode.GrowAndShrink. Further more I set the MaximumSize property to (maxwidth,0). maxwidth is the width of the panel. So the button does not grow too wide.

What I see is, that the widht of the Button is limited by the MaximumSize property, but when text wrapping occurs, the Button's height doesn't autosize to the height of the wrapped text. Is there a solution to that problem?


I also tried this manually sizing the button like this:

using (Graphics cg = this.CreateGraphics()) {
SizeF size = cg.MeasureString(button.Text, button.Font, 200);
  button.Width = (int)size.Width+20;
  button.Height = (int)size.Height+20;
  button.Text = someLongTextWithSpaces;
}

But please note that I added 20 to the calculated size. It's working, but is there a proper way to determin this additional size? Maybe 2x Padding + ?????


A few hours later...

I came to this version which seems to work quite fine.

using (Graphics cg = this.CreateGraphics()) {
  var fmt = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak;
  var prop = new Size(tableLayoutPanel1.Width - 20, 0);
  var size = TextRenderer.MeasureText(button.Text, button.Font, prop, fmt);

  int border = button.Height - button.Font.Height;
  button.Width = (int)size.Width + border;
  button.Height = (int)size.Height + border;
  button.Text = someLongTextWithSpaces;
}

It seems that the initial button height is borders + the height the font. So I calculated the border subtracting button.Height-button.font.Height.

According to Hans, I now use the TextRenderer.MeasureText. I tested it without enabling VisualStyles and it worked fine. Any comments on that?

Upvotes: 4

Views: 2605

Answers (3)

bebo
bebo

Reputation: 839

It seems that the initial button height is borders + the height the font. So I calculated the border subtracting button.Height-button.font.Height. (See the last block of my original post)

This also works with VisualStyles enabled/disabled.

Upvotes: 2

Hans Passant
Hans Passant

Reputation: 941277

There is a proper way, but it isn't exactly very subtle. Reverse-engineering it from the ButtonRenderer class source code, the Winforms class that draws the button text, you must use the TextRenderer class to measure the text. And you must use the VisualStyleRenderer.GetBackgroundContentRectangle() method to obtain the effective drawing bounds. Note that it is smaller than the button's Size because of the border and a margin that depends on the selected visual style.

Non-trivial problems are mapping a calculated content rectangle back to the outer button size and dealing with old machines that don't have visual styles enabled. Sample code that appeared to arrive at the correct size:

    private static void SetButtonSize(Graphics gr, Button button) {
        VisualStyleElement ButtonElement = VisualStyleElement.Button.PushButton.Normal;
        var visualStyleRenderer = new VisualStyleRenderer(ButtonElement.ClassName, ButtonElement.Part, 0);
        var bounds = visualStyleRenderer.GetBackgroundContentRectangle(gr, button.Bounds);
        var margin =  button.Height - bounds.Height;
        var fmt = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak;
        var prop = new Size(bounds.Width, 0);
        var size = TextRenderer.MeasureText(button.Text, button.Font, prop, fmt);
        button.ClientSize = new Size(button.ClientSize.Width, size.Height - margin);
    }

    protected override void OnLoad(EventArgs e) {
        using (var gr = this.CreateGraphics()) {
            SetButtonSize(gr, this.button1);
        }
        base.OnLoad(e);
    }

Not extensively tested for corner cases, can't say I recommend this.

Upvotes: 3

TaW
TaW

Reputation: 54433

You should control the line breaks by adding newline characters in the text. Automatic text wrapping won't work with spaces alone:

button1.Text = "123232131232\r\nfgfdgfdgdfgdfgdf\r\nASDSADSDASD";

Or :

button1.Text = "123232131232" + Environment.NewLine + 
           "fgfdgfdgdfgdfgdf" + Environment.NewLine + "ASDSADSDASD";

If you'd rather get the automatic wrapping you could try to use TextMeasure to determine the height needed for the text and then set the button's height accordingly but that may need some extra attention..

But I suggest to consider using Labels instead. For a Label the wrapping works out of the box.. Huge Buttons with varying sizes are non-standard UI elements.

Upvotes: 0

Related Questions