C# WPF grab screenshot with SnippingTool effect
c#, opacitymask, screenshot, wpf
Solution
You can have a `CombinedGeometry` with `GeometryCombineMode="Exclude"` creating a "punched" effect. Sample:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" AllowsTransparency="True"
WindowStyle="None" Background="Transparent">
<Canvas >
<Path Stroke="Black" Fill="White" Opacity=".5">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<RectangleGeometry Rect="0,0,800,600" >
</RectangleGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<RectangleGeometry Rect="50,50,100,100" >
</RectangleGeometry>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Canvas>
</Window>
Problem
I'm trying to integrate a screenshot grabbing feature in my WPF app and I'd like it to look like snipping tool. So far I've managed accomplish something similar by creating a fullscreen window (with a canvas) with opacity set to 0.5 and dark background. When I click somewhere and start dragging, a white rectangle is drawn, generating an effect similar to this. What I'd like to have is the inner part of that rectangle opening a opacity hole in the background canvas, so that I could see through the selected area - just like snipping tool. Problem is, being fairly new to .NET, I have no idea how or where to start. Did some research and tests on the OpacityMask field of the screenshot window but got nowhere. Here's a little vid to show the current effect. Edit: Also, as bonus question, is there an easy way to grab a screenshot that spans across multiple monitors (virtual screen)? `Graphics.CopyFromScreen()` only seems to work for 1 screen. Already fixed this and seems to work for all possible weird virtual desktop layouts: ``` // Capture screenie (rectangle is the area previously selected double left = Canvas.GetLeft(this.rectangle); double top = Canvas.GetTop(this.rectangle); // Calculate left/top offset regarding to primary screen (where the app runs) var virtualDisplay = System.Windows.Forms.SystemInformation.VirtualScreen; var primaryScreen = System.Windows.Forms.Screen.PrimaryScreen.Bounds; if (virtualDisplay.Left < primaryScreen.Left) { left -= Math.Abs(virtualDisplay.Left - primaryScreen.Left); } if (virtualDisplay.Top < primaryScreen.Top) { top -= Math.Abs(virtualDisplay.Top - primaryScreen.Top); } ```