Accesso alle risorse WAM XAML da codice non WPF
-
03-07-2019 - |
Domanda
Attualmente sto creando un'applicazione che consiste di diversi componenti, ognuno dei quali è essenzialmente un controllo utente WPF con un po 'di codice C # attorno perché il sistema di plugin funzioni (usando MEF).
Il problema che sto riscontrando è che ogni componente dovrebbe includere un'icona e per motivi di gentilezza l'ho definito come System.Windows.Media.Brush
in modo da poter semplicemente usare DrawingBrush
esportato da Design lì. Ora ho bisogno di accedere a quel pezzo di XAML da un C # non WPF dove attualmente ho la terribile soluzione di istanziare il controllo utente e chiedergli la risorsa:
private Brush CachedIcon = null;
public override Brush Icon
{
get
{
if (CachedIcon == null)
{
CachedIcon = (Brush)(new BlahControl().TryFindResource("Icon"));
}
return CachedIcon;
}
}
Non sono riuscito a trovare un modo per leggere quella risorsa (che è un file .xaml e referenziato in un ResourceDictionary
nel controllo personalizzato) da un " normale " Classe C #. Qualcosa appartenente a WPF ha quel bel metodo TryFindResource
ma come fare altrimenti? Non voglio avere il file XAML con l'icona che si trova attorno non incorporata.
Soluzione
Nel tuo codice XAML assicurati che la risorsa icona abbia l'opzione di compilazione impostata su " Resource " ;, quindi fai riferimento alla risorsa per renderla una risorsa statica xaml
<UserControl.Resources>
<BitmapImage x:Key="icon1" UriSource="Resources/Icon1.ico" />
</UserControl.Resources>
Quindi nel tuo codice .Net 2.0 troverai la risorsa in " {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);
}
}
}
Altri suggerimenti
I miei suggerimenti sono:
-
Fornisci metadati sul tuo controllo su dove si trova 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.
-
Dato che stai utilizzando MEF, puoi utilizzare i metadati nell'esportazione per ottenere lo stesso risultato di cui sopra. Dettagli qui . Vedi l'esempio 2 di seguito.
-
Tratta la tua icona come un
ImageSource
piuttosto che unBrush
. Puoi usare il controlloImage
di WPF per mostrare il tuoImageSource
, oppure puoi dipingerlo con unImageBrush
. -
Utilizzare la tecnica fornita da TFD per leggere la risorsa con il nome specificato nei metadati. Sfortunatamente, WPF non sembra fornire nulla di simile a un
BamlReader
, il che renderebbe molto più pulito il caricamento della 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
{
...
}
Puoi leggere le risorse dal tuo assembly come stream.
Codice di esempio qui: http://www.wpftutorial.net/ReadWPFResourcesFromWinForms.html
Definisci le icone a livello di app anziché nel controllo, nel file xaml del dizionario delle risorse master o app.xaml. Quindi puoi utilizzare lo stesso metodo TryFindResource, ma senza creare un'istanza del controllo.