Why ActualWidth and ActualHeight start from 0,0? - wpf

I want to add WPF Path to InkCanvas and use selection to select WPF Path.
So, I use this code.
System.Windows.Shapes.Path path = drawCanvas.Children[i] as System.Windows.Shapes.Path;
drawCanvas.Children.RemoveAt(i);
inkCanvas.Children.Add(path);
This is the output. I have to select WPF Path from 0,0 because Actualwidth and ActualHeight start from 0,0.
How do I select absolute WPF Path?
Thanks
Edit:
Now, I can select it absolutely by using this code.
System.Windows.Shapes.Path path = drawCanvas.Children[i] as System.Windows.Shapes.Path;
drawCanvas.Children.RemoveAt(i);
path.Margin = new Thickness(-getMinX(path), -getMinY(path), 0, 0);
containPath.Children.Add(path);
containPath.Width = getMaxX(path) - getMinX(path);
containPath.Height = getMaxY(path) - getMinY(path);
containPath.Margin = new Thickness(getMinX(path), getMinY(path), 0, 0);
inkCanvas.Children.Add(containPath);

You can use the UIElement.UpdateLayout Method on the InkCanvas to update the FrameworkElement.ActualWidth Property and ActualHeight. See the ActualWidth link for background information on why this is needed.
Edit:
I misunderstood the question. It wasn't that ActualWidth and ActualHeight were zero but that their values were relative to (0, 0) on the InkCanvas. A pretty good solution to the problem is to wrap the Path in a Canvas and position it using Margin like this:
<Canvas Width="50" Height="50" Margin="200,200,0,0">
<Line
X1="0" Y1="0"
X2="50" Y2="50"
Stroke="Black"
StrokeThickness="4" />
</Canvas>
which behaves like:
The disadvantage of this approach is the user has to lasso the Canvas which is a rectangle, not an arbitrary shape. Nevertheless, it's a lot better than having to lasso the object and the origin.

For elements that can only be defined via control points (eg Line, Path etc as against Rectangle, Ellipse etc) when you add it to an items control (which I assume the InkCanvas is since it supports selection), first a canvas is added to the panel at 0,0. The width and the Height of the canvas are determined from the maximum X and Y coordinates of the control points. After this the element is added as a child of this canvas.
You will also see that whenever you see this kind of behaviors with an element, the element wont support Layout Properties like Horizontal/Vertical alignment etc.
The only way I see around this is to find the ActualWidth and ActualHeight manually from the coordinates in the path.
Edit: This is from personal experience and not from any documentation.

Related

How to use ScrollViewer.ScrollToVerticalOffset?

I hope this isn't a duplicate but I can't find any documentation or examples on how to actually use ScrollToVerticalOffset(). I'm using it in a Windows Phone 8 app, but I think it will still apply to WP7 and Silverlight (although, feel free to correct me if I'm wrong).
So here is my basic set up (pseudo-code from memory):
<phone.PivotItem>
<ScrollViewer>
<Grid Height="1500">
<Grid.RowDefinitions>
<!-- about 20 rows, all auto-height -->
</Grid.RowDefinitions>
<Border Grid.Row="0">
<TextBox x:Name="txt1" />
</Border>
<Border Grid.Row="1">
<TextBox x:Name="txt2" />
</Border>
<!-- ...... -->
<Border Grid.Row="19">
<TextBox x:Name="txt20" />
</Border>
</Grid>
</ScrollViewer>
</phone.PivotItem>
So as you can see, I've got a ScrollViewer within a PivotItem, and inside is a Grid. In the Grid there are about 20 TextBoxs, each within a Border. I am dynamically setting focus to one of these TextBoxs when this page loads, so anytime I set focus to TextBox #6-20 (roughly) - I have to manually scroll down to see it. I want to auto-scroll my ScrollViewer so that whichever TextBox has focus, it will be centered for the user to see.
The documentation for ScrollToVerticalOffset() says:
Scrolls the content that is within the ScrollViewer to the specified
vertical offset position.
And that it accepts a type of System.Double.
What I don't understand is A) the value I'm supposed to pass, and B) how I could even get that value? Is it supposed to be a number between 0 and the height of my Grid (1500)? If so, how could I determine the position of any given TextBox so I can scroll to it?
If there are any straightforward examples, please feel free to link out to them. I'm not sure if the content within the ScrollViewer matters when calling this method, but in case it does I wanted to show exactly how I'm using it.
Many thanks in advance!
You can see any UIElement's position relative to another UIElement using the UIElement.TransformToVisual call.
First, get the transform between the TextBox and ScrollViewer.
GeneralTransform transform = textBox.TransformToVisual(scrollViewer);
Then, figure out what point (0,0) of the TextBox is relative to the ScrollViewer. Meaning, the TextBox origin (0,0) is located at what ScrollViewer position.
Point textBoxPosition = transform.Transform(new Point(0, 0));
Now that you know the Y position of the TextBox relative to the ScrollViewer, scroll to that Y offset.
scrollViewer.ScrollToVerticalOffset(textBoxPosition.Y);
Good luck!
This is a very old post, but the meaning of VerticalOffset varies.
Most of the solutions I have seen assume VeritcalOffset is in pixels. This is not always the case.
From: https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.scrollviewer.extentheight
If CanContentScroll is true, the values of the ExtentHeight, ScrollableHeight,
ViewportHeight, and VerticalOffset properties are number of items. If
CanContentScroll is false, the values of these properties are Device Independent Pixels.

