Cómo hacer una captura de pantalla de UIElement en WPF

Tengo un problema al crear una captura de pantalla de una vista de dispersión. Mi captura de pantalla siempre contiene un marco negro.

Aquí está mi código XAML:

<s:SurfaceWindow
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MakeScreenshots.SurfaceWindow1"
    Title="MakeScreenshots" Width="1000" Height="700"
    >
  <s:SurfaceWindow.Resources>
    <ImageBrush x:Key="WindowBackground" Stretch="None" Opacity="0.6" ImageSource="pack://application:,,,/Resources/WindowBackground.jpg"/>
  </s:SurfaceWindow.Resources>

  <Grid x:Name="GlobalGrid" Background="{StaticResource WindowBackground}" Width="1000" Height="700" >

    <s:ScatterView x:Name="ScatterViewScreenShot" Margin="108,89,176,73" Width="700" Height="500">
        <s:ScatterView.Background>
            <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ActiveCaptionColorKey}}"/>
        </s:ScatterView.Background>
        <s:ScatterViewItem Margin="0,-26.953,-130.946,-23.047" Content="ScatterViewItem 3" HorizontalAlignment="Right" Width="125.826"/>
        <s:ScatterViewItem Margin="0,0,-490.513,-151.256" HorizontalAlignment="Right" Width="125.77" Height="60.427" VerticalAlignment="Bottom" Content="ScatterViewItem 2"/>
        <s:ScatterViewItem Content="ScatterViewItem 1" Margin="-331.43,0,0,-129.589" HorizontalAlignment="Left" Width="177.949" Height="67.905" VerticalAlignment="Bottom"/>
    </s:ScatterView>
    <Button x:Name="MakeScreenShotButton" Click="MakeScreenShotButton_Click" Content="MakeScreenShot" Margin="267,17,343,0" VerticalAlignment="Top" Height="38.96"/>
        <Button Content="MakeScreenShotButton2" Height="39" HorizontalAlignment="Left" Margin="116,614,0,0" Name="button1" VerticalAlignment="Top" Width="301" Click="MakeScreenShotButton2_Click" />
        <Button Content="MakeScreenShotButton3"  Click="MakeScreenShotButton3_Click" Height="39" HorizontalAlignment="Left" Margin="822,207,0,0" Name="button2" VerticalAlignment="Top" Width="147" />
        <Button Content="MakeScreenShotButton4" Click="MakeScreenShotButton4_Click" Height="39" HorizontalAlignment="Left" Margin="822,349,0,0" Name="button3" VerticalAlignment="Top" Width="147" />
        <Button Content="MakeScreenShotButton5" Click="MakeScreenShotButton5_Click" Height="39" HorizontalAlignment="Left" Margin="822,443,0,0" Name="button4" VerticalAlignment="Top" Width="147" />
    </Grid>
</s:SurfaceWindow>

