题
我在使用 WPF 时遇到了一个奇怪的问题,我在运行时从磁盘加载图像并将它们添加到 StackView 容器中。但是,图像没有显示。经过一番调试,我发现了窍门,但它确实没有任何意义。我制作了一个小型演示应用程序来识别问题:
新建一个WPF项目,粘贴代码如下:
xml:
<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= ...”行上生成异常。如果该行被注释,即使不存在图像,程序也会毫无异常地运行。仅当必要时才加载图像,但是当我将 Image 控件添加到 StackPanel 时,应该加载图像。
有什么想法吗?
编辑:顺便说一句,如果将图像添加为资源,则不需要“int q = ..”行。
解决方案
这是因为创作被延迟。 如果你想要的图片立即加载,你可以简单地添加该代码到初始化阶段。
<强> src.CacheOption = BitmapCacheOption.OnLoad; 强>
是这样的:
src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
其他提示
在代码中执行的程序集,其中我的图像“Freq.png”是文件夹“图标”在和定义为“资源”。
加载资源 this.Icon = new BitmapImage(new Uri(@"pack://application:,,,/"
+ Assembly.GetExecutingAssembly().GetName().Name
+ ";component/"
+ "Icons/Freq.png", UriKind.Absolute));
我也能发功能,如果有人想它...
/// <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,你把它复制过来,这是行不通的。
解决方案1:的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);
的问题:流保持开放。如果您在本方法的最后关闭,图像将不会出现。这意味着该文件保持在系统上写锁定。
解决方案2:MemoryStream的
这基本上是溶液1,但你文件读入到存储器流并传递内存流作为参数。
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 的各种事件:
就图像而言,他们可能会告诉您一些正在发生的事情。
下面是扩展方法来加载从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);
简单!