0

我只是做了一个简单的应用程序来定期获取屏幕截图。

我遇到的主要问题是当我移动它时应用程序会冻结。

所以主要目标是消除屏幕截图、线程等的影响。

我把所有代码都放在这里,它可以工作,所以你可以重现它。

这是此代码的一些 .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];
            }
        }
    }
}
4

1 回答 1

2

我相信您可以通过使用后台工作进程执行截取屏幕截图的功能来避免这种情况。

由于后台工作人员使用另一个线程并且主线程继续渲染 UI,它不应该卡住。

编辑://我在 SO 上发现了这个问题,这可能会澄清背景工作者 VS 代表的问题

祝你好运!

于 2012-04-14T18:13:26.337 回答