WPF PreferredSize property? - wpf

In Windows Forms, you have a PreferredSize property that will tell you how large a control would like to be.
Where's that property in WPF?
I have a Grid with some content (of unknown size) and would like to create an animation that increases the grid in height from 0 up to its preferred (auto) height. Of course the grid is either at 0 height or collapsed at the beginning, because it's not supposed to pop up in an instant but smoothly "fade in". So I cannot use the ActualHeight property for the animation target because it is always 0. The opposite direction animation should be easier because I can animate from ActualHeight (or just no explicit start value) to 0.

Given a FrameworkElement (element) and I wish to allow it to expand fully and then measure it's size I do the following:
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(new Point(0, 0), element.DesiredSize));
element.UpdateLayout();
Size sizeElementWantsToBe = element.DesiredSize;
Caveat: I found this question because I'm having problems with this method of triggering layout with Telerik RadGridViews with templated columns. But I doubt you will have that problem.
Hope this helps.

Related

WPF giving incorrect size values

I have a WPF application in which I am attempting to take a screen grab of a WindowsFormsHost control. To do this I am doing a Graphics.CopyFromScreen. On most boxes we have tested on this works perfect, however we have one machine that is not grabbing the right size values. The width and height that are given by WPF do not match the actual width and height of the control. When snooping, the incorrect values show for the ActualWidth and ActualHeight of the control as well. Even further, when I snoop the main window (which is maximized), I get an ActualWidth of 1550 and and ActualHeight of 840, but my screen resolution is 1920x1080. I would understand being a few pixels off for borders, margins, etc, but to have WPF tell me my maximized window is 370 pixels shorter in width than the actual screen just doesn't make sense. Can anyone explain this behaviour?
The following is the code being used to capture an image of the control:
public static Bitmap CreateBitmapFromVisual(this FrameworkElement target)
{
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
if (bounds.Width == 0 && bounds.Height == 0)
return null;
System.Windows.Point p0 = target.PointToScreen(bounds.TopLeft);
System.Drawing.Point p1 = new System.Drawing.Point((int) p0.X, (int) p0.Y);
Bitmap image = new Bitmap((int)bounds.Width, (int)bounds.Height);
Graphics imgGraphics = Graphics.FromImage(image);
imgGraphics.CopyFromScreen(p1.X, p1.Y, 0, 0, new System.Drawing.Size((int) bounds.Width, (int) bounds.Height));
return image;
}
Here is an image to better describe what I'm talking about:
As you can see, snoop is saying that the actualwidth and actualheight of the WindowsFormsHost is 486x336. Any debug information I log says the same thing. However, when I Print Screen and crop to the control in paint, the actual size is 608x423, a sizeable difference.
As a further update, it seems like the width given by wpf is roughly 80% of the actual width. This is true for both the control and the window.
Have you looked at your DPI settings for your display?
To do this go to Control Panel - Display and select Set custom text size (DPI). In the dialog that opens you will see a scale to percentage. If it is not set at 100% then try this. This could be your issue.

Prevent redraw of window when resizing grid row/column

WPF grid container, with multiple rows/columns with usercontrols loaded in the sections.
Some rows/columns are expanded/collapsed by setting the Column/Row width (from 0 to 125* or a fixed value), based upon a button click.
Simple example code:
If colgrdFolder1.Width.Value Then
Me.Width = Me.Width - colgrdFolder1.ActualHeight
colgrdFolder1.Width = New GridLength(0)
Else
Me.Width = Me.Width + 150
colgrdFolder1.Width = New GridLength(150)
End If
This works, but when the parent resizes, it flashes as the column/row is set. When the parent Width is first increased you can see the grid resize and then when the new colWidth is set, it resizes (and flashes) again.
Is there not a property/method to freeze the window/prevent redraws until the resize is complete?
I think there are BeginInit() and EndInit() methods, that should do what you want (prevent redraw), but in my experience they haven't really worked (maybe I have used them incorrectly).
I don't know of any other way of preventing redraw, perhaps someone who is more of an expert in WPF can shed some more light...

How to tell Size of a Grid Cell?

I have a custom control that I've placed inside a cell of a grid. I have some internal calculations I need to run based on the height and width of the custom control. However, I want it to resize based on the size of the cell.
So, my main question is... how to I programatically determine the height and width of a given cell?
It may be easier to figure out the Height and Width of your Custom Control rather than the cell of a DataGrid.
Your control should have access (through FrameWork Element) to the properties ActualHeight and ActualWidth. These properties will update when the size changes.
Also, the SizedChanged event will be fired on your control every time the Height and Width change.
I highly recommend placing this height and width logic inside of your control. You do not want to be limited to only placing your custom control inside of DataGrids.
private void UserControl_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
HeightBox.Text = this.ActualHeight.ToString();
}
You can get size of grid cell through RowDefinitions and ColumnDefinitions:
MyGrid.RowDefinitions[1].ActualHeight
MyGrid.ColumnDefinitions[1].ActualWidth
but it should be pretty rare situation then you have to resort to this kind of approach

Ability to modify control dissapears when no properties are set

I'm adding controls programmatically to a canvas which is all just wonderful...
var newControlPoint = new ControlPoint() { Width = 10, Height = 10 };
newControlPoint.SetResourceReference(Control.TemplateProperty, "ControlPoint");
SetCanvasPosition(newControlPoint, position.X - (newControlPoint.Width / 2), position.Y - (newControlPoint.Height / 2));
canvas.Children.Add(newControlPoint);
newControlPoint.UpdateLayout();
... but I'm coming unstuck when I attempt to remove the hardwired Width and Height settings from the first line...
var newControlPoint = new ControlPoint();
...the canvas positioning doesn't seem to take effect and the newly created control winds up at {0,0}.
Any ideas?
Two problems:
The Width and Height properties won't be set because you haven't explicitly set them. It's ActualWidth and ActualHeight you want, which are set by WPF.
The controls haven't been laid out yet, so ActualWidth and ActualHeight will be zero.
To work around the problem you could:
Use databinding instead of doing a one-off calculation.
Attach the positioning logic to the control's Loaded event so it has been positioned.
Use Dispatcher.BeginInvoke to run the layout logic in a separate message that runs at a lower priority to layout, thus ensuring the ActualWidth and ActualHeight have been calculated and assigned.

Get the size (after it has been "stretched") of an item in a ViewBox

Consider the following:
Let's say the Window is 1024x768 and the ViewBox fills the entire window,
this means the TextBox is really large on the screen.
I want to get the size of the TextBox as it is currently on the screen.
If I get DesiredSize or ActualSize or even RenderedSize I always get 100.
Any suggestions?
Update: I could probably get the ActualWidth of the ViewBox and divide it by the ActualWidth of it's child which would give me the current scale factor and expose that as a property somehow but I'm not sure that's the best way to do it.
This is how you get the ScaleTransform the ViewBox exerts on its children:
var child = VisualTreeHelper.GetChild(viewBox, 0) as ContainerVisual;
var scale = child.Transform as ScaleTransform;
Here viewBox is the ViewBox that textbox sits in.
Then you can just multiply scale.ScaleX * textBox.ActualWidth and you get the size in Screen coordinates
But it gets even easier! To get that textbox's size directly in Screen Coordinates you do:
textbox.PointToScreen(new Point(textbox.ActualWidth,textbox.ActualHeight)) - textbox.PointToScreen(new Point(0,0))

Resources