Reputation: 4134
I’ve created my own plugin architecture based on the common practices but I’m stuck with icons.
First of all my plugins define Clients to be used by the host and each Client is defined with attributes like:
[Client("Heroes of Newerth", "Heroes of Newerth Chat Client", "hon_16.png")]
With this my host application can read the plugin/client's metainfo without actually creating an instance of it but I’m stuck with the icon part.
As in the above example a client can pass a bitmap file name and in my attributes implementation I can handle it like this:
[AttributeUsage(AttributeTargets.Class)]
public class ClientAttribute : Attribute
{
private string _name;
private string _description;
private Bitmap _icon;
public string Name { get { return this._name; } }
public string Description { get { return this._description; } }
public Bitmap Icon { get { return this._icon; } }
public ClientAttribute(string Name, string Description, string IconFile = null)
{
this._name = Name;
this._description = Description;
this._icon = new Bitmap(IconFile);
}
}
The problem is that within this method I need to publish the icon files with my release as is and can't add them to resources. I'll be happy to hear a method that I can still embed the icons in resources.
Upvotes: 2
Views: 1090
Reputation: 4134
Thanks to timwi here's my final implementation;
internal void ResolveResources(Assembly _assembly)
{
if (_assembly != null && this._icon_name != null)
{
var stream = _assembly.GetManifestResourceStream(string.Format("{0}.Resources.{1}",_assembly.GetName().Name,this._icon_name));
if (stream != null) this._icon = new Bitmap(stream);
}
}
And in my PluginInfo class i call the resolver;
else if(t.IsSubclassOf(typeof(Client)))
{
object[] _attr = t.GetCustomAttributes(typeof(ClientAttribute), true);
(_attr[0] as ClientAttribute).ResolveResources(this._assembly);
}
Upvotes: 0
Reputation: 66573
You can add them to the resources, and then access the resources from the custom attribute. However, you need a reference to the plugin’s assembly, so you can’t do it in the constructor. I would do it like this:
[AttributeUsage(AttributeTargets.Class)]
public class ClientAttribute : Attribute
{
private string _name;
private string _description;
private string _resourceName;
private Bitmap _icon;
public string Name { get { return this._name; } }
public string Description { get { return this._description; } }
public Bitmap Icon { get { return this._icon; } }
public ClientAttribute(string name, string description, string resourceName = null)
{
_name = name;
_description = description;
_resourceName = resourceName;
}
public void ResolveResource(Assembly assembly)
{
if (assembly != null && _resourceName != null)
{
var stream = assembly.GetManifestResourceStream(_resourceName);
if (stream != null)
_icon = new Bitmap(stream);
}
}
}
Of course, this means that when you first retrieve the custom attribute, the Icon
property will return null until you call Resolve
with the correct assembly. I’ve written it so that it stays null if there are problems; you need to decide whether you want to throw exceptions instead. In particular, maybe the Icon
property getter should throw an exception when _icon
is null but _resourceName
isn’t, because then it means that Resolve
wasn’t called, or there was a problem. (You should still be aware that even Resolve
can throw because GetManifestResourceStream
or the Bitmap
constructor might throw.)
Upvotes: 2
Reputation: 54724
can't add them to resources
Why not? You could define IconFile
as the name of a resource within the same assembly as the plugin. Then, given an Assembly
that contains the plugin, call assembly.GetManifestResourceStream
and pass that stream to the Bitmap
constructor.
Upvotes: 0