Search code examples
c#.netwpfgdi+screenshot

Update before screenshot


I want to capture an image of the screen, however there are some wpf controls in my application that I do not want to appear in the screenshot. Using the code below, the hidden controls will sometimes still appear in the screenshot. How do I ensure that this doesn't happen?

Window window = new Window();
Button button = new Button();

void ShowWindow()
{
    button.Content = "button";
    button.ToolTip = "tooltip";
    window.Content = button;
    window.Show();

    button.Click += new RoutedEventHandler(button_Click);
}

void button_Click(object sender, RoutedEventArgs e)
{
    //Hide some controls and all tooltips in the window
    ToolTipService.SetIsEnabled(window, false);
    button.Visibility = Visibility.Hidden;

    //Block until wpf renders
    Application.Current.Dispatcher.Invoke(
        System.Windows.Threading.DispatcherPriority.Background, 
        new System.Threading.ThreadStart(delegate { }));

    //Take screenshot
    Bitmap bmpScreenshot = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width,
                               System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height,
                               System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
    gfxScreenshot.CopyFromScreen(System.Windows.Forms.Screen.PrimaryScreen.Bounds.X,
                                System.Windows.Forms.Screen.PrimaryScreen.Bounds.Y,
                                0, 0,
                                System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size,
                                CopyPixelOperation.SourceCopy);
    bmpScreenshot.Save("Screenshot.png", ImageFormat.Png);

    //Restore controls and tooltips
    button.Visibility = Visibility.Visible;
    ToolTipService.SetIsEnabled(window, true);
}

Solution

  • Try using a low priority on the dispatcher, it still isn't a guarantee though (source).

    Also, from my understanding WPF doesn't start the render process until the UI thread is idle (or lengthily blocked), so you may want to place the dispatch blocking & snapshot code in an actual background thread (or have the dispatcher asynchronously invoke the snapshot code). Then restore the button visibility once that snapshot thread is complete.