Impostazione dell'origine dell'immagine WPF nel codice


325

Sto cercando di impostare nel codice l'origine di un'immagine WPF. L'immagine è incorporata come risorsa nel progetto. Guardando esempi ho trovato il codice qui sotto. Per qualche motivo non funziona: l'immagine non viene visualizzata.

Tramite il debug posso vedere che lo stream contiene i dati dell'immagine. Quindi cosa c'è che non va?

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;

L'icona è definita in questo modo: <Image x:Name="_icon" Width="16" Height="16" />


Se l'immagine si trova su un'unità locale, <Image Source="some_fully_qualified_path">in XAML non fallisce mai.
Laurie Stearn il

@LaurieStearn il punto è che non conosciamo il percorso e abbiamo bisogno di codice per determinarlo. Come nuovo nella programmazione della GUI di Windows, devo ammettere che WinForms sembra più attraente di questa merda XAML.
Alex Jansen,

Risposte:


416

Dopo aver avuto lo stesso problema con te e aver letto qualcosa, ho scoperto la soluzione - Pack URIs .

Ho fatto quanto segue nel codice:

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;

O più breve, usando un altro costruttore BitmapImage:

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

L'URI è suddiviso in parti:

  • Autorità: application:///
  • Percorso: il nome di un file di risorse che viene compilato in un assembly di riferimento. Il percorso deve essere conforme al seguente formato:AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName: il nome breve per l'assembly di riferimento.
    • ; Versione [opzionale]: la versione dell'assembly di riferimento che contiene il file di risorse. Viene utilizzato quando vengono caricati due o più assembly con riferimento con lo stesso nome breve.
    • ; PublicKey [opzionale]: la chiave pubblica utilizzata per firmare l'assembly di riferimento. Viene utilizzato quando vengono caricati due o più assembly con riferimento con lo stesso nome breve.
    • ; componente: specifica che l'assembly a cui si fa riferimento è referenziato dall'assembly locale.
    • / Path: il nome del file di risorse, incluso il suo percorso, relativo alla radice della cartella del progetto dell'assembly di riferimento.

Le tre barre dopo application:devono essere sostituite da virgole:

Nota: il componente di autorizzazione di un URI del pacchetto è un URI incorporato che punta a un pacchetto e deve essere conforme a RFC 2396. Inoltre, il carattere "/" deve essere sostituito con il carattere "," e caratteri riservati come "%" e "?" deve essere evaso. Vedere OPC per i dettagli.

E, naturalmente, assicurati di impostare l'azione di creazione sull'immagine su Resource.


Sì, questa è stata la soluzione che mi sono trovata dopo alcuni tentativi ed errori. Grazie per la spiegazione approfondita. Risposta accettata!
Torbjørn,

Non so perché questo fosse necessario e perché le altre risposte non abbiano funzionato per me ...
Torbjørn

le altre risposte in questa e in altre domande non hanno funzionato neanche per me. Questo funziona perfettamente. Grazie.
Thomas Stock

9
Va bene, ma non esiste un metodo o una classe che il parser XAML utilizza per convertire la stringa del percorso semplice in ImageSource? Non potremmo semplicemente usarlo?
Qwertie,

1
Vedo spesso questo frammento copiato in altri post, dove le persone di solito ignorano l'esistenza del BitmapImage(Uri)costruttore, il che aiuta a evitare la necessità di chiamare BeginInit ed EndInit. L'ho aggiunto qui.
Clemens,

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

Questo caricherà un'immagine chiamata "Untitled.png" in una cartella chiamata "Immagini" con la sua "Azione di costruzione" impostata su "Risorsa" in un assembly chiamato "WpfApplication1".


16
Grazie per quello Un problema che mi ha inciampato come noob in wpf, l'immagine deve essere contrassegnata come risorsa perché funzioni.
si618,

4
Questa soluzione mi ha dato un'eccezione, quindi ho provato la soluzione di Jared Harley e ha funzionato ...
Sangram Nandkhile

2
la cosa più importante è "UriKind.RelativeOrAbsolute" - altri esempi generavano sempre eccezioni
Sven

9
var uriSource = new Uri("Images/Untitled.png", UriKind.Relative);sarebbe sufficiente
Hamzeh Soboh,

... e molto più facile. Grazie Hamzeh
pStan

74

Questo è un po 'meno di codice e può essere fatto in una sola riga.

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

8
Questa è sicuramente la risposta migliore, utilizzando l'implementazione di
.NETs

cosa succede se dobbiamo impostare l'altezza e la larghezza dell'immagine, ad esempio icon.png? Perché usando _image.height e _image.width imposta la finestra dell'immagine non l'immagine reale, ad esempio icon.png.
secretgenes,

41

Molto facile:

Per impostare l'immagine di una voce di menu in modo dinamico, procedi come segue:

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

... mentre "icon.ico" può trovarsi ovunque (attualmente si trova nella directory "Risorse") e deve essere collegato come risorsa ...


2
Più breve = migliore. Ho dovuto impostarlo come @ "/ folder / image.png", ma poi ha funzionato bene. Grazie!
gjvdkamp,

