Impostazione della sorgente di immagini WPF nel codice

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

Con il debug posso vedere che il 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:

Dopo aver avuto lo stesso problema e aver letto un po ‘di lettura, ho scoperto la soluzione – URI del pacchetto .

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 di 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 conforms al seguente formato: AssemblyShortName[;Version][;PublicKey];component/Path

    • AssemblyShortName: il nome breve per l’assembly di riferimento.
    • ; Versione [opzionale]: la versione dell’assembly referenziato che contiene il file di risorse. Viene utilizzato quando vengono caricati due o più assembly di 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 di riferimento con lo stesso nome breve.
    • ; component: specifica che l’assembly a cui si fa riferimento fa riferimento all’assembly locale.
    • / Percorso: il nome del file di risorse, incluso il relativo percorso, relativo alla radice della cartella del progetto dell’assieme di riferimento.

Le tre barre dopo l’ application: devono essere sostituite con virgole:

Nota: il componente di authorization di un URI di pacchetto è un URI incorporato che punta a un pacchetto e deve essere conforms a RFC 2396. Inoltre, il carattere “/” deve essere sostituito con il carattere “,” e caratteri riservati come “%” e “?” deve essere sfuggito. Vedi l’OPC per i dettagli.

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

 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 compilazione” impostata su “Risorsa” in un assembly chiamato “WpfApplication1”.

Questo è un po ‘meno 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; 

Molto facile:

Per impostare dynamicmente l’immagine di una voce di menu, procedi come segue:

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

… mentre “icon.ico” può essere posizionato ovunque (attualmente si trova nella directory “Risorse”) e deve essere collegato come Risorsa …

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

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

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; 

Modo più semplice:

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

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

Ecco un esempio che imposta dynamicmente il percorso dell’immagine (immagine che si trova da qualche parte sul disco anziché build 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 …

Prima pensate, pensereste che la proprietà Icon possa contenere solo un’immagine. Ma in realtà può contenere qualsiasi cosa! L’ho scoperto per errore quando ho tentato di impostare la proprietà Image direttamente su una stringa con il percorso di un’immagine. Il risultato è stato che non mostrava l’immagine, ma il testo reale del percorso!

Ciò porta a un’alternativa a non dover creare un’immagine per l’icona, ma utilizzare il testo con un carattere simbolo invece di visualizzare una semplice “icona”. Nell’esempio seguente viene utilizzato il carattere Wingdings che contiene un simbolo “floppydisk”. Questo simbolo è in realtà il carattere < , che ha un significato speciale in XAML, quindi dobbiamo usare la versione codificata < anziché. Funziona come un sogno! Quanto segue mostra un simbolo floppydisk come un'icona sulla voce di menu:

      

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

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

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

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

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

Metti il ​​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 metti GeometryDrawing in una DrawingImage:

 new DrawingImage(drawing); 

Metti questo sulla tua fonte dell’immagine, e voilà!

Potresti farlo molto più facilmente però:

      

E nel codice:

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

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

Ecco il dizionario delle risorse per un file XAML: l’unica linea che ti interessa è ImageBrush con la chiave “PosterBrush” – il resto del codice è solo per mostrare il contesto

      

Ora, nel codice sottostante, puoi farlo

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

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

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

  1. Aggiungi alle icone della cartella del progetto e metti l’immagine ClickMe.png qui
  2. Nelle proprietà di “ClickMe.png”, imposta “BuildAction” su “Risorsa”
  3. Supponiamo che il nome del tuo assembly compilato sia “Company.ProductAssembly.dll”.
  4. Ora è il momento di caricare la nostra immagine in XAML

      

Fatto.

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

Ho impiegato cinque ore a provare ad aggiungere un file PNG ad un “Progetto libreria di controllo personalizzato WPF” in .NET 3.5 (Visual Studio 2010) e ad impostarlo come sfondo di un controllo ereditato dall’immagine.

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

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

Ho provato un sacco di URI e ho giocato con ResourceManager e con i metodi GetManifest di Assembly, ma tutti c’erano eccezioni o valori NULL.

Qui metto a punto 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; 

Se hai già uno stream e conosci il formato, puoi usare qualcosa come questo:

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

Ti sei appena 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;