2009-03-03 5 views
7

Attualmente sto costruendo un'applicazione che consiste di diversi componenti, ognuno dei quali è essenzialmente un controllo utente WPF con un piccolo codice C# attorno al quale funziona il sistema di plugin (usando MEF) .Acessing WPF XAML Risorse da codice non WPF

Il problema che sto avendo è che ogni componente dovrebbe includere un'icona e per scopi di precisione l'ho definito come System.Windows.Media.Brush così posso semplicemente usare il DrawingBrush esportato da Design lì. Ora ho bisogno di accedere a quel pezzo di XAML da non WPF C#, dove ho attualmente la soluzione orribile di istanziare il controllo utente e chiedendo per la risorsa:

private Brush CachedIcon = null; 

public override Brush Icon 
{ 
    get 
    { 
     if (CachedIcon == null) 
     { 
      CachedIcon = (Brush)(new BlahControl().TryFindResource("Icon")); 
     } 
     return CachedIcon; 
    } 
} 

non riuscivo a trovare un modo per leggere che risorsa (che è un file .xaml e referenziata in un ResourceDictionary nel controllo personalizzato) da una classe "normale" C#. Qualunque cosa appartenga a WPF ha quel bel metodo TryFindResource ma come farlo altrimenti? Non voglio avere il file XAML con l'icona che giace intorno a un-embedded.

risposta

2

Nel codice XAML assicurarsi la risorsa icona ha l'opzione di compilazione impostata su "risorse", e quindi fare riferimento alla risorsa per renderlo una risorsa statica XAML

<UserControl.Resources> 
    <BitmapImage x:Key="icon1" UriSource="Resources/Icon1.ico" /> 
</UserControl.Resources> 

Poi nel codice .Net 2.0 è troverà la risorsa nel "{} xamlName .g.resource" flusso

codice di esempio che carica tutte le icone da una DLL XAML in un dizionario:

using System.IO; 
using System.Reflection; 
using System.Collections; 
using System.Resources; 

... 

var icons = new Dictionary<String, Bitmap>(); 
var externalBaml = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, "MyXaml.dll")); 
Stream resourceStream = externalBaml.GetManifestResourceStream(externalBaml.GetName().Name + ".g.resources"); 
using (ResourceReader resourceReader = new ResourceReader(resourceStream)) { 
    foreach (DictionaryEntry resourceEntry in resourceReader) { 
     if (resourceEntry.Key.ToString().ToUpper().EndsWith(".ICO")) { 
      icons.Add(resourceEntry.Key.ToString(), Image.FromStream(resourceEntry.Value as Stream) as Bitmap); 
     } 
    } 
} 
+0

Sembra funzionare, ma sembra un hackish veeeery. Affidarsi a nomi interni di risorse generate automaticamente non mi sembra molto consigliabile. – Joey

+0

Ehh? Le risorse hanno nomi di stringhe, non c'è nulla che tu possa fare al riguardo! Che cosa sta cercando? – TFD

+0

Mi stavo chiedendo quanto sia affidabile la cosa ".g.resources". Ho letto abbastanza del blog di Raymond Chen che non voglio davvero usare nulla che possa rompere perché è solo un artefatto dell'implementazione, non un comportamento documentato. – Joey

0

È possibile leggere le risorse dall'assieme come flusso.

codice di esempio qui: http://www.wpftutorial.net/ReadWPFResourcesFromWinForms.html

+0

Hmm, non poteva farlo funzionare in questo momento, cercherà Agani tardi. Ma questo non mi sembra esattamente una soluzione ragionevole al problema. Tuttavia, apparentemente i file XAML vengono incorporati come XAML quando si imposta l'azione Crea su Risorsa anziché su Pagina. Potrebbe essere un'opzione migliore in questo modo. Ci proverò. – Joey

0

Definire le icone a livello applicazione anziché nel controllo, sia nel App.xaml o in un file dizionario XAML risorsa master. Quindi è possibile utilizzare lo stesso metodo TryFindResource, ma senza creare un'istanza del controllo.

+0

Poiché il progetto non è un'applicazione WPF ma solo il controllo utente, non vi è App.xaml. E dove woulld chiamo TryFindResource quando ho solo il ResourceDict? L'icona si trova già in uno. – Joey

1

I miei suggerimenti sono:

  • Fornire i metadati sul controllo su dove è possibile trovare l'icona. Puoi farlo con il tuo attributo personalizzato (vedi esempio 1 di seguito). Questi metadati ti permetteranno di caricare l'icona senza creare un'istanza del controllo.

  • Poiché si utilizza MEF, è possibile utilizzare i metadati nell'esportazione per ottenere lo stesso risultato sopra. Dettagli here. Vedere l'esempio 2 di seguito.

  • Tratta l'icona come ImageSource anziché Brush. Puoi usare il controllo Image di WPF per mostrare il tuo ImageSource, oppure puoi dipingerlo con un ImageBrush.

  • Utilizzare la tecnica fornita da TFD per leggere la risorsa con il nome specificato nei metadati. Sfortunatamente, WPF non sembra fornire nulla come un BamlReader, il che renderebbe molto più pulito caricare la risorsa WPF da un contesto non WPF.

Esempio 1:

[Icon("MyIconResourceName")] 
public class BlahControl : Control 
{ 
    ... 
} 

Esempio 2:

[Export(typeof(IApplicationComponent))] 
[ExportMetadata("IconResource", "MyIconResourceName")] 
public class BlahControl : Control 
{ 
    ... 
}