The
CodePudding user response:
It is convenient to use DrawToBitmap
in Windows Form to do what you want. In WPF, you can use RenderTargetBitmap
, BitmapFrame
and BmpBitmapEncoder
to do that.
void SaveToBmp(FrameworkElement control, string fileName)
{
var bmpEncoder = new BmpBitmapEncoder();
SaveControlToImage(control, fileName, bmpEncoder);
}
void SaveControlToImage(FrameworkElement control, string fileName, BitmapEncoder encoder)
{
UIElement container = VisualTreeHelper.GetParent(control) as UIElement;
Point curPos = control.TranslatePoint(new Point(0.0, 0.0), container);
RenderTargetBitmap bitmap = new RenderTargetBitmap((int)control.ActualWidth, (int)control.ActualHeight, 96, 96, PixelFormats.Pbgra32);
Size visualSize = new Size(control.ActualWidth, control.ActualHeight);
control.Measure(visualSize);
control.Arrange(new Rect(visualSize));
bitmap.Render(control);
BitmapFrame frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using (var stream = File.Create(fileName))
{
encoder.Save(stream);
}
control.Arrange(new Rect(curPos, visualSize));
}
And using the following code to save your GridView to image file:
SaveToBmp(GridView1, @"D:\gridview1.bmp");
Refer to
<Window x:Class="PrintableGridDemo.MainWindow"
Title="Printable Grid" Height="600" Width="800">
<DockPanel>
<Button DockPanel.Dock="Top"
HorizontalAlignment="Right"
Margin="0 10 10 0"
Padding="50 10"
Content="Print"
Click="PrintButton_Click"/>
<Border Margin="10"
BorderBrush="DarkGray"
BorderThickness="1">
<ScrollViewer HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible">
<Grid x:Name="MyGrid"
Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
</Grid>
</ScrollViewer>
</Border>
</DockPanel>
</Window>
I've (ab)used the class's constructor to populate the Grid
with sample data including the column number so that you can see the generated image contains all the columns in the grid.
public MainWindow()
{
InitializeComponent();
for (int col = 0; col < MyGrid.ColumnDefinitions.Count; col )
{
var control = new TextBlock() {
Text = $"This is column number { col 1 }. It is a column with almost no dynamic data. The only dynamic data is the number corresponding to this column's index in the grid plus one since users prefer one-indexed values while the framework uses zero-indexed values.",
TextWrapping = TextWrapping.Wrap
};
MyGrid.Children.Add(control);
Grid.SetColumn(control, col);
}
}
Here's what the project looks like when it's running.
And here's the result of clicking the "Print" button. As you can see, using the DesiredSize
of the grid has allowed us to see the contents of all columns (and has also removed the extra layout whitespace where the grid expanded to fill the ScrollViewer
).
Here's what happens when you click the "Print" button:
private void PrintButton_Click(object sender, RoutedEventArgs e)
{
string destination = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string fileName = $"GridImage_{DateTime.Now:yyyy-MMM-dd_hh-mm-ss-tt}.png";
string filePath = Path.Combine(destination, fileName);
RenderTargetBitmap image = new((int)MyGrid.DesiredSize.Width, (int)MyGrid.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
image.Render(MyGrid);
PngBitmapEncoder encoder = new();
encoder.Frames.Add(BitmapFrame.Create(image));
using FileStream stream = File.Create(filePath);
encoder.Save(stream);
}
The key bit is here:
RenderTargetBitmap image = new(
(int)MyGrid.DesiredSize.Width,
(int)MyGrid.DesiredSize.Height,
96, 96, PixelFormats.Pbgra32);
Because we're using the element's DesiredSize
, the render will include parts of the element that would not normally be rendered (since they are not visible in the UI).
If you run into issues with clipping, you can call the element's Measure
method to recalculate the element's current DesiredSize
.