wpf WPF中图片的动态加载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/569561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 20:04:26  来源:igfitidea点击:

Dynamic loading of images in WPF

wpfimagedynamicloading

提问by sindre j

I have a strange issue with WPF, I was loading images from the disk at runtime and adding them to a StackView container. However, the images were not displayed. After some debugging I found the trick, but it really doesn't make any sense. I've made a small demo app to identify the problem:

我对 WPF 有一个奇怪的问题,我在运行时从磁盘加载图像并将它们添加到 StackView 容器中。但是,没有显示图像。经过一些调试后,我找到了诀窍,但这确实没有任何意义。我制作了一个小型演示应用程序来识别问题:

Create a new WPF project, and paste code as follows:

新建一个WPF工程,粘贴代码如下:

xaml:

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, paste below default usings:

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

Copy a image to the bin/Debug folder and call it 'picture.jpg'

将图像复制到 bin/Debug 文件夹并将其命名为“picture.jpg”

This program doesn't display anything, unless the commented line is uncommented.

该程序不显示任何内容,除非注释行被取消注释。

Can anyone explain what I'm doing wrong, or why this happens? If you remove the image and run the program it generates an exception on the 'int q= ...' line. If that line is commented the program runs without exceptions even if no image is present. Loading an image only if nessesary makes sense, but then the image should be loaded when I add the Image control to the StackPanel.

谁能解释我做错了什么,或者为什么会发生这种情况?如果您删除图像并运行程序,它会在“int q= ...”行上生成异常。如果该行被注释,即使没有图像存在,程序也会毫无例外地运行。仅当必要时才加载图像,但是当我将图像控件添加到 StackPanel 时,应该加载图像。

Any ides ?

任何想法?

Edit: By the way, if you add the image as a resource, the 'int q = ..' line is not needed.

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

回答by redHymanwong

It is because the Creation was delayed. If you want the picture to be loaded immediately, you can simply add this code into the init phase.

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

src.CacheOption = BitmapCacheOption.OnLoad;

src.CacheOption = BitmapCacheOption.OnLoad;

like this:

像这样:

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

回答by Eric Ouellet

In code to load resource in the executing assembly where my image 'Freq.png' was in the folder "Icons" and defined as "Resource".

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

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

I also made a function if anybody would like it...

如果有人喜欢,我也做了一个功能......

/// <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)); 
}

Usage:

用法:

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

回答by Szymon Rozga

This is strange behavior and although I am unable to say why this is occurring, I can recommend some options.

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

First, an observation. If you include the image as Content in VS and copy it to the output directory, your code works. If the image is marked as None in VS and you copy it over, it doesn't work.

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

Solution 1: FileStream

解决方案 1:文件流

The BitmapImage object accepts a UriSource or StreamSource as a parameter. Let's use StreamSource instead.

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

The problem: stream stays open. If you close it at the end of this method, the image will not show up. This means that the file stays write-locked on the system.

问题:流保持打开状态。如果在此方法结束时关闭它,图像将不会显示。这意味着文件在系统上保持写锁定。

Solution 2: MemoryStream

解决方案 2:MemoryStream

This is basically solution 1 but you read the file into a memory stream and pass that memory stream as the argument.

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

Now you are able to modify the file on the system, if that is something you require.

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

回答by Drew Noakes

You could try attaching handlers to various events of BitmapImage:

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

They might tell you a little about what's going on, as far as the image is concerned.

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

回答by J Pollack

Here is the extension method to load an image from URI:

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

Sample of use:

使用示例:

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

Simple as that!

就那么简单!