我只是做了一个简单的应用程序定期获取截图。
我遇到的主要问题是,当我移动它时,应用程序会冻结。
所以主要目标是消除屏幕截图,线程等的影响。
我把所有代码放在这里,它可以工作,所以你可以重现它。
以下是此代码的一些.NET概要分析信息。
任何线索如何解决?
XAML
<Window x:Class="Screenshot.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" >
<Grid Height="Auto">
<Image Name="Image1"/>
</Grid>
</Window>
C#
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
ScreenGrabber grabber;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
grabber = new ScreenGrabber(5);
grabber.Changed += new ChangedEventHandler(grabber_Changed);
}
void grabber_Changed(object sender, EventArgs e)
{
Image1.Dispatcher.Invoke(new Action(() => {
BitmapSource bs = ((ScreenGrabber)sender).GetImage();
Image1.Width = bs.Width;
Image1.Height = bs.Height;
Image1.Source = bs;
} ));
}
}
C#DLL
namespace MyScreenGrabber
{
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class ScreenGrabber : Window
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
byte[] BitmapData { set; get; }
int Interval { set; get; }
DispatcherTimer Timer { set; get; }
public ScreenGrabber(int interval)
{
Interval = interval;
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0, 0, Interval);
Timer.Tick += new EventHandler(Timer_Tick);
Timer.Start();
}
void Timer_Tick(object sender, EventArgs e)
{
WindowInteropHelper windowInteropHelper = windowInteropHelper = new WindowInteropHelper(this);
Screen screen = Screen.FromHandle(windowInteropHelper.Handle);
using (MemoryStream ms = new MemoryStream())
{
if (screen != null)
{
using (Bitmap bitmap = new Bitmap(screen.Bounds.Size.Width, screen.Bounds.Size.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size, CopyPixelOperation.SourceCopy);
}
ImageCodecInfo myImageCodecInfo;
myImageCodecInfo = GetEncoderInfo("image/jpeg");
System.Drawing.Imaging.Encoder myEncoder;
myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters encoderParameters = new EncoderParameters();
EncoderParameter encoderParameter = new EncoderParameter(myEncoder, 25L);
encoderParameters.Param[0] = encoderParameter;
bitmap.Save(ms, myImageCodecInfo, encoderParameters);
BitmapData = ms.ToArray();
OnChanged(EventArgs.Empty);
}
}
}
}
static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
public BitmapSource GetImage()
{
using (MemoryStream ms = new MemoryStream(this.BitmapData))
{
var decoder = BitmapDecoder.Create(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
return decoder.Frames[0];
}
}
}
}
优化代码:
namespace MyScreenGrabber
{
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class ScreenGrabber : Window
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
byte[] BitmapData { set; get; }
int Interval { set; get; }
WindowInteropHelper windowInteropHelper;
Screen screen;
DispatcherTimer Timer { set; get; }
BackgroundWorker worker = new BackgroundWorker();
public ScreenGrabber(int interval)
{
Interval = interval;
windowInteropHelper = windowInteropHelper = new WindowInteropHelper(this);
screen = Screen.FromHandle(windowInteropHelper.Handle);
isDone = true;
Timer = new DispatcherTimer();
Timer.Interval = new TimeSpan(0, 0, Interval);
Timer.Tick += new EventHandler(Timer_Tick);
Timer.Start();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
OnChanged(EventArgs.Empty);
isDone = true;
}
bool isDone;
void worker_DoWork(object sender, DoWorkEventArgs e)
{
GetScreenshot();
}
void Timer_Tick(object sender, EventArgs e)
{
if (isDone)
{
isDone = false;
worker.RunWorkerAsync();
}
}
void GetScreenshot()
{
using (MemoryStream ms = new MemoryStream())
{
if (screen != null)
{
using (Bitmap bitmap = new Bitmap(screen.Bounds.Size.Width, screen.Bounds.Size.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, screen.Bounds.Size, CopyPixelOperation.SourceCopy);
}
ImageCodecInfo myImageCodecInfo;
myImageCodecInfo = GetEncoderInfo("image/jpeg");
System.Drawing.Imaging.Encoder myEncoder;
myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters encoderParameters = new EncoderParameters();
EncoderParameter encoderParameter = new EncoderParameter(myEncoder, 25L);
encoderParameters.Param[0] = encoderParameter;
bitmap.Save(ms, myImageCodecInfo, encoderParameters);
BitmapData = ms.ToArray();
}
}
}
}
static ImageCodecInfo GetEncoderInfo(String mimeType)
{
int j;
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
public BitmapSource GetImage()
{
using (MemoryStream ms = new MemoryStream(this.BitmapData))
{
var decoder = BitmapDecoder.Create(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
return decoder.Frames[0];
}
}
}
}
答案 0 :(得分:2)
我相信你可以通过使用后台工作程序来执行截取屏幕截图的功能来避免这种情况。
当后台工作者使用另一个线程并且主线程继续呈现UI时,它不会卡住。
编辑://我在SO上发现了这个问题,可能会澄清Background Workers VS Delegates
上的内容 祝你好运!