我正在尝试创建StackPanel
的png捕获,但是当我保存时,会得到一个扭曲的视图,其中所有内容均为黑色矩形,并且大小不正确。图片保存中的宽度和高度正确,但是所有内容都被压到顶部并压在一起
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Views="clr-namespace:POExpress.Views" x:Class="POExpress.MainWindow"
Title="My Window" Height="500" MinWidth="1000" Width="1000">
<Grid>
<TabControl>
<TabItem Header="My Epics">
<Grid Background="#FFE5E5E5">
<Border Margin="0,52,0,0" BorderThickness="1" BorderBrush="Black">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel x:Name="sp_ports" Orientation="Vertical"/>
</ScrollViewer>
</Border>
<Button x:Name="btn_capture" Content="Save to png" Margin="0,10,114,0" VerticalAlignment="Top" Height="31" Background="White" HorizontalAlignment="Right" Width="99" Click="Btn_capture_Click"/>
</Grid>
</TabItem>
</TabControl>
</Grid>
public RenderTargetBitmap GetImage()
{
Size size = new Size(sp_ports.ActualWidth, sp_ports.ActualHeight);
if (size.IsEmpty)
return null;
RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingvisual = new DrawingVisual();
using (DrawingContext context = drawingvisual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(sp_ports), null, new Rect(new Point(), size));
context.Close();
}
result.Render(drawingvisual);
return result;
}
public static void SaveAsPng(RenderTargetBitmap src)
{
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.Filter = "PNG Files | *.png";
dlg.DefaultExt = "png";
if (dlg.ShowDialog() == true)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
using (var stream = dlg.OpenFile())
{
encoder.Save(stream);
}
}
}
private void Btn_capture_Click(object sender, RoutedEventArgs e)
{
SaveAsPng(GetImage());
}
答案 0 :(得分:6)
所有UIElements
都继承自Visual
,因此您可以将StackPanel
直接提供给Render
方法。
public RenderTargetBitmap GetImage()
{
Size size = sp_ports.DesiredSize;
if (size.IsEmpty)
return null;
RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
result.Render(sp_ports);
return result;
}
更新
如@Clemens所指出的,直接使用UIElement
有一些细微的复杂之处。然而,他的另一种评论是百万美元。
Size size = uiElement.DesiredSize
为我们提供uiElement
可见部分的大小。
Size size = new Size(uiElement.ActualWidth, uiElement.ActualHeight)
返回uiElement
的完整大小,并且也在不可见范围内扩展。
鉴于您遇到了这个问题,那么您就来解决这个问题。主要问题是渲染之前,您需要重新评估视觉效果。当前,您正在将整个视觉投影到UIElement
的所需大小(可见部分)。
public RenderTargetBitmap GetImage(FrameworkElement element)
{
Size size = new Size(element.ActualWidth, element.ActualHeight);
if (size.IsEmpty)
return null;
element.Measure(size);
element.Arrange(new Rect(size));
RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingvisual = new DrawingVisual();
using (DrawingContext context = drawingvisual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(element), null, new Rect(new Point(), size));
}
result.Render(drawingvisual);
return result;
}
我使用FrameworkElement
合并了ActualWidth
和ActualHeight
。
更新2
一旦我改变了堆叠面板的尺寸,屏幕截图就会再次消失。似乎记得最长的状态是什么,并以此压缩。
经过一番摆弄之后,我得以重现您的问题。当StackPanel
必须延伸以填充任何剩余空间时,就会发生这种情况。解决方案是给uiElement
无限的空间来计算其所需的大小,这使我们摆脱了对实际大小的依赖。
public RenderTargetBitmap GetImage(FrameworkElement element)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(element.DesiredSize));
Size size = element.DesiredSize;
if (size.IsEmpty)
return null;
RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingvisual = new DrawingVisual();
using (DrawingContext context = drawingvisual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(element), null, new Rect(new Point(), size));
}
result.Render(drawingvisual);
return result;
}
我已经检查了Expander
的行为(参考测试应用程序),但找不到有趣的地方。
为完整起见,这是我的测试应用程序。
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WpfApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public RenderTargetBitmap GetImage(FrameworkElement element)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(element.DesiredSize));
Size size = element.DesiredSize;
if (size.IsEmpty)
return null;
RenderTargetBitmap result = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, PixelFormats.Pbgra32);
DrawingVisual drawingvisual = new DrawingVisual();
using (DrawingContext context = drawingvisual.RenderOpen())
{
context.DrawRectangle(new VisualBrush(element), null, new Rect(new Point(), size));
}
result.Render(drawingvisual);
return result;
}
public static void SaveAsPng(RenderTargetBitmap src)
{
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.Filter = "PNG Files | *.png";
dlg.DefaultExt = "png";
if (dlg.ShowDialog() == true)
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(src));
using (var stream = dlg.OpenFile())
{
encoder.Save(stream);
}
}
}
private void Btn_capture_Click(object sender, RoutedEventArgs e)
{
SaveAsPng(GetImage(sp_ports));
}
}
}
MainWindow.cs
<Window x:Class="WpfApp.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:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DockPanel LastChildFill="True">
<Button DockPanel.Dock="Top" Click="Btn_capture_Click">Take Pic</Button>
<StackPanel x:Name="sp_ports">
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="H1" Width="40"/>
<DataGridTextColumn Header="H2" Width="*"/>
</DataGrid.Columns>
</DataGrid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="Auto" />
<RowDefinition Height="400" />
</Grid.RowDefinitions>
<StackPanel Background="Red"/>
<Expander Grid.Row="1" ExpandDirection="Down" IsExpanded="False">
<TabControl Height="400">
<TabItem Header="Tab 1">
<TextBox FontSize="50" TextWrapping="Wrap">Text for Tab 1</TextBox>
</TabItem>
<TabItem Header="Tab 2">
<TextBox FontSize="50" TextWrapping="Wrap">Text for Tab 1</TextBox>
</TabItem>
</TabControl>
</Expander>
<StackPanel Grid.Row="2" Background="Blue"/>
</Grid>
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="H1" Width="40"/>
<DataGridTextColumn Header="H2" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</DockPanel>
</Window>