2010-08-06 51 views
12

我將一個ListView綁定到一個對象列表,如下所示;使用XAML將System.Drawing.Image綁定到System.Windows.Image控件

<ListView 
    ItemsSource="{ Binding Path=. }" 
    ItemTemplate="{DynamicResource EventTemplate}"> 

我綁定到聲明兩個屬性的對象;

string DisplayName { get; } 
System.Drawing.Image Image { get; set; } 

我想填充DataTemplate但我無法弄清楚如何;如果我在我的模板中這樣做;

<StackPanel Orientation="Horizontal"> 
    <Image Source="{ Binding Path=Image }" /> 
    <TextBlock Text="{ Binding Path=DisplayName }" /> 
</StackPanel>  

出現文字,但圖像沒有。我究竟做錯了什麼?調試輸出顯示

System.Windows.Data Error: 1 : Cannot create default converter 
to perform 'one-way' conversions between types 
'System.Drawing.Image' and 'System.Windows.Media.ImageSource'. 
Consider using Converter property of Binding. 
BindingExpression:Path=Image; DataItem='RealElement' 
(HashCode=54308798); target element is 'Image' (Name=''); 
target property is 'Source' (type 'ImageSource') 

回答

34

找到一個我很滿意的方式。使用Reed Copsey's pointerthis tutorial我已將代碼封裝爲IValueConverter

下面是從System.Drawing.ImageSystem.Windows.Media.ImageSource的轉換器;

using System; 
using System.Drawing.Imaging; 
using System.Globalization; 
using System.IO; 
using System.Windows.Data; 

namespace System.Windows.Media 
{ 
    /// <summary> 
    /// One-way converter from System.Drawing.Image to System.Windows.Media.ImageSource 
    /// </summary> 
    [ValueConversion(typeof(System.Drawing.Image), typeof(System.Windows.Media.ImageSource))] 
    public class ImageConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, 
      object parameter, CultureInfo culture) 
     { 
      // empty images are empty... 
      if (value == null) { return null; } 

      var image = (System.Drawing.Image)value; 
      // Winforms Image we want to get the WPF Image from... 
      var bitmap = new System.Windows.Media.Imaging.BitmapImage(); 
      bitmap.BeginInit(); 
      MemoryStream memoryStream = new MemoryStream(); 
      // Save to a memory stream... 
      image.Save(memoryStream, ImageFormat.Bmp); 
      // Rewind the stream... 
      memoryStream.Seek(0, System.IO.SeekOrigin.Begin); 
      bitmap.StreamSource = memoryStream; 
      bitmap.EndInit(); 
      return bitmap; 
     } 

     public object ConvertBack(object value, Type targetType, 
      object parameter, CultureInfo culture) 
     { 
      return null; 
     } 
    } 
} 

然後,您需要將圖像轉換器放入XAML作爲資源;

xmlns:med="clr-namespace:System.Windows.Media" 
... 

<ListView.Resources> 
    <med:ImageConverter x:Key="imageConverter" /> 
</ListView.Resources> 

然後,您可以在XAML中使用它直接綁定到圖像,使用新的轉換器;

<Image Source="{ Binding Path=Image, Converter={StaticResource imageConverter} }" /> 
+1

我有一個關於內存使用情況的問題:這個轉換是否只發生一次,或者每次圖像顯示在ListBox的可見部分? – emesx 2011-12-30 22:12:34

+1

無法真正說出 - WPF需要每次都進行轉換 - 所以我認爲這只是一個內部實現細節。我認爲它不會有任何理由被一遍又一遍地轉換,但它可能值得堅持在一個櫃檯,並看到...... – 2012-01-06 00:30:29

+1

'memoryStream'永遠不會關閉或處置,這是一個關注嗎?我有一些非常相似的代碼,可能來自這個問題,但它更醜陋。 – Maslow 2015-09-02 00:19:26

4

不能直接綁定 - 你需要有一些類型的轉換器,將來自GDI圖像轉換爲WPF圖像。

這是one approach - 它使用內存流從GDI圖像中提取數據並創建一個BitmapSource對象。

+0

嗨,感謝您的指點。我目前只是通過閱讀您的「更好的用戶和開發人員體驗 - 從Windows窗體到帶有MVVM的WPF」文章的一半;好東西。無論如何,這給了我足夠的答案。我已經發布了它。 – 2010-08-06 20:04:25

+0

@Steve:很高興聽到你喜歡這個系列;) – 2010-08-06 20:05:33

+0

這真的很有幫助。 WPF模型與Windows窗體非常不同,你的文章正在幫助我解開它。 – 2010-08-06 20:12:45