WPF control default size - wpf

When defining custom resource themes for a wpf application, I can set width / height etc... How can I find the default value for these properties (i.e. the values used in the controls provided in the framework) ?

WPF controls don't generally contain any kind of default size. One of the main functional points of WPF is that everything resizes dynamically unless you specify a size.
If you do want to measure the amount of space a control would like to have if given infinite space, you can create it, call Measure on it with a Size of +infinity, +infinity, and then check DesiredSize. For most controls, this will give you the minimum size the control wants. If you give a fixed size in Measure, some controls will return that they want all that space as they size to their container (e.g., Grid, TextBox, Button...). Some controls size only to their content, so they'll tell you they want no space (e.g., StackPanel).
So you have to ask yourself why you would even think of the concept of a default size in WPF when almost all controls are made so that they either size to their content or size to their container depending on how they are set up. The main thing you'd want to measure is text, and you can do that with the trick above for items like TextBlock or images.
Edit: to query any DependencyProperty for a default value, use the property's metadata:
double defaultWidth = double.NaN;
PropertyMetadata widthMeta = TextBlock.WidthProperty.DefaultMetadata;
if (widthMeta != null && widthMeta.DefaultValue is double)
defaultWidth = widthDefault.DefaultValue;
To Reset a DependencyProperty to its default value, call DependencyObject's ClearValue:
MyTextBlock.ClearValue(TextBlock.WidthProperty);
To check for a locally set value:
if (MyTextBlock.ReadLocalValue(TtextBlock.WidthProperty) != DependencyProperty.UnsetValue)

The default width and height for FrameworkElements is Double.NaN. If you don't specify a different size then WPF controls will automatically size themselves to try and fit their content, their containers or both.

Related

How do I calculate the required size for a CheckedListBox?

I have written some code to automatically scale a CheckedListBox to its contents using mListBox.ItemHeight and mListBox.CreateGraphics().MeasureString(...).
The output from the string measurements is a bit dubious but what really puzzles me is how much to add for borders and such.
I tried both SystemInformation.Border3DSize (= 2) as well as the difference between ClientSize and Size (= 4).
But taking mListBox.ItemHeight * mListBox.Items.Count + 4 for the height makes it one pixel too small and a scrollbar appears.
For the width it does not work at all because it does not take the size of the checkboxes into account for which I can't seem to find a source.
How should I determine the size of the control?
In cases like this, it is typically easier to set the ClientSize rather than the whole Size. One thing to note about ItemHeight is that it does not include the margins of the item. Using a CheckedListBox with default settings, I had an ItemHeight of 13. But the ItemRectangle property had a height of 15.
So here is what I did. I added 9 items to the CheckedListBox (the first Item was longer than the rest), keeping the default size of the control as set by the designer. Then in the constructor of the form, I set the ClientSize like so:
this.checkedListBox1.ClientSize = new Size(TextRenderer.MeasureText(checkedListBox1.Items[0].ToString(), checkedListBox1.Font).Width + 20, checkedListBox1.GetItemRectangle(0).Height * checkedListBox1.Items.Count);
Notice I used TextRenderer.MeasureText to measure the text. It will typically give you better values than Graphics.MeasureString. By default, TextRenderer included a bit of padding in it's measurement. I also included a 20 pixel padding to account for the checkbox. Anyway, with TextRenderer.MeasureText, and the 20 pixel padding for width, and ItemRectangle * Items.Count for the height, that gave me a CheckedListBox that was sized to its contents without ScrollBars.
EDIT: If item widths vary, it may complicate setting the width, as you'll want to set the width based on the longest item. In this case you'll need to measure each item and keep track of which one was the longest.
EDIT 2: Ok so I dug around in the CheckedListBox source code. They use a default size of 13 plus a 3 pixel padding for the width and height of the checkbox. But, if VisualStyles is enabled, they call CheckBoxRenderer.GetGlyphSize to get the size to use because it takes into account the DPI settings. Most machines are set at 96 DPI so that method will still return a size of (13,13). So when you're measuring the text of the item, you can also pass the Graphics object and a CheckBoxState enum to the CheckBoxRenderer.GetGlyphSize to get a size. I used System.Windows.Forms.VisualStyles.CheckBoxState.CheckedNormal for the state, but I'm not sure that the state matters. I tried CheckBoxState.MixedDisabled as well and it returned the same size, (13,13).
So to summarize, you can use CheckBoxRenderer to get the size of the checkbox, but you will still probably need to use some padding. This reduces the need for hardcoding a magic number to account for the checkbox. Since the checkbox is drawn and isn't an actual control, its size can't be determined like sizes of controls can.
Here is a link to the source of CheckedListBox. It wouldn't hurt to look at it. Specifically, look at the protected override void OnDrawItem method.
CheckedListBox Source

