49

我对 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= ...”行生成异常。如果该行被注释,即使没有图像,程序也会毫无例外地运行。仅在必要时才加载图像,但是当我将图像控件添加到 StackPanel 时应该加载图像。

有什么想法吗?

编辑:顺便说一句,如果您将图像添加为资源,则不需要“int q = ..”行。

4

5 回答 5

103

这是因为创造被延迟了。如果您希望立即加载图片,您可以简单地将这段代码添加到 init 阶段。

src.CacheOption = BitmapCacheOption.OnLoad;

像这样:

src.BeginInit();
src.UriSource = new Uri("picture.jpg", UriKind.Relative);
src.CacheOption = BitmapCacheOption.OnLoad;
src.EndInit();
于 2009-02-24T06:56:44.453 回答
11

在执行程序集中加载资源的代码中,我的图像“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");
于 2012-03-16T13:38:37.023 回答
7

这是一种奇怪的行为,虽然我无法说明为什么会发生这种情况,但我可以推荐一些选项。

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

解决方案 1:文件流

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:内存流

这基本上是解决方案 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);

现在您可以修改系统上的文件,如果您需要的话。

于 2009-02-20T14:26:36.387 回答
2

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

就图像而言,他们可能会告诉您一些正在发生的事情。

于 2009-02-20T14:27:27.477 回答
0

这是从 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);

就那么简单!

于 2013-04-16T09:03:40.930 回答