2012-04-14 74 views
0

我只是做了一个简单的应用程序定期获取屏幕截图。WPF应用程序冻结移动

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

所以主要目的是取出截图,线程的这种影响力等

我把这里所有的代码和它的工作原理,这样你们可以重现。

以下是此代码的一些.NET分析信息。

enter image description here

enter image description here

任何线索我怎么能解决这个问题?

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]; 
      } 
     } 
    } 
} 

回答

2

我相信你可以通过使用后台工作进程来执行截图的函数来避免这种情况。

由于后台工作人员使用另一个线程,并且主线程继续呈现UI,因此不应卡住。

编辑://我发现,这样可能会澄清Background Workers VS Delegates

运气好东西,这个问题!

+1

好点的男人!我只是添加了背景工作者,它的工作完美。 – 2012-04-14 19:01:06