Get padding caused by stretch value Uniform - wpf

A WPF UI element has defined a width and height, the background is set to an image brush and pointed the image source to some random images on run-time. The stretch property is not set, hence I assume it is the default value "Fill" that comes into play. Since control size and image size are different, in run-time, the background image brush is filled with some aspect ratio, i.e with a padding (visually) inside the control. Is there a way to get this padded values?
Sample code :
<Grid Width="2000" Height="2000">
<ListBox>
<ListBox.Background>
<ImageBrush ImageSource="{Binding Source={x:Static local:MyModel.Instance},Path=ImageSource,Converter={StaticResource pathImageConverter}}" />
</ListBox.Background>
</ListBox>
</Grid>
Instead of image brush if I use a color, it fills the entire area.But if I use an image say 5000 * 4000 dimension, it stretches somewhat to fill inside the space (without skewing and cropping). That is not the real padding, visually we feel there is a padding from the list box boundaries and image boundaries. Let me try to get a snapshot of this.

There are multiple tools to get those values, and where they are assigned when running the application:
XAMLSpy
Snoop
And probably more, but these are the ones I use when encountering a problem like yours.

There is no API to get those values, I'm afraid you need to do the calculations yourself. Let me elaborate...
As indicated in the comments, the ImageBrush is not causing your padding. The brush will simply paint the area it gets. Of course, depending on the mode of the ImageBrush, it won't paint the entire area, but only a portion. Changing the brush to a SolidColorBrush will show you the entire area the brush will get. That should be identical to the area the image brush will fill, if it's put in... well, Fill mode.
However, I highly doubt it's the brush, but rather the ControlTemplate of the ListBox. If you're running in the Aero theme, by default, the template starts with a Border, which has its Background property template binded back to the ListBox, and it does the same with the BorderThickness (and to make things worse, it also has a fixed padding of 1, however, the background is drawn on top of that).
So to calculate the "padding" of the brush, you need to do the same as Border does: BorderThickness + Padding.
However, if you're running in a different theme, or if your controls have been restyled, then your control templates might be different, and the calculation might be different...

Related

How do I auto resize a label's text in WPF?

I put my label inside a two-column grid and set its size to auto and when I run my application, the label's size grows if I maximize it (I'm sure it grows because I've put a background color and the background color also resizes to accommodate the entire two-column grid it's been placed into. My problem is that the label's text itself doesn't grow and stays the same 9pt. Am I missing a property option to set my Label's text to also auto-resize?
I've read tutorials doing this with a viewbox and a textblock and although it works, I've had trouble setting it up in two columns as it resizes weirdly when I run the application despite setting it up right.
Okay I finally did it. What I did was use the Viewbox + Textblock and I've put a border around the viewbox and set its background accordingly and had the textblock's background to none and now it's working as I wanted it to.
The problem I had back then was I didn't know how to put a background color on the viewbox so I tried a remedy wherein I changed the textblock's background but the problem was the textblock has its own size and even if I stretch it, it would only encompass the width of the text and not the whole viewbox.

How can I prevent WPF from clipping my image?

