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
{
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With