9

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);
}
biasedbit
  • 2,860
  • 4
  • 30
  • 47
  • 1
    Relevant: http://stackoverflow.com/questions/3123776/net-equivalent-of-snipping-tool/3124252#3124252 – Hans Passant Oct 27 '10 at 13:17
  • I see that you took the approach of grabbing a desktop screenshot. Does make sense, even though I kind of wanted to avoid it! Also, I've realized that CopyFromScreen can be fed with negative coordinates (say if my other screen is to the left of the main) so now it's just a matter of maths :) – biasedbit Oct 27 '10 at 13:48
  • If you look closely, the snipping tool is also grabbing a desktop screenshot – Eduardo Molteni Oct 27 '10 at 14:17

1 Answers1

3

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>
Eduardo Molteni
  • 38,786
  • 23
  • 141
  • 206
  • This works nicely but has a little problem: when the mouse moves to the "punched" area, you lose MouseMove events. I guess I'd have to mix this solution with the one pointed out by Hans Passant. Nice effect, though! – biasedbit Oct 27 '10 at 19:31
  • I've played around with this and, if used in conjunction with the approach of grabbing a screenshot and using it as window background, it produces the desired effect, so I'm marking this one as right - even though I wanted to keep a "live" view of what was happening on the desktop (i.e. no screenshot before the selection). – biasedbit Oct 28 '10 at 10:45
  • Well, good for you. As nice as keeping a live view would be, I think no user would care or notice. In fact, I found that the snipping tool was grabbing a screenshot because I look into it, and I use the tool all the time. – Eduardo Molteni Oct 28 '10 at 11:49
  • 1
    @biasedbit: I know this is REALLY an old thread, but I was playing around with this and found a way to not lose the MouseMove events and still have the "live" view. Place the Canvas in the XAML above inside of another Canvas, with `Background=White` and `Opacity=0.1`. The 10% opacity is virtually transparent, but it still blocks mouse clicks from passing through the window. Just grab the MouseMove commands you need from the outer canvas rather than the inner, as they should bubble up to the parent anyways. – Keven M Mar 05 '19 at 17:50