清理画布有延迟

时间:2013-08-23 15:22:36

标签: c# wpf wpf-controls

下面是一个简单应用程序的代码,该应用程序在窗口中的画布上绘制一个矩形,然后在按下任何键时使用CopyFromScreen函数拍摄应用程序的屏幕截图。然而,在调用它之前,我调用canvas.Children.Clear()。然后我会期望结果图像中没有矩形,但确实如此。似乎在调用函数时不会从画布中删除实际的矩形图像,但是在一段时间之后。

我尝试输入System.Threading.Thread.Sleep(1000);在Clear()调用之后,矩形也会在屏幕上停留一整秒。显然,在按键功能完成后它会被删除,有没有办法在CopyFromScreen调用之前将其删除?

要运行此功能,您需要添加对System.Drawing的引用。

XAML代码

<Window x:Class="CanvasTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Width="210" Height="240"
        KeyDown="keyPressed">
    <Window.Background>
        <SolidColorBrush Color="White"/>
    </Window.Background>
    <Grid>
        <Canvas Name="canvas"
            HorizontalAlignment="Left" VerticalAlignment="Top">
        </Canvas>
    </Grid>
</Window>

.cs代码

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;

namespace CanvasTest {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();

            Left = 0;
            Top = 0;

            Rectangle rect = new Rectangle {
                Stroke = System.Windows.Media.Brushes.Black,
                StrokeThickness = 1,
                Width = 100,
                Height = 100
            };

            canvas.Children.Add(rect);
            Canvas.SetLeft(rect, 50);
            Canvas.SetTop(rect, 50);
        }

        private void keyPressed(object sender, System.Windows.Input.KeyEventArgs e) {
            System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap((int)Width, (int)Height);

            System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap);

            canvas.Children.Clear();
            graphics.CopyFromScreen(0, 0, 0, 0,
                                    new System.Drawing.Size(bitmap.Width, bitmap.Height),
                                    System.Drawing.CopyPixelOperation.SourceCopy);

            String path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            path += "\\MuckleEwesPic.png";

            bitmap.Save(path, System.Drawing.Imaging.ImageFormat.Png);
        }
    }
}

如何在不发生此行为的情况下清除画布然后拍摄屏幕截图?没有'不添加矩形'不是解决方案,这只是一个发生问题的大型应用程序的最小示例。

感谢。

1 个答案:

答案 0 :(得分:1)

使用像ColinSmith的链接:

static void WaitForRenderPass()
{
  Application.Current.Dispatcher
    .BeginInvoke( DispatcherPriority.ApplicationIdle, new Action( () => {} ) )
    .Wait();
}

等待渲染过程的一些工作,但问题是不能(afaik)判断渲染过程是否包含你想要的一切。

在实践中,取决于系统负载/视频卡驱动程序/ ...必须多次调用它。我有一台机器,必须在一个循环中调用最多3次,每次调用大约需要2帧@ 60Hz才能完成。只有这样,对上面的调用才会立即返回,表明渲染线程确实处于空闲状态,这可能意味着您想要的所有更改都已呈现,这反过来意味着屏幕捕获包含它们应具有的所有内容。所以我们最终使用了

for( int i = 0 ; i < 5 ; ++i )
{
  WaitForRenderPass();
  Thread.Sleep( 10 );
}

它丑陋而且它是一个黑客,但它还没有失败(还)。

关于HighCore的评论:您也可以捕获屏幕with Wpf-only classes,但是:

  • 它有同样的问题,OP首先启动了这个问题所以它不会立即解决任何问题(除非不使用System.Drawing)
  • 您无法在捕获中获得主窗口的镶边
  • 它明显慢于CopyScreen
  • 它不会渲染与渲染到屏幕完全相同的像素