Recursos de imagen de WPF

408

Vengo de un fondo principalmente web y un poco de Windows Forms. Para un nuevo proyecto, utilizaremos WPF. La aplicación WPF necesitará de 10 a 20 iconos e imágenes pequeños con fines ilustrativos. Estoy pensando en almacenarlos en el ensamblado como recursos integrados. ¿Es ese el camino correcto?

¿Cómo especifico en XAML que un control de imagen debería cargar la imagen desde un recurso incrustado?

driis
fuente

Respuestas:

473

Si va a usar la imagen en varios lugares, entonces vale la pena cargar los datos de la imagen solo una vez en la memoria y luego compartirlos entre todos los Imageelementos.

Para hacer esto, cree un BitmapSource como recurso en alguna parte:

<BitmapImage x:Key="MyImageSource" UriSource="../Media/Image.png" />

Luego, en su código, use algo como:

<Image Source="{StaticResource MyImageSource}" />

En mi caso, descubrí que tenía que configurar el Image.pngarchivo para que tuviera una acción de compilación en Resourcelugar de solo Content. Esto hace que la imagen se transporte dentro de su ensamblaje compilado.

Drew Noakes
fuente
66
¿Sería posible hacer esto dinámicamente? Si tengo un número diferente de imágenes que me gustaría cargar al inicio, ¿podría crear un BitmapSource por imagen y referirme a ellas de la misma manera que arriba?
Becky Franklin el
2
@Becky - Sí, podría hacerlo, aunque si quisiera referirse a ellos en Xaml, entonces podría necesitar usar la DynamicResourceextensión de marcado en lugar de StaticResource, suponiendo que conozca las claves en el momento de la compilación. En WPF puede crear diccionarios de recursos en tiempo de ejecución. De hecho, eso es lo que sucede cuando carga un documento Xaml, es solo que no ve el C # equivalente.
Drew Noakes
99
Algo que golpeé: si agrega su recurso de imagen a un diccionario de recursos, no olvide referirse a ese diccionario de imagen en el XAML para su componente. Algo así como: <UserControl.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source = "Dictionary1.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </UserControl.Resources>
Dan Mitchell
44
Por lo general, agrego Width="{Binding Source.PixelWidth, RelativeSource={RelativeSource Self}}" al Image, ya que de lo contrario a menudo veo imágenes que se amplían grotescamente por alguna razón (como iconos de 16x16 estirados a algo que parece 200x200 píxeles).
O Mapper
55
Descubrí que si la BitmapImage se declara en una biblioteca de recursos del ensamblado referenciado, el UriSource debe ser un packURI para que esto funcione. De lo contrario, encontrará que puede ver la imagen en su editor xaml en VS pero no hay imagen al depurar. Paquete URIS: msdn.microsoft.com/en-au/library/aa970069(v=vs.100).aspx
fallida el
174

Descubrí que la mejor práctica de usar imágenes, videos, etc. es:

  • Cambie sus archivos "Crear acción" a "Contenido" . Asegúrese de marcar Copiar al directorio de compilación .
    • Se encuentra en el menú "Clic derecho" en la ventana del Explorador de soluciones.
  • Fuente de imagen en el siguiente formato:
    • "/ « YourAssemblyName » ; componente /« YourPath »/ « YourImage.png » "

Ejemplo

<Image Source="/WPFApplication;component/Images/Start.png" />

Beneficios:

  • Los archivos no están incrustados en el ensamblaje.
    • El Administrador de recursos generará algunos problemas de desbordamiento de memoria con demasiados recursos (en el momento de la compilación).
  • Se puede llamar entre ensamblajes.
Nuno Rodrigues
fuente
36
Este mismo enfoque funciona si incrusta el recurso en el ensamblado, pero debe establecer la "Acción de compilación" en "Recurso".
Ashley Davis
55
Funciona, gracias. Una nota para los demás: se requiere "componente" "tal cual", "Imágenes" es una ruta relativa de png en el proyecto. Es decir, la imagen que se coloca en la raíz será "<Image Source =" / WPFApplication; component / Start.png "/>"
Badiboy
3
Un ejemplo de cómo hacer esto en C # sería bueno. (Ese no es un URI válido, por lo que no se puede usar al construir una imagen de
mapa de bits
55
Entonces, ¿cómo lo hace si el archivo está configurado como Recurso incorporado? Esto no parece funcionar. Y no quiero incluir la imagen en mi proyecto dos veces. (Ya lo estoy usando como recurso integrado)
BrainSlugs83
2
Dónde y cómo entra el "componente" en el camino. ¿Es eso parte de alguna especificación?
Triynko
46

Algunas personas preguntan acerca de hacer esto en código y no obtener una respuesta.

Después de pasar muchas horas buscando, encontré un método muy simple, no encontré ningún ejemplo, así que comparto el mío aquí que funciona con imágenes. (el mío era un .gif)

