2016-08-21 2 views
0

В моем приложении я делаю снимок экрана рабочего стола. Прямо перед тем, что я скрыть мое приложение в Window, поэтому он не будет покрывать часть рабочего стола:WPF - как запустить код сразу после того, как окно скрыто

MainWindow.Hide(); 
TakeScreenShot(); 

Проблема заключается в том, что иногда окно не получает скрытый достаточно быстро, так что я в конечном итоге принимает скриншот него слишком , Я попытался сделать снимок экрана с обработчика события Window.IsVisibleChanged, но результат тот же.

Конечно, я могу использовать Thread.Sleep или аналогичный, но я ищу лучшее решение.

Update

Я только что перешел на Aero тему и включен композицию рабочего стола, а сейчас ситуация еще хуже. Теперь окно «исчезает» вместо мгновенного скрытия при вызове Window.Hide. Итак, теперь мое приложение всегда сделало снимок экрана из окна затухания ... Я попробую winapi с SetWindowPos или ShowWindow и опубликует обновление.

Обновление 2

  1. ShowWindow и SetWindowPos дают тот же результат, как Window.Hide (Window.Hide использует ShowWindow(HWND, SW_HIDE) внутренне).

  2. Чтобы отключить эффект угасания при скрытии окна, я использую DwmSetWindowAttribute.

так:

using System.Windows.Interop; 
using System.Runtime.InteropServices; 

[DllImport("dwmapi.dll")] 
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); 

private const int DWMWA_TRANSITIONS_FORCEDISABLED = 3; 

и в обработчик события Window.Loaded:

if (Environment.OSVersion.Version.Major >= 6) { 

    IntPtr WinHandle = new WindowInteropHelper(this).Handle; 

    int BOOL_TRUE = 1; 

    int HR = DwmSetWindowAttribute(WinHandle, DWMWA_TRANSITIONS_FORCEDISABLED, BOOL_TRUE, Marshal.SizeOf(BOOL_TRUE)); 

    if (HR != 0) 
     Marshal.ThrowExceptionForHR(HR); 
} 

Так рядом с эффектом постепенного исчезновения, проблема остается.

+0

Вы пробовали простой [OnDeactivated] (https://msdn.microsoft.com/en-us/library/system.windows.window.deactivated (v = vs.110) .aspx)? или [OnStateChanged] (https://msdn.microsoft.com/en-us/library/system.windows.window.statechanged (v = vs.110) .aspx) с проверкой фильтра 'minimized' state? – quetzalcoatl

+0

@quetzalcoatl: Я попытался снять скриншот из Window.Deactivated обработчика событий. Результат тот же. Я не пытался из StateChanged, потому что я не хочу минимизировать окно. – Bohoo

+0

@Bohoo вы можете рассказать мне, как выглядит ваш «TakeScreenShot»? – Gopichandar

ответ

0

Вы можете начать с пробития вашего окна за пределами области, которую вы пытаетесь скопировать (когда была принята во внимание проблема восстановления подзаголовка).

public partial class MainWindow : Window 
{ 

    private DispatcherOperation _action; 
    private int _width = 2000; 
    private int _height = 1000; 
    private double _top; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     Dispatcher.Hooks.OperationCompleted += HooksOnOperationCompleted; 
    } 

    private void HooksOnOperationCompleted(object sender, DispatcherHookEventArgs dispatcherHookEventArgs) 
    { 
     if(dispatcherHookEventArgs.Operation != _action) return; 
     _action.Task.ContinueWith((t) => 
     { 
      Rectangle rect = new Rectangle(0, 0, _width, _height); 
      Bitmap bmp = new Bitmap(rect.Width, rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
      Graphics g = Graphics.FromImage(bmp); 
      g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy); 
      bmp.Save("help" + DateTime.Now.Ticks + ".jpg", ImageFormat.Jpeg); 
     }).ContinueWith(t => 
     { 
      Dispatcher.BeginInvoke((Action)(() => 
      { 
       Top = _top; 
      })); 
     }); 


    } 

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e) 
    { 
     _top = Top; 
     _action = Dispatcher.BeginInvoke((Action) (() => 
     { 
      Top = 10000; 
     })); 
    } 
} 
+0

Спасибо за ваш ответ. Включение окна с экрана работает, но его взлом ... Я не знаю, что на самом деле происходит, когда я это делаю, и каковы последствия. Поскольку это производственный код, я предпочитаю не использовать его. Также вы можете увидеть мое обновление к моему вопросу. – Bohoo

+0

Ok @Bohoo. Но я не могу понять, что вы имеете в виду, говоря: «что на самом деле происходит, когда я это делаю, и каковы последствия». Применяя Top = Y_POSITION Вы просто переместите окно в определенную позицию (Y_POSITION) на экране. С уважением. – Ilan

0

Попробуйте свести к минимуму Window прежде, чем прятать Window и запустить его Asynchronously с наименьшим приоритетом. Что-то вроде этого.

private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     //Minimize here before hiding. . 
     this.WindowState = WindowState.Minimized; //this is the key 
     this.Visibility = Visibility.Hidden; 
     this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, new Action(() => 
     {     
      CaptureImage(); 
     }));    
    } 

    private void CaptureImage() 
    { 
     System.Drawing.Rectangle bounds = new System.Drawing.Rectangle(0, 0, (int)System.Windows.SystemParameters.PrimaryScreenWidth, (int)System.Windows.SystemParameters.PrimaryScreenHeight); 
     using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height)) 
     { 
      using (Graphics g = Graphics.FromImage(bitmap)) 
      { 
       g.CopyFromScreen(System.Drawing.Point.Empty, System.Drawing.Point.Empty, bounds.Size); 
      } 
      bitmap.Save("test.jpg", ImageFormat.Jpeg); 
     } 
    } 

Надеюсь, это поможет. Благодарю.

+0

Спасибо за ваш ответ. Я предпочитаю не сводить к минимуму окно из-за анимации, которую он включает. Использование 'DispatcherPriority.SystemIdle' само по себе не помогло. Вы можете увидеть обновление моего вопроса. – Bohoo

Смежные вопросы