0

下面是一个简单应用程序的代码,它在窗口的画布上绘制一个矩形,然后在按下任意键时使用 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);
        }
    }
}

如何清除画布然后截屏而不发生这种行为?并且没有“不添加矩形”不是解决方案哈,这只是发生问题的大型应用程序的一个最小示例。

谢谢。

4

1 回答 1

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 的评论:您也可以使用 Wpf-only 类捕获屏幕,但是:

  • 它有同样的问题,OP首先开始这个questiomn所以它不会立即解决任何问题(除了不使用System.Drawing)
  • 您将无法在捕获中获取主窗口的镶边
  • 它明显比 CopyScreen 慢
  • 它不会渲染与渲染到屏幕完全相同的像素
于 2015-04-02T08:05:58.557 回答