Все 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
(приложение ref test), ноне могу найти там ничего смешного.
Для полноты вот мое тестовое приложение.
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>