Determine Control's 'AutoSize'-size at runtime - c#

I want to layout controls during runtime (dynamically created). For the purpose of this question, let's restrict to a Button control. I want to set the control's properties (such as Text) and then determine the minimum size for the control for it to display properly; the size that setting AutoSize = true would give. In C# example code, with GetAutoSizeSize being this minimum size:
Button button = new Button();
this.Controls.Add(button);
button.Text = "Example";
button.Size = GetAutoSizeSize(button);
button.Location = /* Some calculation based on button.Size */
Possible solution: AutoSize
One can set button.AutoSize = true and button.AutoSizeMode = AutoSizeNode.GrowAndShrink. After that, the button.Size can be fetched, after which AutoSize can be turned off and the control size can be changed.
Potential issues:
It looks odd and I can't help but feel that this could easily break, but maybe I am wrong?
Possible solution: GetPreferredSize
button.GetPreferredSize can be used to get a size that the control wants to be.
Problems with this:
Its usage is internal and/or meant for flow layout.
GetPreferredSize takes a suggested size as a parameter, so one needs to guess at what would be appropriate.
The size returned is wrong, in that it returns the 'comfy' size of a control, which can be much larger than the minimum size that AutoSize gives.
EDIT: From the comments and some trial-and-error, I was able to conclude that the problems I originally listed with the AutoSize-method were due to needing both the control to be added to the control collection first and AutoSizeMode set to GrowAndShrink.
I would like to know if there is a function (and/or more 'robust' way) of determining the AutoSize-size: a function like GetPreferredSize that returns the size without actually having to toggle AutoSize.

This works when you are drawing on a control.
String sMyString = "this is my string";
Font fntFont = new Font("Arial", 8);
SizeF sfMySize = new SizeF(5,5);
sfMySize = System.Graphics.MeasureString(sMyString, fntFont, sfMySize);
This will give you the dimensions of the bounding box around the control text. You would have to work out the appropriate buffer around the text to set the button size.

Related

WPF - how can I programmatically allow a control to find its desired size when it is never drawn on the screen (for a screenshot)?

I am trying to programmatically take a screenshot of a control that I will never actually display on the screen (it is a duplicate of a control is shown in a different area of the application - this area is just writing a report).
I can set the control size to a fixed size using the following code:
Size renderSize = new Size(1000, 1000);
chartControl.Measure(renderSize);
chartControl.Arrange(new Rect(renderSize));
chartControl.UpdateLayout();
This correctly sets the size of the control to 1000x1000, but unfortunately the height of the control can vary - so I either risk losing a part of the picture, or include a region of blank canvas just to make sure.
I've tried various different approaches, but what I really want is something like:
chartControl.Resize("Auto"); // Pseudo code
chartControl.UpdateLayout();
Does anybody know a practical way to do this?
EDIT:
Just to clarify: at present the UserControl "chartControl" is currently never added to any container. I'm happy for that to remain the case, or to create a dummy container (like a Window) if this can "trick" WPF into sizing the UserControl...
EDIT 2:
Thanks to #Lennart for pointing me in the right direction for this:
It seems that DesiredSize is only available (i.e. not (0,0)) after the Measure call has been made, but after the Measure call, the Desired size is the minimum of the control's actual desired size and the size that it has been given in the Measure call. My original effort set the Measure too small, so I never found out the true desired size of the chartControl.
From this, the following ought to work:
Size renderSize = new Size(2000, 2000);
chartControl.Measure(renderSize);
chartControl.Measure(chartControl.DesiredSize);
chartControl.Arrange(new Rect(renderSize));
chartControl.UpdateLayout();
However, the second call to Measure doesn't have any affect - the ActualWidth and height after the first call becomes 2000, but doesn't get updated on the second call to Measure.
The work-around would be to destroy the original chartControl once its DesiredSize has been determined, and then create a new one using the previously determined DesiredSize. It seems a bit clunky, though...
Thanks to #Lennart for pointing me in the right direction for this, and everyone else who gave pointers:
It seems that DesiredSize is only available (i.e. not (0,0)) after the Measure call has been made, but after the Measure call, the Desired size is the minimum of the control's actual desired size and the size that it has been given in the Measure call. My original effort set the Measure too small, so I never found out the true desired size of the chartControl.
This appears to work:
Size overSize = new Size(2000, 2000); // Something oversized.
chartControl.Measure(overSize);
chartControl.Arrange(new Rect(chartControl.DesiredSize));
chartControl.UpdateLayout();
// Take a screenshot of the chart control
BitmapSource bitmapSource = ScreenshotHelper.CreateScreenshot(chartControl, new Int32Rect(0, 0, (int)chartControl.ActualWidth, (int)chartControl.ActualHeight));

Get default TitleBar height programmatically before a titlebar is created?

