2009-05-11 18 views
8

Je souhaite éviter de placer un objet EditorAttribute sur chaque instance d'un certain type pour lequel j'ai écrit un UITypeEditor personnalisé.Comment injecter un UITypeEditor personnalisé pour toutes les propriétés d'un type à source fermée?

Je ne peux pas placer un objet EditorAttribute sur le type car je ne peux pas modifier la source.

J'ai une référence à la seule instance de PropertyGrid qui sera utilisée. Puis-je demander à une instance PropertyGrid (ou à toutes les instances) d'utiliser un UITypeEditor personnalisé à chaque fois qu'il rencontre un type spécifique?

Here est un article MSDN qui fournit un point de départ sur la façon de faire cela dans .NET 2.0 ou supérieur.

Répondre

16

Vous pouvez généralement associer des éditeurs, etc. à l'exécution via TypeDescriptor.AddAttributes. Par exemple (la Bar propriété doit montrer un « ... » qui affiche « Edition »):

using System; 
using System.ComponentModel; 
using System.Drawing.Design; 
using System.Windows.Forms; 

class Foo 
{ 
    public Foo() { Bar = new Bar(); } 
    public Bar Bar { get; set; } 
} 
class Bar 
{ 
    public string Value { get; set; } 
} 

class BarEditor : UITypeEditor 
{ 
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) 
    { 
     return UITypeEditorEditStyle.Modal; 
    } 
    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) 
    { 
     MessageBox.Show("Editing!"); 
     return base.EditValue(context, provider, value); 
    } 
} 
static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     TypeDescriptor.AddAttributes(typeof(Bar), 
      new EditorAttribute(typeof(BarEditor), typeof(UITypeEditor))); 
     Application.EnableVisualStyles(); 
     Application.Run(new Form { Controls = { new PropertyGrid { SelectedObject = new Foo() } } }); 
    } 
} 
+0

Marc, bien joué. Je vous aurais conseillé de créer un descripteur de type personnalisé et le fournisseur pour le publier, mais votre méthode est un bon raccourci pour enregistrer le fournisseur derrière la scène et injecter l'éditeur !! J'ai appris quelque chose. –

+0

Wow, c'est très simple en pratique. Merci! –

+0

C'est parfait! Je travaille sur une bibliothèque de dessin et je voulais fournir le support de l'éditeur PropertyGrid pour les objets sans prendre une dépendance sur Windows Forms de la bibliothèque d'objets afin de décorer les propriétés. Cette solution me permet de créer les éditeurs en dehors de la bibliothèque principale et de les ajouter lors de l'exécution. –

0

Ajoutez simplement Editor attribute à votre cours.

+2

Bonne idée, mais j'ai oublié de mentionner que je ne peux pas placer un EditorAttribute sur le type car je ne peux pas modifier la source. –

3

solution de Marc applique brutalement le EditorAttribute au barreau de type dans le monde. Si vous avez une disposition délicate, vous pouvez plutôt annoter les propriétés d'une instance spécifique. Hélas, ce n'est pas possible avec TypeDescriptor.AddAttributes

Ma solution était d'écrire un wrapper ViewModel<T>, qui copie les propriétés de T, en annotant certaines avec des attributs supplémentaires. Supposons que nous ayons une datum variable de rapport de type, nous utiliserions comme ça

 var pretty = ViewModel<Report>.DressUp(datum); 
     pretty.PropertyAttributeReplacements[typeof(Smiley)] = new List<Attribute>() { new EditorAttribute(typeof(SmileyEditor),typeof(UITypeEditor))}; 
     propertyGrid1.SelectedObject = pretty; 

ViewModel<T> est défini:

public class ViewModel<T> : CustomTypeDescriptor 
{ 
    private T _instance; 
    private ICustomTypeDescriptor _originalDescriptor; 
    public ViewModel(T instance, ICustomTypeDescriptor originalDescriptor) : base(originalDescriptor) 
    { 
     _instance = instance; 
     _originalDescriptor = originalDescriptor; 
     PropertyAttributeReplacements = new Dictionary<Type,IList<Attribute>>(); 
    } 

    public static ViewModel<T> DressUp(T instance) 
    { 
     return new ViewModel<T>(instance, TypeDescriptor.GetProvider(instance).GetTypeDescriptor(instance)); 
    } 

    /// <summary> 
    /// Most useful for changing EditorAttribute and TypeConvertorAttribute 
    /// </summary> 
    public IDictionary<Type,IList<Attribute>> PropertyAttributeReplacements {get; set; } 

    public override PropertyDescriptorCollection GetProperties (Attribute[] attributes) 
    { 
     var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>(); 

     var bettered = properties.Select(pd => 
      { 
       if (PropertyAttributeReplacements.ContainsKey(pd.PropertyType)) 
       { 
        return TypeDescriptor.CreateProperty(typeof(T), pd, PropertyAttributeReplacements[pd.PropertyType].ToArray()); 
       } 
       else 
       { 
        return pd; 
       } 
      }); 
     return new PropertyDescriptorCollection(bettered.ToArray()); 
    } 

    public override PropertyDescriptorCollection GetProperties() 
    { 
     return GetProperties(null); 
    } 
} 

Tel que défini ci-dessus, ce substitue les propriétés d'un type particulier, mais vous peut substituer des propriétés par nom si vous avez besoin de la plus grande résolution.

+0

Depuis décidé c'est beaucoup trop faff, et d'utiliser la solution globale beaucoup plus simple. –

+0

Nous sommes retournés à l'utilisation de ceci, mais ATTENTION il pourrait être incompatible avec les objets implémentant ICustomTypeDescriptor –