WPF BitmapImage DownloadCompleted 事件从未引发

Posted

技术标签:

【中文标题】WPF BitmapImage DownloadCompleted 事件从未引发【英文标题】:WPF BitmapImage DownloadCompleted event never raised 【发布时间】:2018-03-30 14:10:51 【问题描述】:

我有一个 WPF 图像控件,它的源属性绑定到返回 Image 对象的属性“ImageSrc”。

<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();

永远不会执行,因此我的视图模型中的 Method() 永远不会执行。

当我使用视图模型中绑定的 ImageSrc 属性从视图中的 Image 对象更新 Source 属性时,我检查了转换器是否正确执行。

我做错了什么?

【问题讨论】:

【参考方案1】:

我找到了一种方法来做到这一点,虽然不是最好的方法,但我花了一整天的时间来处理绑定触发器和图像和流的可用方法。我最终做的是分配一个全局布尔值,表示图像已更改,然后使用 Image.LayoutUpdated 操作来检查该布尔值。一旦它看到布尔值并验证图像大小不为零,它就会反转布尔值(因此它不会再次运行)并在图像加载/视图中执行需要执行的操作。

【讨论】:

【参考方案2】:

看看BitmapImageDownloadCompleted事件documentation,备注部分:

可能不会为所有类型的位图内容引发此事件。

【讨论】:

【参考方案3】:

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"/>

你也可以用更少的代码创建一个 BitmapFrame,而不是 BitmapImage:

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;
    

【讨论】:

好的,但是您的解决方案确保我只有在图像被渲染、准备好并且对用户可见/显示时才执行 Method()?我需要一种方法来仅在图像对用户可见之后才执行方法,而不是之前。通过在 ImageSource 属性中调用 Method,我不确定是否仅在用户可见图像后才调用它。可能会发生 Method() 在图像显示并对用户可见之前几秒钟执行的情况。 查看编辑后的答案,了解如何只调用一次 Method()。当渲染线程最终在屏幕上显示图像时,Afaik 无法获得通知。这是你能得到的最好的。【参考方案4】:

DownloadCompleted 事件没有被触发,我遇到了类似的问题。 在我用类中的 BitmapImage 属性替换方法中的局部变量之后。 事件再次被触发。 应该是垃圾收集器,收集了参考资料。

【讨论】:

以上是关于WPF BitmapImage DownloadCompleted 事件从未引发的主要内容,如果未能解决你的问题,请参考以下文章

WPF BitmapImage DownloadCompleted 事件从未引发

从 System.Drawing.Bitmap 加载 WPF BitmapImage

WPF BitmapImage 占用资源无法释放无法删除问题

C# wpf BitmapImage从本地资源获得未知像素大小的图片,如何将其对象设为指定大小

BitMapImage 到字节和反转

WPF-将列表绑定到列表视图