Take a screenshot of a control (or a set of controls) using RenderTargetBitmap
.
Source:
<Grid Height="200" Width="500">
<!-- Here goes any content, in my case, a Label or a Shape-->
<Label VerticalAligment="Top" HorizontalAligment="Left" Content="Text">
</Grid>
Expected result:
This one basically uses the UIElement
as the source of the RenderTargetBitmap
.
public static ImageSource GetRender(this UIElement source)
{
double actualHeight = source.RenderSize.Height;
double actualWidth = source.RenderSize.Width;
var renderTarget = new RenderTargetBitmap((int)Math.Round(actualWidth),
(int)Math.Round(actualHeight), 96, 96, PixelFormats.Pbgra32);
renderTarget.Render(source);
return renderTarget;
}
Result:
Instead of directly setting the UIElement
as the source of the RenderTargetBitmap
, I'll use a VisualBrush
.
//Same RenderTargetBitmap...
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
Result:
This one ignores the position and size of the Grid
and the Label
inside:
What's happening here?
I just needed to get the bounds of the descendant of the Grid
and render only the needed part.
public static ImageSource GetRender(this UIElement source, double dpi)
{
Rect bounds = VisualTreeHelper.GetDescendantBounds(source);
var scale = dpi / 96.0;
var width = (bounds.Width + bounds.X)*scale;
var height = (bounds.Height + bounds.Y)*scale;
RenderTargetBitmap rtb =
new RenderTargetBitmap((int)Math.Round(width, MidpointRounding.AwayFromZero),
(int)Math.Round(height, MidpointRounding.AwayFromZero),
dpi, dpi, PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(source);
ctx.DrawRectangle(vb, null,
new Rect(new Point(bounds.X, bounds.Y), new Point(width, height)));
}
rtb.Render(dv);
return (ImageSource)rtb.GetAsFrozen();
}
Result:
The rendered Label
/Shape
:
Merged with another Picture: