首页 > 解决方案 > 如何截取 ScrollViewer 的内容

问题描述

我想截取 a 中的任何内容ScrollViewer,而不仅仅是ViewPort. 但是到目前为止,我尝试的所有操作都会导致完全黑色的图像或仅显示部分内容而其他所有内容都是黑色的图像。我认为这可能是因为我没有指定任何背景,但是改变 myWindow或 my TreeViewto的背景White并没有改变任何事情。你能告诉我哪里出了问题,或者我怎么能截取 a 的全部内容ScrollViewer

这是我放在一起的一个小示例(显示主窗口后按“P”)。

主窗口(只是一个TreeView太小Window而无法显示全部内容的窗口):

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ScreenshotTest"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="200" Width="300"
        KeyDown="Window_KeyDown">
    <TreeView x:Name="Tree">
        <TreeViewItem Header="Node 1 - Lorem ipsum dolor sit amet, consetetur sadipscing elitr" IsSelected="True" IsExpanded="True">
            <TreeViewItem Header="Node 1.1" />
            <TreeViewItem Header="Node 1.2" IsExpanded="True">
                <TreeViewItem Header="Node 1.2.1"/>
            </TreeViewItem>
            <TreeViewItem Header="Node 1.3" IsExpanded="True">
                <TreeViewItem Header="Node 1.3.1" />
                <TreeViewItem Header="Node 1.3.2" />
                <TreeViewItem Header="Node 1.3.3" />
            </TreeViewItem>
        </TreeViewItem>
        <TreeViewItem Header="Node 2 - sed diam nonumy eirmod tempor invidunt ut labore et dolore" IsExpanded="True">
            <TreeViewItem Header="Node 2.1"/>
            <TreeViewItem Header="Node 2.2" IsExpanded="True">
                <TreeViewItem Header="Node 2.2.1"/>
            </TreeViewItem>
            <TreeViewItem Header="Node 2.3" IsExpanded="True">
                <TreeViewItem Header="Node 2.3.1" />
                <TreeViewItem Header="Node 2.3.2" />
                <TreeViewItem Header="Node 2.3.3" />
            </TreeViewItem>
        </TreeViewItem>
    </TreeView>
</Window>

以及窗口后面的代码:

Class MainWindow

Private Sub Window_KeyDown(sender As Object, e As KeyEventArgs)
    If e.Key <> Key.P Then
        Exit Sub
    End If

    Dim sv As ScrollViewer = GetFirstChildOfType(Of ScrollViewer)(Me.Tree)
    Me.CaptureScreen(sv.Content, "C:\Temp\Screenshot.png")
End Sub

Private Shared Function GetFirstChildOfType(Of T As DependencyObject)(obj As DependencyObject) As T
    Dim result As T
    Dim child As DependencyObject

    If (obj Is Nothing) Then
        Return Nothing
    End If

    If (VisualTreeHelper.GetChildrenCount(obj) = 0) Then
        Return Nothing
    End If

    For index As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj)
        child = VisualTreeHelper.GetChild(obj, index)
        result = TryCast(child, T)

        If (result Is Nothing) Then
            result = GetFirstChildOfType(Of T)(child)
        End If

        If (result IsNot Nothing) Then
            Return result
        End If
    Next index

    Return Nothing
End Function

Private Sub CaptureScreen(source As UIElement, filename As String)
    Dim height As Double
    Dim renderHeight As Double
    Dim width As Double
    Dim renderWidth As Double
    Dim renderTarget As RenderTargetBitmap
    Dim vb As VisualBrush
    Dim dv As DrawingVisual
    Dim encoder As PngBitmapEncoder

    Try
        height = source.RenderSize.Height
        renderHeight = height
        width = source.RenderSize.Width
        renderWidth = width

        renderTarget = New RenderTargetBitmap(Convert.ToInt32(renderWidth), Convert.ToInt32(renderHeight), 96, 96, PixelFormats.Pbgra32)
        vb = New VisualBrush(source)

        dv = New DrawingVisual

        Using dc As DrawingContext = dv.RenderOpen
            dc.DrawRectangle(vb, Nothing, New Rect(New Point(0, 0), New Point(width, height)))
        End Using

        renderTarget.Render(dv)

        encoder = New PngBitmapEncoder
        encoder.Frames.Add(BitmapFrame.Create(renderTarget))

        Using fs As IO.FileStream = New IO.FileStream(filename, IO.FileMode.Create, IO.FileAccess.Write)
            encoder.Save(fs)
        End Using
    Catch ex As Exception
        Stop
    End Try
End Sub

End Class

我对 C# 中的答案也很好。

标签: wpfvb.net

解决方案


经过大量的试验和错误,我发现,我做错了几件事。

首先,我用错了UIElement. 我不得不拿第一个StackPanel而不是第一个ScrollViewer

其次,虽然我Window的背景设置为白色,但我里面的所有控件Window都没有背景,这可能就是我生成的图片是黑色的原因。

因此,只需将我的代码的一个功能更改为

Private Sub Window_KeyDown(sender As Object, e As KeyEventArgs)
    Dim panel As StackPanel

    If e.Key <> Key.P Then
        Exit Sub
    End If

    panel = GetFirstChildOfType(Of StackPanel)(Me.Tree)
    panel.Background = Brushes.White
    panel.UpdateLayout()

    Me.CaptureScreen(panel, "C:\Temp\Screenshot.png")
End Sub

成功了,现在我至少得到一张白色背景的照片和我的所有元素TreeView,而不仅仅是屏幕上可见的那些。

现在我还有一些其他问题,但这是另一个问题的问题。


推荐阅读