2009-05-11 16 views
8

Voglio evitare di posizionare un EditorAttribute su ogni istanza di un certo tipo per cui ho scritto un UITypeEditor personalizzato.Come si inietta un UITypeEditor personalizzato per tutte le proprietà di un tipo closed-source?

Non riesco a inserire un EditorAttribute sul tipo perché non riesco a modificare l'origine.

Ho un riferimento all'unica istanza di PropertyGrid che verrà utilizzata.

Posso dire a un'istanza PropertyGrid (oa tutte le istanze) di utilizzare un UITypeEditor personalizzato ogni volta che incontra un tipo specifico?

Here è un articolo MSDN che fornisce il punto di partenza su come eseguire questa operazione in .NET 2.0 o versioni successive.

risposta

16

In genere è possibile associare gli editor ecc. Al runtime tramite TypeDescriptor.AddAttributes. Per esempio (la proprietà Bar dovrebbe mostrare con un "..." che visualizza 'Modifica'): la soluzione

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, ben fatto. Avrei consigliato di creare un descrittore di tipo personalizzato e il provider per pubblicarlo, ma il tuo metodo è una buona scorciatoia per registrare il provider dietro la scena e iniettare l'editor !! Imparato qualcosa –

+0

Wow, è molto semplice nella pratica. Grazie! –

+0

Questo è perfetto! Sto lavorando su una libreria di disegni e volevo fornire il supporto dell'editor PropertyGrid per gli oggetti senza prendere una dipendenza da Windows Form dalla libreria di oggetti per decorare le proprietà. Questa soluzione mi consente di creare gli editor all'esterno della libreria principale e aggiungerli in fase di runtime. –

0

Basta aggiungere un Editor attribute alla classe.

+2

Ottima idea, ma ho dimenticato di menzionare che non posso inserire un EditorAttribute sul tipo perché non posso modificare l'origine. –

3

di Marc applica senza mezzi termini l'EditorAttribute al bar tipo a livello mondiale. Se si dispone di una disposizione delicata, è preferibile annotare le proprietà di istanze specifiche. Purtroppo, questo non è possibile con TypeDescriptor.AddAttributes

La mia soluzione era scrivere un wrapper ViewModel<T>, che copia le proprietà da T, annotandone alcune con attributi aggiuntivi. Supponiamo di avere una variabile di tipo datum relazione, saremmo usare in questo modo

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

Dove ViewModel<T> è definito:

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

come sopra definito, questo sostituisce le proprietà di un tipo specifico, ma si può sostituire le proprietà per nome se è necessaria la risoluzione maggiore.

+0

Da quando è stato deciso questo è troppo falso, e usare la soluzione globale molto più semplice. –

+0

Torna a utilizzare questo, ma ATTENZIONE potrebbe essere incompatibile con gli oggetti che implementano ICustomTypeDescriptor –

Problemi correlati