How can I draw this shape in xaml WPF? - wpf

I have to draw this shape in XAML. How can I draw this?
I tried this and this is OK but can't split two color
<Path Grid.Column="1" Fill="Red">
<Path.Data>
<GeometryGroup FillRule="EvenOdd">
<EllipseGeometry Center="5,0" RadiusX="5" RadiusY="5" />
<RectangleGeometry Rect="0,0 5 80" />
<RectangleGeometry Rect="5,0 5 80" />
<EllipseGeometry Center="5,80" RadiusX="5" RadiusY="5" />
</GeometryGroup>
</Path.Data>
</Path>

You may use two Paths in a Canvas like these:
<Canvas>
<Path Fill="Yellow" Data="M0,0 A5,5 0 0 0 5,5 L5,75 A5,5 0 0 0 0,80Z"/>
<Path Fill="Red" Data="M5,5 A 5,5 0 0 0 10,0 L10,80 A5,5 0 0 0 5,75Z"/>
</Canvas>
For details, see Path Markup Syntax.

There are several ways. Perhaps the easiest one would be to create a Grid with two Ellipse elements that overlay the yellow and red parts:
<Grid Width="50" Height="200">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Background="Yellow" />
<Grid Background="Red" Grid.Column="1" />
<Ellipse Width="50" Height="50" Fill="White" Grid.ColumnSpan="2" VerticalAlignment="Top" Margin="0,-25,0,0" />
<Ellipse Width="50" Height="50" Fill="White" Grid.ColumnSpan="2" VerticalAlignment="Bottom" Margin="0,0,0,-25" />
</Grid>

Related

combine elements on form

I've got two rectangles and an ellipse. How to combine them and use the same animation on new combined element?
<Rectangle Height="100" HorizontalAlignment="Left" Margin="220,235,0,0" Name="rectangle2" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="38" Fill="LightGreen" />
<Ellipse Height="23" HorizontalAlignment="Left" Margin="227,269,0,0" Name="ellipse1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="24" Fill="Yellow" />
<Ellipse Height="17" HorizontalAlignment="Left" Margin="12,266,0,0" Name="ellipse2" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="17" Fill="#FF58FF00" />
If you want fixed size elements, moved relative to each other, then place them in a canvas and use canvas coordinates to position them.
A canvas has a low overhead for rendering as it displays nothing but its child elements, in pixel offsets, and has no complex calculation of margins or rows.
The equivalent of your example is:
<Canvas HorizontalAlignment="Left" Margin="12,235,0,145" Width="246">
<Rectangle Height="100" x:Name="rectangle2" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="38" Fill="LightGreen" Canvas.Left="208" />
<Ellipse Height="23" x:Name="ellipse1" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="24" Fill="Yellow" Canvas.Left="215" Canvas.Top="34" />
<Ellipse Height="17" x:Name="ellipse2" Stroke="Black" StrokeThickness="1" VerticalAlignment="Top" Width="17" Fill="#FF58FF00" Canvas.Top="31" />
</Canvas>
Group into T:Panel.
Usually I'm grouping in Canvas first, then in Viewbox (Fill ot Fit) second.

Bind the height of a Polygon to the StackPanel height

I can't figure how to bind the height of a polygon to the height of my stack panel.
If I wanted to add a rectangle, all I had to do is something like that:
<Rectangle Width="75" >
<Rectangle.Fill>
<SolidColorBrush Color="Red" />
</Rectangle.Fill>
</Rectangle>
This one won't brake the height of the panel. but with the polygon it seems like I can't leave some of the points as blank so that will scale with the parent panel.
Thanks
Wrap your polygon with a <Viewbox>.
The Viewbox automatically scales its content to its size. Exactly how it does so can be tweaked with the Stretch and StretchDirection properties.
this solution works too
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Black" BorderThickness="1,1,0,1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="TextBlock1" Margin="2" />
<TextBlock Text="TextBlock2" Margin="2" />
<TextBlock Text="TextBlock3" Margin="2" />
<TextBlock Text="TextBlock4" Margin="2" />
<TextBlock Text="TextBlock5" Margin="2" />
</StackPanel>
</Border>
<Path Fill="Yellow" Stroke="Black" StrokeThickness="1"
Width="50" Stretch="Fill">
<Path.Data>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="1,0.5">
<LineSegment Point="0,0" IsSmoothJoin="True" />
<LineSegment Point="0,1" IsSmoothJoin="True" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</StackPanel>
</Grid>

