Drawing a 2px Hatch brush in WPF - wpf

I'm trying to build a WPF DrawingBrush that will draw a hatch pattern using two 1px by 1px rectangles. The resulting pattern would look like the background on classic Macintosh apps.
Here's what I'm working with:
<Canvas SnapsToDevicePixels="True">
<Canvas.Background>
<DrawingBrush x:Name="gridBackgroundBrush"
Viewport="0,0,10,10"
ViewportUnits="Absolute"
TileMode="Tile">
<DrawingBrush.Drawing>
<DrawingGroup>
<DrawingGroup.Children>
<GeometryDrawing Geometry="M0,0 L10,0 10,10, 0,10Z" Brush="Green"/>
<GeometryDrawing Geometry="M10,10 L20,10 20,20, 10,20Z" Brush="Green" />
</DrawingGroup.Children>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Canvas.Background>
</Canvas>
Everything looks clear and sharp, except that the boxes are way too big. As I adjust the Viewport on the brush, things start to get blurry. It looks like the anti-aliasing is what is killing me; it wants to use 3px to fade from solid green to nothing, which doesn't work when I get to sizes below 3-4px. Is there anything I can do to totally disable the anti-aliasing and do pixel-precise drawing?

Offset the drawing with 0.5px and you'll get rid of the antialiasing effect. It happens because drawing is done on the edge of the pixel offset, rather than on the actual pixel offset that you have specified. By offset'ing X,Y with half a pixel, you tell the drawing engine to draw on the pixel itself, which eliminates the need of antialiasing.
For some reason this doesn't work with gradientbrushes though.
This behaviour is similar to what you have in Quarts drawing on Mac.
Note: It's not the viewport that you should offset, but the actual shape you're drawing when using the specified brush.
For a more complete answer, please read this article.

Related

Refresh an ImageSource efficiently: BitmapImage vs DrawingImage

I have a WPF control with a GeometryModel3D with DiffuseMaterial using an ImageBrush with data bound ImageSource.
My goal is to display a "cross-section" while hovering the mouse, and for that I can already get the proper position on the object. The problem is: There is no "3D Line" in WPF.
I have made a test drawing the line in the image I use for ImageSource and the visual result is exactely what I want.
So I plan to do the following: generate the base image once, and then draw the appropriate line on it, setting the property used as ImageSource.
I have considered two approaches:
Have the bound ImageSource of type BitmapImage. Then I create a System.Drawing.Bitmap once with the blank texture (without the line), and then each time I want the line to change position, I recreate the BitmapImage drawing a line with System.Drawing.Graphics;
Have the bound ImageSource of type DrawingGroup. Then I create a System.Windows.Media.ImageDrawing once, and then each time I want the line to change position, I recreate the DrawingGroup by changing only the GeometryDrawing composed by one single line.
Is there any inherent advantage of one method over the other?
I must admit that I've never actually tested the performance difference, but I know that the Drawing class enables a light-weight way to manipulate basic shapes and images. From the Drawing Class page on MSDN:
Drawing objects are light-weight objects that enable you to add geometric shapes, images, text, and media to an application. Drawing objects are considered light-weight because they do not provide support for Layout, Input Overview, and focus. Because of their performance benefits, drawings are ideal for backgrounds and clip art. You also use drawings when programming at the Visual level.
Conversely, the BitmapImage class has all sorts of additional extra functionality and convenience features built into it, making it less light-weight than the Drawing class. From the Imaging Overview page on MSDN:
BitmapImage is a specialized BitmapSource that is optimized for Extensible Application Markup Language (XAML) loading and is an easy way to display images as the Source of an Image control.
I ended up replacing the old GDI+ based "Graphics over Bitmap and then convert to BitmapImage"
by a very WPF/XAML friendly way of generating the image with a somewhat bulky but actually very straightforward way of stacking "layers" of Drawing objects, with elimination of A LOT of code-behind.
The line itself is a hard-coded one, with its Geometry.Transform.Y property being directly set by events in code-behind using the alturaFatia Name.
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<ImageBrush>
<ImageBrush.ImageSource>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.ClipGeometry>
<RectangleGeometry Rect="{Binding LimitesMapa}" />
</DrawingGroup.ClipGeometry>
<ImageDrawing x:Name="MapaAtivo"
ImageSource="{Binding MapaAtivo}" Rect="{Binding LimitesMapa}"/>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Thickness="2" Brush="Blue"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<LineGeometry>
<LineGeometry.StartPoint>
<Point X="-200" Y="0"/>
</LineGeometry.StartPoint>
<LineGeometry.EndPoint>
<Point X="200" Y="0" />
</LineGeometry.EndPoint>
<LineGeometry.Transform>
<TranslateTransform x:Name="alturaFatia" Y="-200" />
</LineGeometry.Transform>
</LineGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</ImageBrush.ImageSource>
</ImageBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>

Reveal a picture covered with a solid color

