I am arranging quite freely a lot of elements on a Canvas layout, in fact the elements represent an interactive flow-chart. As transformations are applied, I need relative transformations on some of the elements.
Especially I require some elements being anchored or docked to their parent elements. I found different solutions, however I don't know if they solve my problem in the most elegant way.
Here is an example:
<Line X1="80" X2="800" Y1="730" Y2="730"/>
<Polygon Points="0,30 40,0 40,60" Canvas.Left="48" Canvas.Top="700"/>
The Polygon draws a triangle and I would like to let it dock on the left side of line. Which means, when translating the line to a new position or when scaling it down, the Polygon should move with it.
Is this possible?
put them in a canvas of their own, that way you can position the outer canvas absolutely and keep the inner stuff together.
like this:
<Canvas>
<Line X1="60" X2="820" Y1="60" Y2="760"> <!--some other line--> </Line>
<Canvas Canvas.Left="48" Canvas.Top="700">
<Polygon Points="0,30 40,0 40,60"/>
<Line X1="32" X2="752" Y1="30" Y2="30"/>
</Canvas>
</Canvas>
Related
I just started using Geomectry Drawing in xaml and I came across this interesting article https://msdn.microsoft.com/en-us/library/aa480159.aspx. Here, I find out that the following drawingbrush gives a graph diagram as an output.
<DrawingBrush x:Name="gridBackgroundBrush"
Viewport="0,0,10,10"
ViewportUnits="Absolute"
TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="Green" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="Green" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
From further reading, I figure out that M means starting point or move to, L means line and Z means close but could not figure out how this will give me two lines - one horizontal and one vertical? Any help understanding this will be highly appreciated. Thanks.
So here's a quick break down for you.
Your example is a DrawingBrush which is explicitly set to TileMode="Tile" which is the equivalent of repeat-x/repeat-y if you're more familiar with CSS as example. So it's instructed to repeat itself up-down/left-right repeating.
Your two bits of your Geometry Drawing if translated individually are two squares with one stretching vertical, one stretching horizontal. While your explicitly set ViewportUnits is dictating the size and position effectively making repeated columns and rows.
Your Path Geometry uses Path Markup Syntax to draw these lines as you pointed out. For a more visual explanation replace your Brush on each.
<GeometryDrawing Geometry="M0,0 L1,0 1,0.1, 0,0.1Z" Brush="Red" />
<GeometryDrawing Geometry="M0,0 L0,1 0.1,1, 0.1,0Z" Brush="Blue" />
...and voila! You have yourself a repeated line background with effective vertical/horizontal columns creating your grid. See links for more detail and hope this helps. Cheers!
Oh, and the question you got that from also had a link that would have shed a little light on it but not as much as you'd like so I didn't mark this duplicate.
ADDENDUM:
A little more clarification. Though if you want to learn more I'd follow the documentation link someone spent a lot of time writing to answer this already. Think if you have an x,y grid you're drawing points on.
Say you're using the pen tool in something like Adobe Illustrator, or Blend. Your first click is setting your M as your start point based on the relative size of the container. Then you click in another spot...well now you effectively have a L line.
So when we see: M0,0 L1,0 that's our first starting Line. In this case it's the top corner stretching to the right corner since there's not another anchor in the line between the two points. The next set acts as the anchor to tell that line to change it's direction to make the side, and so on, and so fourth until you hit the end at Z. Hope this helps but I would encourage the documentation first.
Here they are individually if you feel like tinkering with numbers and learning:
<Path Data="M0,0 L1,0 1,0.1, 0,0.1Z"
Height="150" Width="150" Stroke="Red" />
<Path Data="M0,0 L0,1 0.1,1, 0.1,0Z"
Height="150" Width="150" Stroke="Blue" />
I came cross the same thing when I used GMaps V3. It is an SVG path notation path that allows you to draw on WPF and on browsers too. You can find the complete documentation in the link.
Wherever you look in Windows 10, there are circles. It's fairly easy to make images circular, but camera is a bit different. Is there a simple XAML way to clip the camera stream in a CaptureElement to make it a circle?
I tried putting it in a border, but CaptureElement doesn't care about its borders. I also tried using the Clip property, but it can only clip to RectangleGeometry.
One way would certainly be to grab CaptureElement frames, transforming them to images (frame by frame) and applying to Image element, and then clipping the image, but it seems like that would have awful performance.
Is there something in the framework to make this really simple, but I'm not seeing it?
Well after seeing that might be the background is always black of the Canvas DirectX the only way I see is:
1.- Clip a rectangle with an ellipse in Inkscape for instance.
2.- Copy to Expression Design and Ctrl-Shift-C (to copy XAML)
3.- Place inside a ViewBox only the path generated
<Grid Width="300" Height="300">
<CaptureElement Name="PreviewControl" Stretch="Uniform" Width="280" Height="280" />
<Viewbox Width="280" Height="280">
<Path Width="813.701" Height="813.701" Canvas.Left="-33.3503" Canvas.Top="-45.3503" Stretch="Fill" Fill="#FF800080" Data="F1 M -33.3503,-45.3503L -33.3503,768.35L 780.35,768.35L 780.35,-45.3503L -33.3503,-45.3503 Z M 373.54,158.095C 485.863,158.095 576.985,249.137 576.985,361.54C 576.985,473.863 485.863,564.985 373.54,564.985C 261.137,564.985 170.095,473.863 170.095,361.54C 170.095,249.137 261.137,158.095 373.54,158.095 Z "/>
</Viewbox>
</Grid>
With that you can place an image in the path or a solid color, that's the only way I see to do it. Hope it helps
Hi I have created an UML diagram in C# with nodes and edges. The nodes are connected to the other nodes with edges, but I want to add text to the edges.
To draw the edges I have use Bindings to startNode and endNode (simple).
<Line Stroke="Black" X1="{Binding StartNode.Center_x}" Y1="{Binding StartNode.Center_y}" X2="{Binding EndNode.Center_x}" Y2="{Binding EndNode.Center_y}" StrokeThickness="5"/>
It is simple to add text before or after the edge, but if I do so, it is overidden by the connected node.
My question is, how do I add a label or textbox in the middle of the line?
Do I need to create two lines, one at the beginning and before the text, and the second after the text and to the end? And if so, how to?
I think a better way to approach your problem is to have a single UI Container like a Panel, and then inside the container you draw the line and put the text as you wish, that may help you to overlay the multiple objects dilemma.
I have a Canvas with 2 "dots" drawn on it. See this (simplified) code:
<Canvas>
<Ellipse />
<Ellipse />
<Canvas.RenderTransform>
<RotateTransform x:Name="rotateEllipse" />
</Canvas.RenderTransform>
</Canvas>
As you can see, I want to rotate the canvas using the given RotateTransform.
Next, I want to put a TextBlock near to each Ellipse (a label). However, I don't want to include this TextBlock into the Canvas because it will then rotate also. I want the text to remain horizontal.
Any idea how to solve this in an elegant way?
Something like this, should work for you
<TextBlock RenderTransform="{Binding RelativeSource={RelativeSource AncestorType=Canvas},
Path=RenderTransform.Inverse}"/>
Assign to text box transformation matrix an inverse of the transformation matrix of the Canvas.
Good question! And I'm going to guess, so please take this answer with a pinch of salt.
I believe you are trying to place text annotations next to ellipses on a rotated canvas, but these annotations need to remain horizontal. Two things you could try:
Firstly, given the XY point that you know of each ellipse from Canvas.GetTop/GetLeft, you could find its new rotated XY location by applying the RotateTransform to the ellipse location, using the formula U = M*V, where U is the output point, V is the input point (XY location of ellipse) and M is the Rotation Matrix.
Secondly, you could place a second canvas over the first (assuming they are both in a grid, the second canvas is at higher Z-index and is the same size as the underlying canvas). Call it an annotation layer. Your annotations (text labels) can appear at the new transformed locations and unrotated using this approach.
You'd have to do this in code of course, not Xaml, although you might find a binding friendly approach by creating a value converter on the TextBlock that bound to the source RotateTransform/Ellipse and did this operation for you.
Another approach would be to take the .Inverse of the RotateTransform and apply that to the textblocks, however you may still need to translate to get to the new location. Either way I think it demands some experimentation.
Best regards,
I'm creating a map in Silverlight that contains a bunch of rooms. All of the rooms are polygons, most of them are rectangles.
So what I'm doing is creating a Polygon using the x y point coordinates for the room. Something like
Polygon p = new Polygon
p.points = pointCollection;
MainCanvas.Chilren.Add(p);
This works great. Next, I want to put the name of each room inside these on the map. I figured I'd just add a textblock child to the polygon. Unfortunately, it seems that UIElements cannot contain child UIElements. I think this is dumb, but whatever.
Next plan: Create a new Silverlight user control containing the polygon and a text field. Center text field in polygon within user control. So I just create one of these UserControls "Room" set the property "RoomShape" to the polygon and add it to the canvas. The problem here is that The Usercontrol is always added at position (0,0) and the room shape is in the bottom right position. What I really wanted was for the control to take on the size and shape of the polygon I add to it so I can find the center and add the text in. Is this possible?
Also, let's say I add a polygon to my layout in a control:
LayoutRoot.Children.Add(poly);
Why do
poly.ActualHeight
poly.ActualWidth
poly.height
poly.width
all return 0 or NaN when I can clearly see them on the Canvas?
And why do
Canvas.GetTop(poly);
Canvas.GetLeft(poly);
both return 0 when I can clearly see they are not located at (0,0)?
Any other suggestions for centering text in a polygon is appreciated.
First of all, for sure you cannot add UIElements to Polygon. The Polygon is not a container so you can't add elements in it.
Second, if you want to set text in the middle of your polygon, why don't you wrap your polygon in a Grid. Then in the Grid, add your polygon, and your textblock like that :
<Grid x:Name="room1" Background="LightBlue" HorizontalAlignment="Center" VerticalAlignment="Center">
<Polygon Stroke="Black" Fill="Beige">
<Polygon.Points >
<Point X="0" Y="0" />
<Point X="20" Y="100" />
<Point X="100" Y="50" />
<Point X="0" Y="0" />
</Polygon.Points>
</Polygon>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Room Name</TextBlock>
</Grid>
Third, for the size always at 0, this is probably because you create/add the usercontrol at Load time. I know its sad but you will have to do the work in the UserControl_SizeChanged event of the container.