I am pretty new with WPF design (and design in general), and I need help with one task.
I have a style for a button that contains some data in a Path, which draws an icon on it (basically simple add new icon). Now I would like to make a copy icon out of it.
I could not find a way to manipulate with Path I have in Blend, so what I had in mind was:
1) Copy Path data so we can draw two icons (to have two Path objects in Content)
2) Shift first a little to the left and top
3) Shift second a little to the right and bottom
4) Make second one overlap first one
This is what I did:
Since we cannot have two elements set for Content, I have added one Grid element, and inside I copied Path element twice. Then I repositioned both path to simulate duplicate data.
<Setter Property="Content">
<Setter.Value>
<Grid>
<Path Data="..." Margin="10" Stretch="Fill" Fill="{StaticResource IconBrush}" RenderTransformOrigin="0.5,0.4">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform Angle="-90" />
<TranslateTransform />
</TransformGroup>
</Path.RenderTransform>
</Path>
<Path Data="..." Margin="10" Stretch="Fill" Fill="{StaticResource IconBrush}" RenderTransformOrigin="0.5,0.6">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform Angle="-90" />
<TranslateTransform />
</TransformGroup>
</Path.RenderTransform>
</Path>
</Grid>
</Setter.Value>
</Setter>
Problem: I do not get overlap with second icon (basically everything is transparent. That means that I probsably need to delete some points on first icon, but I could not achieve that in Blend?
Can anyone share some light how to achieve what I need?
Not sure what your icons should look like, but the following XAML will display two overlapping plus signs using the same Path data for both, but with a simple TranslateTransform to offset the second one.
<Grid>
<Path Fill="#FF008000" >
<Path.Data>
<PathGeometry Figures="m 30 25.362188 0 30.000001 -30 0 0 20 30 0 0 29.999991 20 0 0 -29.999991 30 0 0 -20 -30 0 0 -30.000001 -20 0 z" FillRule="nonzero"/>
</Path.Data>
</Path>
<Path Fill="#FF92D050" >
<Path.Data>
<PathGeometry Figures="m 30 25.362188 0 30.000001 -30 0 0 20 30 0 0 29.999991 20 0 0 -29.999991 30 0 0 -20 -30 0 0 -30.000001 -20 0 z" FillRule="nonzero"/>
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="25" Y="-25"/>
</Path.RenderTransform>
</Path>
</Grid>
I would recommend not putting margins or 'Stretch' properties in your actual path objects. Take care of that in the Grid container they are in, or a containing Viewbox if you need to scale them up or down.
EDIT
If you are actually using the Fill property of the Path object to draw the icon geometry, as with a VisualBrush object, instead of the Path.Data, then you don't want to use a Path in the first place. Just use two Rectangle objects, with your 'IconBrush' Fill in the grid and do the TranslateTransform on one of them so that they overlap to the desired amount. Remember that with XAML, the object that appears last in the listing is rendered on top.
EDIT 2
<Grid>
<Path Fill="#FFFFFFFF">
<Path.Data>
<PathGeometry Figures="m 13.123027 65.796864 0 81.448876 133.750213 0 0 -133.778725 -67.192062 0 z" FillRule="NonZero"/>
</Path.Data>
</Path>
<Path Fill="#FFB3B3B3">
<Path.Data>
<PathGeometry Figures="M 79.624708 0.36218262 0 62.950511 l 0 97.411669 160 0 0 -159.99999738 -80.375292 0 z m 2.28303 16.89635038 61.172792 0 0 126.207297 -126.161061 0 0 -76.829978 0.187646 -0.156158 64.800623 0 0 -49.221161 z" FillRule="NonZero"/>
</Path.Data>
</Path>
<Path Fill="#FFFFFFFF">
<Path.Data>
<PathGeometry Figures="m 13.123027 65.796864 0 81.448876 133.750213 0 0 -133.778725 -67.192062 0 z" FillRule="NonZero"/>
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="30" Y="30"/>
</Path.RenderTransform>
</Path>
<Path Fill="#FFB3B3B3">
<Path.Data>
<PathGeometry Figures="M 79.624708 0.36218262 0 62.950511 l 0 97.411669 160 0 0 -159.99999738 -80.375292 0 z m 2.28303 16.89635038 61.172792 0 0 126.207297 -126.161061 0 0 -76.829978 0.187646 -0.156158 64.800623 0 0 -49.221161 z" FillRule="NonZero"/>
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="30" Y="30"/>
</Path.RenderTransform>
</Path>
</Grid>
The above XAML is probably way too big for your needs. You can just put the whole grid in a Viewbox and then set the Height and Width properties of the Viewbox to get it to the size you need.
EDIT 3
Custom button style:
<Style x:Key="btnCustom" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Viewbox>
<Grid Margin="0,0,30,30">
<Path Fill="#FFFFFFFF">
<Path.Data>
<PathGeometry Figures="m 13.123027 65.796864 0 81.448876 133.750213 0 0 -133.778725 -67.192062 0 z" FillRule="NonZero"/>
</Path.Data>
</Path>
<Path Fill="#FFB3B3B3">
<Path.Data>
<PathGeometry Figures="M 79.624708 0.36218262 0 62.950511 l 0 97.411669 160 0 0 -159.99999738 -80.375292 0 z m 2.28303 16.89635038 61.172792 0 0 126.207297 -126.161061 0 0 -76.829978 0.187646 -0.156158 64.800623 0 0 -49.221161 z" FillRule="NonZero"/>
</Path.Data>
</Path>
<Path Fill="#FFFFFFFF">
<Path.Data>
<PathGeometry Figures="m 13.123027 65.796864 0 81.448876 133.750213 0 0 -133.778725 -67.192062 0 z" FillRule="NonZero"/>
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="30" Y="30"/>
</Path.RenderTransform>
</Path>
<Path Fill="#FFB3B3B3">
<Path.Data>
<PathGeometry Figures="M 79.624708 0.36218262 0 62.950511 l 0 97.411669 160 0 0 -159.99999738 -80.375292 0 z m 2.28303 16.89635038 61.172792 0 0 126.207297 -126.161061 0 0 -76.829978 0.187646 -0.156158 64.800623 0 0 -49.221161 z" FillRule="NonZero"/>
</Path.Data>
<Path.RenderTransform>
<TranslateTransform X="30" Y="30"/>
</Path.RenderTransform>
</Path>
</Grid>
</Viewbox>
</Setter.Value>
</Setter>
</Style>
Button implementation:
<Button HorizontalAlignment="Right" Style="{StaticResource btnCustom}"
Height="30" Width="100"/>
What it looks like in the WPF Window:
Related
I'm making an app that is a venn diagram and I don't know how to do the first step. There are to ellipses and I want to color the shared area of two ellipses.
The green area is the shared area I meant.
You can use intersect mode on a combinedgeometry to find the parts overlap:
<Grid>
<Grid.Background>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<Canvas>
<Path Fill="Yellow">
<Path.Data>
<EllipseGeometry Center="150,50" RadiusX="75" RadiusY="75" />
</Path.Data>
</Path>
<Path Fill="Yellow">
<Path.Data>
<EllipseGeometry Center="50,50" RadiusX="75" RadiusY="75" />
</Path.Data>
</Path>
<Path Fill="Green">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Intersect">
<CombinedGeometry.Geometry1>
<EllipseGeometry Center="150,50" RadiusX="75" RadiusY="75"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="50,50" RadiusX="75" RadiusY="75"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
Position textblocks in the grid on top of the background shapes using rows and columns.
Or just put everything in a canvas rather than using a visualbrush.
Use Canvas.Left and Canvas.Top to position some textblocks on top of the ellipses.
The problem: how can I design button, which inherits Foreground from its parent, but allows changing it via style?
More precisely, given following button:
<StackPanel TextBlock.Foreground="Red">
<ToggleButton Width="16" Height="16" FontSize="10" Style="{StaticResource ...}">
<Grid>
<Path Width="8" Height="8" Fill="...">
<Path.Data>
<PathGeometry Figures="M 1 0 L 1 4 L 0 4 L 0 5 L 3 5 L 3 8 L 4 8 L 4 5 L 7 5 L 7 4 L 6 4 L 6 0 L 1 0 z M 2 1 L 4 1 L 4 4 L 2 4 L 2 1 z " FillRule="NonZero"/>
</Path.Data>
</Path>
</Grid>
</ToggleButton>
</StackPanel>
I need, that:
Path's fill color matches StackPanel's current Foreground color, and
When user hovers mouse over the button, path's fill color becomes some specific, constant color.
I tried designing style for button, including the ControlTemplate, but there's a problem with Foreground. Button has its Foreground property set to some DynamicResource via theme, so it doesn't match StackPanel's Foreground.
Obviously I can bind it, but then style and control template triggers stops working, because I've set an immediate value to a dependency property, what overrules all other means of providing value to it.
To give a context to the problem, this is what I want to achieve:
You could bind to the attached TextBlock.Foreground of the ToggleButton's parent Panel like this:
<Path Width="8" Height="8"
Fill="{Binding (TextBlock.Foreground),
RelativeSource={RelativeSource AncestorType=Panel, AncestorLevel=2}}">
...
If you want the Fill to change on mouse over, you could define a Style with a DataTrigger:
<StackPanel TextBlock.Foreground="Red">
<ToggleButton Width="16" Height="16" FontSize="10">
<Grid>
<Path Width="8" Height="8">
<Path.Data>
<PathGeometry Figures="M 1 0 L 1 4 L 0 4 L 0 5 L 3 5 L 3 8 L 4 8 L 4 5 L 7 5 L 7 4 L 6 4 L 6 0 L 1 0 z M 2 1 L 4 1 L 4 4 L 2 4 L 2 1 z "
FillRule="NonZero"/>
</Path.Data>
<Path.Style>
<Style TargetType="Path">
<Setter Property="Fill" Value="{Binding (TextBlock.Foreground),
RelativeSource={RelativeSource AncestorType=Panel, AncestorLevel=2}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseOver,
RelativeSource={RelativeSource AncestorType=ToggleButton}}" Value="True">
<Setter Property="Fill" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Grid>
</ToggleButton>
</StackPanel>
I figured it out by myself - I forgot, that style setters may set bindings as well. The solution is following.
Style:
<Style TargetType="ButtonBase" x:Key="DocumentTabButtonStyle">
<Style.Setters>
<Setter Property="TextBlock.Foreground" Value="{Binding Path=(TextBlock.Foreground), RelativeSource={RelativeSource AncestorType=StackPanel}}" />
<Setter Property="Template">
...
</Setter>
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextBlock.Foreground" Value="{StaticResource DocumentButtonHoverForegroundBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
Button:
<Button Style="{StaticResource DocumentTabButtonStyle}">
<Path Fill="{Binding Path=(TextBlock.Foreground), RelativeSource={RelativeSource AncestorType={x:Type Button}}}">
<Path.Data>
<PathGeometry Figures="M 0 1 L 3 4 L 0 7 L 2 7 L 4 5 L 6 7 L 8 7 L 5 4 L 8 1 L 6 1 L 4 3 L 2 1 Z" />
</Path.Data>
</Path>
</Button>
I'm trying to draw a circle with perfect X mark.
I managed to draw a circle with half of the X mark. I'm not sure how to draw the second half.
Thank you
<Path Stroke="Black"
StrokeThickness="4" Fill="Red" VerticalAlignment="Center" HorizontalAlignment="Center">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0">
<PathFigure.Segments>
<LineSegment Point="100,100" />
<ArcSegment Size="50,50"
RotationAngle="45"
IsLargeArc="True"
SweepDirection="Clockwise"
Point="0,0" />
<ArcSegment Size="50,50"
RotationAngle="45"
IsLargeArc="True"
SweepDirection="Clockwise"
Point="100,100" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
You can "simplify" this, or at least make it take up less space in the XAML editor, by using Path Markup Syntax. The portion of Data before the blank line reproduces what you've already got: M for "move", L for "line to", A for "arc". The "Move" and "Line To" commands after the blank line add the second line.
<Path
Stroke="Black"
StrokeThickness="4"
Fill="Red"
Data="
M 0,0
L 100,100
A 50,50 45 1 1 0,0
A 50,50 45 1 1 100,100
M 100,0
L 0,100"
/>
You don't need to format it with newlines like that; I just inserted the newlines to clarify how it maps onto your version. Fortunately, you added the attributes to your ArcSegment elements in the same order as the corresponding arguments to A in the markup syntax.
This is how it's usually done, though it's arguably less readable:
Data="M 0,0 L 100,100 A 50,50 45 1 1 0,0 A 50,50 45 1 1 100,100 M 100,0 L 0,100"
Alternatively, to finish it the same way you started, just add the second line as another PathFigure:
<Path
Stroke="Black"
StrokeThickness="4"
Fill="Red"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="0,0">
<PathFigure.Segments>
<LineSegment Point="100,100" />
<ArcSegment
Size="50,50"
RotationAngle="45"
IsLargeArc="True"
SweepDirection="Clockwise"
Point="0,0"
/>
<ArcSegment
Size="50,50"
RotationAngle="45"
IsLargeArc="True"
SweepDirection="Clockwise"
Point="100,100"
/>
</PathFigure.Segments>
</PathFigure>
<!-- Second line -->
<PathFigure StartPoint="100,0">
<PathFigure.Segments>
<LineSegment Point="0,100" />
</PathFigure.Segments>
</PathFigure>
<!-- /Second line -->
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
use this...https://materialdesignicons.com/
<Viewbox Width="48" Height="48">
<Canvas Width="24" Height="24">
<Path Data="M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22C17.53,22 22,17.53 22,12C22,6.47 17.53,2 12,2M14.59,8L12,10.59L9.41,8L8,9.41L10.59,12L8,14.59L9.41,16L12,13.41L14.59,16L16,14.59L13.41,12L16,9.41L14.59,8Z" Fill="Black" />
</Canvas>
I have this ellipse:
<Ellipse Name="backgroundEllipse1" Fill="Pink">
<Ellipse.Clip>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<EllipseGeometry x:Name="backgroundEllipseMask1" Center="150,150" RadiusX="300" RadiusY="300"></EllipseGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry x:Name="backgroundEllipseMask2" Center="150,150" RadiusX="130" RadiusY="130"></EllipseGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Ellipse.Clip>
</Ellipse>
How can I make something like this?
I'm trying to combine the center and Radius values but something escapes me.
You need an ArcSegment
<Canvas>
<Path Stroke="Pink" StrokeThickness="10" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="400,400">
<ArcSegment IsLargeArc="True"
Size="100, 100"
Point="480, 410"
SweepDirection="Counterclockwise" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
Note that the arc starts form (400,400) and ends in (480,410). It moves Counterclockwise and is a large arc. Size="100, 100" determines the size of the Ellipse (or Circle if they are equal) This post can help you.
I encountered following problem during creation of radioactive geometry:
Orange dot represents RadialGradientBrush center point (0,0). It should be in the center of black circle, not on the bottom. This cause another problem: spinning animation.
Is there a way to fix this at the geometry level ? I could fix it by setting brush's center point explicitly, but that is inconvenient and brittle.
<GeometryDrawing>
<GeometryDrawing.Geometry>
<GeometryGroup>
<PathGeometry Figures="
M-10,0 Q0,5 10,0
Q20,25 25,50
Q0,60 -25,50
Q-20,25 -10,0 Z">
<PathGeometry.Transform>
<TranslateTransform Y="15" />
</PathGeometry.Transform>
</PathGeometry>
<PathGeometry Figures="
M-10,0 Q0,5 10,0
Q20,25 25,50
Q0,60 -25,50
Q-20,25 -10,0 Z" >
<PathGeometry.Transform>
<TransformGroup>
<TranslateTransform Y="15" />
<RotateTransform Angle="120" />
</TransformGroup>
</PathGeometry.Transform>
</PathGeometry>
<PathGeometry Figures="
M-10,0 Q0,5 10,0
Q20,25 25,50
Q0,60 -25,50
Q-20,25 -10,0 Z" >
<PathGeometry.Transform>
<TransformGroup>
<TranslateTransform Y="15" />
<RotateTransform Angle="240" />
</TransformGroup>
</PathGeometry.Transform>
</PathGeometry>
<EllipseGeometry RadiusX="10" RadiusY="10" />
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<RadialGradientBrush ColorInterpolationMode="ScRgbLinearInterpolation">
<GradientStop Offset="0" Color="Orange" />
<GradientStop Offset="0.03" Color="Black" />
</RadialGradientBrush>
</GeometryDrawing.Brush>
<GeometryDrawing.Pen>
<Pen Thickness="0">
<Pen.Brush>
<SolidColorBrush Color="Black" />
</Pen.Brush>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
This is caused by the fact that the top of the box cuts off the top of the big circle. It is cut off because the top two petals are rotated.
You could fix this by adding the outer circle (transparent) to the geometry or perhaps by adding a margin to the top.
this will move down the black parts of the drawing, centering the orange dot and fixing the rotation.
Does this make sense? It is hard to explain, when needed I could create a sketch.