WPF图像:.Source = Clipboard.GetImage()未显示

4

这个简单的程序无法正常工作,图像没有出现在窗口中。

namespace ClipBoardTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void CopyButton_Click(object sender, RoutedEventArgs e)
        {
            if (Clipboard.ContainsImage())
            {
                ImageUIElement.Source = Clipboard.GetImage();
                Console.WriteLine("Clipboard copied to UIElement");
            }
            else
            {
                Console.WriteLine("No image in Clipboard");
            }
        }
    }
 }

输出是“已将剪贴板复制到UIElement”,但图像未出现在窗口中。

XAML:

 <Window x:Class="ClipBoardTest.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="MainWindow" Height="350" Width="525">
     <Grid>
         <Button x:Name="CopyButton" Content="Copy" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="CopyButton_Click"/>
         <Image x:Name="ImageUIElement" Margin="90,10,10,10"/>
     </Grid>
 </Window>

有人能理解出问题所在吗?


请尝试按照此处指定的解决方法进行操作:http://social.msdn.microsoft.com/Forums/vstudio/en-US/10589cd6-6a48-4497-8f7d-a12490f376c6/clipboardgetimage-and-imagesource。 - Rohit Vats
我也遇到了这种情况,但奇怪的是只有剪贴板上的某些图像。从浏览器复制的图像可以正常工作。从 SnagIt 复制的图像出现问题,即使我可以捕获并将相同的图像显式保存到磁盘并使用它。对我来说,另一种替代方法是先保存到磁盘,然后从那里加载以在控件中显示。 - Rick Strahl
3个回答

7
使用 Clipboard.GetDataObject 获取位图并将其转换为位图源。请注意,Bitmap.GetHbitmap() 会泄漏内存,除非您在其上调用 DeleteObject。
因此,正确的解决方案是在使用后处理 IntPtr。在类级别声明该方法,并从您的代码中使用它。
// at class level
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

if (Clipboard.ContainsImage())
{
    IDataObject clipboardData = Clipboard.GetDataObject();
    if (clipboardData != null)
    {
        if (clipboardData.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap))
        {
            System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)clipboardData.GetData(System.Windows.Forms.DataFormats.Bitmap);
            IntPtr hBitmap = bitmap.GetHbitmap();
            try
            {
                ImageUIElement.Source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
                Console.WriteLine("Clipboard copied to UIElement");
            }
            finally 
            {
                DeleteObject(hBitmap)
            }
        }
    }
}

Source - MSDN and Memory leak in Bitmap.


谢谢。如果我不需要System.Windows.Forms用于其他目的,那么这比social.msdn.microsoft.com上的解决方法更好。谢谢。 :-) - Torsten Crull
1
应该使用bitmap.GetHbitmap()而不是bmp.GetHbitmap()。 - Chris Zeh
1
@ChrisZeh - 是的,有一个小错别字。已经更正了。谢谢.. :-) - Rohit Vats
2
注意:在第3行中,“Clipboard”指的是“System.Windows.Forms.Clipboard”,而不是“System.Windows.Clipboard”。 - AstroRP

3

使用 Visual Studio 2019,针对 .NET Core 3.1 的 WPF C# 项目,以下内容有效(或者至少对我是有效的):

myImage.Source = GetImageFromClipBoard();

其中:

public static ImageSource GetImageFromClipBoard ()
        {
        if (Clipboard.ContainsImage())
            {
            return Clipboard.GetImage();
            }
        else
            return null;
        }

3
请注意,并非所有复制的位图都可以使用此方法。例如,如果在Microsoft Paint中复制位图,则会得到一个空白区域,但如果在Paint.NET、LibreOffice或类似软件中复制位图,则可以正常工作。一般来说,问题在于某些程序(如Microsoft Paint)仅复制与设备相关的位图,而WPF更喜欢使用与设备无关的位图。您需要通过添加BITMAPINFOHEADER结构将其转换,如此博客所示:https://thomaslevesque.com/2009/02/05/wpf-paste-an-image-from-the-clipboard/。 - AndresRohrAtlasInformatik
对于任何需要从画图中获取图像的人,强烈推荐@AndresRohrAtlasInformatik评论中附带的链接。 - Eduards

1
现在它工作得很好。
if (Clipboard.ContainsImage())
{
    // ImageUIElement.Source = Clipboard.GetImage(); // does not work
    System.Windows.Forms.IDataObject clipboardData = System.Windows.Forms.Clipboard.GetDataObject();
    if (clipboardData != null)
    {
        if (clipboardData.GetDataPresent(System.Windows.Forms.DataFormats.Bitmap))
        {
            System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)clipboardData.GetData(System.Windows.Forms.DataFormats.Bitmap);
            ImageUIElement.Source =  System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty,BitmapSizeOptions.FromEmptyOptions());
            Console.WriteLine("Clipboard copied to UIElement");
        }
    }
}

终于,一个可行且简单的解决方案出现了。干得好。 - Andrea Antonangeli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接