2009-05-11 9 views
8

Ich möchte vermeiden, ein EditorAttribute für jede Instanz eines bestimmten Typs, für den ich einen benutzerdefinierten UITypeEditor geschrieben habe, zu platzieren.Wie injiziere ich einen benutzerdefinierten UITypeEditor für alle Eigenschaften eines Closed-Source-Typs?

Ich kann kein EditorAttribute auf dem Typ platzieren, da ich die Quelle nicht ändern kann.

Ich habe einen Verweis auf die einzige PropertyGrid-Instanz, die verwendet wird.

Kann ich einer PropertyGrid-Instanz (oder allen Instanzen) mitteilen, einen benutzerdefinierten UITypeEditor zu verwenden, wenn ein bestimmter Typ gefunden wird?

Here ist ein MSDN-Artikel, der als Ausgangspunkt für .NET 2.0 oder höher zur Verfügung steht.

Antwort

16

Sie können Editoren usw. zur Laufzeit normalerweise über TypeDescriptor.AddAttributes verknüpfen. Zum Beispiel (die Bar Eigenschaft sollte mit einem „...“ zeigen, die anzeigt, ‚Bearbeiten‘):

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, gut gemacht. Ich hätte empfohlen, einen benutzerdefinierten Typdeskriptor und den Provider zu veröffentlichen, aber Ihre Methode ist eine gute Abkürzung, um den Anbieter hinter der Szene zu registrieren und den Editor zu injizieren !! Etwas gelernt. –

+0

Wow, das ist in der Praxis sehr einfach. Vielen Dank! –

+0

Das ist perfekt! Ich arbeite an einer Zeichnungsbibliothek und wollte PropertyGrid-Editor-Unterstützung für Objekte bereitstellen, ohne eine Abhängigkeit von Windows Forms aus der Objektbibliothek zu nehmen, um die Eigenschaften zu dekorieren. Diese Lösung ermöglicht es mir, die Editoren außerhalb der Kernbibliothek zu erstellen und sie zur Laufzeit hinzuzufügen. –

0

Fügen Sie Ihrer Klasse einfach einen Editor attribute hinzu.

+2

Großartige Idee, aber ich habe vergessen zu erwähnen, dass ich ein EditorAttribute nicht auf den Typ legen kann, weil ich die Quelle nicht ändern kann. –

3

Marc-Lösung gilt unverblümt die Editor an die Bar global geben. Wenn Sie eine delikate Disposition haben, können Sie Eigenschaften bestimmter Instanzen annotieren. Leider ist das mit TypeDescriptor.AddAttributes

nicht möglich Meine Lösung war, einen Wrapper ViewModel<T> zu schreiben, der Eigenschaften von T kopiert, einige mit zusätzlichen Attributen annotierend. Angenommen, wir haben eine variable datum vom Typ Report, würden wir es verwenden, wie diese

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

Wo ViewModel<T> definiert:

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

Wie oben definiert, diese ersetzt Eigenschaften eines bestimmten Typs, aber Sie kann Eigenschaften nach Namen ersetzen, wenn Sie die größere Auflösung benötigen.

+0

Seit entschieden, das ist viel zu viel faff, und die viel einfachere globale Lösung zu verwenden. –

+0

Ging zurück zur Verwendung dieser, aber WARNING ist möglicherweise nicht mit Objekten kompatibel, die ICustomTypeDescriptor implementieren –