Acessing WPF XAML Resources from non

I am currently building an application that consists of several components, each of which is essentially a WPF user control with a little C# code around it for the plugin system to work (using MEF).

The problem I am having is that each component should include an icon and for niceness purposes I defined that as a System.Windows.Media.Brush so I can just use the DrawingBrush exported from Design there. Now I need to access that piece of XAML from non-WPF C# where I currently have the horrible workaround of instantiating the user control and asking it for the resource:

private Brush CachedIcon = null;

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

I couldn't find a way to read that resource (which is a .xaml file, and referenced in a ResourceDictionary in the custom control) from a "normal" C# class. Anything belonging to WPF has that nice TryFindResource method but how to do that otherwise? I don't want to have the XAML file with the icon lying around un-embedded.


In your XAML code make sure the icon resource has the build option set to "Resource", and then reference the resource to make it a xaml static resource

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

Then in your .Net 2.0 code you will find the resource in the "{xamlName}.g.resource" stream

Example code that loads all icons from a xaml dll into a dictionary:

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

My suggestions are:

  • Provide metadata on your control about where the icon can be found. You can do this with your own custom attribute (see example 1 below). This metadata will allow you to load the icon without creating an instance of the control.

  • Since you're using MEF, you can use metadata in your export to achieve the same as above. Details here. See example 2 below.

  • Treat your icon as an ImageSource rather than a Brush . You can use WPF's Image control to show your ImageSource , or you can paint it with an ImageBrush .

  • Use the technique provided by TFD to read the resource with the name specified in the metadata. Unfortunately, WPF does not appear to provide anything like a BamlReader , which would make it much cleaner to load the WPF resource from a non-WPF context.

  • Example 1:

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

    Example 2:

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

    You can read resources from your assembly as stream.

    Example code here: http://www.wpftutorial.net/ReadWPFResourcesFromWinForms.html

    链接地址: http://www.djcxy.com/p/50430.html

    上一篇: 如何在XAML中引用图像资源?

    下一篇: 使用非WPF XAML资源