I am creating a custom title bar for my uwp app. I want to match the height of the system bar.
I might be able to get that height be calling
CoreApplication.GetCurrentView().TitleBar.Height
But that depends on a lot of things. The title bar may not have been sized yet.
I've also seen a suggestion (from winforms) to look at the difference of the y coordinates of the window top and the content view top. But again that seems fishy. For one thing, once I've set ExtendViewIntoTitleBar to true, I don't think the method would work.
Is there reliable way to programmatically get the default height?
I know that this answer might not be useful to the person who initially asked, at this point of time, but I would still like to suggest the answer:
You can register a handler for when the size of title bar changes. (The docs mention size change, but it may only be the caption button offset and not height)
This piece of code works well for me, at least at the moment
//Put the below line in the Page initialization/OnNavigated function
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
coreTitleBar.LayoutMetricsChanged += CoreTitleBar_LayoutMetricsChanged;
private void CoreTitleBar_LayoutMetricsChanged(CoreApplicationViewTitleBar sender, object args)
{
MyAppTitleBar.Height = sender.Height;
}
The above code calls your function (CoreTitleBar_LayoutMetricsChanged) automatically whenever the dimensions of the titleBar change (like change in DPI). Here, MyAppTitleBar is a Grid I made for my custom title bar.
Futher info can be found here

How do you calculate pixel size of string?

I have a string. I know the font family and the font size it is going to be displayed in. I need to know how many pixels the text will take up in the ui. So that I can determine whether to show another element. How would I do that?
I found a couple of things, but none of them were available in my Windows universal project. For example:
Graphics.MeasureString
TextRenderer.MeasureText
Edit:
This is not a web project.
I want to calculate the size it will take in the ui before it is in the ui.
I think you need to create a textblock in code and assign the desired text to it. Then you can get the actual height and width from it. See the below code
TextBlock txt=new TextBlock();
//set additional properties of textblock here . Such as font size,font family, width etc.
txt.Text = "your text here";
var height = txt.ActualHeight;
var width = txt.ActualWidth;
You can do further operations based on this height and width
I am not saying this is the optimized solution .But this will work for you
Try checking the values of the Width and Height properties of the control you use to display your text (eg. your TextBox), after setting your string as text/content, to decide whether to show another element.

Resize Controls with Form Resize

I have read several stack overflow questions without finding a good working solution to my problem. How can I resize my controls whenever the form is resized? I would like them to get larger or smaller when the form becomes larger or smaller.
In visual basic this was quite easy to do with the form.Zoom property (which did't really require resizing controls of course, but solved what I needed). Unfortunately this is not available in C# winforms.
Here is some other things I have tried without luck:
private void formMain_Resize(object sender, EventArgs e)
{/*
double scale;
this.scaleWidth = (float)this.Width / (float)this.origWidth;
this.scaleHeight = (float)this.Height / (float)this.origHeight;
if (this.scaleHeight > this.scaleWidth)
{
scale = this.scaleHeight;
}
else
{
scale = this.scaleWidth;
}
foreach (Control control in this.Controls)
{
control.Height = (int)(control.Height * this.scaleHeight);
control.Width = (int)(control.Width * this.scaleWidth);
this.Refresh();
// control.Font = new Font("Verdana", control.Font.SizeInPoints * heightRatio * widthRatio);
}
///////This scaling didnt work for me either
//this.Scale(new SizeF(this.scaleWidth, this.scaleHeight));
//this.Refresh();
*/
}
If I overlooked an actualy working sample of code on another stack overflow question I would love to see it, but the ones I found were similar to those above which are not working.
Perhaps I was misusing it and someone could post sample code to show for those of us who keep asking this question how to go about solving the problem.
Also, I have tried using some of the anchor/docking tools thinking they would automatically allow it but it didn't.
The best option is to use a TableLayoutPanel. Put TableLayoutPanel on the form, set the Dock property to Fill, create required rows and columns and put the controls inside the cells. Of course you need to set Dock/Anchor on the controls inside the cells, so they respond to changes to the cell size. In some situations you may need to put a Panel into a cell and drop the controls inside it, because every cell can only contain a single control. You may also need to set RowSpan/ColumnSpan on the controls.
By using a TableLayoutPanel, you have complete control over how your cotrols should be arranged. You can set absolute or percentage size for rows and columns.
Use Anchor of the control. There's an option on anchoring the top, bottom, left and right. And you're good to go.
I found an alternative solution that is working well for me, appreciate any negative or positive comments on the solution.
Using several Split Containers and Split Containers inside of Split Containers in different regions I am able to section off the primary pieces of the layout, and within there utilizing Docking and Anchoring I am able to accomplish exactly what I wanted to do - it works beautifully.
I would point out I am aware that some folks online mention split containers use lots of resources.
If your controls are in a group box, be sure to set the group boxes properties to resize. Controls inside the box are controlled by the box. The box size (unless it is inside another box) is controlled by the form.
What you are trying to do in your code is to change the sizes of the controls which isn't so good approach. Generally, the size of the Buttons and TextBoxes shouldn't be changed when you re-size your form, but they often need to move (change location). Some controls do need to change size according to the re-sized form and but in most cases only one dimension. The central controls that are used for working area (if you are developing the tool for drawing for instance) should change sizes of both dimensions. All this you can accomplish by properly setting Dock and/or Anchor properties of the controls.
textBox1.Dock = DockStyle.Bottom;
textBox1.Anchor = AnchorStyles.Bottom & AnchorStyles.Left;
All these are also easily set in the Properties panel when using designer.
But if that isn't enough for you, in rare cases, you will most definitely want to only change the location of the control:
textBox1.Location = new Point(newX, newY);

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