Y aquí está el código C #:

    private void MakeScreenShotButton_Click(object sender, RoutedEventArgs e)
    {          
        RenderTargetBitmap targetBitmap = new RenderTargetBitmap((int)ScatterViewScreenShot.ActualWidth, (int)ScatterViewScreenShot.ActualHeight, 80d, 80d, PixelFormats.Default);

        targetBitmap.Render(ScatterViewScreenShot);

        // add the RenderTargetBitmap to a Bitmapencoder

        JpegBitmapEncoder encoder = new JpegBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(targetBitmap));

        // Encoder zum Speichern des Bildes
        JpegBitmapEncoder encoderToSave = new JpegBitmapEncoder();
        encoderToSave.Frames.Add(BitmapFrame.Create(targetBitmap));

        // Speichern des Bildes auf der Festplatte
        string fileName = "M:\\TestForStackOverflow.jpg";
        System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.OpenOrCreate);
        encoderToSave.Save(fs);

        encoder.QualityLevel = 40;

        MemoryStream ms = new MemoryStream();
        encoder.Save(ms);

        // Convert Image to byte[]
        byte[] imageBytes = ms.ToArray();

        int anzahlBytes = imageBytes.Length;

        string imageAsBase64String = Convert.ToBase64String(imageBytes);

        TCP_Client client = new TCP_Client("192.168.5.3", 4321);
        client.sendeNachricht(imageAsBase64String);
    }

    private void MakeScreenShotButton2_Click(object sender, RoutedEventArgs e)
    {
        // 1. Bitmap der gewünschten Größe erstellen
        int width = (int)ScatterViewScreenShot.ActualWidth;
        int height = (int)ScatterViewScreenShot.ActualHeight;
        RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 100d, 100d, PixelFormats.Default); // 500 x 500 genau wie bei den Produktfotos

        // 2. Control in Bitmap hinein rendern
        Visual vis = (Visual)ScatterViewScreenShot;
        rtb.Render(vis);

        // 3. Control-Image erzeugen und dem Control-Image als Source das Bitmap übergeben
        System.Windows.Controls.Image img = new System.Windows.Controls.Image();
        img.Source = rtb;
        img.Stretch = Stretch.None;

        // 4. Aktualisieren der Größe des Elements entsprechend des Inhaltes mittels der Methoden Measure und Arrange.
        img.Measure(new System.Windows.Size(width, height));
        System.Windows.Size sizeImage = img.DesiredSize;
        img.Arrange(new System.Windows.Rect(new System.Windows.Point(0, 0), sizeImage));

        // 5. Image wird mit der korrekten Größe erneut gerendert und an PngBitmapEncoder übergeben
        RenderTargetBitmap rtb2 = new RenderTargetBitmap((int)rtb.Width, (int)rtb.Height, 60, 60, PixelFormats.Default);
        rtb2.Render(img);

        PngBitmapEncoder jpeg = new PngBitmapEncoder();
        jpeg.Frames.Add(BitmapFrame.Create(rtb2));


        // 6. Image in Stream schreiben
        MemoryStream ms = new MemoryStream();
        jpeg.Save(ms);

        // Convert Image to byte[]
        byte[] imageBytes = ms.ToArray();

        int anzahlBytes = imageBytes.Length;

        string imageAsBase64String = Convert.ToBase64String(imageBytes);

        TCP_Client client = new TCP_Client("192.168.5.3", 4321);
        client.sendeNachricht(imageAsBase64String);
    }

    private void MakeScreenShotButton3_Click(object sender, RoutedEventArgs e)
    {
        int width_x = 240;
        int width_y = 400;

        Bitmap screen = TakeScreenshot(100, 100, width_x, width_y);

        System.Drawing.Image img = (System.Drawing.Image)screen;
        //Image img = Image.FromFile("bla.jpg");
        MemoryStream ms = new MemoryStream();

        try
        {
            //Ein ImageCodecInfo-Objekt für den JPEG-Codec anlegen
            ImageCodecInfo jpegCodec = null;

            //Den Qualitätsarameter konfigurieren (Qualitätsfaktor in
            //Prozent angeben)

            EncoderParameter qualitaetsParameter = new EncoderParameter(
                        System.Drawing.Imaging.Encoder.Quality, 40);

            //Alle im System verfügbaren Codecs auflisten
            ImageCodecInfo[] alleCodecs = ImageCodecInfo.GetImageEncoders();

            EncoderParameters codecParameter = new EncoderParameters(1);
            codecParameter.Param[0] = qualitaetsParameter;

            //Den JPEG-Codec unter allen Codecs finden und dem
            //Codec-Info-Objekt zuweisen
            for (int i = 0; i < alleCodecs.Length; i++)
            {
                if (alleCodecs[i].MimeType == "image/jpeg")
                {
                    jpegCodec = alleCodecs[i];
                    break;
                }
            }

            // Bild in Stream schreiben
            img.Save(ms, jpegCodec, codecParameter);
        }
        catch (ArgumentException w)
        {
            throw w;
        }

        //  Console.WriteLine(StreamToBase64(ms, System.Drawing.Imaging.ImageFormat.Jpeg));
        String bildBase64 = StreamToBase64(ms, System.Drawing.Imaging.ImageFormat.Jpeg);

        TCP_Client client = new TCP_Client("192.168.5.3", 4321);
        client.sendeNachricht(bildBase64);
    }

    private void MakeScreenShotButton4_Click(object sender, RoutedEventArgs e)
    {
        // save current canvas transform
        Transform transform = ScatterViewScreenShot.LayoutTransform;

        // get size of control
        System.Windows.Size sizeOfControl = new System.Windows.Size(ScatterViewScreenShot.ActualWidth, ScatterViewScreenShot.ActualHeight);
        // measure and arrange the control
        ScatterViewScreenShot.Measure(sizeOfControl);
        // arrange the surface
        ScatterViewScreenShot.Arrange(new Rect(sizeOfControl));

        // craete and render surface and push bitmap to it
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap((Int32)sizeOfControl.Width, (Int32)sizeOfControl.Height, 96d, 96d, PixelFormats.Pbgra32);
        // now render surface to bitmap
        renderBitmap.Render(ScatterViewScreenShot);

        // encode png data
        PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
        // puch rendered bitmap into it
        pngEncoder.Frames.Add(BitmapFrame.Create(renderBitmap));

        /* Speichern des Bildes auf der Festplatte
        string fileName = "M:\\ScreenshotClick4.jpg";
        System.IO.FileStream fs = System.IO.File.Open(fileName, System.IO.FileMode.OpenOrCreate);
        pngEncoder.Save(fs);*/

        // Encoder zum Senden des Bildes
        JpegBitmapEncoder encoder = new JpegBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(renderBitmap));

        MemoryStream ms = new MemoryStream();
        encoder.Save(ms);

        // Convert Image to byte[]
        byte[] imageBytes = ms.ToArray();

        int anzahlBytes = imageBytes.Length;

        string imageAsBase64String = Convert.ToBase64String(imageBytes);

        TCP_Client client = new TCP_Client("192.168.5.3", 4321);
        client.sendeNachricht(imageAsBase64String);

    }

    private void MakeScreenShotButton5_Click(object sender, RoutedEventArgs e)
    {
        int scale = 1;

        double actualHeight = ScatterViewScreenShot.RenderSize.Height;
        double actualWidth = ScatterViewScreenShot.RenderSize.Width;

        double renderHeight = actualHeight * scale;
        double renderWidth = actualWidth * scale;

        RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32);
        VisualBrush sourceBrush = new VisualBrush(ScatterViewScreenShot);

        DrawingVisual drawingVisual = new DrawingVisual();
        DrawingContext drawingContext = drawingVisual.RenderOpen();

        using (drawingContext)
        {
            drawingContext.PushTransform(new ScaleTransform(actualWidth, actualHeight));
            drawingContext.DrawRectangle(sourceBrush, null, new Rect(new System.Windows.Point(0, 0), new System.Windows.Point(actualWidth, actualHeight)));
        }
        renderTarget.Render(drawingVisual);

        JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
        jpgEncoder.QualityLevel = 40;
        jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

        MemoryStream ms = new MemoryStream();
        jpgEncoder.Save(ms);

        // Convert Image to byte[]
        byte[] imageBytes = ms.ToArray();

        int anzahlBytes = imageBytes.Length;

        string imageAsBase64String = Convert.ToBase64String(imageBytes);

        TCP_Client client = new TCP_Client("192.168.5.3", 4321);
        client.sendeNachricht(imageAsBase64String);

    }

    #region Hilfsmethoden

    public string StreamToBase64(MemoryStream ms, System.Drawing.Imaging.ImageFormat format)
    {
        // Convert Image to byte[]
        byte[] imageBytes = ms.ToArray();

        // Convert byte[] to Base64 String
        string base64String = Convert.ToBase64String(imageBytes);
        return base64String;
    }

    private Bitmap TakeScreenshot(int StartX, int StartY, int Width, int Height)
    {
        Bitmap Screenshot = new Bitmap(Width, Height);
        Graphics G = Graphics.FromImage(Screenshot);

        G.CopyFromScreen(StartX, StartY, 0, 0, new System.Drawing.Size(Width, Height), CopyPixelOperation.SourceCopy);
        return Screenshot;
    }

    #endregion


}
}

Respuestas a la pregunta(4)

Su respuesta a la pregunta