I need a way to dynamically retrieve (not knowing what type of frameworkElement), the content/items presenter size and offset from the owner's edges in any form.
I need to create an adorner that covers the content area of a control.
Use the VisualTreeHelper to identify the ContentPresenter/ItemPresenter from the object if it exists.
Use the following code to get an offset:
presenter.TransformToVisual(control).Transform(new Point(0,0));
Call on presenter whatever desired properties that will give you size (Actual[Height/Width], etc.)
Related
If a parent control asks its children "How big do you want to be?", then what use is the availableSize parameter that's passed along? I've taken a peek via Reflector into the StackPanel's source and I still can't figure it out.
If the child wants to be 150x30, then it still reports 150x30 even if availableSize is 100x20, doesn't it? And if the child is expected to constrain itself to the availableSize, then that might as well be done on the size that's returned from calling MeasureOverride on the child - no point in passing that parameter.
Is there something that I'm not taking into account?
If the child wants to be 150x30, then it still reports 150x30 even if availableSize is 100x20, doesn't it?
It depends on the control, but generally the answer is no. In any case, the point is to give it the opportunity to fit itself to the container, but it is not required to do so.
Think about the difference between a Grid and a StackPanel. The Grid will typically size itself precisely to the available size. The StackPanel, by contrast, will size itself infinitely in one direction only (depending on its orientation), regardless of the available size. In the other direction, it will extend itself only as far as the space needed for its children, unless its "HorizontalAlignment" / "VerticalAlignment" is set to "Stretch", in which case it will stretch itself out to the available size in that direction.
The ViewBox is a more complex example that makes good use of "availableSize". It generally sizes itself to the available space, and scales/stretches its children depending on the values of "Stretch" and "StretchDirection".
The point is to give the element the opportunity to size itself correctly. After all the parent control might clip it if it doesn't respect the available size.
One has to differentiate between the following possibilities:
Container
Container has unlimited size (ScrollViewer) or wants to know how much space the child needs. In this case the availableSize in MeasureOverride() is infinite.
Container has limited size. In this case the availableSize in MeasureOverride() is the limited size.
Child
Child can adjust to Container size. In this case it returns availableSize if availableSize is not infinite. If it is infinite and Child cannot calculate size on its own, it can return 0.
Child has a fixed size. In this case it does not care about the availableSize but returns the fixed size.
The same thing happens again in ArrangeOverride(Size arrangeBounds), although with possibly different sizes. Therefore, do not use values calculated in MeasureOverride(), but recalculate them in ArrangeOverride().
arrangeBounds cannot be infinite. Instead of infinite, the container passes the available size calculated in its Arrange() method. The child can still use a different size. If it is too big, the container will clip it. If it is too small, the Container needs to align it somehow (ContentAlignment).
If a control (Container, Child) is fixed size or not depends also on properties like Width, MinWidth, MaxWidth, HorizontalAlignment, etc. Depending on these settings, a control demands in some parameter combinations a fixed size and in others it can adjust to the available size.
I have a window that has a menu, a toolbar at the top, and various other controls. I then have my own control that derives from ContentControl that I want to have use up all remaining space. I can't leave it to its own devices unfortunately, because the control is a Win32 control that's sort of... put inside this WPF control, and I need to use SetWindowPos.
At the moment what I am doing is using ArrangeOverride, getting the MainWindow.Content control and looking at the Height and Width. I then use Size I get in as a parameter and call the SetWindowPos function. It's written in C++/CLI, and here's the code:
Size WebView::ArrangeOverride(Size finalSize)
{
Application::Current->MainWindow->Measure(finalSize);
UIElement^ obj = dynamic_cast<UIElement^>(Application::Current->MainWindow->Content);
double objHei = obj->RenderSize.Height;
double objWid = obj->RenderSize.Width;
SetWindowPos(hWnd, NULL, objWid-finalSize.Width, objHei-finalSize.Height, finalSize.Width, finalSize.Height, NULL);
So in my head I thought this would then set the position of the control to within the remaining available space. And it does sort of work, but it seems as if the MainWindow.Content control is not being measured until afterwards? What am I doing wrong here?
edit: most of the problems seem to be when full-screening the window and then un-fullscreening it.
I have managed to fix this by using the answer to this question here
I simply put my control into a Frame, so it'd be the parent.
Then using the Point I set the window position to that, along with the size that is passed through as a parameter to the ArrangeOverride method.
In Winforms, I have implemented a custom object with a draw method, which is called by Form_Paint. I now want to be able to get the coordinates of this object after being drawn to the form, for the sake of a Move procedure in the works. I have tried using object.Location, object.Left, and object.Top, but these just give 0,0. I then tried object.Size to test, and it gave me the size of the form.
How can I get the location of my runtime object on the form? Thanks
Try using
Point objLocation= cusObject.FindForm().PointToClient(
cusObject.Parent.PointToScreen(cusObject.Location));
I'm implementing a custom control with some labels on it and I need to measure the size of those labels to have an optimal layout. In this way I can properly show the control for each font and font size.
Could you tell me how can I do that, please?
Thank you.
The correct way to size and arrange your custom control according to the size of its sub-elements is to override MeasureOverride and ArrangeOverride.
See the links for details, but in a nutshell, your control is supposed to (in MeasureOverride):
call UIElement.Measure on all children (which will include your labels), which will return the size that each of your children would like to have,
calculate your own desired size and
return this size to the framework (by using it as the return value of MeasureOverride).
Afterwards, in ArrangeOverride, you get the size allocated to your control by the framework as a parameter and you
determine how much of the space you want to allocate to each of your child elements and
call UIElement.Arrange on each child element.
you might want to look up ev.Graphics.MeasureString(str,font)
In normal C# it is easy to draw to a bitmap using the Grpahics.DrawString() method. Silverlight seems to have done away with Bitmap objects and Graphics is no longer available either. So...How am I meant to manipulate/create a bitmap when using Silverlight? If it helps, I am using Silverlight 3.
Let me tell you what I am doing. I am being given a template, basically a pre-rendered image. The user is then able to select from multiple images and enter the deisred text. I then render it to the image, adjusting size etc... within bounds and centering it in the pre-defined area of the image. If I can calculate the size (as in the MeasureString method) and then draw the string (as in the Graphics.DrawString method) that would be fine. The real question, no matter why I want to be able to do this, is can it be done?
The question is: why do you want to? Why not just use a TextBlock?
If you are trying to dynamically generate an image, use standard Silverlight/WPF controls (including TextBlock) and render them to a WritableBitmap.
Edit:
Ok, you've updated and expanded, which gives me more to go on. Unfortunately, you're not going to like the answer. First, keep in mind that Silverlight and WPF in general are vector based, and intended to be used as such. Although the Canvas allows you to do pseudo-pixel manipulations, you cannot be nearly as pixel-accurate as old-school GDI. This is a factor of your medium. If you absolutely have to measure things the way you want to measure them, I suggest you build your images on a remote server and transmit them to your Silverlight app.
You can calculate the size on-screen of the text rendered via a TextBlock using the ActualWidth and ActualHeight properties. But it only works on an already rendered control. Something like MeasureString is simply not available in Silverlight. Based on your description of your app, some user interaction could accomplish what you want. The user selects the image, enters the text, and is shown a preview. The user can then adjust the width and height of the various text areas until satisfied, at which point you can take a snapshot using the render method I liked to above.
The following may work, its a bit nebulous because I haven't tried yet myself.
The object you are looking for is the WritableBitmap.
You create a Visual tree, for example create your self a Grid or Canvas (you're not adding this to the UI). Add to it the selected image and a TextBlock positioned and sized as you prefer.
Create a new WritableBitmap either of a specific size or using the selected image to initialize it.
Use the WritableBitmap Render method passing the above root Grid or Canvas to it.
Now you have a bitmap which you should able to use to do whatever its you needed to do that required all this hoop jumping in the first place.