How to make clipping geometry scale with the target? - wpf

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>

Related

How can I draw this shape in xaml 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>

wpf Why is this path being scaled weirdly?

Can someone tell me why the purple path is not to the same scale as the second path? They are set in the control template for togglebutton, shown below. In addition, you can see the result here:
http://picpaste.com/weird_path-nxRoeKjb.jpg
<Grid x:Name="ToggleButtonGrid"
Background="Navy"
>
<Path x:Name="ExpandPath"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Fill"
Fill="Gray"
Stroke="Purple"
Data="M 0 0 L 12 0 L 12 12 L 0 12 Z" />
<Path
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="Gray"
Stretch="Fill"
Stroke="Yellow"
Data="M 0 6 L 12 6 Z" />
</Grid>
which is then set in the controltemplate for the treeview. I don't see why it is being resized. Both of them are just contained in a grid. I would expect the grid to resize, but I am getting this
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="TreeViewExpanderColumn" MinWidth="19"
Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander"
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding Path=IsExpanded,
RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"/>
<Border Name="Bd"
Grid.Column="1"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0"
Padding="0">
<ContentPresenter x:Name="PART_Header"
ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Border>
<ItemsPresenter
x:Name="ItemsHost"
Margin="-19,0,0,0"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="2"/>
It was an issue with using a Path to draw a line and some scaling. Not sure what was going on, but using a Line instead fixed it.
<Path
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Fill"
Fill="Gray"
Stroke="White"
Data="M 0 0 L 12 0 L 12 12 L 0 12 Z" />
<Line
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="Gray"
X1="0"
Y1="0"
X2="12"
Y2="0"
Stroke="White"
/>
<Line x:Name="VerticalCrossBar"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Fill="Gray"
X1="0"
Y1="0"
X2="0"
Y2="12"
Stroke="White"
/>

WPF does not align path properly at run time

I have a 16x16 vector drawn up in Expression Design that I imported in to Blend and used in a control template. Here's the XAML:
<ControlTemplate x:Key="CircularButtonTemplate" TargetType="{x:Type Button}">
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Layer_1" Width="16" Height="16" Canvas.Left="0" Canvas.Top="0">
<Ellipse x:Name="_circle" Width="15.0208" Height="15.0208" Canvas.Left="0.375033" Canvas.Top="0.479169" Stretch="Fill" Fill="#FF666666" />
<Path x:Name="_darkShadow" Width="14.727" Height="14.686" Canvas.Left="0.232" Canvas.Top="0.357" StrokeThickness="3" StrokeLineJoin="Round" Stroke="Black" Data="M 2.02083,8.03473L 13.7501,8.03473M 7.84484,2.14584L 7.84484,13.8333"/>
<Path x:Name="_lightShadow" Width="14.727" Height="14.686" Canvas.Left="0.857" Canvas.Top="0.732" StrokeThickness="3" StrokeLineJoin="Round" Stroke="#FFABABAB" Data="M 2.02083,8.03473L 13.7501,8.03473M 7.84484,2.14584L 7.84484,13.8333"/>
<Path x:Name="_plus" Width="14.7292" Height="14.6875" Canvas.Left="0.520833" Canvas.Top="0.645836" StrokeThickness="3" StrokeLineJoin="Round" Stroke="#FFFFFFFF" Data="M 2.02083,8.03473L 13.7501,8.03473M 7.84484,2.14584L 7.84484,13.8333"/>
</Canvas>
While Blend and Exp Design shows image neatly, at run time, the + sign in the center does not align properly when applied to a button:
How do I fix this?
Try setting UseLayoutRounding="True" on the Canvas.
Just needed to tweak that generated code it gave you to give more defined values. Try this.
<Canvas x:Name="Layer_1" Width="16" Height="16" VerticalAlignment="Center" HorizontalAlignment="Center">
<Ellipse x:Name="_circle" Width="16" Height="16" Stretch="Fill" Fill="#FF666666" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Path x:Name="_darkShadow" Width="16" Height="16" StrokeThickness="3" Stroke="Black" Data="M 2.02083,8.03473L 13.7501,8.03473M 7.84484,2.14584L 7.84484,13.8333" HorizontalAlignment="Center" VerticalAlignment="Center" UseLayoutRounding="False" Canvas.Left="-0.5" Canvas.Top="-0.5"/>
<Path x:Name="_lightShadow" Width="16" Height="16" StrokeThickness="3" Stroke="#FFABABAB" Data="M 2.02083,8.03473L 13.7501,8.03473M 7.84484,2.14584L 7.84484,13.8333" Canvas.Left="-0.5" Canvas.Top="-0.5" Visibility="Collapsed"/>
<Path x:Name="_plus" Width="14" Height="14" StrokeThickness="3" Stroke="#FFFFFFFF" Data="M 2.02083,8.03473L 13.7501,8.03473M 7.84484,2.14584L 7.84484,13.8333" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Canvas>

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>

In pure XAML, is it possible to get a Line to align to part of a Grid?

Is it possible to create a Line in XAML (without any C# code behind) to align a line inside of a layout container such as a Grid?
I'd like to effectively have:
<Grid>
<Line StrokeThickness="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Stroke="Red"/>
</Grid>
I need to use StrokeDashArray and StrokeDashOffset, otherwise I would just use a Border control with the BorderThickness set to "0,0,0,1"...
Thanks for any ideas!
To elaborate on kanchirk's response, this works for me:
<Path StrokeThickness="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Data="M0,0 L1,0"
Stretch="Fill"
StrokeEndLineCap="Square"
StrokeStartLineCap="Square"
Stroke="Red"/>
You can also the same thing with a Line:
<Line StrokeThickness="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
X2="1"
Stretch="Fill"
StrokeEndLineCap="Square"
StrokeStartLineCap="Square"
Stroke="Red"/>
I think you need to use Path like this
<Grid x:Name="LayoutRoot" Background="White">
<Path Fill="Red" Stretch="Fill" Stroke="Black" StrokeDashArray="1" Height="4" Margin="8,0,7,7" VerticalAlignment="Bottom" UseLayoutRounding="False" Data="M8,127 L457,127" StrokeThickness="13"/>
</Grid>
Hope this Helps. Expression Blend is a must have for this kind of Challenges or even VS 2010 RC1 (For now)
How about this?
<Line x:Name="line"
StrokeThickness="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Stroke="Red"
X2="{Binding ActualWidth, ElementName=line, Mode=OneWay}"
Stretch="Fill"
StrokeStartLineCap="Square"
StrokeEndLineCap="Square"/>

Resources