How can I create a brush (DrawingBrush) for stripes as shown in the blog:
http://blog.pixelingene.com/2008/09/quick-tip-to-get-a-striped-background/
I can't use it because it uses scale transform, which means if the UI element is small, the stripes are pretty much not visible or too close together.
I can't use image brush because I need to bind the colors.
Just use MappingMode="Absolute":
<LinearGradientBrush MappingMode="Absolute" x:Key="HatchBrush" StartPoint="0,0" EndPoint="4,4" SpreadMethod="Repeat">
<GradientStop Offset="0" Color="LightCoral"/>
<GradientStop Offset="0.75" Color="LightCoral"/>
<GradientStop Offset="0.75" Color="Gray"/>
<GradientStop Offset="1" Color="Gray"/>
</LinearGradientBrush>
Creates downward 45 degree angle stripe pattern.
Alter viewport to change size of stripes
<DrawingBrush Stretch="UniformToFill" ViewportUnits="Absolute" Viewport="0,0,10,10" TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="Black">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="100,0"/>
<LineSegment Point="100,100"/>
<LineSegment Point="0,100"/>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FF404040">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="25,0"/>
<LineSegment Point="100,75"/>
<LineSegment Point="100,100"/>
<LineSegment Point="75,100"/>
<LineSegment Point="0,25"/>
<LineSegment Point="0,0"/>
</PathFigure>
<PathFigure StartPoint="75,0">
<LineSegment Point="100,25"/>
<LineSegment Point="100,0"/>
</PathFigure>
<PathFigure StartPoint="0,75">
<LineSegment Point="25,100"/>
<LineSegment Point="0,100"/>
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
Alternatively you could bind the scale transform to the height and width of the control using multibinding. Then with a converter, you alter the scale to the max of height or width, then the stripes will remain the same size.
Related
<Style x:Key="ICON" TargetType="Rectangle">
<Setter Property="Fill">
<Setter.Value>
<DrawingBrush TileMode="None">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Gray" Geometry="F1M19.5625,0.999954C29.8144,0.999954 38.125,9.31053 38.125,19.5625 38.125,29.8142 29.8143,38.1249 19.5625,38.1249 9.31073,38.1249 1,29.8142 1,19.5625 1,9.31053 9.31064,0.999954 19.5625,0.999954z">
<GeometryDrawing.Pen>
<Pen DashCap="Square" EndLineCap="Flat" LineJoin="Round" MiterLimit="10" StartLineCap="Flat" Thickness="2">
<Pen.Brush>
<LinearGradientBrush EndPoint="0.849422,0.849423" StartPoint="0.150577,0.150578">
<GradientStop Color="#FF657783" Offset="0"/>
<GradientStop Color="White" Offset="0.146"/>
<GradientStop Color="#FF2C4758" Offset="1"/>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle/>
</Pen.DashStyle>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
<DrawingGroup>
<GeometryDrawing Brush="Gray" Geometry="F1 M0,25 L25,50, 50,25 25,0z">
<GeometryDrawing.Pen>
<Pen DashCap="Triangle" EndLineCap="Flat" LineJoin="Bevel" MiterLimit="10" StartLineCap="Flat" Thickness="5">
<Pen.Brush>
<LinearGradientBrush>
<GradientStop Color="#FF657783" Offset="0"/>
<GradientStop Color="White" Offset="0.5"/>
<GradientStop Color="#FF2C4758" Offset="1"/>
</LinearGradientBrush>
</Pen.Brush>
<Pen.DashStyle>
<DashStyle/>
</Pen.DashStyle>
</Pen>
</GeometryDrawing.Pen>
</GeometryDrawing>
<DrawingGroup.Transform>
<TranslateTransform X="0.2" Y="0.2" />
</DrawingGroup.Transform>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Setter.Value>
</Setter>
</Style>
The inner icon should dominate the outer icon but here, its happening the reverse. My initial guess is that transform is not working but on further observation, I feel that the code is written correctly. Can anyone point out whats the mistake here?
It's working, but you should adjust it properties a little. So the code should look like this. Also I've added code for scaling romb.
<DrawingGroup.Transform>
<TransformGroup>
<TranslateTransform X="12" Y="12" />
<ScaleTransform ScaleX="0.75" ScaleY="0.75" />
</TransformGroup>
</DrawingGroup.Transform>
I'm struggling with some WPF performance issues. The Ants profiler and dotTrace both show that all the time is deep in the WPF internals. I have a number of DrawingBrush objects presently in use. The old WpfPerf.exe shows that my DrawingBrush objects are being rendered on the CPU instead of the GPU. Is there something I can do to change that? Below is an example of one. Why does it render CPU-side?
<DataTemplate DataType="mapViewModel:ObstacleVM" x:Key="ObstacleShapeTemplate">
<Path Stroke="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}" StrokeThickness="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=1}" StrokeLineJoin="Bevel" StrokeEndLineCap="Square" StrokeStartLineCap="Flat">
<Path.Fill>
<DrawingBrush Stretch="Uniform" ViewportUnits="Absolute" TileMode="Tile">
<DrawingBrush.Transform>
<ScaleTransform ScaleY="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=5}" />
</DrawingBrush.Transform>
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeFillBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="1,0" />
<LineSegment Point="1,1" />
<LineSegment Point="0,1" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="0,.33" />
<LineSegment Point="1,.33" />
<LineSegment Point="1,0" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Path.Fill>
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="{Binding Figures, FallbackValue={StaticResource DefaultFigures}}" />
</Path.Data>
</Path>
</DataTemplate>
After reading around further, I found some sources suggesting the use of VisualBrish instead. Indeed, I tried this and it seems to fix it (again, according to WpfPerf.exe).
<DataTemplate DataType="mapViewModel:ObstacleVM" x:Key="ObstacleShapeTemplate">
<Path Stroke="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}" StrokeThickness="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=1}" StrokeLineJoin="Bevel" StrokeEndLineCap="Square" StrokeStartLineCap="Flat">
<Path.Fill>
<VisualBrush Stretch="Uniform" ViewportUnits="Absolute" TileMode="Tile">
<VisualBrush.Transform>
<ScaleTransform ScaleY="{Binding WorldAndScreen.MetersPerPixel, Converter={StaticResource Multiplier}, ConverterParameter=5}" />
</VisualBrush.Transform>
<VisualBrush.Visual>
<Image Stretch="None">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeFillBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="1,0" />
<LineSegment Point="1,1" />
<LineSegment Point="0,1" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="{DynamicResource Mobius.UI.Resources.Colors.ObstacleShapeOutlineBrush}">
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="Nonzero">
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment Point="0,.33" />
<LineSegment Point="1,.33" />
<LineSegment Point="1,0" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</VisualBrush.Visual>
</VisualBrush>
</Path.Fill>
<Path.Data>
<PathGeometry FillRule="Nonzero" Figures="{Binding Figures, FallbackValue={StaticResource DefaultFigures}}" />
</Path.Data>
</Path>
</DataTemplate>
It's not too hard to track down how to programmatically convert path strings into path objects in WPF, but is there a built-in function to convert a geometry or path back to a string in the mini-language?
Edit: Looking at this just now i thought that there should be a class called GeometryConverter which should be able to do this, and indeed there is. Just create one of those and use ConvertToString on the geometry you want to convert.
You can use the XamlWriter class to output objects as XAML, geometry will automatically be reduced to the mini-language.
e.g. if this is your input:
<DrawingImage x:Name="segmentsDrawing">
<DrawingImage.Drawing>
<DrawingGroup>
<GeometryDrawing Brush="Red">
<GeometryDrawing.Pen>
<Pen Brush="Black" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PathFigure.Segments>
<LineSegment Point="100,0"/>
<ArcSegment Point="186.6,150" SweepDirection="Clockwise" Size="100,100"/>
<LineSegment Point="100,100"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="Blue">
<GeometryDrawing.Pen>
<Pen Brush="Black"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PathFigure.Segments>
<LineSegment Point="186.6,150"/>
<ArcSegment Point="13.4,150" SweepDirection="Clockwise" Size="100,100"/>
<LineSegment Point="100,100"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="Green">
<GeometryDrawing.Pen>
<Pen Brush="Black"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure StartPoint="100,100">
<PathFigure.Segments>
<LineSegment Point="13.4,150"/>
<ArcSegment Point="100,0" SweepDirection="Clockwise" Size="100,100"/>
<LineSegment Point="100,100"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
...and you serialize it...
XmlTextWriter writer = new XmlTextWriter(#"C:\Users\Public\Test.xml", new UTF8Encoding());
writer.Formatting = Formatting.Indented;
writer.Indentation = 1;
writer.IndentChar = '\t';
XamlWriter.Save(segmentsDrawing, writer);
...you get the following:
<DrawingImage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Brush="#FFFF0000">
<GeometryDrawing.Pen>
<Pen Brush="#FF000000" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M100,100L100,0A100,100,0,0,1,186.6,150L100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FF0000FF">
<GeometryDrawing.Pen>
<Pen Brush="#FF000000" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M100,100L186.6,150A100,100,0,0,1,13.4,150L100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Brush="#FF008000">
<GeometryDrawing.Pen>
<Pen Brush="#FF000000" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry Figures="M100,100L13.4,150A100,100,0,0,1,100,0L100,100" />
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup.Children>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
All the PathGeometry is now in mini-language. If you want to use this right away in your application i suppose you could write it to a MemoryStream and get the data from it by creating a XmlDocument from it.
I am trying to animate a clipping path. I read from Mask Animations (Clipping Path Animations) In Silverlight Without a Line of Code that I should animate the clipping path 1st so
Data=”M159.67175,104.26108 L177.91812,28.328932 L195.51648,104.43327 L255.0802,102.6104 L206.86984,151.82758 L225.8029,226.56477 L179.0616,179.17046 L129.73396,229.29906 L147.97842,150.63879 L98.650803,101.53297 z”
will be changed to
<Path.Data>
<PathGeometry>
<PathFigure IsClosed=”True” StartPoint=”91.0527648925781,84.0121078491211?>
<LineSegment Point=”118.057907104492,0.549586236476898?/>
<LineSegment Point=”144.103973388672,84.2013778686523?/>
<LineSegment Point=”232.259979248047,82.1977386474609?/>
<LineSegment Point=”160.907287597656,136.2958984375?/>
<LineSegment Point=”188.928756713867,218.444961547852?/>
<LineSegment Point=”119.750289916992,166.350433349609?/>
<LineSegment Point=”46.7439804077148,221.450408935547?/>
<LineSegment Point=”73.7462997436523,134.989212036133?/>
<LineSegment Point=”0.740016639232636,81.0134506225586?/>
</PathFigure>
</PathGeometry>
</Path.Data>
but after animating the path, my XAML still looks like
<Path x:Name="path" Data="M0.5,0.5 L84.5,0.5 L84.5,150.5 L0.5,150.5 z" HorizontalAlignment="Left" Height="151" Margin="76,55,0,0" Stretch="Fill" Stroke="{x:Null}" VerticalAlignment="Top" Width="85" Fill="Black" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Path.RenderTransform>
</Path>
A short video on the problem http://screenr.com/1Wc
You need to create the clipping path prior to doing the animation.
Then, use the Direct Select tool (the second arrow down on the toolbar in Blend 4) to select the clipping path. Moving the clipping path while recording a timeline will result in the clipping being animated the way you expect.
Here's the XAML from two rectangles - a big one with a linear gradient, and a smaller one that is the clipping path. The clipping rectangle is animated and follows the gradient.
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="WpfSplash.TemplatePanel"
x:Name="UserControl" Height="1000" Width="544">
<UserControl.Resources>
<Storyboard x:Key="OnLoaded1">
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[1].(LineSegment.Point)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="495,184.5"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[2].(LineSegment.Point)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="-14.9999999999998,184.5"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.StartPoint)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="-14.9999999999998,142.5"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Clip).(PathGeometry.Figures)[0].(PathFigure.Segments)[0].(LineSegment.Point)" Storyboard.TargetName="rectangle">
<EasingPointKeyFrame KeyTime="0:0:1" Value="495,142.5"/>
</PointAnimationUsingKeyFrames>
</Storyboard>
</UserControl.Resources>
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource OnLoaded1}"/>
</EventTrigger>
</UserControl.Triggers>
<Canvas x:Name="LayoutRoot">
<Rectangle x:Name="rectangle" Height="207" Canvas.Left="33" Canvas.Top="106.5" Width="481.5">
<Rectangle.Clip>
<PathGeometry>
<PathFigure IsClosed="True" StartPoint="-15,16.5">
<LineSegment Point="495,16.5"/>
<LineSegment Point="495,54"/>
<LineSegment Point="-15,54"/>
</PathFigure>
</PathGeometry>
</Rectangle.Clip>
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFD6904A" Offset="1"/>
<GradientStop Color="#FFEBD8FF"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Canvas>
I'm trying to draw a hand-made DB drum alike shape. The problem is that the top ellipse is not completely filled.
Sample:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image Width="126" Height="42" Margin="3" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Brush="Silver">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="1" LineJoin="Bevel" EndLineCap="Round" StartLineCap="Round" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup FillRule="NonZero">
<EllipseGeometry Center="62,8" RadiusX="62" RadiusY="5" />
<PathGeometry>
<PathFigure StartPoint="0,8" IsClosed="False">
<LineSegment Point="0,38" />
<QuadraticBezierSegment Point1="60,49" Point2="124,38" />
<LineSegment Point="124,8" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Grid>
</Page>
Any alternatives to solve this issue?
Thanks.
Finally... the solution was to make two separate path figures using arc segments:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Image Width="126" Height="42" Margin="3" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Brush="Silver">
<GeometryDrawing.Pen>
<Pen Brush="Black" Thickness="1" LineJoin="Bevel" EndLineCap="Round" StartLineCap="Round" />
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<GeometryGroup x:Key="Drum" FillRule="NonZero">
<PathGeometry>
<PathFigure StartPoint="0,6" IsClosed="True">
<ArcSegment Point="125,6" IsLargeArc="False" IsStroked="True" SweepDirection="Clockwise" Size="15,1.5" />
<ArcSegment Point="0,6" IsLargeArc="False" IsStroked="True" SweepDirection="Clockwise" Size="15,1.5" />
</PathFigure>
</PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,6" IsClosed="True">
<ArcSegment Point="125,6" IsLargeArc="False" IsStroked="True" Size="15,1.5" IsSmoothJoin="True" />
<LineSegment Point="125,35" IsSmoothJoin="True" />
<ArcSegment Point="0,35" IsLargeArc="False" IsStroked="True" SweepDirection="Clockwise" Size="15,1.5" IsSmoothJoin="True" />
<LineSegment Point="0,6" IsSmoothJoin="True" />
</PathFigure>
</PathGeometry>
</GeometryGroup>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</Grid>
</Page>