2010-08-18 6 views
2

J'ai créé ma propre architecture de plugin basée sur les pratiques courantes mais je suis coincé avec des icônes.Comment créer un attribut Icon pour un plugin en C#?

d'abord tous mes plugins définissent les clients à utiliser par l'hôte et chaque client est définie avec des attributs tels que:

[Client("Heroes of Newerth", "Heroes of Newerth Chat Client", "hon_16.png")] 

Avec cette ma application hôte peut lire sans réellement créer une instance de méta-informations du plugin/client mais je suis coincé avec la partie icône.

Comme dans l'exemple ci-dessus un client peut passer un nom de fichier bitmap et dans ma mise en œuvre des attributs je peux gérer comme ceci:

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

Le problème est que, dans cette méthode, je dois publier les fichiers d'icônes avec ma version comme est et ne peut pas les ajouter aux ressources. Je serai heureux d'entendre une méthode que je peux encore intégrer les icônes dans les ressources.

+0

Est-ce WinForms ou WPF? – flq

+1

En aparté, vous ne devriez probablement pas appeler 'new bitmap (IconFile)' quand 'IconFile' est' null'. – Timwi

+0

ouais je viens de coller le squelette ici et c'est winforms. – HuseyinUslu

Répondre

0

Merci à timwi voici ma dernière implémentation;

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

Et dans ma classe PluginInfo j'appelle le résolveur;

  else if(t.IsSubclassOf(typeof(Client))) 
      { 
       object[] _attr = t.GetCustomAttributes(typeof(ClientAttribute), true); 
       (_attr[0] as ClientAttribute).ResolveResources(this._assembly); 
      } 
0

ne peut pas les ajouter aux ressources

Pourquoi pas? Vous pouvez définir IconFile comme nom d'une ressource dans le même assembly que le plug-in. Ensuite, étant donné un Assembly qui contient le plugin, appelez assembly.GetManifestResourceStream et passez ce flux au constructeur Bitmap.

+0

J'ai essayé cette solution une fois mais le problème est que je ne peux pas obtenir l'assemblage réel des ressources dans le ctor de l'attribut. Tout d'abord j'ai 3 assemblages séparés dans mon projet; l'ensemble d'interface utilisateur, l'ensemble hôte et l'ensemble plugin. Après l'exécution, il semble que mscorlib est l'appelant, l'assembly ui est le participant et l'assembly hôte l'exécuteur du code. Si je pouvais obtenir une référence à l'assemblage de plugins, je pourrais mettre en œuvre la méthode que vous avez mentionnée. – HuseyinUslu

+0

Ce que vous pouvez faire dans un constructeur d'attributs est assez limité. C'est limité par le fait que l'attribut ne peut pas savoir à quoi il a été appliqué. Une meilleure approche consiste pour l'attribut à exposer ces trois valeurs en tant que propriétés, et déplacez le code de chargement vers quelque part qui peut voir le plugin 'Type'. –

2

Vous pouvez les ajouter aux ressources, puis accéder aux ressources à partir de l'attribut personnalisé. Cependant, vous avez besoin d'une référence à l'assembly du plugin, vous ne pouvez donc pas le faire dans le constructeur. Je le ferais comme ceci:

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

Bien sûr, cela signifie que lorsque vous récupérez l'attribut personnalisé, la propriété Icon renvoie null jusqu'à ce que vous appelez Resolve avec l'ensemble correct. Je l'ai écrit pour qu'il reste nul s'il y a des problèmes; vous devez décider si vous voulez lancer des exceptions à la place. En particulier, peut-être que la propriété Icon getter devrait lever une exception quand _icon est nulle mais _resourceName ne l'est pas, car cela signifie que Resolve n'a pas été appelée, ou il y a eu un problème. (Vous devriez toujours être conscient que même Resolve peut lancer car GetManifestResourceStream ou le constructeur Bitmap pourrait lancer.)

+0

il semble que votre réponse est assez viable, car pour mon architecture j'ai une classe PluginInfo où je reçois des métainfo sur les plugins et les instaure. Cela peut être un bon point pour résoudre l'assembly de ClientAttribute car le PluginInfo connaît l'assembly. Je vais essayer cette implémentation mais j'ai aussi cherché sur google pour d'autres exemples d'architectures de plugins où la plupart d'entre elles expose des attributs de plugin avec un nom et une description mais aucun n'utilise l'attribut d'icône. Il serait bon de voir comment les autres sont surmontés avec le problème. – HuseyinUslu

Questions connexes