I'm trying to build an application that reveals a picture covered initially with a solid color(black). The idea is that when I click somewhere on that black screen (initially) a circular area around the black pixel I clicked to be made transparent so I can see the image behind.
The solution that I came up with is to use a canvas with the picture I want covered set as background. The black cover will be divided in pixels (stored on a matrix perhaps - the image will be maximum 500x500). All those pixels will be colored black initially and then, knowing the pixel the user clicks make transparent (or delete) all pixels around that one until I clear a circular area with a preset diameter.
I don't have much experience with canvases and this solution seems quite rough to me. I wanted ask a second opinion, or if someone can give me a better solution
I'm developing the app in Silverlight, if that's relevant.
Thanks!
After some time I spend reading about silverlight controls I ended up using Image.Clip. Here's an example in case somebody like me needs it:
<Image Source="Images/img.jpg" Width="150" Height="150" Canvas.Left="30" Canvas.Top="19">
<Image.Clip>
<GeometryGroup FillRule="Nonzero">
<EllipseGeometry RadiusX="20" RadiusY="20" Center="100,100"></EllipseGeometry>
<EllipseGeometry RadiusX="20" RadiusY="20" Center="80,100"></EllipseGeometry>
<EllipseGeometry RadiusX="20" RadiusY="20" Center="80,83"></EllipseGeometry>
<EllipseGeometry RadiusX="20" RadiusY="20" Center="60,60"></EllipseGeometry>
</GeometryGroup>
</Image.Clip>
</Image>
Of course, ellipses can be placed programmatic.

XAML Border vs Rectangle

I want to get a window like this
How should i get this and i am confused between Border and Rectangle in XAML.
Border is a container control aos its use is pretty simple to get, what is the use of ractangle as it can't contain any control in it.
Kindly help
Neither Border nor Rectangle will achieve this, you probably need a Path or something similar.
I would like to answer your last question
What is the use of ractangle as it can't contain any control in it.
Yes it can't contain any controls, but you can always draw it in the background
<Grid>
<Rectangle/>
<TextBlock/>
</Grid>
The user will propably don't see any difference. Why having two different Controls for that? Not sure, but my guess is that a Border is a shortcut to have a rectangle around a control, there might be more behind it, but thats how i see it. Also a Rectangle is a Shape, and it makes sense to have a Rectangle besides an Ellipse, Line etc.
You can draw a plygon as follow:
<Polygon
Points="100 50, 100 150,250 150, 250 75, 225 50"
Stroke="Black"
StrokeThickness="2">
<Polygon.Fill>
<SolidColorBrush Color="White"/>
</Polygon.Fill>
</Polygon>
Here you can find some other interesting example
This path is like your shape, if you use Expression Blend you can draw it into the editor.
<Path Data="M20.5,0.5 L153.81876,0.5 194.5,41.181242 194.5,103.5 C194.5,114.54569 185.5457,123.5 174.5,123.5 L20.5,123.5 C9.4543047,123.5 0.5,114.54569 0.5,103.5 L0.5,20.500004 C0.5,9.4543067 9.4543047,0.50000197 20.5,0.5 z" Fill="#FFF4F4F5" Stretch="Fill" Stroke="Black" HorizontalAlignment="Left" Height="124" VerticalAlignment="Top" Width="195"/>

WPF. How to show only part of big canvas?

Lets say I have a canvas defined to be 1000x1000 big. Is it possible to only show a 100x100 part of it in a Viewbox(or a rectangel)?
Any help is apreciated.....
If you work with Brushes, you might want to take a look at Viewbox and Viewport in WPF
Edit: I just realised that Viewbox and Viewport are used for Brushes
This is not really appropiate in your situation. I looked it up, and I think you will like the Clip property on UIElement.
Since Canvas is also a UIElement, you can use the Clip property to simulate a viewport on your Canvas..
Click here for some simple Geometry types
I think you would suffice with a RectangleGeometry
<Canvas>
<Canvas.Clip>
<RectangleGeometry Rect="50,50,25,25" />
</Canvas.Clip>
</Canvas>
Edit #2:
Hehe ok.. if you want your total Canvas displayed, only smaller, perheps you should take a look and LayoutTransform. Then use a ScaleTranform to resize your Canvas ;).
<Canvas>
<Canvas.LayoutTransform>
<ScaleTransform CenterX="0" CenterY="0" ScaleX="0.5" ScaleY="0.5" />
</Canvas.LayoutTransform>
</Canvas>
Tweak the parameters until you receive the desired effect ;)

Round window playing movie using WPF

Is it possible with WPF to create a window that has the shape of a circle and uses a playing movie as the background?
To make a non-rectangular window, you need to first do three things.
Set Window.WindowStyle to WindowStyle.None
Set Window.AllowsTransparency to True
Set Window.Background to Transparent (or {x:Null})
Now, your window is completely transparent. You can use the other tips in this thread to paint a piece of media onto the window's geometry.
You should just need to throw something like this in your xaml:
<Ellipse Height="80" Width="80">
<Ellipse.Fill>
<VisualBrush TileMode="None">
<VisualBrush.Visual>
<MediaElement Source="myMovie.wmv" />
</VisualBrush.Visual>
</VisualBrush>
</Ellipse.Fill>
</Ellipse>
Actually making the window round would be more difficult. Have a look at this if you want the window to be round, it should help figure that part out.
HTH
Don't use AllowsTransparency, it has very poor performance and a lot of compatibility problems, go to this link for alternatives:
http://blogs.msdn.com/wpfsdk/archive/2008/09/08/custom-window-chrome-in-wpf.aspx
EDIT: there is an example there how to use SetWindowRgn to get rounded corners for a rectangular windows, if you pass an ellipse region instead of a rounded-rect region you will get an elliptic window, it's easy to create a region for any shape you can imagine.
you can have a canvas as your parent container (set to transparent) then add a circle with a media brush as it's background. that should do it. :)

Resources