Resumen:

Devuelve un BitmapFrame que parece gustarle a los "destinos" de ImageSource.

Utilizar:

doGetImageSourceFromResource ("[YourAssemblyNameHere]", "[YourResourceNameHere]");

Método:

static internal ImageSource doGetImageSourceFromResource(string psAssemblyName, string psResourceName)
{
    Uri oUri = new Uri("pack://application:,,,/" +psAssemblyName +";component/" +psResourceName, UriKind.RelativeOrAbsolute);
    return BitmapFrame.Create(oUri);
}

Aprendizajes:

Según mi experiencia, la cadena del paquete no es el problema, verifique sus transmisiones y, especialmente, si la lee por primera vez ha establecido el puntero al final del archivo y necesita volver a establecerlo en cero antes de volver a leerlo.

¡Espero que esto te ahorre las muchas horas que deseo que esta pieza tuviera para mí!

Craig
fuente
44

En el código para cargar un recurso en el ensamblaje en ejecución donde mi imagen Freq.pngestaba en la carpeta Iconsy definida como Resource:

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

También hice una función:

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

Uso (se supone que coloca la función en una clase ResourceHelper):

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

Nota : vea los URI del paquete MSDN en WPF :
pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

Eric Ouellet
fuente
nuevo Uri arroja URI no válido: puerto especificado no válido.
Steve
¿Tienes el uri ofensivo?
Eric Ouellet
1
mismo uri que el tuyo, excepto que el mío se estaba ejecutando dentro de un WPF alojado en winform Y el esquema de "paquete" aún no estaba registrado cuando llamé al nuevo Uri.
Steve
1
Vaya ... probablemente se retiró a WinPF alojado en WPF. Lo siento. No intentaré solucionarlo porque creo que no es un uso muy común. ¡Buena suerte!
Eric Ouellet
En mi caso, usar new Uri(@"pack://application:,,,/" + pathInApplication)también hizo el truco.
Adam Calvet Bohl el
40

Sí, es el camino correcto.

Puede usar la imagen en el archivo de recursos simplemente usando la ruta:

<Image Source="..\Media\Image.png" />

Debe establecer la acción de compilación del archivo de imagen en "Recurso".

ema
fuente
1
Gracias por esto. ¿Hay alguna manera de hacer algo similar con un ImageSource, esencialmente cargando la imagen una vez en un diccionario de recursos? Me temo que este enfoque carga los datos de la imagen varias veces en la memoria.
Drew Noakes
2
Esto será un desastre cuando necesite refactorizar su código. Tendrá que cambiar manualmente todas las referencias de imagen si su documento xaml cambia el espacio de nombres. El método descrito por Drew Noakes es mucho más fluido y fácil de mantener.
Kasper Holdum
14

Descripción completa de cómo utilizar los recursos: recursos de aplicaciones, contenido y archivos de datos de WPF

Y cómo hacer referencia a ellos, lea "URI de paquete en WPF".

En resumen, incluso hay medios para hacer referencia a recursos de ensamblados referenciados / referenciados.

techfan
fuente
El enlace parece estar en vivo y bien (aunque dice "Esta documentación está archivada y no se mantiene" ).
Peter Mortensen
5
  1. Visual Studio 2010 Professional SP1.
  2. .NET Framework 4 Perfil del cliente.
  3. Imagen PNG agregada como recurso en las propiedades del proyecto.
  4. Nuevo archivo en la carpeta Recursos creado automáticamente.
  5. Crear acción establecida en recurso.

Esto funcionó para mí:

<BitmapImage x:Key="MyImageSource" UriSource="Resources/Image.png" />
JoanComasFdz
fuente
3

Si está utilizando Blend , para hacerlo más fácil y no tener problemas para obtener la ruta correcta para el atributo Fuente , simplemente arrastre y suelte la imagen desde el panel Proyecto en el diseñador.

usuario42467
fuente
3

Sí, es el camino correcto. Puede usar imágenes en el archivo de Recursos usando una ruta:

<StackPanel Orientation="Horizontal">
    <CheckBox  Content="{Binding Nname}" IsChecked="{Binding IsChecked}"/>
    <Image Source="E:\SWorking\SharePointSecurityApps\SharePointSecurityApps\SharePointSecurityApps.WPF\Images\sitepermission.png"/>
    <TextBlock Text="{Binding Path=Title}"></TextBlock>
</StackPanel>
Sanjay Ranavaya
fuente
-5

Lo siguiente funcionó y las imágenes a configurar son recursos en propiedades:

    var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(),
                                      IntPtr.Zero,
                                      Int32Rect.Empty,
                                      BitmapSizeOptions.FromEmptyOptions());
    MyButton.Background = new ImageBrush(bitmapSource);
img_username.Source = bitmapSource;
Raghulan Gowthaman
fuente
55
Sin ofender, pero esto huele a mala práctica.
ShloEmi