// Get the size of the canvas
Size size = new Size(surface.Width, surface.Height);
// Measure and arrange elements
surface.Measure(size);
surface.Arrange(new Rect(size));
For some reason this is returning an error reading:
UIElement.Measure(availableSize) cannot be called with NaN size.
Now what I'm doing is seeing if reading the StackPanel properties on the first page, and then when I load up on another page it will let me Edit it, but I get this error.
Try using surface.ActualHeight and surface.ActualWidth instead of surface.Height and surface.Width. The values are NaN currently.
The size contains NaN value. Thus it can't measure the size. Make sure that the passes surface.Wigth and surface. Height values are not NaN.
Try using ActualHeight and ActualWidth properties of the Canvas, which are containing the actual height and width values of the Canvas.
availableSize can be any number from zero to infinite. Elements participating in layout should return the minimum Size they require for a given availableSize
/ Get the size of the canvas
Size size = new Size(surface.ActualWidth, surface.ActualHeight);
// Measure and arrange elements
surface.Measure(availableSize);
surface.Arrange(new Rect(availableSize));
Related
I'm facing an odd bug for around a month onwards.
I have a form that looks like this :
When I click on Save picture :
var g = new Grid();
var mv = new MyControl();
g.Children.Add(mv);
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
var rtb = new RenderTargetBitmap((int)g.ActualWidth, (int)g.ActualHeight,
96, 96, PixelFormats.Pbgra32);
rtb.Render(g);
Calling Measure() and Arrange() sets the size of the grid with proper size ( retrieved from MyControl )
The form control and the user control being rendered on the RenderTargetBitmap share no common data.
The visuals which become hidden are there and the viewmodel data is populated properly.
After executing this code and showing the dialog again it looks like this :
Both of the checkboxes have disappeared.Why?!
This problem doesn't appear if I set the size of the grid ( var g in the code )
var g = new Grid()
{
Width = 1024,
Height = 768
};
The default RowDefinition and ColumnDefinition for Grid is 1*. This means that the contents are given however much space the Grid has. In this case, the Grid will ask its parent to give it the maximum amount of space available for itself.
In your case, because your Grid has no visual parent, it has no idea how big it should render itself. You need to give it an explicit width/height. If you want to convert the contents of MyControl into Bitmap, why not just do it without the Grid?
If you insist on using Grid, and the size is dynamic, then you should manually specify the RowDefinitions and ColumnDefinitions. Change both of them to auto, which would force the Grid to size itself to the contents' sizes.
As said on MSDN info about Measure (Remarks section):
Computation of layout positioning in Windows Presentation Foundation
(WPF) is comprised of a Measure call and an Arrange call. During the
Measure call, an element determines its size requirements by using an
availableSize input. During the Arrange call, the element size is
finalized.
availableSize can be any number from zero to infinite. Elements
participating in layout should return the minimum Size they require
for a given availableSize.
When a layout is first instantiated, it always receives a Measure call
before Arrange. However, after the first layout pass, it may receive
an Arrange call without a Measure; this can happen when a property
that affects only Arrange is changed (such as alignment), or when the
parent receives an Arrange without a Measure. A Measure call will
automatically invalidate an Arrange call.
Layout updates happen asynchronously, such that the main thread is
not waiting for every possible layout change. Querying an element via
code-behind checking of property values may not immediately reflect
changes to properties that interact with the sizing or layout
characteristics (the Width property, for example).
Layout updates can be forced by using the UpdateLayout method.
However, calling this method is usually unnecessary and can cause poor
performance.
Hence call g.UpdateLayout in your save picture button click.
var g = new Grid();
var mv = new MyControl();
g.Children.Add(mv);
g.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
g.Arrange(new Rect(g.DesiredSize));
g.UpdateLayout();
var rtb = new RenderTargetBitmap((int)g.ActualWidth, (int)g.ActualHeight,
96, 96, PixelFormats.Pbgra32);
rtb.Render(g);
I am writing MeasureOverride implementation and there is one point I am kind of stuck.
The return value of the function.
This is the code.
protected override Size MeasureOverride(Size availableSize)
{
Double cHeight = 0.0;
Double cWidth = 0.0;
Size size = new Size(0, 0);
foreach (UIElement child in InternalChildren)
{
child.Measure(new Size(availableSize.Width, availableSize.Height));
if (child.DesiredSize.Width > cWidth)
{
cWidth = child.DesiredSize.Width;
}
cHeight += child.DesiredSize.Height;
}
size.Width = double.IsPositiveInfinity(availableSize.Width) ? size.Width : cWidth;
size.Height = double.IsPositiveInfinity(availableSize.Height) ? size.Height : cHeight;
return size;
}
My understanding is that returning an empty Size object is an indication that the element will use all the space available. However in this case when the space available is infinite positive, then it is returning zero.
Should it not be other way around. When infinite space is available then use only the space needed by the child elements? Otherwise constrain itself to use whatever space is available?
size.Width = double.IsPositiveInfinity(availableSize.Width) ? cWidth : availableSize.Width;
size.Height = double.IsPositiveInfinity(availableSize.Height) ? cHeight : availableSize.Height;
This one is kind of difficult to answer. It depends on what you want to achieve.
Probably you know that the measure phase determins the desired sizes only. The arrange phase fiddles with final values then.
I can imagine a panel with a behavior as in the code above. It could avoid a parent ScrollViewer to reserve too much space in case a child of our panel desires very much space (for example because it is an ItemsControl with many items itself). By returning zero the surrounding ScrollViewer would not reserve this space and in the arrange phase our panel could occupy space as needed although we returned zero.
It would be a very special case, but I was dicussing this very problem with a collegue today when he had a DataGrid along other elements within a ScrollViewer.
Without the code in "Arrange" this is all speculative but it's a possible usage of such code.
With MeasureOverride, you are returning the size that your control wants to be. If MeasureOverride is given infinite bounds then you can make it the size that holds all of the children or not; it is up to you. On the other hand, if you return a size that is larger than you are given, your control parent might accept that and just cut off your control later. For instance, if your control is in a grid and the grid width is set to 500, your MeasureOverride function will get passed an available width of 500. You can return 600 for the width and you will get that 600 width in the ArangeOverride function, but the parent grid will still only give your control 500 width and your content will just get cut off.
I tried this with my own PriorityStackPanel control written for WinRT (Windows 8.1 Store App) and it worked as I described. I think that WPF is just about identical in this case.
In WinRT, there is no "empty" size object. The size object will have some value set for it. NAN and PositiveInfinity both cause exceptions so you really should be returning the size that you want for your control. How you pick that size is up to you but it can't be a "you can decide for me: value like an empty size object (in WinRT). Even if you can return that in WPF, I advise against it since it makes the code less-than-clear. Just return the available size that you were given if that is what you need. Return a larger size if you need more room, but don't expect the container to show all of your content if you ask for more room than it is giving you.
As the tittle says I am looking for a way to use SizeF instead of normal Size for setting and getting Control dimensions.
Controls are using integer values internally and the size and locations cannot be set to float numbers.
SizeF has a ToSize method
Size size = sizeF.ToSize();
Or
myControl.Size = sizeF.ToSize();
Controls are backed by the Windows API, which use integer based (pixel) sizing. As such, SizeF would not be appropriate or have any effect. You could always use a SizeF, then map to a Size when you set the values.
Note that, in WPF, all of the location and size types now use double precision, and do allow adjustments smaller than per pixel, since they're being rendered using DirectX instead of as windows handles.
I am trying to create a custom user control in WPF. I want to be able to set the size manually when I later use the control within another window.
As a short test I have just made a control comprising a canvas within a grid, which totally fills the control. When initialised it draws a rectangle within itself showing its size. I then position this on a window, making it whatever size I want.
However I now have problems, as if I make the height of the rectangle I draw
this.ActualHeight
then when the control initialises this value is still 0, and so I get nothing. If instead I use
this.Height
then I get the height that I made it during design time, and not the size I have subsequently made it within the window.
The height and width seem to be set within the XAML designer, so I don't know what to do.
Is there an easy way around this?
I think what you're experiencing is how WPF performs layout and specifically how Canvas does not participate in Layout.
In your specific case you are setting the width of the Rectangle to Canvas.ActualWidth? Unless the width / height of the canvas have been explictly set then the ActualWidth/Actualheight will be zero, hence you can't get a point of reference within which to position children of Canvas. What I would do is bind the canvas width and height to its parent container (or set in code) to get the ActualWidth / ActualHeight correctly propagated.
As a point of interest try this example to understand how the WPF Layout engine works. The following code can force a height on a FrameworkElement to set the Width, Height as normal, then force a layout (measure, arrange pass) on the element in question. This causes the WPF layout engine to measure/arrange the element and propagate the Width, Height to ActualWidth, ActualHeight.
For example:
// Set the width, height you want
element.Width = 123;
element.Height = 456;
// Force measure/arrange
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(0, 0, element.DesiredWidth, element.DesiredHeight));
// Subject to sufficient space, the actual width, height will have
// the values propagated from width/height after a measure and arrange call
double width = element.ActualWidth;
double height = element.ActualHeight;
Also see this related question for clarity. I have used the above method occasionally to measure the text in a textblock so as to position correctly on a canvas.
I've stumpled upon a problem that I can't solve. I am given the amount of elements to populate a grid with, but through this, I need to know (beforehand) what the width and height (in amount of elements) the grid should be.
I would like the aspect ratio between width and height of the grid to be 1:1. Even with this simple aspect ratio, I fail at doing the calculations.
Could someone help me?
Example provided below
Let's say I have 9 elements in total. The width and height of the grid would then be 3. This is easy (by using the square root of the amount of elements).
But what about (for instance) 10 elements, or 11? With 10 elements, I would like either the width or height of the grid to be 4. Same with 11.
How do I perform these calculations?
It all depends on how you want to handle non-square layouts. Either way, though, you can take the square root of the number of items, and then take either the floor or ceiling to get the desired width/height.
For example, Math.Sqrt(11) is ~3.3166, so Math.Ceiling(Math.Sqrt(11)) == 4, which is your desired height/width.