【问题标题】:WPF BitmapImage DownloadCompleted event never raisedWPF BitmapImage DownloadCompleted 事件从未引发
【发布时间】: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 属性时,我检查了转换器是否正确执行。

我做错了什么?

【问题讨论】:

    标签: c# wpf mvvm visual-studio-2008 .net-3.5


    【解决方案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 属性替换方法中的局部变量之后。 事件再次被触发。 应该是垃圾收集器,收集了参考资料。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-26
          • 1970-01-01
          • 2012-12-20
          • 1970-01-01
          • 1970-01-01
          • 2010-09-10
          相关资源
          最近更新 更多