Reputation: 4110
I would like to draw a rectangle in WPF (by code) and to fill the outside of it.
Here is an example :
The outside of the rectangle is grey (with low opacity), and the fill of the rectangle is trasparent.
Upvotes: 11
Views: 4899
Reputation: 636
This is a variation on the solution using OpacityMask. Instead of doing it in the code, it is done in XAML. Also, it reverses the logic: instead of drawing 4 border rectangles, it draws 2 rectangles on top of each other. Finally, the important property of this solution is that the size of the central transparent rectangle is relative to the image size (rather than in absolute pixels). You do not need to know the actual image size or how it is stretched/positioned (particularly important for Stretch="Uniform"). Here, I have specified the image size (maskRect) as 1,1 and used fractional numbers as relative mask size and position (transpRect). You may as well specify the image size as 100,100 and use percentage values for the mask (or, even use the actual pixel values).
<Grid Background="#FFF4F4F5" >
<Image Name="PhotoImage" Source="...">
<Image.OpacityMask>
<DrawingBrush>
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry x:Name="maskRect" Rect="0,0,1,1"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="#60000000" />
</GeometryDrawing.Brush>
</GeometryDrawing>
<GeometryDrawing>
<GeometryDrawing.Geometry>
<RectangleGeometry x:Name="transpRect" Rect=".25,.20,.40,.40"/>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Black" />
</GeometryDrawing.Brush>
</GeometryDrawing>
</DrawingGroup>
</DrawingBrush.Drawing>
</DrawingBrush>
</Image.OpacityMask>
</Image>
</Grid>
Upvotes: 1
Reputation: 128106
You may also overlay your image with a semi-transparent Path
element that uses a CombinedGeometry
which combines one very large outer rectangle with an inner rectangle:
<Grid>
<Image Name="image" Source="C:\Users\Public\Pictures\Sample Pictures\Koala.jpg"/>
<Path Fill="#AAFFFFFF">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Xor">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,10000,10000"/>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<RectangleGeometry x:Name="transparentRect" Rect="150,100,200,100"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Grid>
You would now programatically adjust the Rect
property of the transparentRect
member as needed.
Upvotes: 8
Reputation: 2236
You can use a combination of OpacityMask and DrawingBrush:
XAML:
<Grid Background="Gray">
<Image Name="image"Source="...">
<Image.OpacityMask>
<DrawingBrush x:Name="mask"/>
</Image.OpacityMask>
</Image>
</Grid>
Code-behind:
private void UpdateOpactiyMask()
{
Point topLeft = new Point();
Point bottomRight = new Point(image.ActualWidth, image.ActualHeight);
GeometryDrawing left = new GeometryDrawing();
left.Brush = borderBrush;
left.Geometry = new RectangleGeometry(new Rect(topLeft, new Point(SelectedArea.Left, bottomRight.Y)));
GeometryDrawing right = new GeometryDrawing();
right.Brush = borderBrush;
right.Geometry = new RectangleGeometry(new Rect(new Point(SelectedArea.Right, topLeft.Y), bottomRight));
GeometryDrawing top = new GeometryDrawing();
top.Brush = borderBrush;
top.Geometry = new RectangleGeometry(new Rect(new Point(SelectedArea.Left, topLeft.Y), new Point(SelectedArea.Right, SelectedArea.Top)));
GeometryDrawing bottom = new GeometryDrawing();
bottom.Brush = borderBrush;
bottom.Geometry = new RectangleGeometry(new Rect(new Point(SelectedArea.Left, SelectedArea.Bottom), new Point(SelectedArea.Right, bottomRight.Y)));
GeometryDrawing center = new GeometryDrawing();
center.Brush = selectionBrush;
center.Geometry = new RectangleGeometry(SelectedArea);
DrawingGroup drawing = new DrawingGroup();
drawing.Children.Add(left);
drawing.Children.Add(right);
drawing.Children.Add(top);
drawing.Children.Add(bottom);
drawing.Children.Add(center);
mask.Drawing = drawing;
}
SelectedArea is a Rect.
Upvotes: 2
Reputation: 34293
You can use UIElement.Clip
property:
<Window x:Class="So17720970_RectangularBoublik.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
SizeToContent="WidthAndHeight">
<Grid Width="500" Height="500">
<Image Source="https://i.sstatic.net/Py65S.jpg"/> <!-- image -->
<Rectangle Fill="#AA000000"> <!-- selection -->
<Rectangle.Clip>
<GeometryGroup FillRule="Nonzero"> <!-- selection clip: -->
<RectangleGeometry Rect="0 0 500 200"/> <!-- top -->
<RectangleGeometry Rect="0 0 100 500"/> <!-- left -->
<RectangleGeometry Rect="0 300 500 200"/> <!-- bottom -->
<RectangleGeometry Rect="400 0 100 500"/> <!-- right -->
</GeometryGroup>
</Rectangle.Clip>
</Rectangle>
<Rectangle StrokeThickness="1" Stroke="Black" StrokeDashArray="1 2" SnapsToDevicePixels="True"
Margin="100 200 100 200"/> <!-- "ants" -->
</Grid>
</Window>
Upvotes: 2