在代码中设置WPF图像源

时间:2008-12-08 16:15:29

标签: c# .net wpf image

我正在尝试在代码中设置WPF图像的源代码。图像作为资源嵌入到项目中。通过查看示例,我提出了以下代码。由于某种原因,它不起作用 - 图像不显示。

通过调试,我可以看到流包含图像数据。那有什么不对?

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
PngBitmapDecoder iconDecoder = new PngBitmapDecoder(iconStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
ImageSource iconSource = iconDecoder.Frames[0];
_icon.Source = iconSource;

图标的定义如下:<Image x:Name="_icon" Width="16" Height="16" />

19 个答案:

答案 0 :(得分:393)

在遇到与您相同的问题并进行阅读后,我发现了解决方案 - Pack URIs

我在代码中执行了以下操作:

Image finalImage = new Image();
finalImage.Width = 80;
...
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png");
logo.EndInit();
...
finalImage.Source = logo;

或更短,使用另一个BitmapImage构造函数:

finalImage.Source = new BitmapImage(
    new Uri("pack://application:,,,/AssemblyName;component/Resources/logo.png"));

URI分为几部分:

  • 权限:application:///
  • 路径:编译为引用的程序集的资源文件的名称。路径必须符合以下格式:AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName:引用的程序集的短名称。
    • ; Version [可选]:包含资源文件的引用程序集的版本。当加载两个或多个具有相同短名称的引用程序集时,将使用此方法。
    • ; PublicKey [可选]:用于对引用的程序集进行签名的公钥。当加载两个或多个具有相同短名称的引用程序集时,将使用此方法。
    • ; component:指定所引用的程序集是从本地程序集引用的。
    • / Path:资源文件的名称,包括其路径,相对于引用程序集的项目文件夹的根目录。

application:之后的三个斜杠必须用逗号代替:

  

注意:包URI的权限组件   是一个指向a的嵌入式URI   包,必须符合RFC 2396。   此外,“/”字符必须   替换为“,”字符,   和保留字符,如“%”   和“?”必须逃脱。见OPC   详情。

当然,请确保将图片上的构建操作设置为Resource

答案 1 :(得分:169)

var uriSource = new Uri(@"/WpfApplication1;component/Images/Untitled.png", UriKind.Relative);
foo.Source = new BitmapImage(uriSource);

这将在名为“Images”的文件夹中加载名为“Untitled.png”的图像,并在名为“WpfApplication1”的程序集中将“Build Action”设置为“Resource”。

答案 2 :(得分:73)

这是一个较少的代码,可以在一行中完成。

string packUri = "pack://application:,,,/AssemblyName;component/Images/icon.png";
_image.Source = new ImageSourceConverter().ConvertFromString(packUri) as ImageSource;

答案 3 :(得分:41)

非常简单:

要动态设置菜单项的图像,只需执行以下操作:

MyMenuItem.ImageSource = 
    new BitmapImage(new Uri("Resource/icon.ico",UriKind.Relative));

...而“icon.ico”可以位于任何地方(目前它位于“资源”目录中),并且必须作为资源链接...

答案 4 :(得分:16)

您也可以将此缩小为一行。这是我用来为我的主窗口设置Icon的代码。它假定.ico文件被标记为内容并被复制到输出目录。

 this.Icon = new BitmapImage(new Uri("Icon.ico", UriKind.Relative));

答案 5 :(得分:15)

最简单的方法:

var uriSource = new Uri("image path here");
image1.Source = new BitmapImage(uriSource);

答案 6 :(得分:14)

你试过了吗?

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream("SomeImage.png");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
_icon.Source = bitmap;

答案 7 :(得分:11)

这是我的方式:

internal static class ResourceAccessor
{
    public static Uri Get(string resourcePath)
    {
        var uri = string.Format(
            "pack://application:,,,/{0};component/{1}"
            , Assembly.GetExecutingAssembly().GetName().Name
            , resourcePath
        );

        return new Uri(uri);
    }
}

用法:

new BitmapImage(ResourceAccessor.Get("Images/1.png"))

答案 8 :(得分:8)

这是一个动态设置图像路径的示例(图像位于光盘上的某个位置而不是构建为资源):

if (File.Exists(imagePath))
{
    // Create image element to set as icon on the menu element
    Image icon = new Image();
    BitmapImage bmImage = new BitmapImage();
    bmImage.BeginInit();
    bmImage.UriSource = new Uri(imagePath, UriKind.Absolute);
    bmImage.EndInit();
    icon.Source = bmImage;
    icon.MaxWidth = 25;
    item.Icon = icon;
}

对图标的反思......

首先想到的是,你会认为Icon属性只能包含一个图像。但它实际上可以包含任何东西!当我以编程方式尝试将Image属性直接设置为带有图像路径的字符串时,我偶然发现了这一点。结果是它没有显示图像,而是显示路径的实际文本!

这导致了不必为图标制作图像的替代方法,而是使用带有符号字体的文本来显示简单的“图标”。以下示例使用包含“floppydisk”符号的Wingdings font。此符号实际上是字符<,它在XAML中具有特殊含义,因此我们必须使用编码版本&lt;。这就像一场梦!以下显示了一个floppydisk符号作为菜单项上的图标:

<MenuItem Name="mnuFileSave" Header="Save" Command="ApplicationCommands.Save">
  <MenuItem.Icon>
    <Label VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Wingdings">&lt;</Label>
  </MenuItem.Icon>
</MenuItem>

答案 9 :(得分:6)

如果您的图像存储在ResourceDictionary中,则只能使用一行代码执行此操作:

MyImage.Source = MyImage.FindResource("MyImageKeyDictionary") as ImageSource;

答案 10 :(得分:5)

还有一种更简单的方法。如果图像作为资源加载到XAML中,并且有问题的代码是该XAML内容的代码隐藏:

Uri iconUri = new Uri("pack://application:,,,/ImageNAme.ico", UriKind.RelativeOrAbsolute);
NotifyIcon.Icon = BitmapFrame.Create(iconUri);

答案 11 :(得分:3)

还有一种更简单的方法。如果图像作为资源加载到XAML中,并且有问题的代码是该XAML的代码隐藏:

这是XAML文件的资源字典 - 你关心的唯一一行是带有“PosterBrush”键的ImageBrush - 其余代码只是为了显示上下文

<UserControl.Resources>
        <ResourceDictionary>
            <ImageBrush x:Key="PosterBrush" ImageSource="..\Resources\Images\EmptyPoster.jpg" Stretch="UniformToFill"/>

        </ResourceDictionary>
    </UserControl.Resources>

现在,在后面的代码中,你可以这样做

ImageBrush posterBrush = (ImageBrush)Resources["PosterBrush"];

答案 12 :(得分:3)

将框架放在VisualBrush中:

VisualBrush brush = new VisualBrush { TileMode = TileMode.None };

brush.Visual = frame;

brush.AlignmentX = AlignmentX.Center;
brush.AlignmentY = AlignmentY.Center;
brush.Stretch = Stretch.Uniform;

将VisualBrush放入GeometryDrawing

GeometryDrawing drawing = new GeometryDrawing();

drawing.Brush = brush;

// Brush this in 1, 1 ratio
RectangleGeometry rect = new RectangleGeometry { Rect = new Rect(0, 0, 1, 1) };
drawing.Geometry = rect;

现在将GeometryDrawing放在DrawingImage中:

new DrawingImage(drawing);

将它放在你的图像来源上,然后瞧!

你可以轻松地做到这一点:

<Image>
    <Image.Source>
        <BitmapImage UriSource="/yourassembly;component/YourImage.PNG"></BitmapImage>
    </Image.Source>
</Image>

在代码中:

BitmapImage image = new BitmapImage { UriSource="/yourassembly;component/YourImage.PNG" };

答案 13 :(得分:2)

我是WPF的新手,但不是.NET。

我花了五个小时尝试将PNG文件添加到.NET 3.5(Visual Studio 2010)中的“WPF自定义控件库项目”中,并将其设置为图像继承控件的背景。

与URI无关。我无法想象为什么没有方法通过IntelliSense从资源文件中获取URI,可能是:

Properties.Resources.ResourceManager.GetURI("my_image");

我尝试过很多URI并使用ResourceManager和Assembly的GetManifest方法,但所有的都有例外或NULL值。

这里我提供了适合我的代码:

// Convert the image in resources to a Stream
Stream ms = new MemoryStream()
Properties.Resources.MyImage.Save(ms, ImageFormat.Png);

// Create a BitmapImage with the stream.
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.EndInit();

// Set as source
Source = bitmap;

答案 14 :(得分:2)

如何从嵌入在资源图标和图像中的图像加载图像(Arcturus的更正版本):

假设您要添加带图像的按钮。你应该怎么做?

  1. 添加到项目文件夹图标并将图像ClickMe.png放在此处
  2. 在“ClickMe.png”的属性中,将“BuildAction”设置为“Resource”
  3. 假设您的已编译程序集名称为“Company.ProductAssembly.dll”。
  4. 现在是时候在XAML中加载我们的图像了

    <Button Width="200" Height="70">
      <Button.Content>
        <StackPanel>
          <Image Width="20" Height="20">
            <Image.Source>
              <BitmapImage UriSource="/Company.ProductAssembly;component/Icons/ClickMe.png"></BitmapImage>
              </Image.Source>
          </Image>
          <TextBlock HorizontalAlignment="Center">Click me!</TextBlock>
        </StackPanel>
      </Button.Content>
    </Button>
    
  5. 完成。

答案 15 :(得分:1)

你只是错过了一点。

要从任何程序集中获取嵌入式资源,您必须使用您在此处提到的文件名提及程序集名称:

Assembly asm = Assembly.GetExecutingAssembly();
Stream iconStream = asm.GetManifestResourceStream(asm.GetName().Name + "." + "Desert.jpg");
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = iconStream;
bitmap.EndInit();
image1.Source = bitmap;

答案 16 :(得分:1)

如果您已有流并知道格式,则可以使用以下内容:

static ImageSource PngStreamToImageSource (Stream pngStream) {
    var decoder = new PngBitmapDecoder(pngStream,
        BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    return decoder.Frames[0];
}

答案 17 :(得分:0)

如果要在可执行文件旁边找到它(相对于可执行文件)

img.Source = new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + @"\Images\image.jpg", UriKind.Absolute));

答案 18 :(得分:-1)

Force 选择 UriKind 是正确的:

Image.Source = new BitmapImage(new Uri("Resources/processed.png", UriKind.Relative));

UriKind 选项:

UriKind.Relative // relative path
UriKind.Absolute // exactly path