I have a problem with visualizing a path which contains multiple line segments on a canvas.
Right now a user can connect two controls on canvas with a direct path. This is done by creating an instance of a viewmodel class which is passed to a templateselector which returns the datatemplate for a path.
This template looks like
<Path StrokeThickness="2"
Stroke="Black"
Fill="Black"
MinWidth="1"
MinHeight="1"
Name="arrowPath">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="False"
StartPoint="{Binding Path=Source, ElementName=_this}">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment IsStroked="True"
Point="{Binding Path=Destination, ElementName=_this}" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<PathFigure IsClosed="True"
IsFilled="True"
StartPoint="{Binding Path=Destination, ElementName=_this}">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment IsSmoothJoin="True"
IsStroked="True"
Point="{Binding Path=TrianglePoint2, ElementName=_this}" />
<LineSegment IsSmoothJoin="True"
IsStroked="True"
Point="{Binding Path=TrianglePoint3, ElementName=_this}" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
The Start- and EndPoint Attributes of the Path are bound to properties of the viewmodel instance.
Everythings working fine so far. But with more Controls the canvas is really a mess and i want to give the user the opportunity to connect controls via paths consisting of multiple line segments. The new viewmodel class stores the mouseposition(s) when clicked in a List.
Designing the new Control I cannot figure out how to dynamically add a LineSegment in my xaml for each Point in my List.
I hope you understand what I mean, thank you.
Consider looking at this CodeProject article, it contains a step-by-step tutorial on creating a diagram designer, including orthogonal connector routing and how to model them in the UI.
Related
Scenario as follows.
I have an canvas on which I want to move, lets say an rectangel, across the screen. The way the rectangle is supposed to move is determined by one specific path (like a railway, the rectangle is supposed to only move on the rails). The position on which the rectangle is currently located is provided by external source.
Current Location is provided every ~200-500ms.
So far I have tried the following:
simple TranslateTransform. Does the trick, but the rectangle jumps from Point a to b. No smooth Translation.
Storyboard with a doubleAnimation
Smoother, but the rectangle doesn´t follow the required path.
DoubleAnimationUsingPath. Rectangle is moving on the path. But now I am not able to provide the current position by external source.
Easiest for me would be a way to use an DoubleAnimationUsingPath and providing the X-Koordinate by external source.
But I am not sure if overall storyboards and animations are the best way to tackel that Problem.
If you know of any completely different Approach I am more than happy hear about it.
Kind regards
Just to get an idea of what can be done with animations, take a look at this little demo of a object moving along a track:
<Canvas>
<Canvas.Resources>
<PathGeometry x:Key="track">
<PathFigure StartPoint="200,100" IsClosed="True">
<LineSegment Point="300,100"/>
<ArcSegment SweepDirection="Clockwise"
Size="100,100" Point="300,300"/>
<LineSegment Point="200,300"/>
<ArcSegment SweepDirection="Clockwise"
Size="100,100" Point="200,100"/>
</PathFigure>
</PathGeometry>
</Canvas.Resources>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<MatrixAnimationUsingPath
Storyboard.TargetName="train"
Storyboard.TargetProperty="RenderTransform.Matrix"
PathGeometry="{StaticResource track}"
DoesRotateWithTangent="True"
Duration="0:0:10"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Path Data="{StaticResource track}" Stroke="Black"
StrokeThickness="6"/>
<Path Data="{StaticResource track}" Stroke="White"
StrokeThickness="4" StrokeDashArray="2,2"/>
<Rectangle x:Name="train" Width="10" Height="6" Fill="Red"
Canvas.Left="-5" Canvas.Top="-3"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<MatrixTransform />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
I was drawing a series of points with Path in c# code. I just give an example in xaml.
So the polyline is from (20,37) to (20,36) and returns to (20,37). It is supposed to be very short, right? But it turns to be a segment roughly 9dp long.
if I simply draw from (20,37) to (20,36), it behaves normal. Because the points are drawn in real-time that I cannot do preprocessing.
Why is that and how to solve it?
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="20,37">
<PathFigure.Segments>
<LineSegment Point="20,36"/>
<LineSegment Point="20,37"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
change StrokeMiterLimit of Path (default is 10)
<Path Stroke="Black" StrokeThickness="2" StrokeMiterLimit="1">
I'm trying to draw a square with a round hole in it, so that one can see what's behind the rectangle. I've used the following code to accomplish this in WPF:
<Path Grid.Row="0" Grid.Column="1" Stretch="Uniform" Stroke="Black" Fill="Yellow">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,100,100"></RectangleGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="50,50" RadiusX="40" RadiusY="40"></EllipseGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
The CombinedGeometry class doesn't appear to exist in WinRT-XAML. Basically I want to create a game board that you drop pieces into from the top, and animate the pieces falling into place behind the board.
Any suggestions for what I should use instead of a CombinedGeometry? ... or suggestions on how to get CombinedGeometry to work in WinRT-XAML?
Thanks!
Dave
It is not really an equivalent, but it can do the Job :
<!-- Creates a composite shape from three geometries. -->
<GeometryGroup FillRule="EvenOdd">
<LineGeometry StartPoint="10,10" EndPoint="50,30" />
<EllipseGeometry Center="40,70" RadiusX="30" RadiusY="30" />
<RectangleGeometry Rect="30,55 100 30" />
</GeometryGroup>
</Path.Data>
This question already has an answer here:
Combine multiple Ellipses
(1 answer)
Closed 8 years ago.
I'm having these two shapes:
Fist picture code:
<Path Fill="Orange">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,100">
<BezierSegment Point1="50,110" Point2="50,110" Point3="100,100"></BezierSegment>
<LineSegment Point="100,80"></LineSegment>
<LineSegment Point="120,90"></LineSegment>
<LineSegment Point="120,70"></LineSegment>
<LineSegment Point="100,60"></LineSegment>
<LineSegment Point="100,20"></LineSegment>
<LineSegment Point="80,0"></LineSegment>
<LineSegment Point="20,0"></LineSegment>
<LineSegment Point="0,20"></LineSegment>
<LineSegment Point="0,40"></LineSegment>
<LineSegment Point="-20,20"></LineSegment>
<LineSegment Point="-20,40"></LineSegment>
<LineSegment Point="0,60"></LineSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Second picture code:
<Path Fill="Orange">
<Path.Data>
<PathGeometry>
<PathFigure>
<LineSegment Point="0,25"></LineSegment>
<LineSegment Point="250,25"></LineSegment>
<LineSegment Point="250,0"></LineSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
How do i combine them for something like this(ignore the text):
I need this to be done in C# ( not xaml ). Thanks!
For users wanting to know the XAML method
Basically, you can use a CombinedGeometry object to do this:
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<!-- Combines two geometries using the exclude combine mode. -->
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<PathGeometry>
<PathFigure StartPoint="0,100">
<BezierSegment Point1="50,110" Point2="50,110" Point3="100,100"></BezierSegment>
<LineSegment Point="100,80"></LineSegment>
<LineSegment Point="120,90"></LineSegment>
<LineSegment Point="120,70"></LineSegment>
<LineSegment Point="100,60"></LineSegment>
<LineSegment Point="100,20"></LineSegment>
<LineSegment Point="80,0"></LineSegment>
<LineSegment Point="20,0"></LineSegment>
<LineSegment Point="0,20"></LineSegment>
<LineSegment Point="0,40"></LineSegment>
<LineSegment Point="-20,20"></LineSegment>
<LineSegment Point="-20,40"></LineSegment>
<LineSegment Point="0,60"></LineSegment>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<PathGeometry>
<PathFigure StartPoint="0,100">
<LineSegment Point="0,25"></LineSegment>
<LineSegment Point="250,25"></LineSegment>
<LineSegment Point="250,0"></LineSegment>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
Please take a look at the How to: Create a Combined Geometry page on MSDN for full details.
Please also note that you will need to set the StartPoint property of these PathFigure objects to correctly line up your shapes.
UPDATE >>>
For users wanting to know the C# method
Sorry, I didn't notice that you wanted to use code. In code you would have to name your PathGeometry objects and put them into a Resources section:
<Application.Resources>
<PathGeometry x:Key="Shape1">
...
</PathGeometry>
<PathGeometry x:Key="Shape2">
...
</PathGeometry>
</Application.Resources>
Then you can still use a CombinedGeometry object:
PathGeometry shape1 = (PathGeometry)Application.Current.FindResource("Shape1");
PathGeometry shape2 = (PathGeometry)Application.Current.FindResource("Shape2");
CombinedGeometry combinedGeometry = new CombinedGeometry(
GeometryCombineMode.Union, shape1, shape2);
Path combinedPath = new Path();
combinedPath.Data = combinedGeometry;
Please take a look at the CombinedGeometry Class page at MSDN for more information with this method.
I ran into a problem. I'm trying to animate a simple Path with PointAnimation. I have a working solution for WPF, and I tried to use it in my Metro app. However it's syntactically correct, it doesn't do anything. What I missed? What I need to change in my XAML?
<Path Stroke="DarkMagenta" StrokeThickness="2">
<Path.Data>
<GeometryGroup>
<PathGeometry>
<PathFigure StartPoint="0,0">
<BezierSegment x:Name="bezierSegment1" Point1="100,0" Point2="100,200" Point3="200,200" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard>
<PointAnimation Storyboard.TargetName="bezierSegment1" Storyboard.TargetProperty="Point1" From="0,0" To="100,0" />
<PointAnimation Storyboard.TargetName="bezierSegment1" Storyboard.TargetProperty="Point2" From="0,0" To="100,200" />
<PointAnimation Storyboard.TargetName="bezierSegment1" Storyboard.TargetProperty="Point3" From="0,0" To="200,200" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
I tried to put the storyboard into resources and begin outside from a Button_Click handler, but it doesn't helped.
Oh yes,yes.
EnableDependentAnimation is an important property to animations that allows you to animate your custom dependency properties. It’s handy, but not enough people know about it yet. Spread the word to save people from banging their heads against the wall!
Thank you Jerry Nixon: http://blog.jerrynixon.com/2012/06/windows-8-animated-pie-slice.html