@Yanger Yang's answer is close, but you should use the element's DesiredSize
instead of its ActualWidth
/ActualHeight
. This is, of course, assuming that you're not setting an explicit size on the Grid
element itself. This approach should work with your telerik:RadGridView
, but I do not have the library available for testing.
Here's a sample project containing a Grid
with fifteen (15) columns inside a ScrollViewer
.

<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)
{
// Set up the output file.
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);
// Render the control as a Bitmap.
RenderTargetBitmap image = new((int)MyGrid.DesiredSize.Width, (int)MyGrid.DesiredSize.Height, 96, 96, PixelFormats.Pbgra32);
image.Render(MyGrid);
// Encode the Bitmap image as a PNG instead.
PngBitmapEncoder encoder = new();
encoder.Frames.Add(BitmapFrame.Create(image));
// Save the PNG to the file.
using FileStream stream = File.Create(filePath);
encoder.Save(stream);
}
The key bit is here:
RenderTargetBitmap image = new(
// The key bit.
(int)MyGrid.DesiredSize.Width,
(int)MyGrid.DesiredSize.Height,
// Format specific parameters. You can ignore these.
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
.