2017-10-18 149 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操作来检查该布尔值。一旦它看到布尔值并验证图像大小不为零,它就会颠倒布尔值(所以它不会再运行),并且在图像加载/视图中执行需要完成的操作。