Vertical aligning content of PathListBox

I have a control containing a PathListBox from Blend SDK (see XAML below). The items inside are of identical width and various height. Currently, the midpoint of the items follow the arc's path (see the picture) i.e. they are clearly vertically arranged 'center'. However, I would like the items 'top' vertically aligned, so their top follows the arc's path. How can I do that?
<Grid x:Name="LayoutRoot">
<ec:PathListBox Margin="160,290,-30,-250">
<ec:PathListBox.LayoutPaths>
<ec:LayoutPath SourceElement="{Binding ElementName=arc}"
Padding="-25" FillBehavior="NoOverlap"
Distribution="Even" Span="0.5"/>
</ec:PathListBox.LayoutPaths>
<Rectangle Fill="#FFF4F4F5" Height="103" Width="100"/>
<Rectangle Fill="#FFF4F4F5" Height="120" Width="100"/>
<Rectangle Fill="#FFF4F4F5" Height="140" Width="100"/>
<Rectangle Fill="#FFF4F4F5" Height="265" Width="100"/>
<Rectangle Fill="#FFF4F4F5" Height="100" Width="100"/>
<Rectangle Fill="#FFF4F4F5" Height="265" Width="100"/>
</ec:PathListBox>
<ed:Arc x:Name="arc"
ArcThickness="10" ArcThicknessUnit="Pixel" Margin="160,290,-30,-250"
Stretch="None" Stroke="Transparent" StartAngle="-7"
RenderTransformOrigin="0.5,0.5" StrokeThickness="3"
Opacity="0.155" Fill="LightGray">
<ed:Arc.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="1" ScaleX="-1"/>
<SkewTransform AngleY="-17" AngleX="-16"/>
<RotateTransform Angle="0"/>
<TranslateTransform/>
</TransformGroup>
</ed:Arc.RenderTransform>
</ed:Arc>
</Grid>
Just change margins of your rects:
...
<Rectangle Fill="Green" Height="103" Width="100" Margin="0,130,0,0"/>
<Rectangle Fill="Green" Height="120" Width="100" Margin="0,120,0,0"/>
<Rectangle Fill="Green" Height="140" Width="100" Margin="0,140,0,0"/>
<Rectangle Fill="Green" Height="265" Width="100" Margin="0,265,0,0"/>
<Rectangle Fill="Green" Height="100" Width="100" Margin="0,100,0,0"/>
<Rectangle Fill="Green" Height="265" Width="100" Margin="0,265,0,0"/>
...
I'm after trying it myself on Blend4 and it works.

How to make clipping geometry scale with the target?

