I recently wanted to create a patterned brush in WPF. Of course, WPF is more than capable of doing hatching patterns, but it took me a little while to work out how to do it, especially since the MSDN2 website seems to have lost all example XAML snippets at the moment.
The approach I chose is to use a VisualBrush, although a DrawingBrush would probably work equally well. In the Visual property of the VisualBrush you add your graphics. So for my examples I have one which just has a circle, allowing you to fill an object with dots, and one with two diagonal lines, to create cross-hatching. Then you need to set some additional properties on the VisualBrush:
- TileMode would be set to Tile as this is a repeating pattern
- Stretch is set to None
- The ViewBox rectangle specifies a window onto the Visual allowing you to select just a part of it. Both my fill pattern visuals were 10x10, but I made the ViewBox for the dot fill 12x12 which effectively added some spacing between the dots.
- The ViewPort rectangle gives more flexibility by specifying the position and dimensions of the first "tile". Normally you would simply set this to the same as the ViewBox, but you could use it to scale the tiled image in X or Y dimensions, or effectively slide the tiles across.
Here's some example XAML:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Page.Resources> <VisualBrush x:Key="DotFillBrush" TileMode="Tile" Viewport="0,0,10,10" ViewportUnits="Absolute" Viewbox="0,0,12,12" ViewboxUnits="Absolute"> <VisualBrush.Visual> <Ellipse Fill="#00C0FF" Width="10" Height="10" /> </VisualBrush.Visual> </VisualBrush> <VisualBrush x:Key="HatchBrush" TileMode="Tile" Viewport="0,0,10,10" ViewportUnits="Absolute" Viewbox="0,0,10,10" ViewboxUnits="Absolute"> <VisualBrush.Visual> <Canvas> <Rectangle Fill="Azure" Width="10" Height="10" /> <Path Stroke="Purple" Data="M 0 0 l 10 10" /> <Path Stroke="Purple" Data="M 0 10 l 10 -10" /> </Canvas> </VisualBrush.Visual> </VisualBrush> </Page.Resources> <Canvas> <Rectangle Canvas.Top="20" Canvas.Left="20" Width="80" Height="40" Fill="{StaticResource DotFillBrush}"/> <Rectangle Canvas.Top="20" Canvas.Left="120" Width="80" Height="40" Fill="{StaticResource HatchBrush}"/> <TextBlock Canvas.Top="80" Canvas.Left="20" Text="Hello" FontSize="80" Foreground="{StaticResource DotFillBrush}"/> <TextBlock Canvas.Top="80" Canvas.Left="220" Text="World" FontSize="80" Foreground="{StaticResource HatchBrush}"/> </Canvas> </Page>
And here's what it looks like:
9 comments:
Unfortunately, Silverlight doesn't have the DrawingBrush or the VisualBrush, which means that so far I have been unable to figure out how to fill in a rectangle with the simplest of patterns instead of a solid color.
Hi Steve, yes it is a shame that Silverlight doesn't have all the features of WPF. Hopefully this will be rectified in future version
When creating diagonal hashes, you are stuck with empty pixels at the corners with this approach. It is more evident if you change your visualbrush to use just a single path at a diagonal (0,10 to 10,-10). You will see what appears to be small gaps at the corners. An alternative way would be to always create the lines vertical or horizontal and set the transform on the brush to be rotate the entire brush.
Hi Mark,
Thanks for this tutorial but unfortunately i couldn't get it working. Maybe i have missed some functions but things like GetNoteYPosition or NoteSeperateBrush variable don't seem to be recognized. You never specified where these were meant to go.
Since i am currently doing some research into how midi works within C#, do you think that it would be possible to put a compressed solution version of the tutorials underneath the tutorial names? If this isn't possible then will you be able to paste the whole xaml and the window code?
Thanks, i would of dropped you an e-mail but it appears that your website doesn't have it on.
Mark
Hi, I was able to do a dot pattern starting from your example and it worked perfectly :D.
VisualBrush vb = new VisualBrush();
vb.TileMode = TileMode.Tile;
vb.Viewport = new Rect(0, 0, 10, 10);
vb.ViewportUnits = BrushMappingMode.Absolute;
vb.Viewbox = new Rect(0, 0, 12, 12);
vb.ViewboxUnits = BrushMappingMode.Absolute;
Ellipse ellipse = new Ellipse();
ellipse.Fill = Brushes.Black;
ellipse.Width = 10;
ellipse.Height = 10;
vb.Visual = ellipse;
return vb;
Thanks!
Thanks Mark - I was looking for a crosshatch and came across your article - it helped a lot!
I was looking for a hatched example to "hatch" a datagrid row based on a DataTrigger and this worked great!!
Thanks...
Also in VB.NET we have it:
Dim MyBrush As New VisualBrush With {.TileMode = TileMode.Tile, .Viewport = New Rect(0, 0, 10, 10), .ViewportUnits = BrushMappingMode.Absolute, .Viewbox = New Rect(0, 0, 12, 12), .ViewboxUnits = BrushMappingMode.Absolute}
MyBrush.Visual = New Ellipse With {.Fill = Brushes.Black, .Width = 10, .Height = 10}
Extremely simple and extremely helpful. Thank you! And my UI thanks you too!
Post a Comment