2012-04-14 18 views
0

私はちょうど単純なアプリケーションを使ってスクリーンショットを定期的に取得しました。WPFアプリケーションが動くとフリーズ

私が持っている主な問題は、移動するとアプリケーションがフリーズすることです。

だから、主な目標は、スクリーンショットのこの影響を取り出すことで、スレッドとなど

私はここですべてのコードを入れて、それはそうuがそれを再現することができます動作します。

このコードの.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をレンダリングし続けるため、スタックしないでください。

EDIT://私はSOそれはBackground Workers VS Delegates

幸運に物事を明らかにする可能性がある上、この質問を見つけました!

+1

グッドポイントマン!私はちょうどバックグラウンドワーカーを追加し、それは完璧に動作します。 –

関連する問題