How to take a screenshot of a WPF control?
A screenshot is a shot of the screen... everything on the screen. What you want is to save an image from a single UIElement
and you can do that using the RenderTargetBitmap.Render
Method. This method takes a Visual
input parameter and luckily, that is one of the base classes for all UIElement
s. So assuming that you want to save a .png file, you could do this:
RenderTargetBitmap renderTargetBitmap =
new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(yourMapControl);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create(filePath))
{
pngImage.Save(fileStream);
}
Saving image (screenshot) of control in WPF - MVVM Pattern
Trick with CommandParameter can let you pass some FrameworkElement to your command placed in your ViewModel. My example
xaml (you can refine if you need only your control in CommandParameter)
<Window x:Class="WpfTestApp.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:WpfTestApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
d:DataContext="{d:DesignInstance Type=local:YourViewModel, IsDesignTimeCreatable=True}">
<Grid>
<Button Content="Make screenShot" Command="{Binding MakeScreenShotCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
</Grid>
ViewModel
public class YourViewModel
{
private ICommand _makeScreenShotCommand;
public ICommand MakeScreenShotCommand => _makeScreenShotCommand ?? (_makeScreenShotCommand = new ActionCommand(TakeScreenShot));
private void TakeScreenShot(object control)
{
FrameworkElement element = control as FrameworkElement;
if (element == null)
throw new Exception("Invalid parameter");
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)element.ActualWidth, (int)element.ActualHeight, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(element);
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create("filePath"))
{
pngImage.Save(fileStream);
}
}
}
WPF: Take a screenshot and save it
In WPF project, you have to manually add reference to System.Drawing.dll
library. To do so, Project > Add reference > Assembly tab (Framework) > check the desired library.
Moreover your code needs just a bit of tweaking, but the idea it's correct.
double screenLeft = SystemParameters.VirtualScreenLeft;
double screenTop = SystemParameters.VirtualScreenTop;
double screenWidth = SystemParameters.VirtualScreenWidth;
double screenHeight = SystemParameters.VirtualScreenHeight;
using (Bitmap bmp = new Bitmap((int)screenWidth,
(int)screenHeight))
{
using (Graphics g = Graphics.FromImage(bmp))
{
String filename = "ScreenCapture-" + DateTime.Now.ToString("ddMMyyyy-hhmmss") + ".png";
Opacity = .0;
g.CopyFromScreen((int)screenLeft, (int)screenTop, 0, 0, bmp.Size);
bmp.Save("C:\\Screenshots\\" + filename);
Opacity = 1;
}
}
C# Take screenshot of WPF application
This is how I have used in my application earlier.
I created class to handle screenshot functionality.
public sealed class snapshotHandler
{
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int m_left;
public int m_top;
public int m_right;
public int m_bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
public static void Savesnapshot(IntPtr handle_)
{
RECT windowRect = new RECT();
GetWindowRect(handle_, ref windowRect);
Int32 width = windowRect.m_right - windowRect.m_left;
Int32 height = windowRect.m_bottom - windowRect.m_top;
Point topLeft = new Point(windowRect.m_left, windowRect.m_top);
Bitmap b = new Bitmap(width, height);
Graphics g = Graphics.FromImage(b);
g.CopyFromScreen(topLeft, new Point(0, 0), new Size(width, height));
b.Save(SNAPSHOT_FILENAME, ImageFormat.Jpeg);
}
}
To use above functionality, I am calling SaveSnapshot method.
SnapshotHandler.SaveSnapshot(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
Create a screenshot of a WPF control in a background thread
It is possible, the bit you are missing is possibly the measure and arrange of the control:
public MainWindow()
{
InitializeComponent();
var thread = new Thread(CreateScreenshot);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
private void CreateScreenshot()
{
Canvas c = new Canvas { Width = 100, Height = 100 };
c.Children.Add(new Rectangle { Height = 100, Width = 100, Fill = new SolidColorBrush(Colors.Red) });
var bitmap = new RenderTargetBitmap((int)c.Width, (int)c.Height, 120, 120, PixelFormats.Default);
c.Measure(new Size((int)c.Width, (int)c.Height));
c.Arrange(new Rect(new Size((int)c.ActualWidth, (int)c.ActualHeight)));
bitmap.Render(c);
var png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(bitmap));
using (Stream stm = File.Create("c:\\temp\\test.png"))
{
png.Save(stm);
}
}
Related Topics
Dataview.Sort - More Than Just Asc/Desc (Need Custom Sort)
Sqlparameter Does Not Allows Table Name - Other Options Without SQL Injection Attack
Reading a Key from the Web.Config Using Configurationmanager
Owin Security - How to Implement Oauth2 Refresh Tokens
Insert into C# with SQLcommand
Center Multiple Rows of Controls in a Flowlayoutpanel
Unrolled Loop Works, for Loop Does Not Work
Resharper Warning - Access to Modified Closure
Determining If File Exists Using C# and Resolving Unc Path
Creating Diagonal Pattern in Wpf
How to Implement Gzip Compression in ASP.NET
.Net - Convert Generic Collection to Datatable
Adding Images into Excel Using Epplus
Filter All Queries (Trying to Achieve Soft Delete)