2017-10-18 151 views
0

我有一個WPF圖像控件,它的源屬性綁定到返回Image對象的屬性「ImageSrc」。WPF BitmapImage DownloadCompleted event never raised

<Window x:Class="My.Apps.WPF.Main" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:viewmodel="clr-namespace:My.Apps.WPF.ViewModels" 
    xmlns:classes="clr-namespace:My.Apps.WPF.Classes" 
    > 
    <Window.Resources> 
     <viewmodel:MyViewModel x:Key="myViewModel" />  
     <classes:ImgToSrcConverter x:Key="imgToSrcConverter" />  
    </Window.Resources> 

    <Grid x:Name="TopGrid" DataContext="{StaticResource myViewModel}"> 

     <Image Grid.Row="0"> 
      <Image.Source> 
      <MultiBinding NotifyOnTargetUpdated="True" Converter="{StaticResource imgToSrcConverter}"> 
       <Binding Path="ImageSrc" /> 
       <Binding Path="." /> 
       </MultiBinding> 
      </Image.Source> 
     </Image> 
    </Grid> 
</Window> 

轉換

public class ImgToSrcConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     Image image = values[0] as Image; 
     if (image != null) 
     { 
      MemoryStream ms = new MemoryStream(); 
      image.Save(ms, image.RawFormat); 
      ms.Seek(0, SeekOrigin.Begin); 
      BitmapImage bi = new BitmapImage(); 
      bi.BeginInit(); 
      bi.StreamSource = ms; 
      bi.EndInit(); 

      ViewModel vm = values[1] as ViewModel; 
      bi.DownloadCompleted += (s, e) => 
      { 
       vm.Method(); 
      }; 

      return bi; 
     } 
     return null; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

我很痛苦的問題是,BitmapImage的DownloadCompleted事件是從來沒有提出這樣一行:

vm.Method(); 

永遠不會執行,因此該方法( )在我的視圖模型從未執行。

我已經檢查,當我使用視圖模型中綁定的ImageSrc屬性更新來自Image對象的Source屬性時,轉換器正確執行。

我在做什麼錯?

回答

0

看看到BitmapImageDownloadCompleted事件documentation備註部分:

此事件可能不會引發對所有類型的內容的位圖。

0

DownloadCompleted事件未被觸發,因爲在從流中創建BitmapImage時沒有下載。

您不應該通過綁定轉換器來做到這一點,而是通過異步綁定使用ImageSource類型的另一個視圖模型屬性。

private ImageSource imageSource; 

public ImageSource ImageSource 
{ 
    get 
    { 
     if (imageSource == null) 
     { 
      using (var stream = new MemoryStream()) 
      { 
       ... 

       var bitmap = new BitmapImage(); 
       bitmap.BeginInit(); 
       bitmap.CacheOption = BitmapCacheOption.OnLoad; 
       bitmap.StreamSource = stream; 
       bitmap.EndInit(); 
       bitmap.Freeze(); // necessary for async binding 
       imageSource = bitmap; 
      } 

      Method(); 
     } 

     return imageSource; 
    } 
} 

然後綁定到該屬性是這樣的:

<Image Source="{Binding ImageSource, IsAsync=True}"/> 

而不是一個BitmapImage的,你也可以創建一個BitmapFrame用少一點代碼:

private ImageSource imageSource; 

public ImageSource ImageSource 
{ 
    get 
    { 
     if (imageSource == null) 
     { 
      using (var stream = new MemoryStream()) 
      { 
       ... 
       imageSource = BitmapFrame.Create(
        stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); 
      } 

      Method(); 
     } 

     return imageSource; 
    } 
} 
+0

ok,但是您的解決方案確保了Method()僅在圖像呈現,準備就緒且可見/顯示給用戶時才執行?我需要一種方法,只有在用戶可以看到圖像後才執行方法,而不是之前。通過在ImageSource屬性中調用Method,我不確定僅在圖像對用戶可見後纔會調用它。可能會出現Method()方法在圖像顯示之前的幾秒鐘執行並且用戶可見。 – user1624552

+0

請參閱已編輯的答案,瞭解如何僅調用一次Method()。當渲染線程最終在屏幕上顯示圖像時,Afaik無法獲得通知。這是你可以得到的最好的。 – Clemens

1

我發現一種方法來做到這一點,雖然不是最好的方法,但我掙扎了大約一整天與綁定觸發器和可用的方法搞砸法師和小溪。我最終做的是分配一個全局布爾值,表示圖像已被更改,然後使用Image.LayoutUpdated操作來檢查該布爾值。一旦它看到布爾值並驗證圖像大小不爲零,它就會顛倒布爾值(所以它不會再運行),並且在圖像加載/視圖中執行需要完成的操作。