How to zoom image inside rectangle WPF

I am trying to zoom in and out image inside Rectangle control. But while doing so my entire Rectangle is getting zoomed in instead of just image inside that. for doing so I am using ScaleTransform and TranslateTranform on Rectangle. I should do the same on image instead of Rectangle but I dont know how? Could anyone please help me out.
XAML :
<Rectangle x:Name="LiveViewWindow" Fill="#FFF4F4F5" HorizontalAlignment="Right"
ClipToBounds="True" />
Code:
InteropBitmap m_LiveViewBitmapSource =Imaging.CreateBitmapSourceFromMemorySection(
section, width, height, PixelFormats.Bgr32, width*4, 0) as InteropBitmap;
ImageBrush m_BackgroundFrame = new ImageBrush(m_LiveViewBitmapSource);
RenderOptions.SetBitmapScalingMode(m_BackgroundFrame, BitmapScalingMode.LowQuality);
LiveViewWindow.Fill = m_BackgroundFrame;
n then for I am using Invalidate() property to render InteropBitmap to Rectangle.
You may set the Transform property of the ImageBrush. Get more information in Brush Transformation Overview.

Positioning an element inside the Canvas by its center (instead of the top left corner) using only XAML in WPF

The common question about positioning an element inside a Canvas is "How to position the center of element (instead of the top left corner)".
WPF: Resizing a circle, keeping the center point instead of TopLeft?
WPF Center Ellipse at X, Y
WPF element positioning on a Canvas
Several solutions are presented, but they all have drawbacks.
The easiest solution is to accommodate the element size during while setting the Canvas.Left and Canvas.Top properties programmatically. This works, but only once. This solution doesn't support bindings and it will break when the element size is changed. You also cannot set the Canvas.Left or Canvas.Top using
Another set of solutions involve translate transformations utilizing either RenderTransform or Margin. These solutions require binding some property to the -0.5 * Width or -0.5 * Height. Such binding requires creating a custom ValueConverter and is impossible to create using only XAML.
So, is there a simple way to position an element inside canvas so that its Canvas.Left and Canvas.Top correspond to the element's center and both size and position properties can be bound to some other properties?
XAML and bindings seem very powerful, but sometimes there are simple problems that require very complex solutions. In my bindings library creating such binding would be as easy as writing element.Center = position or element.TopLeft = position - element.Size / 2, but don't let me get carried away.
I've found a very simple solution which uses only XAML and supports binding both size and position properties of the element. It seems that when the WPF control with alignment set too Stretch or Center is placed inside the canvas, the element "gravitates" towards centering as the (Canvas.Left, Canvas.Top) point (the state that we desire), but is stopped by the "angle plate" placed at the same (Canvas.Left, Canvas.Top) point. How do I know about this "gravitation"? It's evident when you ease the block by setting the Margin of the element to a negative value. Setting the negative margin allows the element to move towards its center goal. The element moves until the Margin reaches (-Height / 2, -Width / 2) so that the element becomes perfectly centered at the (Canvas.Left, Canvas.Top) point. Further changes don't cause any movement since the element is already perfectly positioned.
Solution: set Margin="-1000000".
So in the following code the ellipses are both centered at the (200, 200) point. The first ellipse has Left and Top properties corresponding to the ellipse center allowing to easily bind them with some other objects' properties.
<Canvas>
<Ellipse Width="100" Height="100" Canvas.Left="200" Canvas.Top="200" Opacity="0.5" Fill="Red" Margin="-100000" />
<Ellipse Width="100" Height="100" Canvas.Left="150" Canvas.Top="150" Opacity="0.5" Fill="Blue" />
</Canvas>
The bad thing is this solution only work in WPF. Silverlight and WinRT don't have the described behavior.
Even simpler, at least for Shapes, would be to use a Path with an appropriate Geometry:
<Canvas>
<Path Canvas.Left="200" Canvas.Top="200" Fill="Red" Opacity="0.5">
<Path.Data>
<EllipseGeometry RadiusX="50" RadiusY="50"/>
</Path.Data>
</Path>
</Canvas>
I solved this by putting the canvas into the bottom-right cell of a 2x2 grid. That makes the 0,0 coordinate the center of the grid, and then you can do all your drawing relative to that.
This solution worked for me Center text at a given point on a WPF Canvas. He uses a MultiBinding and a custom Converter to adjust the margin on his element. Brilliant!