In the following example whenever Grid size is changed, the clipping region size remains as it is expressed in absolute coordinates.
<Grid Clip="M10,10 L10,150 L150,150 L150,10 Z">
<Rectangle Fill="Red"/>
</Grid>
Is is possible somehow to clip the region such that the clipping geometry is scaled along with the clipped object?
Code behind solutions are not accepted, because this is to be used in the control template. Also, the region in the example is a simple shape for clarity sake. The actual used region is a complex and asymmetric shape.
EDIT:
It looks like I have to be more specific. This is the snipped that is part of custom control template for ProgressBar. When scaling the outer grid, the PART_Indicator rectangle does not scale its clipping region. The correct composition is when grid is sized 200x200.
<Grid>
<Path Name="PART_Track"
Data="M100,0 A100,100 0 1 0 100,200 A100,100 0 1 0 100,0 Z"
Fill="AliceBlue" Stretch="Fill"/>
<Rectangle Clip="M100,0 A100,100 0 1 0 100,200 A100,100 0 1 0 100,0 Z"
Stretch="Fill"
Name="PART_Indicator" Fill="Red"
Height="100" VerticalAlignment="Top"/>
<Path Name="Border" Data="M100,0 A100,100 0 1 0 100,200 A100,100 0 1 0 100,0 Z"
Stretch="Fill" StrokeThickness="3" Stroke="Black"/>
</Grid>
UPDATE:
Rick provided excellent suggestion, though it took time for me to understand how to use it.
Here is the final code.
<Viewbox StretchDirection="Both" Stretch="Fill" >
<Grid>
<Path Name="PART_Track"
Data="M100,0 A100,100 0 1 0 100,200 A100,100 0 1 0 100,0 Z"
Fill="AliceBlue" Stretch="Fill"/>
<Border Clip="M100,0 A100,100 0 1 0 100,200 A100,100 0 1 0 100,0 Z"
Height="200" VerticalAlignment="Bottom">
<Rectangle Name="PART_Indicator" Fill="Red" VerticalAlignment="Bottom"
Height="40"/>
</Border>
<Path Name="Border"
Data="M100,0 A100,100 0 1 0 100,200 A100,100 0 1 0 100,0 Z"
StrokeThickness="3"
Stretch="Fill" Stroke="Black"/>
</Grid>
</Viewbox>
Put the Grid inside of a Viewbox and change the size of the Viewbox instead of the Grid.
<Viewbox>
<Grid Clip="M10,10 L10,150 L150,150 L150,10 Z" Width="200" Height="200">
<Rectangle Fill="Red"/>
</Grid>
</Viewbox>
An alternative approach to this is to define the clipping path using element rather than attribute syntax, and then use the same transformation on the clip as you apply to the element as a whole, e.g.:
<Grid.Clip>
<PathGeometry FillRule="Nonzero" Transform="{Binding Path=MatrixTransform, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}">
<PathFigure StartPoint="715, 96.3333" IsClosed="True" IsFilled="True">
<PolyLineSegment IsStroked="False">
<PolyLineSegment.Points>
<Point X="1255.2526" Y="540" />
<Point X="426.3333" Y="1342.3333" />
<Point X="64.66666" Y="7356.6666" />
</PolyLineSegment.Points>
</PolyLineSegment>
</PathFigure>
</PathGeometry>
</Grid.Clip>

Path with broken shadow effect

I hope that it is clear enough in the image, I have a triangle with shadow effect that doesn't look so good, seems to be broken somehow.
Any help will be greatly appreciated.
(Update: the rectangle and the path have to be separated)
XAML:
<Grid Height="50" Width="60" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="1" Stroke="Black" Fill="White">
<Rectangle.Effect>
<DropShadowEffect Opacity="0.5" ShadowDepth="4" BlurRadius="10" />
</Rectangle.Effect>
</Rectangle>
<Path Fill="White" Stretch="Fill" Stroke="Black" HorizontalAlignment="Left" Margin="0,15,-1,15"
Data="M44.386378,164.8791 L22.983157,171.42119 44.713478,176.58567" Width="23.167">
<Path.Effect>
<DropShadowEffect BlurRadius="10" Opacity="0.5" ShadowDepth="4" />
</Path.Effect>
</Path>
</Grid>
</Grid>
On your triangle:
Remove the Margin
Set the Path height explicitly ("22" is pretty close what you have there).
That should prevent the triangle's shadow from being clipped.
Here's the xaml for that:
<Grid Height="50" Width="60" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="1" Stroke="Black" Fill="White" >
<Rectangle.Effect>
<DropShadowEffect Opacity="0.5" ShadowDepth="4" BlurRadius="10" />
</Rectangle.Effect>
</Rectangle>
<Path Fill="White" Stretch="Fill" Stroke="Black" HorizontalAlignment="Left"
Data="M44.386378,164.8791 L22.983157,171.42119 44.713478,176.58567" Width="23.167" Height="22">
<Path.Effect>
<DropShadowEffect BlurRadius="10" Opacity="0.5" ShadowDepth="4" />
</Path.Effect>
</Path>
</Grid>
The problem is you have two separate elements each with a drop shadow. You cannot expect their shadows to join up nicely, the 'blur' is applied separately to each element. Try combining your rectangle and triangle into a single path. e.g.
<Path Fill="White" Stretch="Fill" Stroke="Black" HorizontalAlignment="Left" Margin="0,15,-1,15"
Data="M 0,0 L 100,0 L 100,400 L 0,400 L 0,300 L -50, 200 L 0, 100 L 0,0">
<Path.Effect>
<DropShadowEffect BlurRadius="10" Opacity="0.5" ShadowDepth="4" />
</Path.Effect>
</Path>

Resources