Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将WPF控件的图像输出到剪贴板_Wpf_Clipboard_Bitmapsource - Fatal编程技术网

如何将WPF控件的图像输出到剪贴板

如何将WPF控件的图像输出到剪贴板,wpf,clipboard,bitmapsource,Wpf,Clipboard,Bitmapsource,我有下面的代码,它接受一个控件(作为一个可视对象),使用一个可视笔刷将控件绘制成一个RenderTargetBitmap,然后保存到磁盘上。这是成功的 我想使用相同的代码将图像放置在剪贴板中。这似乎不起作用;尽管剪贴板接受数据,但它不接受数据是图像。 这显然是一个格式问题,但我不知道如何排序 守则如下:- public void CopyToClipBoard(Visual forDrawing) { RenderTargetBitmap bmp = Control

我有下面的代码,它接受一个控件(作为一个可视对象),使用一个可视笔刷将控件绘制成一个RenderTargetBitmap,然后保存到磁盘上。这是成功的

我想使用相同的代码将图像放置在剪贴板中。这似乎不起作用;尽管剪贴板接受数据,但它不接受数据是图像。 这显然是一个格式问题,但我不知道如何排序

守则如下:-

public void CopyToClipBoard(Visual forDrawing)
{           
    RenderTargetBitmap bmp = ControlToImage(forDrawing, 96, 96);
    CopyToClipBoard(bmp);
}
private void CopyToClipBoard(BitmapSource bmp)
{
   Thread thread = new Thread(() =>
   {                
      Clipboard.SetImage(bmp);
   });
   thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
   thread.Start();
}
private static RenderTargetBitmap ControlToImage(Visual target, double dpiX, double dpiY)
{
   if (target == null)
   {
      return null;
   }
   // render control content
   Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
   RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
                                                   (int)(bounds.Height * dpiY / 96.0),
                                                  dpiX, dpiY,
                                                  PixelFormats.Pbgra32);
   DrawingVisual dv = new DrawingVisual();
   using (DrawingContext ctx = dv.RenderOpen())
   {
       VisualBrush vb = new VisualBrush(target);
       ctx.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), bounds.Size));
    }
    rtb.Render(dv);
    return rtb;           
}

在检查代码之后,我希望在线程委托中抛出一个跨线程异常(
CopyToClipBoard(BitmapSource):void
BitmapSource
是一个
DispatcherObject
,它是在不同的调度程序线程(在主线程上)上创建的,而不是在主线程上处理的。不能在线程之间传递
DispatcherObject
实例。除了实例extends
Freezable
Freezable.Freeze()
之外,此实例上调用了

这意味着,为了将
bmp
引用传递给处理剪贴板的线程(或通常相关线程以外的任何其他线程),您必须调用
bmp.Freeze()

我假设异常被
线程
吞没,并且您从未在调试模式下运行应用程序。这就是为什么你从未意识到这个例外

正如我之前所写的,您不需要生成新的STA线程来访问剪贴板。我不推荐这个

如果继续使用专用线程,只需在将其传递给线程之前冻结
Freezable

public void CopyToClipBoard(Visual forDrawing)
{           
    RenderTargetBitmap bmp = ControlToImage(forDrawing, 96, 96);
   
    // Freeze the freezable DispatcherObject so that it can be consumed by other threads
    bmp.Freeze();

    CopyToClipBoard(bmp);
}

剪贴板操作必须在应用程序的主线程上进行。无需为剪贴板集操作生成新的UI线程。如果您有后台线程,则至少应通过调用其Freeze()方法确保可从该线程(或从创建RenderTargetBitmap的线程以外的任何线程)访问该RenderTargetBitmap。冻结BitmapSource就可以做到这一点。我使用线程是因为它不在应用程序的主线程上。实际上,我是在调试模式下运行软件的,但出于某种原因,VS2019没有捕获异常-因此我假设(总是一个错误!)某些内容正在以不友好的格式传递到剪贴板。您应该至少启用所有CLR异常:按Ctrl+Alt+E并选中相关框。默认情况下,VS不会因所有异常而中断。事实证明,这非常有用-谢谢