3
Quando assegno la fonte di immagini, viene visualizzata vuota :(
HaloMediaz

Il percorso di @HaloMediaz potrebbe essere sbagliato .... ad esempio, hai risorse ma puoi scriverlo Risorsa
Rouzbeh Zarandi

Questo ha funzionato per me, e molto più semplice degli URI assoluti nelle altre risposte.
Psiloc,

16

Puoi anche ridurlo a una riga. Questo è il codice che ho usato per impostare l'icona per la mia finestra principale. Presuppone che il file .ico sia contrassegnato come Contenuto e che venga copiato nella directory di output.

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

16

Il modo più semplice:

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

15

Hai provato:

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

13

Questo è il mio modo:

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

Uso:

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

8

Ecco un esempio che imposta dinamicamente il percorso dell'immagine (immagine posizionata da qualche parte sul disco anziché costruire come risorsa):

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

Riflessioni sulle icone ...

In primo luogo, potresti pensare che la proprietà Icon possa contenere solo un'immagine. Ma in realtà può contenere qualsiasi cosa! L'ho scoperto per caso quando ho cercato a livello di codice di impostare la Imageproprietà direttamente su una stringa con il percorso di un'immagine. Il risultato è stato che non mostrava l'immagine, ma il testo effettivo del percorso!

Questo porta a un'alternativa per non dover creare un'immagine per l'icona, ma utilizzare il testo con un carattere simbolo invece di visualizzare una semplice "icona". L'esempio seguente utilizza il carattere Wingdings che contiene un simbolo "floppydisk". Questo simbolo è davvero il personaggio <, che ha un significato speciale in XAML, quindi dobbiamo usare &lt;invece la versione codificata . Funziona come un sogno! Quanto segue mostra un simbolo floppydisk come icona sulla voce di menu:

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

Domanda: " L'immagine è incorporata come risorsa nel progetto ", rispondi: " Ecco un esempio [per un'immagine] situato da qualche parte sul disco piuttosto che crearlo come risorsa ".
minuti

7

Se la tua immagine è memorizzata in un ResourceDictionary, puoi farlo con una sola riga di codice:

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

6

C'è anche un modo più semplice. Se l'immagine viene caricata come risorsa in XAML e il codice in questione è il codice per quel contenuto XAML:

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

4

Inserisci il frame in un VisualBrush:

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

brush.Visual = frame;

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

Inserisci VisualBrush in 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;

Ora inserisci GeometryDrawing in un DrawingImage:

new DrawingImage(drawing);

Posizionalo sulla tua fonte dell'immagine e voilà!

Potresti farlo molto più facilmente però:

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

E nel codice:

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

LOL! Perché renderlo facile quando puoi renderlo difficile per la prima volta :) Proverò la tua soluzione semplice prima di accettare però ...
Torbjørn

In realtà questo non mi ha aiutato affatto. Forse sono stupido :( Non ho tempo di guardare più da vicino in questo momento (progetto per animali domestici). Vorrei più risposte per quando torno ad esso :)
Torbjørn

3

C'è anche un modo più semplice. Se l'immagine viene caricata come risorsa in XAML e il codice in questione è il codice dietro tale XAML:

Ecco il dizionario delle risorse per un file XAML - l'unica riga che ti interessa è ImageBrush con il tasto "PosterBrush" - il resto del codice è solo per mostrare il contesto

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

        </ResourceDictionary>
    </UserControl.Resources>

Ora, nel codice dietro, puoi semplicemente farlo

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

2

Come caricare un'immagine da incorporata in icone e immagini di risorse (versione corretta di Arcturus):

Supponiamo di voler aggiungere un pulsante con un'immagine. Cosa dovresti fare

  1. Aggiungi alle icone delle cartelle di progetto e metti qui l'immagine ClickMe.png
  2. Nelle proprietà di "ClickMe.png", imposta "BuildAction" su "Risorsa"
  3. Supponiamo che il nome dell'assembly compilato sia "Company.ProductAssembly.dll".
  4. Ora è il momento di caricare la nostra immagine in 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>

Fatto.


2

Sono una novità di WPF, ma non in .NET.

Ho trascorso cinque ore cercando di aggiungere un file PNG a un "Progetto libreria di controllo personalizzato WPF" in .NET 3.5 (Visual Studio 2010) e impostandolo come sfondo di un controllo ereditato da immagine.

Non ha funzionato nulla di relativo agli URI. Non riesco a immaginare perché non esiste un metodo per ottenere un URI da un file di risorse, tramite IntelliSense, forse come:

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

Ho provato molti URI e ho giocato con i metodi ResManManager e GetManifest di Assembly, ma c'erano tutte eccezioni o valori NULL.

Qui pot il codice che ha funzionato per me:

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

3
Penso che il problema sia che WPF non "apprezzi" l'approccio tradizionale di mettere risorse nei file resx. Dovresti invece aggiungere l'immagine direttamente al tuo progetto e impostare la proprietà Build Action su Resource. Non so quale sia la differenza (in termini di formato di file fisico) tra i due approcci.
Qwertie,

1
Assicurati che l'azione di costruzione sia contenta
Jerry Nixon,

1

Se hai già uno stream e conosci il formato, puoi usare qualcosa del genere:

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

1

Ti sei perso un po '.

Per ottenere una risorsa incorporata da qualsiasi assembly, è necessario menzionare il nome dell'assembly con il nome del file come ho menzionato qui:

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;

BeginInit () non sembra esistere in WPF.
Myosotis,

E 'disponibile controllano sotto il collegamento msdn.microsoft.com/en-us/library/...
Maulik Kansara
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.