Sizing WPF windows automatically

When designing WPF dialog windows in the XAML designer (that are not manually resizeable by the user), the windows automatically resize to fit their content, and everything is fine. But when I run my app, the windows become huge and there's a lot of empty space.
I know this is a "feature" of WPF that can be "fixed" by setting the SizeToContent tag, but another issue arises when I do this: If the window contains a textbox, for instance, and the user enters data that overflows the visible area, the window will stretch to accommodate it. This happens with listboxes, treeviews, you name it.
All I want is for Visual Studio to figure out the ideal window size that it shows me at design time, then set the window to be that size at runtime, and don't change the size after that. It seems like this should be an easy thing to do.
Edit: Figured out part of the problem: I have controls set up in a grid, and the column's width is set to "Auto" which is why everything is resizing.
Use View Box
The ViewBox is a very useful control in WPF. If does nothing more than scale to fit the content to the available size. It does not resize the content, but it transforms it. This means that also all text sizes and line widths were scaled. Its about the same behavior as if you set the Stretch property on an Image or Path to Uniform.
Although it can be used to fit any type of control, it's often used for 2D graphics, or to fit a scalable part of a user interface into an screen area.
<Viewbox>
<Enter your code/>
</Viewbox>
Try setting the window's height and width to Auto. Also, remove the SizeToContent attribute. This should fix it.
I do not think that this is this is something which is commonly requested so it's probably not easy to do, one method i can think of would be starting with automatic SizeToContent and handling the Loaded event and setting:
Height = ActualHeight;
Width = ActualWidth;
SizeToContent = System.Windows.SizeToContent.Manual;

How to resize multiple WPF controls when the text size changes?

What's the correct pattern to resize controls when a font size changes?
For example, I used the WPF designer to make a form, and placed UI elements from the toolbox. Late in the game I got the requirement that the font size of every UI element needs to be configurable, so now I'm thinking there has to be a better way to resize controls when the font size changes. Right now I'm doing alot of code behind calculations on Margin properties.
For such cases I usually place my control inside Grids and StackPanels, this way font size won't affect the layout, everything will be stretchable.
Never place controls on the Window using absolute coordinates.
Make sure your Height and Width on the controls are set to Auto.
When you use the designer/toolbox to add controls it usually provides a static height/width. If you type the tag in the XAML editor you get the control default which is usually Auto.
You'll notice the black diamond in the property window next to the attributes that are changed from their default value. You can right click and choose reset value to clear the attribute from your XAML and see what the default value is.

Setting control height explicitly

I have a XamDataGrid in one of my user controls, inside of a stackpanel. I want the grid to maintain the same height regardless of how many rows are present in the grid. To do that, I set the grid's Height property to an explicit value.
Is that how things are done in WPF? Every time I do explicit sizing I feel like I am doing WinForms and not using WPF properly. Is setting the Height directly the only/correct solution?
There's nothing wrong with setting an explicit Height in situations where you want an element to always stay the same height. Where it's less appropriate is in situations where sizing is better handled by the parent layout Panel or the element's child content which can use the available space dynamically.
WPF uses a relative measurement system which at first glance is not intuitive. I have never found an example when I was forced to use explicit sizes ( once when I paint something on Canvas). I use styles in 90% cases where I define Padding, Margin, Aligment etc. Sometimes I use MinHeight and MinWidth for simple things.
About that Grid you can put it in the ScrollViewer or ViewBox to have dynamic sizing, yet If it won't be trouble set the explicit Height.

How to determine width of a windows forms controls whose width was increased because it is Anchored?

I currently have a Textbox on a Windows Forms, and I need to dynamically add a PictureBox box control at the right of the Textbox.
I create the PictureBox programmatically and I when setting the location of the PictureBox, i'm setting like this:
pBox.Location = new Point(tbControl.Location.X + ctrl.Width, ctrl.Location.Y);
So i'm setting the picture box to be located at the X location of the textbox PLUS the width of the textbox. However, since the textbox has an anchor property set to right, its width increases to fill the space between itself and the form border.
Problem is, that even though the textbox's width is visually bigger than the actual value of Textbox.Width. the Width property is not taking into account the extra width of being anchored.
I already tried properties like Textbox.Bounds.Width, Textbox.ClientSize.Width, Textbox.DisplayRectangle.Width, etc. with no luck. All of those properties return the original Width of the control without taking into account the resized width due to the Anchor property.
Does anyone know how I can determine the real size of the textbox? Thank you
The Width property always tracks the current width of a control, whether it is anchored or not. However, the TextBox is going to grow when you make the container larger and that will make it overlap the PictureBox. You have to anchor the PB to the right as well.
These should be returning the adjusted size. Either you are referring to the wrong textbox, or you are doing the query before the size has actually changed.

Resources