在WPF中dynamic加载图像

我有一个WPF的奇怪问题,我在运行时从磁盘加载图像,并将它们添加到一个StackView容器。 但是,图像不显示。 经过一些debugging后,我发现了这个窍门,但是它确实没有任何意义。 我已经做了一个小的演示程序来识别问题:

创build一个新的WPF项目,并粘贴代码如下:

XAML:

<Window x:Class="wpfBug.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300" Loaded="Window_Loaded"> <StackPanel Name="sp"> </StackPanel> </Window> 

xaml.cs,粘贴在默认使用下面:

 namespace wpfBug { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { Image i = new Image(); BitmapImage src = new BitmapImage(); src.BeginInit(); src.UriSource = new Uri("picture.jpg", UriKind.Relative); src.EndInit(); i.Source = src; i.Stretch = Stretch.Uniform; //int q = src.PixelHeight; // Image loads here sp.Children.Add(i); } } } 

复制一个图像到bin / Debug文件夹中,并将其命名为'picture.jpg'

这个程序不会显示任何东西,除非注释行不注释。

任何人都可以解释我做错了什么,或为什么发生这种情况? 如果您删除图像并运行该程序,则会在“int q = …”行上生成一个exception。 如果该行被注释,即使没有图像存在,该程序也将无例外地运行。 只有在有意义的情况下才加载图像,但是当我将Image控件添加到StackPanel时,应该加载图像。

任何ides?

编辑:顺便说一句,如果您添加图像作为资源,'int q = ..'行是不需要的。

这是因为创作被推迟了。 如果您想要立即加载图片,只需将此代码添加到初始阶段即可。

src.CacheOption = BitmapCacheOption.OnLoad;

喜欢这个:

 src.BeginInit(); src.UriSource = new Uri("picture.jpg", UriKind.Relative); src.CacheOption = BitmapCacheOption.OnLoad; src.EndInit(); 

在执行程序集中加载资源的代码中,图像“Freq.png”位于文件夹“Icons”中,并定义为“Resource”。

  this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/" + Assembly.GetExecutingAssembly().GetName().Name + ";component/" + "Icons/Freq.png", UriKind.Absolute)); 

如果有人愿意,我也做了一个function…

 /// <summary> /// Load a resource WPF-BitmapImage (png, bmp, ...) from embedded resource defined as 'Resource' not as 'Embedded resource'. /// </summary> /// <param name="pathInApplication">Path without starting slash</param> /// <param name="assembly">Usually 'Assembly.GetExecutingAssembly()'. If not mentionned, I will use the calling assembly</param> /// <returns></returns> public static BitmapImage LoadBitmapFromResource(string pathInApplication, Assembly assembly = null) { if (assembly == null) { assembly = Assembly.GetCallingAssembly(); } if (pathInApplication[0] == '/') { pathInApplication = pathInApplication.Substring(1); } return new BitmapImage(new Uri(@"pack://application:,,,/" + assembly.GetName().Name + ";component/" + pathInApplication, UriKind.Absolute)); } 

用法:

  this.Icon = ResourceHelper.LoadBitmapFromResource("Icons/Freq.png"); 

这是奇怪的行为,虽然我不能说为什么这是发生,我可以推荐一些选项。

首先是观察。 如果您在VS中包含图像作为内容,并将其复制到输出目录,您的代码工作。 如果图像在VS中被标记为“无”,并且将其复制,则不起作用。

解决scheme1:FileStream

BitmapImage对象接受UriSource或StreamSource作为参数。 现在让我们使用StreamSource。

  FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read); Image i = new Image(); BitmapImage src = new BitmapImage(); src.BeginInit(); src.StreamSource = stream; src.EndInit(); i.Source = src; i.Stretch = Stretch.Uniform; panel.Children.Add(i); 

问题:stream保持打开。 如果在此方法结束时closures它,图像将不会显示出来。 这意味着该文件在系统上保持写入locking状态。

解决scheme2:MemoryStream

这基本上是解决scheme1,但您将文件读入内存stream并将该内存stream作为parameter passing。

  MemoryStream ms = new MemoryStream(); FileStream stream = new FileStream("picture.png", FileMode.Open, FileAccess.Read); ms.SetLength(stream.Length); stream.Read(ms.GetBuffer(), 0, (int)stream.Length); ms.Flush(); stream.Close(); Image i = new Image(); BitmapImage src = new BitmapImage(); src.BeginInit(); src.StreamSource = ms; src.EndInit(); i.Source = src; i.Stretch = Stretch.Uniform; panel.Children.Add(i); 

现在,您可以修改系统上的文件,如果这是您需要的东西。

您可以尝试将处理程序附加到BitmapImage的各种事件:

  • DecodeFailed
  • DownloadFailed
  • DownloadCompleted

就形象而言,他们可能会告诉你一些什么事情。

这里是从URI加载图片的扩展方法:

 public static BitmapImage GetBitmapImage( this Uri imageAbsolutePath, BitmapCacheOption bitmapCacheOption = BitmapCacheOption.Default) { BitmapImage image = new BitmapImage(); image.BeginInit(); image.CacheOption = bitmapCacheOption; image.UriSource = imageAbsolutePath; image.EndInit(); return image; } 

使用示例:

 Uri _imageUri = new Uri(imageAbsolutePath); ImageXamlElement.Source = _imageUri.GetBitmapImage(BitmapCacheOption.OnLoad); 

就那么简单!