在我之前的一个问题中,我问过如何才能截取ScrollViewer中所有内容的屏幕截图,而不仅仅是ViewPort中可见的内容。经过多次尝试,我给自己找到了一个答案,但不幸的是,这个答案提出了另一个问题。
看看下面的示例代码:
ItemViewModel.vb (我的TreeViewItems的一个简单视图模型):
Public Class ItemViewModel
Public Property Text As String
Public Property Items As New ObservableCollection(Of ItemViewModel)
End ClassViewModel.vb (我的主窗口的视图模型,在构造函数中创建一些项):
Public Class ViewModel
Public Property Items As New ObservableCollection(Of ItemViewModel)
Private Const levels As Integer = 3
Public Sub New()
Dim item1 As ItemViewModel
Dim item2 As ItemViewModel
Dim item3 As ItemViewModel
For index1 As Integer = 1 To levels
item1 = New ItemViewModel With {.Text = String.Format("Node {0} - {1}", index1, Guid.NewGuid.ToString)}
Me.Items.Add(item1)
For index2 As Integer = 1 To levels
item2 = New ItemViewModel With {.Text = String.Format("Node {0}.{1} - {2}", index1, index2, Guid.NewGuid.ToString)}
item1.Items.Add(item2)
For index3 As Integer = 1 To levels
item3 = New ItemViewModel With {.Text = String.Format("Node {0}.{1}.{2} - {3}", index1, index2, index3, Guid.NewGuid.ToString)}
item2.Items.Add(item3)
Next index3
Next index2
Next index1
End Sub
End ClassMainWindow.xaml (主窗口本身,显示一个TreeView):
<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">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<TreeView x:Name="Tree" ItemsSource="{Binding Items}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:ItemViewModel}" ItemsSource="{Binding Items}">
<Border BorderThickness="1" BorderBrush="Black" Margin="1">
<TextBlock Text="{Binding Text}" Margin="2" />
</Border>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Window>MainWindow.xaml.vb (主窗口的代码隐藏,这里是“有用”代码所在的位置):
Class MainWindow
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
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如果你运行这个程序,你会看到一个包含几个项目的TreeView,如果你按下P,TreeView内容的屏幕截图就会被截取并保存为"C:\Temp\Screenshot.png“。
到目前为止,屏幕截图看起来和屏幕上看到的大致相同(质量方面)。例如,如果您在IrfanView中查看创建的png文件( 100%大小),则所有内容都是可读的。
但是如果我创建越来越多的项目(将levels常量增加到5,然后增加到7),图片质量会变得更差,当levels=7时,用户无法读取屏幕截图上的任何内容。
有没有人知道这里发生了什么,我怎么解决这个问题?我对C#中的答案也很满意。
这里有几个屏幕截图来直观地说明我的问题:
屏幕上的主窗口

levels=3的屏幕截图

levels=5的屏幕截图

levels=7的屏幕截图

发布于 2020-11-19 10:05:22
我不是那么精通WPF,但创建一个VisualBrush来绘制项目似乎是错误的。因此,不用使用VisualBrush和DrawingVisual编写代码,只需使用renderTarget.Render(source)即可。
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
Debug.Print(height.ToString)
renderHeight = height
width = source.RenderSize.Width
renderWidth = width
renderTarget = New RenderTargetBitmap(Convert.ToInt32(renderWidth), Convert.ToInt32(renderHeight), 96, 96, PixelFormats.Pbgra32)
renderTarget.Render(source)
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这对我来说似乎很有效。
https://stackoverflow.com/questions/64903293
复制相似问题