2009-03-03 18 views
7

Actualmente estoy construyendo una aplicación que consta de varios componentes, cada uno de los cuales es esencialmente un control de usuario WPF con un pequeño código C# para que el sistema de complemento funcione (usando MEF) .Acessing WPF XAML Resources from non-WPF code

El problema que tengo es que cada componente debe incluir un icono y para fines de simpatía lo definí como System.Windows.Media.Brush, así que puedo usar el DrawingBrush exportado desde Diseño allí. Ahora necesito acceder a ese pedazo de XAML de la no-WPF C#, donde actualmente tengo la solución horrible de la instancia del control de usuario y pidiendo que para el recurso:

private Brush CachedIcon = null; 

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

no pude encontrar una manera de leer que recurso (que es un archivo .xaml, y se hace referencia en un ResourceDictionary en el control personalizado) de una clase C# "normal". Todo lo que pertenece a WPF tiene ese buen método TryFindResource, pero ¿cómo hacerlo? No quiero tener el archivo XAML con el ícono sin incrustar.

Respuesta

2

En su código XAML asegúrese de que el recurso de icono tiene la opción de generación establecido en "Recursos", y luego hacer referencia al recurso para que sea un recurso estático xaml

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

Luego, en el código .Net 2.0 se se encuentra el recurso en el "{} xamlName .g.resource" corriente

código de ejemplo que carga todos los iconos de un archivo DLL xaml en un diccionario:

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

Parece que funciona, pero parece muy cutre. Depender de los nombres internos de los recursos generados automáticamente no me parece muy recomendable. – Joey

+0

Ehh? Los recursos tienen nombres de cadenas, ¡no hay nada que puedas hacer al respecto! ¿Qué estás buscando? – TFD

+0

Me preguntaba qué tan confiable será la cosa ".g.resources". He leído lo suficiente sobre el blog de Raymond Chen que realmente no quiero usar nada que pueda romperse porque es solo un artefacto de la implementación, un comportamiento no documentado. – Joey

0

Puede leer recursos de su conjunto como transmisión.

Código de ejemplo aquí: http://www.wpftutorial.net/ReadWPFResourcesFromWinForms.html

+0

Hmm, no podía conseguir que funcione en este momento, intentará agani más tarde. Pero esto tampoco me parece exactamente una solución sensata al problema. Sin embargo, aparentemente los archivos XAML se incrustan como XAML al configurar la acción de compilación en el recurso en lugar de la página. Podría ser una mejor opción de esa manera. Lo intentaré. – Joey

0

Definir los iconos en el nivel de aplicación en lugar de en el control, ya sea en el App.xaml o un archivo de diccionario de recursos XAML maestro. Luego puede usar el mismo método TryFindResource, pero sin crear una instancia del control.

+0

Como el proyecto no es una aplicación WPF sino solo el control del usuario, no hay App.xaml. ¿Y a dónde llamaré TryFindResource si solo tengo el ResourceDict? El icono ya reside en uno. – Joey

1

Mis sugerencias son:

  • Proporcione metadatos sobre su control sobre dónde se puede encontrar el icono. Puede hacerlo con su propio atributo personalizado (vea el ejemplo 1 a continuación). Estos metadatos le permitirán cargar el ícono sin crear una instancia del control.

  • Dado que está utilizando MEF, puede usar metadatos en su exportación para lograr lo mismo que el anterior. Detalles here. Vea el ejemplo 2 a continuación.

  • Trate su icono como ImageSource en lugar de Brush. Puede usar el control Image de WPF para mostrar su ImageSource, o puede pintarlo con un ImageBrush.

  • Utilice la técnica provista por TFD para leer el recurso con el nombre especificado en los metadatos. Desafortunadamente, WPF no parece proporcionar nada como un BamlReader, lo que haría mucho más limpio cargar el recurso WPF desde un contexto que no sea WPF.

Ejemplo 1:

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

Ejemplo 2:

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