2009-07-22 3 views
1

Ich möchte ein Bild des Bildschirms erfassen, aber es gibt einige WPF-Steuerelemente in meiner Anwendung, die ich nicht im Screenshot erscheinen möchte. Mit dem folgenden Code erscheinen die versteckten Steuerelemente manchmal immer noch im Screenshot. Wie stelle ich sicher, dass dies nicht passiert?Update vor dem Screenshot

Window window = new Window(); 
Button button = new Button(); 

void ShowWindow() 
{ 
    button.Content = "button"; 
    button.ToolTip = "tooltip"; 
    window.Content = button; 
    window.Show(); 

    button.Click += new RoutedEventHandler(button_Click); 
} 

void button_Click(object sender, RoutedEventArgs e) 
{ 
    //Hide some controls and all tooltips in the window 
    ToolTipService.SetIsEnabled(window, false); 
    button.Visibility = Visibility.Hidden; 

    //Block until wpf renders 
    Application.Current.Dispatcher.Invoke(
     System.Windows.Threading.DispatcherPriority.Background, 
     new System.Threading.ThreadStart(delegate { })); 

    //Take screenshot 
    Bitmap bmpScreenshot = new Bitmap(System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width, 
           System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height, 
           System.Drawing.Imaging.PixelFormat.Format32bppArgb); 
    Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot); 
    gfxScreenshot.CopyFromScreen(System.Windows.Forms.Screen.PrimaryScreen.Bounds.X, 
           System.Windows.Forms.Screen.PrimaryScreen.Bounds.Y, 
           0, 0, 
           System.Windows.Forms.Screen.PrimaryScreen.Bounds.Size, 
           CopyPixelOperation.SourceCopy); 
    bmpScreenshot.Save("Screenshot.png", ImageFormat.Png); 

    //Restore controls and tooltips 
    button.Visibility = Visibility.Visible; 
    ToolTipService.SetIsEnabled(window, true); 
} 

Antwort

1

Versuchen Sie es mit einer niedrigen Priorität auf dem Dispatcher, es ist aber immer noch keine Garantie (source).

Auch von meinem Verständnis WPF startet den Renderprozess nicht, bis der UI - Thread im Leerlauf (oder längstens blockiert) ist, so dass Sie den Snapshot & Snapshot Code in einem tatsächlichen Hintergrund Thread (oder haben Sie die Dispatcher ruft den Snapshot-Code asynchron auf. Stellen Sie dann die Schaltflächensichtbarkeit wieder her, sobald dieser Snapshot-Thread abgeschlossen ist.

+0

Danke für den Link. Es scheint unmöglich zu sagen, ob eine Änderung an einem wpf-Steuerelement gerendert wurde. – kova

+1

Diese Antwort war am hilfreichsten. Was ich tun möchte, ist unmöglich (deterministisch). Die beste Wette ist es, einige Tricks auszuprobieren, die hoffentlich dazu führen, dass der Render-Thread läuft und das Rendern vor der Aufnahme beendet, obwohl ich bisher sagen kann, dass es keine Möglichkeit gibt, dies zu garantieren. – kova

0

Haben Sie versucht, die DispatcherPriority-Normal anstatt Background Einstellung?

+0

Oder Render, anstelle von Normal/Hintergrund –

+0

Ändern von DispacherPriority scheint nicht zu helfen. Ich glaube, dass diese Zeile funktioniert, indem alle Aktionen höherer Priorität zur Verarbeitung gezwungen werden. Um ein Rendern zu erzwingen, muss es daher eine niedrigere Priorität haben als das Rendern. Wenn Sie jedoch die Einstellung auf die niedrigste Priorität ändern, wird das Problem nicht behoben. – kova

+0

Interessant und ein guter Punkt. IIRC, das eigentliche Rendern in WPF erfolgt in einem anderen Thread (nicht im Dispatcher-Thread). Das heißt, nur weil der Dispatcher fertig ist, heißt das nicht, dass die Pixel noch auf dem Bildschirm sind. Ich bin nicht sicher, ob diese Informationen upstream sind, wo Sie sind ... Entschuldigung :) –