How to Centre Silverlight Elements relative to each other?

I have an Ellipse and a TextBlock that I want to be Centred relative to each other - ie the TextBlock shows in the Centre of the Ellipse no matter the content eg. its says 88 (like a Bingo Ball) and the Ellipse is the Ball itself - and the number shows in the centre of this ball.
How to I accomplish this in Silverlight, where the sizes are not fixed, as if possible I want the Ellipse and TextBlock to be the relative size of their parent - which I cannot seem to do in Silverlight either.
Related to this problem is I cannot find the code behind equivelent for "LimeGreen" the colour, which can be set in XAML but not in Code, where only a few Colours are available the in the Color class?
The style of layout desired is provided by the Grid control. However I suspect you would also want the text to scale with the size of the ellipse, this can be acheived with the Silverlight Toolkit Viewbox control:-
<Grid>
<Ellipse Fill="Blue" />
<controlstk:Viewbox>
<TextBlock Text="88" Margin="2" />
</controlstk:Viewbox>
</Grid>
BTW, LimeGreen is #FF32CD32.

How to change x,y origin of canvas to bottom left and flip the y coordinates?

I have a bunch of data points that I would like to two-way bind to points on a canvas.
The points assume larger y values are reflected in an upwards direction like most math graphs.
How do I change the x,y origin of the canvas to the bottom left corner and reverse it's interpretation of the y coordinate?
(I would like to stay in XAML)
<Canvas>
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5" />
</Canvas.LayoutTransform>
</Canvas>
I tried the ScaleTransform method extensively: It does not work. It only shifts one of the 2 coordinates, never both. This, however, works as advertised:
<Canvas Name="myCanvas" Width="0" Height="0" RenderTransform="1 0 0 -1 0 0"
HorizontalAlignment="Center" VerticalAlignment="Center" >
If you use databinding you can use a TypeConvertor, but for that you have to go outside the XAML and you need to know the size of the canvas beforehand.
I'd probably create a custom panel instead of using Canvas and give it the attached properties that make sense for your needs. Here is an example of implementing a custom panel:
http://blog.boschin.it/articles/silverlight-radialpanel.aspx
Something like Canvas is very simple since you don't have to do much in the measure and arrange overrides.
You may also be able to inherit from Canvas and override ArrangeOverride, I haven't tried that but it may work.

Resources