I am writing a WPF app that displays an image that is initially centered. The user can zoom in/out and move the image, which are implemented using ScaleTransform and TranslateTransform. That works great.
The problem is when the image is significantly bigger than the window, and the user moves the image or zooms out enough so that the entire image should be visible. The portion of the image that was originally hidden isn't rendered, and instead only the originally viewable part of the image is drawn.
Based on some other questions, if I put my image inside of a Canvas that will cause the entire image to be rendered, and when moved it will be rendered correctly. The problem is that I don't want my image to be in a Canvas, since that prevents any other layout from occurring - the HorizontalAlignment and VerticalAlignment properties are ignored (so the image is no longer centered), and I need to implement an option that will draw the image as large as possible to fill the entire area of the window which no longer works (setting the Stretch property to UniformToFill doesn't do anything).
Currently the two transforms are set to the RenderTransform property. If I use LayoutTransform instead, the entire image is drawn, but this also prevents the user from moving any portion of the image off the edge of the window (which is behavior that I would like to keep).
How can I tell WPF to always render the entire image without using a Canvas or a LayoutTransform?
I suggest not using a TranslateTransform but instead rely on the ScrollViewer.
<ScrollViewer>
<Grid>
<Image Source="blabla">
<Image.LayoutTransform>
<ScaleTransform />
</Image.LayoutTransform>
</Image>
</Grid>
</ScrollViewer>
The ScrollViewer gives the Image infinite space to expand, the entire image will be rendered. The Grid forces a centered layout while still allowing the image to expand. If you don't like the scrollbars to control the translate then you can hide them and roll your own solution.
LayoutTransform is definetely the way to go, so that the image's actual size in pixels (based on the zoom) is properly reflected onto your window.

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 calculate a bounding box for an Expander?

I have an Expander control and i need to calculate its bounds without invisible elements and margins. It commonly can be done by VisualTreeHelper.GetDescendantsBounds. But it seems that the rect is calculated by VisualTreeHelper doesn't depend on the expander state. For example:
http://i.piccy.info/i5/58/39/273958/collapsed.jpg
(i can't post images. sorry)
The same result as for expanded state (light green rectangle on the image). Does anybody know how to solve this problem?
The Expander control will set its content's visibility to Collapsed, which means it won't be considered during layout and won't be included in GetDescendantBounds. However, the Expander can be forced to have a larger size by the layout engine, and the Expander's own size is included in GetDescendantBounds.
Try setting VerticalAlignment="Top" on the Expander. The default is Stretch, which will allow it to increase in size if the parent has more space available. Also make sure you aren't explicitly setting the Height property.
This is the sample application. The style is applied here to the TreeView control and its items. But the problem doesn't depend on the style.

WPF Resizable Canvas

I need to implement a Canvas which scales its contents according to its size. I know there is Viewbox, which scales everything inside of it. However I cannot use that, because some elements have a fixed size and cannot be scaled.
Also how can I bind the size of the Canvas to the parent element (for example a resizable window). There is sizeToContent for windows, I want the size fitting exactly the other way round. Also the canvas uses some drawing based on the size of the hosting element, how is redraw triggered and how can I ensure that it only draws if it gets a valid (or min) size?
If you don't specify any width or height to the canvas it automatically uses all the available space. This is because the default VerticalAlignment and HorizontalAlignment are set to Stretch.
What do you mean by canvas that scales it's contents according to it's size without scaling all the contents as some have fixed size?
Update after comments
If your drawing algorithm already scales the content to the canvas' height and width then all you need to do is to resize the canvas to fit the area I believe? In that case just remove the hardcoded height/width values and the canvas will resize to fit the container.
You might need to use ActualHeight/ActualWidth instead of Height/Width in the drawing algorithm after this though. ActualHeight/ActualWidth return the values that the layout container will give your canvas so these represents the values the canvas is drawn with.
I think you can find the answers to all your questions in my London Underground demo.
I'm doing this from memory, but if I recall correctly a Window uses either a Panel or a Canvas as part of it's ControlTemplate (in which lies the ContentPresenter), which means that a Canvas placed directly in a Window will have issues resizing automatically like it might elsewhere. There are a few basic ways to address this.
1 Write a new ControlTemplate for your Window to use. :(2 Place your content directly in the Window rather than in a Canvas inside the Window. :/
3 Do a by-name binding. :)
<MyWindow x:Name="topWindow">
<Canvas x:Name="topCanvas" Width="{Binding ElementName=topWindow, Path=ActualWidth}" Height="{Binding ElementName=topWindow, Path=ActualHeight}">
...Content...
</Canvas>
</MyWindow>
(As it happens, I often bind grids inside Canvases in this fashion, so I can easily animate items moving from one grid position to another.)

Resources